6ea140af54
feat(chemistry-8): Phase 1 — раздел «Количественные понятия» (§1–9 + ПР1) Полноценная интерактивная страница chemistry_8_intro.html (9 § + ПР1 + босс): - §1 карта элементов (Z, название, Ar), §2 калькулятор Mr по формуле - §3 «порция вещества» n⇒N,m, §4 счётчик частиц N=n·N_A, §5 M+молярный объём - §6 звёздный виджет: интерактивный треугольник n–m–M - §7 универсальный калькулятор газа (m–n–V–N), §8 балансировщик уравнений - §9 пошаговый решатель по уравнению; босс раздела (4 задачи) + ачивка «Счёт в химии» - прогресс/XP через /api/textbooks/chemistry-8-intro/progress, scrollspy, тема chem8_svg.js: реализованы движки — molarMass (школьные Ar: Mr(H2O)=18), elementCounts, moleTriangle, equationBalancer (+ fmt, arOf). Фикс порядка загрузки: инициализация обёрнута в DOMContentLoaded (defer-скрипты готовы к этому моменту). Генератор каркасов получил skip-if-exists (--force для перезаписи). Тесты: chemistry8.test.js (14) + chemistry8-dom.test.js (jsdom-смоук виджетов, 3) — 17/17. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
783 lines
55 KiB
HTML
783 lines
55 KiB
HTML
<!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@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.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}],throwOnError:false})"></script>
|
||
<script src="/js/api.js" defer></script>
|
||
<script src="/js/xp.js" defer></script>
|
||
<script src="/js/biochem-core.js" defer></script>
|
||
<script src="/js/chem8_svg.js" defer></script>
|
||
<style>
|
||
:root{
|
||
--bg:#fffbeb; --card:#fff; --card-soft:#fef9ec; --text:#1c1917; --muted:#78716c; --border:#f0e6cf;
|
||
--pri:#d97706; --pri-d:#b45309; --pri-l:#fbbf24; --pri-soft:#fef3c7;
|
||
--ok:#15803d; --ok-bg:#dcfce7; --bad:#b91c1c; --bad-bg:#fee2e2; --warn:#b45309; --warn-bg:#fef3c7;
|
||
--sh:0 1px 3px rgba(120,80,10,.07); --sh2:0 8px 28px rgba(120,80,10,.13);
|
||
--mono:'JetBrains Mono',ui-monospace,monospace;
|
||
}
|
||
html.dark{ --bg:#1c1410; --card:#271c14; --card-soft:#2e2118; --text:#fef3c7; --muted:#c9ab82; --border:#4a3520;
|
||
--pri-soft:rgba(217,119,6,.18); --ok-bg:rgba(21,128,61,.2); --bad-bg:rgba(185,28,28,.2); --warn-bg:rgba(180,83,9,.2); }
|
||
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
|
||
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}
|
||
a{color:inherit}
|
||
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}
|
||
|
||
/* HEADER */
|
||
.hdr{position:relative;background:linear-gradient(110deg,#92400e 0%,#d97706 55%,#fbbf24 100%);color:#fff;padding:34px 24px 30px;overflow:hidden;border-bottom:2px solid rgba(255,255,255,.18)}
|
||
.hdr::before{content:'ВВОДНЫЙ РАЗДЕЛ';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(3rem,9vw,7rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(255,255,255,.12);line-height:1;pointer-events:none;user-select:none;z-index:0;white-space:nowrap}
|
||
.hdr-inner{position:relative;z-index:1;max-width:1180px;margin:0 auto;display:flex;align-items:center;gap:16px;flex-wrap:wrap}
|
||
.hdr-back{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;background:rgba(255,255,255,.16);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,.26)}
|
||
.hdr-kicker{font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.14em;opacity:.85}
|
||
.hdr h1{font-family:'Outfit',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.25;margin-top:3px}
|
||
.hdr-side{margin-left:auto;display:flex;gap:8px}
|
||
.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}
|
||
.hdr-btn:hover{background:rgba(255,255,255,.26)}
|
||
|
||
/* HERO */
|
||
.hero{max-width:1180px;margin:18px auto 0;padding:0 24px}
|
||
.hero-card{background:linear-gradient(135deg,var(--pri-soft),rgba(251,191,36,.1));border:1px solid var(--border);border-radius:16px;padding:16px 20px;display:flex;gap:16px;align-items:center;flex-wrap:wrap}
|
||
.hero-ic{width:46px;height:46px;border-radius:12px;background:linear-gradient(135deg,#d97706,#fbbf24);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-family:'Outfit';font-weight:900;font-size:1.2rem}
|
||
.hero-t{flex:1;min-width:180px}
|
||
.hero-lab{font-size:.74rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
|
||
.hero-bar{height:8px;background:rgba(217,119,6,.16);border-radius:5px;overflow:hidden;margin-top:6px}
|
||
.hero-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--pri-l));border-radius:5px;width:0;transition:width .5s}
|
||
.hero-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;background:linear-gradient(135deg,#f59e0b,var(--pri));color:#fff;border-radius:99px;font-size:.8rem;font-weight:800;font-family:'Unbounded'}
|
||
|
||
/* LAYOUT */
|
||
.wrap{max-width:1180px;margin:0 auto;padding:24px;display:grid;grid-template-columns:240px 1fr;gap:26px;align-items:start}
|
||
@media(max-width:900px){.wrap{grid-template-columns:1fr;padding:16px}}
|
||
.side{position:sticky;top:14px;background:var(--card);border:1px solid var(--border);border-radius:14px;padding:10px;box-shadow:var(--sh);max-height:calc(100vh - 28px);overflow:auto}
|
||
@media(max-width:900px){.side{position:static;max-height:none}}
|
||
.side-h{font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);padding:6px 10px}
|
||
.side a{display:flex;gap:9px;align-items:center;padding:8px 10px;border-radius:9px;text-decoration:none;font-size:.86rem;color:var(--text);transition:background .14s}
|
||
.side a:hover{background:var(--pri-soft)}
|
||
.side a.active{background:var(--pri-soft);color:var(--pri-d);font-weight:700}
|
||
.side a.note{color:var(--muted);font-size:.8rem}
|
||
.side-num{font-weight:800;color:var(--pri);min-width:30px;font-size:.82rem}
|
||
.side a.done .side-num::after{content:'\2713';margin-left:3px;color:var(--ok)}
|
||
|
||
/* SECTIONS */
|
||
.col{min-width:0;display:flex;flex-direction:column;gap:26px}
|
||
.sec{scroll-margin-top:14px}
|
||
.ph{border-radius:16px;padding:20px 22px;color:#fff;position:relative;overflow:hidden;background:linear-gradient(135deg,var(--pri-d),var(--pri) 60%,var(--pri-l))}
|
||
.ph::after{content:'';position:absolute;right:-30px;top:-30px;width:150px;height:150px;border-radius:50%;background:rgba(255,255,255,.1)}
|
||
.ph-num{font-size:.72rem;font-weight:800;letter-spacing:.1em;text-transform:uppercase;opacity:.85}
|
||
.ph h2{font-family:'Outfit';font-size:1.22rem;font-weight:800;margin:4px 0 8px;line-height:1.25;position:relative;z-index:1}
|
||
.ph-key{display:inline-block;background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.25);border-radius:10px;padding:6px 14px;font-size:.95rem;font-weight:700;position:relative;z-index:1}
|
||
|
||
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px 18px;box-shadow:var(--sh)}
|
||
.card+.card{margin-top:14px}
|
||
.card h3{font-family:'Outfit';font-size:1rem;font-weight:800;margin-bottom:8px;display:flex;align-items:center;gap:8px}
|
||
.card h3 .tg{font-size:.64rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em;padding:2px 8px;border-radius:99px;background:var(--pri-soft);color:var(--pri-d)}
|
||
.card p{font-size:.94rem;margin-bottom:8px}
|
||
.card p:last-child{margin-bottom:0}
|
||
.card ul{margin:6px 0 8px 20px;font-size:.92rem}
|
||
.card li{margin-bottom:4px}
|
||
.def{background:var(--pri-soft);border-left:4px solid var(--pri);border-radius:0 10px 10px 0;padding:11px 14px;font-size:.94rem;margin:8px 0}
|
||
.def b{color:var(--pri-d)}
|
||
html.dark .def b{color:var(--pri-l)}
|
||
.exa{background:var(--card-soft);border:1px dashed var(--border);border-radius:10px;padding:12px 14px;font-size:.92rem;margin-top:8px}
|
||
.exa .step{margin:5px 0;padding-left:14px;position:relative}
|
||
.exa .step::before{content:'';position:absolute;left:0;top:9px;width:6px;height:6px;border-radius:50%;background:var(--pri)}
|
||
.note-safe{display:flex;gap:9px;background:var(--warn-bg);border:1px solid var(--pri-l);border-radius:10px;padding:10px 13px;font-size:.88rem;margin-top:8px}
|
||
.note-safe svg{stroke:var(--pri-d);margin-top:2px}
|
||
|
||
/* WIDGET shell */
|
||
.wgt{background:var(--card);border:1.5px solid var(--pri-soft);border-radius:14px;padding:16px 18px;box-shadow:var(--sh);margin-top:14px}
|
||
.wgt-h{font-family:'Outfit';font-size:.96rem;font-weight:800;color:var(--pri-d);margin-bottom:10px;display:flex;align-items:center;gap:8px}
|
||
html.dark .wgt-h{color:var(--pri-l)}
|
||
.wgt-h svg{stroke:var(--pri)}
|
||
.fld{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:8px 0}
|
||
.fld label{font-size:.86rem;font-weight:600;color:var(--muted)}
|
||
input[type=text],input[type=number],select{font-family:inherit;font-size:.95rem;padding:8px 11px;border:1.5px solid var(--border);border-radius:9px;background:var(--card);color:var(--text);transition:border-color .14s}
|
||
input:focus,select:focus{outline:0;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-soft)}
|
||
.btn{font-family:inherit;font-weight:700;font-size:.9rem;padding:8px 16px;border-radius:9px;border:1.5px solid var(--border);background:var(--card);color:var(--text);cursor:pointer;transition:.14s}
|
||
.btn:hover{border-color:var(--pri);background:var(--pri-soft)}
|
||
.btn.primary{background:linear-gradient(135deg,var(--pri),var(--pri-l));color:#fff;border-color:transparent}
|
||
.btn.primary:hover{filter:brightness(1.07)}
|
||
.out{margin-top:10px;padding:11px 14px;border-radius:10px;font-size:.94rem;background:var(--card-soft);border:1px solid var(--border)}
|
||
.out.ok{background:var(--ok-bg);border-color:#86efac;color:var(--ok)}
|
||
.out.bad{background:var(--bad-bg);border-color:#fca5a5;color:var(--bad)}
|
||
.bd{font-family:var(--mono);font-size:.9rem;line-height:1.7}
|
||
|
||
/* mole triangle */
|
||
.mtri{display:grid;grid-template-columns:170px 1fr;gap:16px;align-items:center}
|
||
@media(max-width:560px){.mtri{grid-template-columns:1fr}}
|
||
.mtri-svg{width:170px;height:128px;color:var(--pri)}
|
||
.mtri-fields{display:flex;flex-direction:column;gap:9px}
|
||
.mtri-f{display:flex;flex-direction:column;gap:3px}
|
||
.mtri-lab{font-size:.78rem;font-weight:700;color:var(--muted)}
|
||
.mtri-f input{width:100%}
|
||
.mtri-out{grid-column:1/-1;padding:10px 13px;border-radius:10px;background:var(--card-soft);border:1px solid var(--border);font-size:.92rem}
|
||
.mtri-out.ok{background:var(--ok-bg);border-color:#86efac;color:var(--ok)}
|
||
.mtri-out b{display:block;font-size:1.02rem}
|
||
.mtri-form{display:block;font-family:var(--mono);font-size:.84rem;opacity:.85;margin-top:3px}
|
||
|
||
/* equation balancer */
|
||
.ceqb-row{display:flex;align-items:center;gap:6px;flex-wrap:wrap;font-size:1.05rem;font-weight:600;margin-bottom:12px}
|
||
.ceqb-sp{display:inline-flex;align-items:center;gap:3px}
|
||
.ceqb-coef{width:46px;text-align:center;padding:6px 4px;font-weight:800}
|
||
.ceqb-f{font-weight:700}
|
||
.ceqb-plus,.ceqb-arrow{color:var(--muted);font-weight:800;padding:0 2px}
|
||
.ceqb-arrow{color:var(--pri);font-size:1.2rem}
|
||
.ceqb-actions{display:flex;gap:8px;flex-wrap:wrap}
|
||
.ceqb-out{margin-top:10px}
|
||
.ceqb-msg{font-weight:700;margin-bottom:6px}
|
||
.ceqb-out.ok .ceqb-msg{color:var(--ok)}
|
||
.ceqb-out.bad .ceqb-msg{color:var(--bad)}
|
||
.ceqb-tab{border-collapse:collapse;font-size:.86rem;font-family:var(--mono)}
|
||
.ceqb-tab th,.ceqb-tab td{border:1px solid var(--border);padding:4px 12px;text-align:center}
|
||
.ceqb-tab tr.ne td{background:var(--bad-bg);color:var(--bad)}
|
||
.ceqb-tab tr.eq td{background:var(--ok-bg);color:var(--ok)}
|
||
|
||
/* element lookup */
|
||
.el-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(54px,1fr));gap:6px;margin-top:8px}
|
||
.el-cell{aspect-ratio:1;border:1px solid var(--border);border-radius:8px;background:var(--card);display:flex;flex-direction:column;align-items:center;justify-content:center;cursor:pointer;transition:.12s;padding:2px}
|
||
.el-cell:hover,.el-cell.on{background:var(--pri-soft);border-color:var(--pri);transform:translateY(-2px)}
|
||
.el-cell .z{font-size:.6rem;color:var(--muted)}
|
||
.el-cell .s{font-size:1.05rem;font-weight:800;color:var(--pri-d)}
|
||
html.dark .el-cell .s{color:var(--pri-l)}
|
||
.el-cell .a{font-size:.56rem;color:var(--muted)}
|
||
.el-info{margin-top:10px;padding:12px 14px;border-radius:10px;background:var(--card-soft);border:1px solid var(--border);font-size:.94rem;min-height:48px}
|
||
|
||
/* trainer / proverka */
|
||
.tr{margin-top:12px;background:var(--card-soft);border:1px solid var(--border);border-radius:12px;padding:13px 15px}
|
||
.tr-q{font-size:.94rem;font-weight:600;margin-bottom:9px}
|
||
.tr-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
||
.tr-fb{margin-top:8px;font-size:.88rem;font-weight:600;display:none}
|
||
.tr-fb.show{display:block}
|
||
.tr-fb.ok{color:var(--ok)}
|
||
.tr-fb.bad{color:var(--bad)}
|
||
.opt{padding:7px 13px;border:1.5px solid var(--border);border-radius:9px;background:var(--card);cursor:pointer;font-size:.9rem;font-weight:600;transition:.12s}
|
||
.opt:hover{border-color:var(--pri)}
|
||
.opt.ok{background:var(--ok-bg);border-color:#86efac;color:var(--ok)}
|
||
.opt.bad{background:var(--bad-bg);border-color:#fca5a5;color:var(--bad)}
|
||
|
||
/* mark read */
|
||
.mark{margin-top:14px;display:flex;gap:10px;align-items:center;flex-wrap:wrap}
|
||
.mark .btn.primary{padding:9px 18px}
|
||
.mark .done-lab{font-size:.86rem;font-weight:700;color:var(--ok);display:none;align-items:center;gap:6px}
|
||
.mark.done .done-lab{display:inline-flex}
|
||
.mark.done .btn{display:none}
|
||
|
||
/* boss */
|
||
.boss{background:var(--card);border:2px solid var(--pri-soft);border-radius:16px;padding:18px;box-shadow:var(--sh2)}
|
||
.boss-h{font-family:'Outfit';font-size:1.1rem;font-weight:800;color:var(--pri-d);display:flex;align-items:center;gap:9px;margin-bottom:6px}
|
||
html.dark .boss-h{color:var(--pri-l)}
|
||
.boss-sub{font-size:.88rem;color:var(--muted);margin-bottom:12px}
|
||
.bossbar{display:flex;gap:12px;align-items:center;margin-bottom:14px;flex-wrap:wrap}
|
||
.bossbar .lab{font-weight:700;font-size:.9rem}
|
||
.bossbar .bar{flex:1;min-width:140px;height:8px;background:var(--pri-soft);border-radius:5px;overflow:hidden}
|
||
.bossbar .fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--pri-l));width:0;transition:width .5s}
|
||
.bcard{border:1.5px solid var(--border);border-radius:12px;padding:14px;margin-bottom:11px;transition:.3s}
|
||
.bcard.solved{border-color:#86efac;box-shadow:0 0 0 3px var(--ok-bg)}
|
||
.bcard .q{font-size:.95rem;margin-bottom:10px}
|
||
.bcard .q b{color:var(--pri-d)}
|
||
html.dark .bcard .q b{color:var(--pri-l)}
|
||
.bcard .row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
||
.bcard .fb{margin-top:8px;font-size:.88rem;font-weight:600;display:none}
|
||
.bcard .fb.show{display:block}
|
||
.bcard .fb.ok{color:var(--ok)}.bcard .fb.bad{color:var(--bad)}
|
||
.hintbox{margin-top:8px;padding:9px 12px;background:var(--warn-bg);border-left:3px solid var(--pri);border-radius:7px;font-size:.86rem;display:none}
|
||
.hintbox.show{display:block}
|
||
.final-cta{margin-top:14px;padding:15px 18px;border-radius:13px;background:linear-gradient(135deg,#fef3c7,#fde68a);border:1.5px solid var(--pri-l);display:none;gap:13px;align-items:center;flex-wrap:wrap}
|
||
.final-cta.show{display:flex}
|
||
html.dark .final-cta{background:linear-gradient(135deg,rgba(217,119,6,.2),rgba(180,83,9,.18))}
|
||
.final-cta b{color:#92400e;font-family:'Outfit'}
|
||
html.dark .final-cta b{color:#fde68a}
|
||
.final-cta a{margin-left:auto;padding:9px 16px;border-radius:9px;background:var(--pri);color:#fff;text-decoration:none;font-weight:700;font-size:.88rem}
|
||
|
||
.foot{text-align:center;padding:26px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:10px}
|
||
.popup{position:fixed;bottom:20px;left:50%;transform:translateX(-50%) translateY(120px);background:linear-gradient(135deg,var(--pri),var(--pri-l));color:#fff;padding:12px 22px;border-radius:12px;font-weight:700;box-shadow:var(--sh2);z-index:50;transition:transform .35s;font-size:.92rem}
|
||
.popup.show{transform:translateX(-50%) translateY(0)}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<header class="hdr">
|
||
<div class="hdr-inner">
|
||
<a href="/textbook/chemistry-8" class="hdr-back">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
|
||
К разделам
|
||
</a>
|
||
<div>
|
||
<div class="hdr-kicker">Вводный раздел · § 1–9 · ПР 1</div>
|
||
<h1>Количественные понятия в химии</h1>
|
||
</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>
|
||
|
||
<div class="hero">
|
||
<div class="hero-card">
|
||
<div class="hero-ic">n</div>
|
||
<div class="hero-t">
|
||
<div class="hero-lab">Прогресс раздела</div>
|
||
<div id="prog-text" style="font-weight:700">0 из 9 параграфов · 0%</div>
|
||
<div class="hero-bar"><div class="hero-fill" id="prog-fill"></div></div>
|
||
</div>
|
||
<div class="hero-xp" id="xp-badge">0 XP</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wrap">
|
||
<nav class="side" id="side">
|
||
<div class="side-h">Содержание</div>
|
||
</nav>
|
||
|
||
<main class="col" id="col">
|
||
|
||
<section class="sec" id="p1">
|
||
<div class="ph"><div class="ph-num">§ 1</div><h2>Атомы. Химические элементы. Относительная атомная масса</h2><span class="ph-key">$A_r(\text{O}) = 16$</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">теория</span> Атом и химический элемент</h3>
|
||
<p><b>Атом</b> — мельчайшая химически неделимая частица вещества. <b>Химический элемент</b> — вид атомов с одинаковым зарядом ядра. Каждый элемент имеет символ (например, <b>H</b>, <b>O</b>, <b>Fe</b>) и порядковый номер $Z$ в периодической системе.</p>
|
||
<div class="def"><b>Относительная атомная масса</b> $A_r$ показывает, во сколько раз масса атома больше $\tfrac{1}{12}$ массы атома углерода-12. Величина безразмерная: $A_r(\text{H})=1$, $A_r(\text{O})=16$, $A_r(\text{Fe})=56$.</div>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v10M7 12h10"/></svg> Карта элементов: клик → $Z$, название, $A_r$</div>
|
||
<div class="el-grid" id="el-grid"></div>
|
||
<div class="el-info" id="el-info">Выберите элемент, чтобы увидеть его характеристики.</div>
|
||
</div>
|
||
<div class="tr" data-tr="t1">
|
||
<div class="tr-q">Во сколько раз атом серы ($A_r=32$) тяжелее атома кислорода ($A_r=16$)?</div>
|
||
<div class="tr-row" data-opts><button class="opt">в 2 раза</button><button class="opt">в 16 раз</button><button class="opt">в 48 раз</button></div>
|
||
<div class="tr-fb"></div>
|
||
</div>
|
||
<div class="mark" data-mark="p1"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p2">
|
||
<div class="ph"><div class="ph-num">§ 2</div><h2>Молекулы. Простые и сложные вещества. Химические формулы. $M_r$</h2><span class="ph-key">$M_r=\sum A_r$</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">теория</span> Вещества и формулы</h3>
|
||
<p><b>Простое вещество</b> образовано атомами одного элемента ($\text{O}_2$, $\text{Fe}$), <b>сложное</b> — разных ($\text{H}_2\text{O}$, $\text{CaCO}_3$). <b>Химическая формула</b> показывает качественный и количественный состав: индекс — число атомов элемента.</p>
|
||
<div class="def"><b>Относительная молекулярная масса</b> $M_r$ равна сумме относительных атомных масс всех атомов в формуле. Например, $M_r(\text{H}_2\text{O}) = 2\cdot1 + 16 = 18$.</div>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h10"/></svg> Калькулятор $M_r$ по формуле</div>
|
||
<div class="fld">
|
||
<label>Формула</label>
|
||
<input type="text" id="mr-in" value="CaCO3" style="width:160px;font-family:var(--mono)">
|
||
<button class="btn primary" id="mr-go">Вычислить</button>
|
||
</div>
|
||
<div class="fld" style="gap:6px">
|
||
<button class="btn mr-ex" data-f="H2O">H₂O</button>
|
||
<button class="btn mr-ex" data-f="H2SO4">H₂SO₄</button>
|
||
<button class="btn mr-ex" data-f="Ca(OH)2">Ca(OH)₂</button>
|
||
<button class="btn mr-ex" data-f="Al2(SO4)3">Al₂(SO₄)₃</button>
|
||
</div>
|
||
<div class="out" id="mr-out">Введите формулу и нажмите «Вычислить».</div>
|
||
</div>
|
||
<div class="mark" data-mark="p2"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p3">
|
||
<div class="ph"><div class="ph-num">§ 3</div><h2>Химическое количество вещества</h2><span class="ph-key">$n$, моль</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">теория</span> Порция вещества</h3>
|
||
<p>Считать атомы и молекулы поштучно невозможно — их слишком много. Поэтому ввели специальную «порцию» — <b>химическое количество вещества</b> $n$, единица — <b>моль</b>. Одна и та же порция ($1$ моль) любого вещества содержит одинаковое число частиц.</p>
|
||
<div class="def">Химическое количество $n$ связывает массу $m$, число частиц $N$ и объём газа $V$. Это «мост» между миром атомов и граммами на весах.</div>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><circle cx="6" cy="6" r="2"/><circle cx="12" cy="6" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="15" cy="12" r="2"/><circle cx="12" cy="18" r="2"/></svg> Порция вещества: $n \Rightarrow N$ и $m$</div>
|
||
<div class="fld">
|
||
<label>Вещество</label>
|
||
<select id="port-sub"><option value="H2O">вода H₂O (M=18)</option><option value="O2">кислород O₂ (M=32)</option><option value="CO2">углекислый газ CO₂ (M=44)</option><option value="NaCl">соль NaCl (M=58,5)</option></select>
|
||
<label>n, моль</label>
|
||
<input type="range" id="port-n" min="0.1" max="5" step="0.1" value="1" style="vertical-align:middle">
|
||
<span class="bd" id="port-nv">1,0</span>
|
||
</div>
|
||
<div class="out" id="port-out"></div>
|
||
</div>
|
||
<div class="mark" data-mark="p3"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p4">
|
||
<div class="ph"><div class="ph-num">§ 4</div><h2>Моль — единица химического количества. Постоянная Авогадро</h2><span class="ph-key">$N = n\cdot N_A$</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">теория</span> Постоянная Авогадро</h3>
|
||
<div class="def"><b>1 моль</b> — это химическое количество вещества, содержащее столько же частиц, сколько атомов в $12$ г углерода-$12$, а именно $N_A = 6{,}02\cdot10^{23}$ частиц/моль — <b>постоянная Авогадро</b>.</div>
|
||
<p>Число частиц: $N = n\cdot N_A$. Отсюда $n = \dfrac{N}{N_A}$.</p>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M12 2v20M2 12h20"/></svg> Счётчик частиц $N = n\cdot N_A$</div>
|
||
<div class="fld"><label>n, моль</label><input type="range" id="av-n" min="0.25" max="10" step="0.25" value="2"><span class="bd" id="av-nv">2,0</span></div>
|
||
<div class="out" id="av-out"></div>
|
||
</div>
|
||
<div class="tr" data-tr="t4">
|
||
<div class="tr-q">Сколько молекул содержится в $0{,}5$ моль воды? ($N_A=6{,}02\cdot10^{23}$)</div>
|
||
<div class="tr-row" data-opts><button class="opt" data-ok>$3{,}01\cdot10^{23}$</button><button class="opt">$6{,}02\cdot10^{23}$</button><button class="opt">$12{,}04\cdot10^{23}$</button></div>
|
||
<div class="tr-fb"></div>
|
||
</div>
|
||
<div class="mark" data-mark="p4"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p5">
|
||
<div class="ph"><div class="ph-num">§ 5</div><h2>Молярная масса. Молярный объём газов</h2><span class="ph-key">$V_m=22{,}4$ л/моль</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">теория</span> M и Vm</h3>
|
||
<div class="def"><b>Молярная масса</b> $M$ — масса $1$ моль вещества (г/моль). Численно $M$ равна $M_r$: $M(\text{H}_2\text{O})=18$ г/моль.</div>
|
||
<div class="def"><b>Молярный объём</b> $V_m$ — объём $1$ моль газа. При нормальных условиях (н.у.) $V_m = 22{,}4$ л/моль для любого газа (закон Авогадро).</div>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h16"/></svg> M по формуле и объём 1 моль газа</div>
|
||
<div class="fld"><label>Формула газа</label><input type="text" id="m5-in" value="CO2" style="width:140px;font-family:var(--mono)"><button class="btn primary" id="m5-go">Найти M</button></div>
|
||
<div class="out" id="m5-out">M(CO₂) и объём при н.у. появятся здесь.</div>
|
||
</div>
|
||
<div class="mark" data-mark="p5"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p6">
|
||
<div class="ph"><div class="ph-num">§ 6 · звёздный виджет</div><h2>Вычисление $n$ по массе и массы по $n$</h2><span class="ph-key">$n = \dfrac{m}{M}$</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">правило</span> Треугольник n–m–M</h3>
|
||
<p>Три величины связаны формулой $m = n\cdot M$. Закрой искомую — получишь формулу: $n=\dfrac{m}{M}$, $m=n\cdot M$, $M=\dfrac{m}{n}$.</p>
|
||
<div class="exa">
|
||
<div class="step">Дано: $m=36$ г воды, $M=18$ г/моль.</div>
|
||
<div class="step">$n = \dfrac{m}{M} = \dfrac{36}{18} = 2$ моль.</div>
|
||
</div>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M12 3 2 21h20z"/></svg> Интерактивный треугольник n–m–M</div>
|
||
<div class="fld"><label>Подставить M вещества</label><select id="mt-sub"><option value="">— вручную —</option><option value="H2O">H₂O · 18</option><option value="CO2">CO₂ · 44</option><option value="NaOH">NaOH · 40</option><option value="CaCO3">CaCO₃ · 100</option><option value="H2SO4">H₂SO₄ · 98</option></select></div>
|
||
<div id="mt-mount"></div>
|
||
</div>
|
||
<div class="mark" data-mark="p6"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p7">
|
||
<div class="ph"><div class="ph-num">§ 7</div><h2>Вычисление $n$ газа по объёму и объёма по $n$</h2><span class="ph-key">$n = \dfrac{V}{V_m}$</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">правило</span> Связка m – n – V – N</h3>
|
||
<p>Для газа при н.у.: $n=\dfrac{V}{V_m}$, $V=n\cdot V_m$ ($V_m=22{,}4$ л/моль). Вместе с $n=\dfrac{m}{M}$ и $N=n\cdot N_A$ это единая система: зная одно — найдёшь всё.</p>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M3 12h18M12 3v18"/></svg> Универсальный калькулятор газа</div>
|
||
<div class="fld"><label>Газ</label><select id="g7-sub"><option value="O2">O₂ · M=32</option><option value="CO2">CO₂ · M=44</option><option value="H2">H₂ · M=2</option><option value="N2">N₂ · M=28</option></select></div>
|
||
<div class="fld"><label>Известно</label>
|
||
<select id="g7-key"><option value="n">n, моль</option><option value="m">m, г</option><option value="V">V, л (н.у.)</option><option value="N">N, частиц</option></select>
|
||
<input type="text" id="g7-val" value="1" style="width:120px;font-family:var(--mono)">
|
||
<button class="btn primary" id="g7-go">Рассчитать</button>
|
||
</div>
|
||
<div class="out" id="g7-out"></div>
|
||
</div>
|
||
<div class="mark" data-mark="p7"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="pr1">
|
||
<div class="ph" style="background:linear-gradient(135deg,#7c2d12,#ea580c 60%,#fb923c)"><div class="ph-num">Практическая работа 1</div><h2>Химическое количество вещества</h2><span class="ph-key">$n=\dfrac{m}{M}$</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">практика</span> Порядок работы</h3>
|
||
<ul>
|
||
<li>Взвесь на весах образцы веществ (например, $\text{NaCl}$, $\text{CuSO}_4$).</li>
|
||
<li>Запиши массу $m$ и определи молярную массу $M$ по формуле.</li>
|
||
<li>Вычисли химическое количество $n=\dfrac{m}{M}$ и число частиц $N=n\cdot N_A$.</li>
|
||
<li>Оформи вывод: какому числу частиц соответствует взятая масса.</li>
|
||
</ul>
|
||
<div class="note-safe"><svg class="ic" viewBox="0 0 24 24"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg> Работай аккуратно с реактивами и весами; не пробуй вещества на вкус.</div>
|
||
</div>
|
||
<div class="mark" data-mark="pr1"><button class="btn primary">Отметить выполненной (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Выполнено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p8">
|
||
<div class="ph"><div class="ph-num">§ 8 · звёздный виджет</div><h2>Химические реакции</h2><span class="ph-key">закон сохранения массы</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">теория</span> Уравнение реакции</h3>
|
||
<p>В химической реакции одни вещества превращаются в другие, но <b>атомы не исчезают и не появляются</b> (закон сохранения массы М. В. Ломоносова, А. Лавуазье). Поэтому уравнение реакции <b>уравнивают коэффициентами</b> — число атомов каждого элемента слева и справа равно.</p>
|
||
<p>Типы реакций: <b>соединения</b> ($A+B\to AB$), <b>разложения</b> ($AB\to A+B$), <b>замещения</b> ($A+BC\to AC+B$), <b>обмена</b> ($AB+CD\to AD+CB$).</p>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M3 12h18M14 6l6 6-6 6"/></svg> Балансировщик: расставь коэффициенты</div>
|
||
<div class="fld" style="gap:6px"><label>Реакция</label>
|
||
<select id="bal-pick">
|
||
<option value="H2 + O2 -> H2O|2,1,2">H₂ + O₂ → H₂O</option>
|
||
<option value="Fe + O2 -> Fe2O3|4,3,2">Fe + O₂ → Fe₂O₃</option>
|
||
<option value="Al + HCl -> AlCl3 + H2|2,6,2,3">Al + HCl → AlCl₃ + H₂</option>
|
||
<option value="CH4 + O2 -> CO2 + H2O|1,2,1,2">CH₄ + O₂ → CO₂ + H₂O</option>
|
||
</select>
|
||
</div>
|
||
<div id="bal-mount"></div>
|
||
</div>
|
||
<div class="mark" data-mark="p8"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="p9">
|
||
<div class="ph"><div class="ph-num">§ 9 · звёздный виджет</div><h2>Количественные расчёты по уравнениям реакций</h2><span class="ph-key">по мольным отношениям</span></div>
|
||
<div class="card">
|
||
<h3><span class="tg">правило</span> Алгоритм расчёта</h3>
|
||
<ul>
|
||
<li>Записать и уравнять уравнение реакции.</li>
|
||
<li>Найти $n$ известного вещества: $n=\dfrac{m}{M}$ (или $\dfrac{V}{V_m}$).</li>
|
||
<li>По коэффициентам найти $n$ искомого (мольное отношение).</li>
|
||
<li>Перейти к массе/объёму: $m=n\cdot M$ ($V=n\cdot V_m$).</li>
|
||
</ul>
|
||
</div>
|
||
<div class="wgt">
|
||
<div class="wgt-h"><svg class="ic" viewBox="0 0 24 24"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg> Пошаговый решатель по уравнению</div>
|
||
<div class="fld"><label>Задача</label><select id="st-pick"></select></div>
|
||
<div class="out" id="st-out"></div>
|
||
<div class="fld"><button class="btn" id="st-step">Следующий шаг ▸</button><button class="btn" id="st-all">Показать всё решение</button></div>
|
||
</div>
|
||
<div class="mark" data-mark="p9"><button class="btn primary">Отметить изученным (+5 XP)</button><span class="done-lab"><svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg> Изучено</span></div>
|
||
</section>
|
||
|
||
<section class="sec" id="boss">
|
||
<div class="boss">
|
||
<div class="boss-h"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><path d="M7 4h10v6a5 5 0 0 1-10 0V4z"/><path d="M9 20h6M12 15v5"/></svg> Босс раздела: количественные понятия</div>
|
||
<div class="boss-sub">4 задачи на всё, что изучено. За каждую — +10 XP. Победишь всех — ачивка «Счёт в химии» и +30 XP.</div>
|
||
<div class="bossbar"><span class="lab" id="boss-lab">Решено: 0 / 4</span><div class="bar"><div class="fill" id="boss-fill"></div></div></div>
|
||
<div id="boss-cont"></div>
|
||
<div class="final-cta" id="boss-cta">
|
||
<svg class="ic" viewBox="0 0 24 24" style="width:26px;height:26px;stroke:var(--pri-d)"><path d="M6 9H4l-1-3h18l-1 3h-2M6 9l1 6h10l1-6"/></svg>
|
||
<b>Вводный раздел пройден! Ачивка «Счёт в химии» получена.</b>
|
||
<a href="/textbook/chemistry-8">К разделам →</a>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
</div>
|
||
|
||
<div class="popup" id="popup"></div>
|
||
<footer class="foot">Интерактивный учебник «Химия — 8 класс» · Вводный раздел · LearnSpace</footer>
|
||
|
||
<script>
|
||
'use strict';
|
||
/* Инициализация — после DOMContentLoaded: к этому моменту отложенные (defer)
|
||
chem8_svg.js / biochem-core.js / api.js / xp.js уже выполнены и доступны. */
|
||
document.addEventListener('DOMContentLoaded', function(){
|
||
const _TB_SLUG = 'chemistry-8-intro';
|
||
const C = window.Chem8 || {};
|
||
const Nav = [
|
||
{id:'p1',n:'§ 1',t:'Атомы. Относительная атомная масса'},
|
||
{id:'p2',n:'§ 2',t:'Формулы. Молекулярная масса'},
|
||
{id:'p3',n:'§ 3',t:'Химическое количество'},
|
||
{id:'p4',n:'§ 4',t:'Моль. Постоянная Авогадро'},
|
||
{id:'p5',n:'§ 5',t:'Молярная масса и объём'},
|
||
{id:'p6',n:'§ 6',t:'Треугольник n–m–M'},
|
||
{id:'p7',n:'§ 7',t:'Расчёты для газов'},
|
||
{id:'pr1',n:'ПР',t:'Практическая работа 1',note:true},
|
||
{id:'p8',n:'§ 8',t:'Химические реакции'},
|
||
{id:'p9',n:'§ 9',t:'Расчёты по уравнениям'},
|
||
{id:'boss',n:'★',t:'Босс раздела',note:true}
|
||
];
|
||
const READ_IDS = ['p1','p2','p3','p4','p5','p6','p7','p8','p9'];
|
||
|
||
/* theme */
|
||
(function(){
|
||
var saved = localStorage.getItem('chemistry8_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 d = document.documentElement.classList.contains('dark');
|
||
localStorage.setItem('chemistry8_theme', d?'dark':'light');
|
||
localStorage.setItem('theme', d?'dark':'light');
|
||
if (lab) lab.textContent = d?'Светлая':'Тёмная';
|
||
});
|
||
})();
|
||
|
||
/* sidebar */
|
||
(function(){
|
||
var side = document.getElementById('side');
|
||
Nav.forEach(function(it){
|
||
var a = document.createElement('a');
|
||
a.href = '#'+it.id; a.id = 'nav-'+it.id;
|
||
if (it.note) a.className = 'note';
|
||
a.innerHTML = '<span class="side-num">'+it.n+'</span><span>'+it.t+'</span>';
|
||
side.appendChild(a);
|
||
});
|
||
})();
|
||
|
||
/* progress / XP */
|
||
var PROG = {};
|
||
function popup(msg){ var p=document.getElementById('popup'); p.textContent=msg; p.classList.add('show'); setTimeout(function(){p.classList.remove('show');},2200); }
|
||
function loadLocal(){ try{ var s=localStorage.getItem('chemistry8_intro_read'); if(s) PROG=JSON.parse(s)||{}; }catch(e){} }
|
||
function saveLocal(){ try{ localStorage.setItem('chemistry8_intro_read', JSON.stringify(PROG)); }catch(e){} }
|
||
function getXp(){ return parseInt(localStorage.getItem('chemistry8_xp')||'0',10)||0; }
|
||
function addXp(n,src){
|
||
localStorage.setItem('chemistry8_xp', String(getXp()+n));
|
||
try{ if(window.LS&&LS.xp&&LS.xp.add) LS.xp.add(n,'chem8-intro-'+(src||'x')); }catch(e){}
|
||
refreshXp();
|
||
}
|
||
function refreshXp(){ var b=document.getElementById('xp-badge'); if(b) b.textContent=getXp()+' XP'; }
|
||
|
||
var _marked=new Set(), _pending=null, _timer=null;
|
||
function _flush(){ var body=_pending; _pending=null; if(!body) return; var tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok) return;
|
||
fetch('/api/textbooks/'+_TB_SLUG+'/progress',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+tok},body:JSON.stringify(body),keepalive:true}).catch(function(){}); }
|
||
function _queue(p){ _pending=Object.assign(_pending||{},p); if(_timer)clearTimeout(_timer); _timer=setTimeout(_flush,600); }
|
||
function markServerRead(id){ if(_marked.has(id))return; _marked.add(id); _queue({mark_read:id}); }
|
||
window.addEventListener('beforeunload',_flush);
|
||
|
||
function refreshProgress(){
|
||
var read = READ_IDS.filter(function(id){return PROG[id];}).length;
|
||
var pct = Math.round(read*100/READ_IDS.length);
|
||
var t=document.getElementById('prog-text'); if(t) t.textContent=read+' из '+READ_IDS.length+' параграфов · '+pct+'%';
|
||
var f=document.getElementById('prog-fill'); if(f) f.style.width=pct+'%';
|
||
Nav.forEach(function(it){ var a=document.getElementById('nav-'+it.id); if(a){ if(PROG[it.id]) a.classList.add('done'); else a.classList.remove('done'); } });
|
||
document.querySelectorAll('[data-mark]').forEach(function(m){ if(PROG[m.getAttribute('data-mark')]) m.classList.add('done'); });
|
||
}
|
||
function markRead(id){
|
||
if(PROG[id]) return;
|
||
PROG[id]=true; saveLocal();
|
||
if(READ_IDS.indexOf(id)!==-1) markServerRead(id);
|
||
addXp(5,id); refreshProgress(); popup('+5 XP · отмечено');
|
||
}
|
||
document.querySelectorAll('[data-mark]').forEach(function(m){
|
||
m.querySelector('.btn').addEventListener('click', function(){ markRead(m.getAttribute('data-mark')); });
|
||
});
|
||
|
||
function loadServer(){
|
||
var tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok){ refreshProgress(); return; }
|
||
fetch('/api/textbooks/'+_TB_SLUG,{headers:{'Authorization':'Bearer '+tok}}).then(function(r){return r.ok?r.json():null;}).then(function(d){
|
||
if(d&&d.progress&&d.progress.read){ d.progress.read.forEach(function(k){ _marked.add(k); PROG[k]=true; }); saveLocal(); }
|
||
refreshProgress();
|
||
}).catch(function(){ refreshProgress(); });
|
||
}
|
||
|
||
/* scrollspy */
|
||
(function(){
|
||
var secs = Nav.map(function(it){return document.getElementById(it.id);}).filter(Boolean);
|
||
function onScroll(){
|
||
var y = window.scrollY + 90, cur = secs[0];
|
||
secs.forEach(function(s){ if(s.offsetTop<=y) cur=s; });
|
||
Nav.forEach(function(it){ var a=document.getElementById('nav-'+it.id); if(a) a.classList.toggle('active', cur && cur.id===it.id); });
|
||
}
|
||
window.addEventListener('scroll', onScroll, {passive:true}); onScroll();
|
||
})();
|
||
|
||
/* ===== WIDGETS ===== */
|
||
|
||
/* §1 element lookup */
|
||
var EL = {
|
||
H:[1,'Водород'],He:[2,'Гелий'],Li:[3,'Литий'],Be:[4,'Бериллий'],B:[5,'Бор'],C:[6,'Углерод'],
|
||
N:[7,'Азот'],O:[8,'Кислород'],F:[9,'Фтор'],Ne:[10,'Неон'],Na:[11,'Натрий'],Mg:[12,'Магний'],
|
||
Al:[13,'Алюминий'],Si:[14,'Кремний'],P:[15,'Фосфор'],S:[16,'Сера'],Cl:[17,'Хлор'],Ar:[18,'Аргон'],
|
||
K:[19,'Калий'],Ca:[20,'Кальций'],Fe:[26,'Железо'],Cu:[29,'Медь'],Zn:[30,'Цинк'],Ag:[47,'Серебро'],Ba:[56,'Барий']
|
||
};
|
||
(function(){
|
||
var grid=document.getElementById('el-grid'), info=document.getElementById('el-info'); if(!grid) return;
|
||
Object.keys(EL).forEach(function(s){
|
||
var ar = C.arOf?C.arOf(s):'';
|
||
var c=document.createElement('div'); c.className='el-cell'; c.dataset.s=s;
|
||
c.innerHTML='<span class="z">'+EL[s][0]+'</span><span class="s">'+s+'</span><span class="a">'+ar+'</span>';
|
||
c.addEventListener('click',function(){
|
||
grid.querySelectorAll('.el-cell').forEach(function(x){x.classList.remove('on');}); c.classList.add('on');
|
||
info.innerHTML='<b>'+EL[s][1]+'</b> ('+s+') · порядковый номер Z = '+EL[s][0]+' · A_r = '+ar;
|
||
});
|
||
grid.appendChild(c);
|
||
});
|
||
})();
|
||
|
||
function bindOpts(trId, okText){
|
||
var tr=document.querySelector('[data-tr="'+trId+'"]'); if(!tr) return;
|
||
var fb=tr.querySelector('.tr-fb');
|
||
tr.querySelectorAll('.opt').forEach(function(o){
|
||
o.addEventListener('click',function(){
|
||
var ok = o.hasAttribute('data-ok') || (okText && o.textContent.trim()===okText);
|
||
tr.querySelectorAll('.opt').forEach(function(x){x.style.pointerEvents='none';});
|
||
o.classList.add(ok?'ok':'bad'); fb.className='tr-fb show '+(ok?'ok':'bad');
|
||
fb.textContent = ok?'Верно! +3 XP':'Неверно.';
|
||
if(!ok){ tr.querySelectorAll('.opt').forEach(function(x){ if(x.hasAttribute('data-ok')||(okText&&x.textContent.trim()===okText)) x.classList.add('ok'); }); }
|
||
else addXp(3,trId);
|
||
});
|
||
});
|
||
}
|
||
bindOpts('t1','в 2 раза');
|
||
bindOpts('t4',null);
|
||
|
||
/* §2 Mr calculator */
|
||
(function(){
|
||
var inp=document.getElementById('mr-in'), out=document.getElementById('mr-out'), go=document.getElementById('mr-go'); if(!inp) return;
|
||
function calc(){
|
||
var f=inp.value.trim(); var cnt=C.elementCounts?C.elementCounts(f):null; var mr=C.molarMass?C.molarMass(f):NaN;
|
||
if(!cnt||isNaN(mr)){ out.className='out bad'; out.textContent='Не удалось разобрать формулу. Проверьте символы элементов.'; return; }
|
||
var terms=Object.keys(cnt).map(function(e){ return (C.arOf?C.arOf(e):'?')+'·'+cnt[e]; });
|
||
out.className='out ok';
|
||
out.innerHTML='<b>M_r('+f+') = '+C.fmt(mr)+'</b><br><span class="bd">'+
|
||
Object.keys(cnt).map(function(e){return e+': A_r='+(C.arOf?C.arOf(e):'?')+' × '+cnt[e];}).join(' | ')+
|
||
'<br>Σ = '+terms.join(' + ')+' = '+C.fmt(mr)+'</span>';
|
||
}
|
||
go.addEventListener('click',calc);
|
||
inp.addEventListener('keydown',function(e){ if(e.key==='Enter') calc(); });
|
||
document.querySelectorAll('.mr-ex').forEach(function(b){ b.addEventListener('click',function(){ inp.value=b.dataset.f; calc(); }); });
|
||
calc();
|
||
})();
|
||
|
||
/* §3 portion */
|
||
(function(){
|
||
var sub=document.getElementById('port-sub'), rng=document.getElementById('port-n'), nv=document.getElementById('port-nv'), out=document.getElementById('port-out'); if(!sub) return;
|
||
var M={H2O:18,O2:32,CO2:44,NaCl:58.5};
|
||
function rr(v){ return (Math.round(v*100)/100).toString().replace('.',','); }
|
||
function upd(){
|
||
var n=parseFloat(rng.value), s=sub.value, m=n*M[s], N=n*6.02;
|
||
nv.textContent=n.toFixed(1).replace('.',',');
|
||
out.innerHTML='<span class="bd">n = '+n.toFixed(1).replace('.',',')+' моль<br>'+
|
||
'm = n·M = '+n.toFixed(1).replace('.',',')+' · '+String(M[s]).replace('.',',')+' = <b>'+rr(m)+' г</b><br>'+
|
||
'N = n·N_A = '+rr(N)+'·10²³ ≈ <b>'+rr(N)+'·10²³ частиц</b></span>';
|
||
}
|
||
sub.addEventListener('change',upd); rng.addEventListener('input',upd); upd();
|
||
})();
|
||
|
||
/* §4 avogadro */
|
||
(function(){
|
||
var rng=document.getElementById('av-n'), nv=document.getElementById('av-nv'), out=document.getElementById('av-out'); if(!rng) return;
|
||
function upd(){ var n=parseFloat(rng.value), N=n*6.02; nv.textContent=n.toFixed(2).replace('.',',');
|
||
out.innerHTML='<span class="bd">N = n · N_A = '+n.toFixed(2).replace('.',',')+' · 6,02·10²³ = <b>'+(Math.round(N*100)/100).toString().replace('.',',')+'·10²³ частиц</b></span>';
|
||
}
|
||
rng.addEventListener('input',upd); upd();
|
||
})();
|
||
|
||
/* §5 M + gas volume */
|
||
(function(){
|
||
var inp=document.getElementById('m5-in'), out=document.getElementById('m5-out'), go=document.getElementById('m5-go'); if(!inp) return;
|
||
function calc(){ var f=inp.value.trim(), mr=C.molarMass?C.molarMass(f):NaN;
|
||
if(isNaN(mr)){ out.className='out bad'; out.textContent='Не удалось разобрать формулу.'; return; }
|
||
out.className='out ok';
|
||
out.innerHTML='<span class="bd">M('+f+') = <b>'+C.fmt(mr)+' г/моль</b><br>1 моль газа при н.у. занимает <b>22,4 л</b>.<br>Плотность газа ≈ M/22,4 = '+(Math.round(mr/22.4*1000)/1000).toString().replace('.',',')+' г/л</span>';
|
||
}
|
||
go.addEventListener('click',calc); inp.addEventListener('keydown',function(e){if(e.key==='Enter')calc();}); calc();
|
||
})();
|
||
|
||
/* §6 mole triangle */
|
||
(function(){
|
||
var mount=document.getElementById('mt-mount'), sub=document.getElementById('mt-sub'); if(!mount||!C.moleTriangle) return;
|
||
var api=C.moleTriangle(mount,{});
|
||
if(sub) sub.addEventListener('change',function(){
|
||
var f=sub.value; if(!f) return;
|
||
var m=C.molarMass(f); if(!isNaN(m)&&api&&api.set) api.set('M',m);
|
||
});
|
||
})();
|
||
|
||
/* §7 universal gas calc */
|
||
(function(){
|
||
var sub=document.getElementById('g7-sub'), key=document.getElementById('g7-key'), val=document.getElementById('g7-val'), go=document.getElementById('g7-go'), out=document.getElementById('g7-out'); if(!sub) return;
|
||
var Vm=22.4, NA=6.02;
|
||
function calc(){
|
||
var f=sub.value, M=C.molarMass(f), k=key.value, x=parseFloat(val.value.replace(',','.'));
|
||
if(isNaN(x)){ out.className='out bad'; out.textContent='Введите число.'; return; }
|
||
var n;
|
||
if(k==='n') n=x; else if(k==='m') n=x/M; else if(k==='V') n=x/Vm; else n=x/NA;
|
||
var m=n*M, V=n*Vm, N=n*NA;
|
||
function r(v){ return (Math.round(v*1000)/1000).toString().replace('.',','); }
|
||
out.className='out ok';
|
||
out.innerHTML='<span class="bd">M('+f+')='+M+' г/моль<br>n = <b>'+r(n)+' моль</b><br>m = <b>'+r(m)+' г</b><br>V(н.у.) = <b>'+r(V)+' л</b><br>N = <b>'+r(N)+'·10²³ частиц</b></span>';
|
||
}
|
||
go.addEventListener('click',calc); val.addEventListener('keydown',function(e){if(e.key==='Enter')calc();}); calc();
|
||
})();
|
||
|
||
/* §8 balancer */
|
||
(function(){
|
||
var pick=document.getElementById('bal-pick'), mount=document.getElementById('bal-mount'); if(!pick||!C.equationBalancer) return;
|
||
function build(){
|
||
var parts=pick.value.split('|'); var skel=parts[0]; var sol=parts[1].split(',').map(Number);
|
||
C.equationBalancer(mount,{skeleton:skel, solution:sol});
|
||
}
|
||
pick.addEventListener('change',build); build();
|
||
})();
|
||
|
||
/* §9 stoichiometry step solver */
|
||
var ST = [
|
||
{ eq:'2H₂ + O₂ → 2H₂O', given:'Дано: m(H₂) = 4 г. Найти m(H₂O).',
|
||
steps:['M(H₂)=2 г/моль, M(H₂O)=18 г/моль.','n(H₂) = m/M = 4/2 = 2 моль.','По уравнению n(H₂):n(H₂O) = 2:2 = 1:1 → n(H₂O)=2 моль.','m(H₂O) = n·M = 2·18 = 36 г. Ответ: 36 г.'] },
|
||
{ eq:'CaCO₃ → CaO + CO₂↑', given:'Дано: m(CaCO₃) = 100 г. Найти V(CO₂) при н.у.',
|
||
steps:['M(CaCO₃)=100 г/моль.','n(CaCO₃) = 100/100 = 1 моль.','n(CaCO₃):n(CO₂) = 1:1 → n(CO₂)=1 моль.','V(CO₂) = n·Vm = 1·22,4 = 22,4 л. Ответ: 22,4 л.'] },
|
||
{ eq:'Zn + 2HCl → ZnCl₂ + H₂↑', given:'Дано: n(Zn) = 0,5 моль. Найти V(H₂) при н.у.',
|
||
steps:['n(Zn):n(H₂) = 1:1 → n(H₂)=0,5 моль.','V(H₂) = n·Vm = 0,5·22,4 = 11,2 л. Ответ: 11,2 л.'] }
|
||
];
|
||
(function(){
|
||
var pick=document.getElementById('st-pick'), out=document.getElementById('st-out'), bStep=document.getElementById('st-step'), bAll=document.getElementById('st-all'); if(!pick) return;
|
||
ST.forEach(function(p,i){ var o=document.createElement('option'); o.value=i; o.textContent=p.eq; pick.appendChild(o); });
|
||
var cur=0, shown=0;
|
||
function render(){
|
||
var p=ST[cur];
|
||
var html='<b>'+p.eq+'</b><br><span style="color:var(--muted)">'+p.given+'</span><div style="margin-top:8px">';
|
||
for(var i=0;i<shown;i++) html+='<div class="exa" style="margin-top:6px"><div class="step">'+p.steps[i]+'</div></div>';
|
||
if(shown===0) html+='<span style="color:var(--muted)">Нажмите «Следующий шаг», чтобы решать пошагово.</span>';
|
||
html+='</div>'; out.className='out'; out.innerHTML=html;
|
||
if(shown>=p.steps.length){ out.className='out ok'; }
|
||
}
|
||
pick.addEventListener('change',function(){ cur=+pick.value; shown=0; render(); });
|
||
bStep.addEventListener('click',function(){ if(shown<ST[cur].steps.length){ shown++; render(); } });
|
||
bAll.addEventListener('click',function(){ shown=ST[cur].steps.length; render(); });
|
||
render();
|
||
})();
|
||
|
||
/* ===== BOSS ===== */
|
||
var BOSS = [
|
||
{ q:'Чему равна молярная масса серной кислоты $\\text{H}_2\\text{SO}_4$? (г/моль)', ans:98, tol:0.5, hint:'M = 2·1 + 32 + 4·16 = 98.' },
|
||
{ q:'Сколько моль вещества в $80$ г $\\text{NaOH}$ ($M=40$ г/моль)?', ans:2, tol:0.05, hint:'n = m/M = 80/40 = 2.' },
|
||
{ q:'Какой объём (л, н.у.) занимают $3$ моль кислорода $\\text{O}_2$?', ans:67.2, tol:0.3, hint:'V = n·Vm = 3·22,4 = 67,2.' },
|
||
{ q:'Сколько молекул в $2$ моль воды? Ответ в виде коэффициента при ·10²³.', ans:12.04, tol:0.1, hint:'N = n·N_A = 2·6,02 = 12,04 (·10²³).' }
|
||
];
|
||
var BKEY='chemistry8_intro_boss', BACH='chemistry8_intro_ach';
|
||
function bossState(){ try{ return JSON.parse(localStorage.getItem(BKEY)||'{}')||{}; }catch(e){ return {}; } }
|
||
function bossSave(s){ try{ localStorage.setItem(BKEY,JSON.stringify(s)); }catch(e){} }
|
||
(function(){
|
||
var cont=document.getElementById('boss-cont'); if(!cont) return;
|
||
var st=bossState();
|
||
BOSS.forEach(function(b,i){
|
||
var solved=!!st[i];
|
||
var d=document.createElement('div'); d.className='bcard'+(solved?' solved':''); d.id='b'+i;
|
||
d.innerHTML='<div class="q"><b>Задача '+(i+1)+'.</b> '+b.q+'</div>'+
|
||
'<div class="row"><input type="text" inputmode="decimal" placeholder="ответ" style="width:120px;font-family:var(--mono)"'+(solved?' value="'+b.ans+'" disabled':'')+'>'+
|
||
'<button class="btn primary go"'+(solved?' disabled':'')+'>Ответить</button><button class="btn hint">Подсказка</button></div>'+
|
||
'<div class="hintbox">'+b.hint+'</div>'+
|
||
'<div class="fb'+(solved?' show ok':'')+'">'+(solved?'Решено! +10 XP':'')+'</div>';
|
||
cont.appendChild(d);
|
||
var inp=d.querySelector('input'), go=d.querySelector('.go'), hint=d.querySelector('.hint'), hb=d.querySelector('.hintbox'), fb=d.querySelector('.fb');
|
||
hint.addEventListener('click',function(){ hb.classList.toggle('show'); });
|
||
if(!solved) go.addEventListener('click',function(){
|
||
var v=parseFloat((inp.value||'').replace(',','.'));
|
||
if(isNaN(v)){ fb.className='fb show bad'; fb.textContent='Введите число.'; return; }
|
||
if(Math.abs(v-b.ans)<=b.tol){
|
||
fb.className='fb show ok'; fb.textContent='Верно! +10 XP'; d.classList.add('solved'); go.disabled=true; inp.disabled=true;
|
||
var s=bossState(); if(!s[i]){ s[i]=true; bossSave(s); addXp(10,'boss'+i); updateBoss(s); }
|
||
} else { fb.className='fb show bad'; fb.textContent='Не то. Проверь расчёт и попробуй снова.'; }
|
||
});
|
||
inp.addEventListener('keydown',function(e){ if(e.key==='Enter'&&!go.disabled) go.click(); });
|
||
});
|
||
updateBoss(st);
|
||
if(window.renderMathInElement) try{renderMathInElement(cont);}catch(e){}
|
||
})();
|
||
function updateBoss(s){
|
||
var won=0; for(var k in s) if(s[k]) won++;
|
||
var lab=document.getElementById('boss-lab'), fill=document.getElementById('boss-fill');
|
||
if(lab) lab.textContent='Решено: '+won+' / '+BOSS.length;
|
||
if(fill) fill.style.width=Math.round(won*100/BOSS.length)+'%';
|
||
if(won>=BOSS.length && localStorage.getItem(BACH)!=='1'){
|
||
localStorage.setItem(BACH,'1'); addXp(30,'ach');
|
||
var cta=document.getElementById('boss-cta'); if(cta) cta.classList.add('show');
|
||
popup('Ачивка «Счёт в химии»! +30 XP');
|
||
try{ if(window.confetti) confetti({particleCount:180,spread:100,origin:{y:.6}}); }catch(e){}
|
||
} else if(won>=BOSS.length){ var c=document.getElementById('boss-cta'); if(c) c.classList.add('show'); }
|
||
}
|
||
|
||
/* init */
|
||
loadLocal(); refreshXp(); refreshProgress(); loadServer();
|
||
window.addEventListener('focus',loadServer);
|
||
|
||
}); /* end DOMContentLoaded */
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|