Files
Learn_System/frontend/textbooks/physics_10_ch6.html
T
Maxim Dolgolyov bed085ac98 feat(phys10 ch6 wave1): §34 «Ток в металлах» + §35 «Электролиты»
§34 «Электрический ток в металлах. Сверхпроводимость»:
- 3 makeCard: природа тока, R(t) для металлов, сверхпроводимость
- IV1: симуляция дрейфа электронов в решётке (SVG, slider U)
- IV2: график R(t) = R_0(1 + alpha t), переключение материалов + скачок T_c
- IV3: квикфайр на носителей заряда в средах (6 вопросов)
- IV4: тренажёр 5 задач (rho L/S, R при разных T, T_c ртути)

§35 «Электрический ток в электролитах. Электролиз»:
- 3 makeCard: электролиты/ионы, законы Фарадея, применение
- IV1: симуляция электролиза (катионы → катоду, анионы → аноду)
- IV2: калькулятор массы m = MIt/(Fn) для Cu/Ag/Al/Fe/H
- IV3: квикфайр направления ионов (6 вопросов, 2 кнопки)
- IV4: тренажёр 5 задач (расчёт m для Cu/Ag, F = 96500)
2026-05-29 18:32:53 +03:00

1600 lines
107 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Физика 10 · Глава 6 · «Ток в различных средах»</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">
<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/g3d.js" defer></script>
<script src="/js/phys.js" 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:#fafafa; --card:#fff; --card-soft:#f8fafc; --text:#0f172a; --ink:#0f172a; --muted:#64748b;
--border:#e2e8f0; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
--pri:#10b981; --pri2:#059669; --pri-soft:#d1fae5;
--acc:#6ee7b7; --acc2:#10b981; --acc-soft:#d1fae5;
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
}
.dark{--bg:#0a0a0e; --card:#13120a; --card-soft:#18160a; --text:#fef9e7; --ink:#fef9e7; --muted:#a39070; --border:#2a2512}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;font-size:15px}
button,input,select,textarea{font-family:inherit;font-size:inherit}
button{cursor:pointer;border:0;background:transparent;color:inherit}
a{color:inherit;text-decoration:none}
.ic{width:16px;height:16px;display:inline-block;flex-shrink:0;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;vertical-align:middle}
.hdr{position:relative;background:linear-gradient(110deg,#064e3b 0%,#10b981 55%,#6ee7b7 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(255,255,255,.2);min-height:130px}
.hdr::before{content:'ГЛАВА 6';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(5rem,15vw,11rem);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}
.hdr-row{position:relative;z-index:1;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.3;padding-top:4px}
.hdr-sub{font-size:.85rem;opacity:.88;margin-top:6px;font-weight:500;line-height:1.4}
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.hdr-btn{padding:7px 12px;border-radius:9px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;text-decoration:none}
.hdr-btn:hover{background:rgba(255,255,255,.24)}
.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}
.hero{background:linear-gradient(135deg,var(--pri-soft) 0%,var(--acc-soft) 50%,var(--pri-soft) 100%);background-size:200% 200%;animation:heroShift 12s ease-in-out infinite;border:1px solid var(--border);border-radius:18px;padding:24px 22px;margin-bottom:24px;position:relative;overflow:hidden}
@keyframes heroShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
.hero::before{content:'n/p';position:absolute;right:0;top:-30px;font-size:clamp(2rem,12vw,8rem);font-weight:900;color:var(--pri);opacity:.10;line-height:1;pointer-events:none;font-family:'Unbounded',sans-serif}
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px;letter-spacing:-.01em}
.hero p{font-size:.95rem;color:var(--text);opacity:.88;margin-bottom:14px;max-width:640px}
.hero-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.btn-primary{padding:11px 22px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:11px;font-weight:700;font-size:.92rem;display:inline-flex;align-items:center;gap:8px;box-shadow:var(--sh2);transition:transform .15s,box-shadow .15s}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(0,0,0,.18)}
.hero-progress{flex:1;min-width:200px;max-width:280px}
.hp-label{font-size:.74rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:5px}
.hp-bar{height:8px;background:rgba(0,0,0,.12);border-radius:5px;overflow:hidden}
.hp-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:5px;width:0%;transition:width .6s cubic-bezier(.16,1,.3,1)}
.hp-text{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:4px;display:block}
.hero-xp-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,var(--warn,#f59e0b),var(--pri));color:#fff;border-radius:99px;font-size:.82rem;font-weight:800;letter-spacing:.02em;box-shadow:0 4px 12px rgba(0,0,0,.18);font-family:'Unbounded',sans-serif}
.psel{margin-bottom:24px}
.psel-title{font-size:.72rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:10px}
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:14px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;text-align:left;position:relative}
.psel-card:hover{transform:translateY(-3px);box-shadow:var(--sh2);border-color:var(--pri)}
.psel-card.active{border-color:var(--pri);background:linear-gradient(135deg,var(--pri-soft),var(--card));box-shadow:var(--sh2)}
.psel-card.active::after{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:13px 13px 0 0}
.psel-num{font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;color:var(--pri);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px}
.psel-name{font-size:.86rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:8px}
.psel-prog{height:4px;background:rgba(0,0,0,.10);border-radius:3px;overflow:hidden}
.psel-prog-fill{height:100%;background:var(--pri);width:0%;transition:width .4s}
.psel-card.final{background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft))}
.psel-card.final .psel-num{color:var(--warn)}
.sec[id="sec-p34"]{ --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#d1fae5; }
.sec[id="sec-p35"]{ --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#d1fae5; }
.sec[id="sec-p36"]{ --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#d1fae5; }
.sec[id="sec-p37"]{ --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#d1fae5; }
.sec[id="sec-final6"]{ --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#d1fae5; }
.sec{display:none;position:relative;animation:fadeIn .35s ease}
.sec.active{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.sec::before{content:attr(data-watermark);position:absolute;right:-20px;top:10%;font-family:'Unbounded',sans-serif;font-size:clamp(6rem,18vw,14rem);font-weight:900;color:transparent;-webkit-text-stroke:1.5px var(--sec-acc-soft,var(--pri-soft));line-height:1;pointer-events:none;user-select:none;z-index:0;opacity:.35}
.sec-header{margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--sec-acc-soft,var(--pri-soft));position:relative;z-index:1}
.sec-num{display:inline-block;padding:4px 10px;background:linear-gradient(135deg,var(--sec-acc,var(--pri)),var(--sec-acc-d,var(--pri2)));color:#fff;border-radius:7px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;margin-bottom:8px}
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.6rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));letter-spacing:-.01em;line-height:1.25}
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:18px 20px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 24px rgba(0,0,0,.04);position:relative;z-index:1;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
.card:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(0,0,0,.06),0 16px 36px rgba(0,0,0,.08)}
.card-header{display:flex;align-items:center;gap:10px;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
.card-icon{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff}
.card-icon.repeat{background:#0ea5e9}.card-icon.theory{background:#8b5cf6}.card-icon.algo{background:#f59e0b}.card-icon.rule{background:#ec4899}.card-icon.example{background:#10b981}.card-icon.oral{background:#06b6d4}
.card-icon .ic{width:18px;height:18px}
.card-title{font-family:'Unbounded',sans-serif;font-size:.82rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);flex:1}
.card-num{font-size:.74rem;font-weight:700;color:var(--muted);background:var(--sec-acc-soft,var(--pri-soft));padding:3px 7px;border-radius:5px}
.card-body{font-size:.94rem;line-height:1.65}
.card-body p{margin-bottom:8px}
.card-body p:last-child{margin-bottom:0}
.btn{padding:8px 16px;border-radius:8px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:600;font-size:.88rem;transition:background .15s,border-color .15s,transform .1s}
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
.btn:active{transform:scale(.96)}
.btn.primary{background:var(--sec-acc,var(--pri));color:#fff;border-color:var(--sec-acc,var(--pri))}
.btn.primary:hover{background:var(--sec-acc-d,var(--pri2));border-color:var(--sec-acc-d,var(--pri2))}
.feedback{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none}
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
.wg{background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)));border:1.5px solid var(--sec-acc,var(--pri));border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1}
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.wg-badge{padding:4px 9px;background:var(--sec-acc,var(--pri));color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));flex:1}
.wg-help{font-size:.88rem;color:var(--text);margin-bottom:12px;line-height:1.55;background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--sec-acc-soft,var(--pri-soft)));border-left:4px solid var(--warn,#f59e0b);padding:9px 14px;border-radius:9px}
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);transition:border-color .15s;font-family:'JetBrains Mono',monospace}
.tinp:focus{outline:0;border-color:var(--sec-acc,var(--pri));box-shadow:0 0 0 3px var(--sec-acc-soft,var(--pri-soft))}
.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:10px}
.sliders label{display:block;font-size:.92rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border);line-height:1.5}
.sliders label b{font-family:'JetBrains Mono',monospace;font-size:1.05rem;color:var(--sec-acc-d,var(--pri2));margin-left:4px}
.sliders label input[type="range"]{display:block;width:100%;margin-top:6px;accent-color:var(--sec-acc,var(--pri))}
.score-display{display:flex;gap:14px;flex-wrap:wrap;align-items:center;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-bottom:12px}
.score-display b{color:var(--sec-acc-d,var(--pri2));font-size:1.15rem}
.spoiler{border:1px solid var(--border);border-radius:10px;background:var(--card);margin:10px 0;overflow:hidden}
.spoiler summary{padding:8px 14px;background:var(--sec-acc-soft,var(--pri-soft));font-weight:700;cursor:pointer;font-size:.88rem;color:var(--sec-acc-d,var(--pri2));list-style:none;display:flex;align-items:center;gap:8px}
.spoiler summary::-webkit-details-marker{display:none}
.spoiler summary::before{content:'+';font-size:1.2rem;font-weight:900;color:var(--sec-acc,var(--pri));width:18px}
.spoiler[open] summary::before{content:'\2212'}
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
.dnd-pool{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;min-height:54px;transition:border-color .18s,background .18s}
.dnd-pool.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid}
.dnd-pool.col{flex-direction:column;align-items:stretch}
.dnd-pool.col .dnd-chip{width:auto}
.dnd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--card);border:1.5px solid var(--border);border-radius:10px;cursor:grab;user-select:none;font-size:.92rem;line-height:1.4;transition:transform .12s,box-shadow .12s,border-color .12s;touch-action:none;max-width:100%}
.dnd-chip:hover{transform:translateY(-1px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)}
.dnd-chip:active{cursor:grabbing}
.dnd-chip.armed{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:0 0 0 3px rgba(0,0,0,.10);transform:translateY(-1px)}
.dnd-chip.dragging{opacity:.28}
.dnd-chip.placed{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
.dnd-chip .dnd-x{padding:0 5px;color:var(--muted);font-weight:700;font-size:1.05rem;border-radius:4px;cursor:pointer}
.dnd-chip .dnd-x:hover{color:var(--bad,var(--fail));background:var(--fail-bg)}
.drop-box{background:var(--card);border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:90px;transition:border-color .15s,background .15s}
.drop-box:hover{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
.drop-box h5{font-family:'Unbounded',sans-serif;font-size:.78rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em}
.drop-box.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid;transform:scale(1.015)}
.drop-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px}
.dnd-hint{font-size:.78rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
.dnd-hint svg{width:14px;height:14px;flex-shrink:0}
.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}
.sidecard-row:last-child{margin-bottom:0}
@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(--acc2);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(--acc2);font-family:'Unbounded',sans-serif}
.xp-bar{height:9px;background:rgba(0,0,0,.10);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}
.sec-nav{display:flex;gap:10px;margin-top:24px;padding-top:20px;border-top:1px solid var(--border);justify-content:space-between;flex-wrap:wrap}
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,var(--pri),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,.32);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
.ach-popup.show{display:flex}
.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(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}
}
.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:14vh}
.search-modal.show{display:flex}
.search-box{background:var(--bg);border:1px solid var(--border);border-radius:14px;width:560px;max-width:92vw;max-height:70vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 64px rgba(0,0,0,.4)}
.search-input{padding:14px 16px;font-size:1rem;border:0;border-bottom:1px solid var(--border);background:transparent;color:var(--text);outline:none}
.search-results{flex:1;overflow-y:auto;padding:6px 0}
.search-row{display:block;padding:8px 16px;cursor:pointer;border-bottom:1px solid var(--border);text-align:left;background:transparent;border:0;width:100%;color:var(--text)}
.search-row:hover,.search-row.active{background:var(--sec-acc-soft,var(--pri-soft))}
.search-row .sr-kind{font-size:.7rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
.search-row .sr-title{font-weight:700;font-size:.92rem;color:var(--text)}
.search-row .sr-desc{font-size:.8rem;color:var(--muted);margin-top:2px}
.search-empty{padding:20px;text-align:center;color:var(--muted);font-size:.88rem}
.search-foot{padding:8px 14px;border-top:1px solid var(--border);font-size:.74rem;color:var(--muted);display:flex;gap:14px}
.search-foot kbd{padding:2px 6px;background:var(--card);border:1px solid var(--border);border-radius:4px;font-family:'JetBrains Mono',monospace;font-size:.72rem}
/* === PHYS10 POLISH (visual + micro-interactions) === */
@keyframes wgFadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.sec.active .wg{animation:wgFadeIn .35s cubic-bezier(.16,1,.3,1) backwards}
.sec.active .wg:nth-of-type(1){animation-delay:.02s}
.sec.active .wg:nth-of-type(2){animation-delay:.08s}
.sec.active .wg:nth-of-type(3){animation-delay:.14s}
.sec.active .wg:nth-of-type(4){animation-delay:.20s}
.sec.active .wg:nth-of-type(5){animation-delay:.26s}
.sec.active .wg:nth-of-type(6){animation-delay:.32s}
.wg svg{transition:filter .25s ease}
.wg:hover svg{filter:drop-shadow(0 4px 16px rgba(0,0,0,.10))}
input[type=range]:active{box-shadow:0 0 0 4px var(--pri-soft);border-radius:8px}
.wg input[type=range]{cursor:ew-resize}
.score-display b{transition:transform .22s cubic-bezier(.16,1,.3,1),color .22s;display:inline-block;transform-origin:center}
.score-display b.bump{transform:scale(1.28);color:var(--pri)}
.katex{transition:color .2s}
.wg-help .katex:hover,.card-body .katex:hover{color:var(--pri2,var(--pri));cursor:help}
.hp-fill,.psel-prog-fill,.xp-fill,[id$="-overall-fill"]{transition:width .6s cubic-bezier(.16,1,.3,1)!important}
.boss-card,.btn.primary,.btn-primary{position:relative;overflow:hidden}
.btn.primary::after,.btn-primary::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at center,rgba(255,255,255,.42) 0%,transparent 60%);opacity:0;transition:opacity .25s;pointer-events:none}
.btn.primary:hover::after,.btn-primary:hover::after{opacity:1}
.psel-card{position:relative}
.psel-card .psel-done{position:absolute;top:6px;right:6px;width:18px;height:18px;border-radius:50%;background:#10b981;display:none;align-items:center;justify-content:center;box-shadow:0 2px 6px rgba(16,185,129,.45);z-index:2}
.psel-card .psel-done svg{width:11px;height:11px;stroke:#fff;fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round}
.psel-card.done .psel-done{display:flex}
.boss-card{transition:border-color .35s,box-shadow .6s,background .3s,transform .2s}
.boss-card.glow{box-shadow:0 0 24px rgba(16,185,129,.6),0 0 0 2px rgba(16,185,129,.45)!important}
@keyframes bossPulse{0%{box-shadow:0 0 0 0 rgba(16,185,129,.55)}70%{box-shadow:0 0 0 14px rgba(16,185,129,0)}100%{box-shadow:0 0 0 0 rgba(16,185,129,0)}}
.boss-card.pulse{animation:bossPulse .8s ease-out}
.sec{transition:opacity .25s}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-row">
<div>
<h1>Физика 10 · Глава 6</h1>
<div class="hdr-sub">Металлы · сверхпроводимость · электролиз · газы · плазма · полупроводники</div>
</div>
<div class="hdr-side">
<a href="/textbook/physics-10" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 10</a>
<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">
<section class="hero">
<h2>Электрический ток в разных средах</h2>
<p>Электрический ток ведёт себя по-разному в металлах, электролитах, газах и полупроводниках. Сверхпроводимость, электролиз, плазма, p-n переход.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p34')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 34</button>
<div class="hero-progress">
<span class="hp-label">Прогресс по главе</span>
<div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div>
<span id="hero-hp-text" class="hp-text">0%</span>
</div>
<div id="hero-xp-badge" class="hero-xp-badge"></div>
</div>
</section>
<section class="psel">
<div class="psel-title">Параграфы главы</div>
<div id="psel-grid" class="psel-grid"></div>
</section>
<section id="sec-p34" class="sec" data-watermark="&rho;(T)"><div class="sec-header"><span class="sec-num">§ 34</span><h2 class="sec-h">Ток в металлах. Сверхпроводимость</h2></div><div id="p34-body"></div></section>
<section id="sec-p35" class="sec" data-watermark="m=kIt"><div class="sec-header"><span class="sec-num">§ 35</span><h2 class="sec-h">Ток в электролитах</h2></div><div id="p35-body"></div></section>
<section id="sec-p36" class="sec" data-watermark="plasma"><div class="sec-header"><span class="sec-num">§ 36</span><h2 class="sec-h">Ток в газах. Плазма</h2></div><div id="p36-body"></div></section>
<section id="sec-p37" class="sec" data-watermark="n/p"><div class="sec-header"><span class="sec-num">§ 37</span><h2 class="sec-h">Ток в полупроводниках</h2></div><div id="p37-body"></div></section>
<section id="sec-final6" class="sec" data-watermark="&#9733;"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#10b981,#6ee7b7)"></span><h2 class="sec-h">Финал главы</h2></div><div id="final6-body"></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>
<footer class="foot">Интерактивный учебник «Физика 10» · Глава 6 · «Ток в различных средах» · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
<div id="search-modal" class="search-modal" role="dialog">
<div class="search-box">
<input type="text" id="search-input" class="search-input" placeholder="Поиск…" autocomplete="off">
<div id="search-results" class="search-results"></div>
<div class="search-foot"><span><kbd>↑↓</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
</div>
</div>
<script>
'use strict';
const STATE = { current:'p34', progress:{}, achievements:new Map(), xp:0, level:1 };
const TOTAL_PARAS = 5;
const _TB_SLUG = 'physics-10-ch6';
const PARAS = [
{ id:'p34', num:'\u00a7 34', name:"Ток в металлах. Сверхпроводимость", sub:'$\\rho(T)$' },
{ id:'p35', num:'\u00a7 35', name:"Ток в электролитах", sub:'$m = kIt$' },
{ id:'p36', num:'\u00a7 36', name:"Ток в газах. Плазма", sub:'Виды разрядов' },
{ id:'p37', num:'\u00a7 37', name:"Ток в полупроводниках", sub:'n-/p-тип' },
{ id:'final6', num:'\u2605', name:'Финал главы', sub:'Итоги \u00b7 боссы главы 6', final:true }
];
PARAS.forEach(p => { STATE.progress[p.id] = 0; });
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
function _xpForLevel(lv){ return (lv-1)*(lv-1)*100; }
const ACH_LABELS = {
start:"Начало главы 6!",
p34_done:"Ток в металлах. Сверхпроводимость освоен!",
p35_done:"Ток в электролитах освоен!",
p36_done:"Ток в газах. Плазма освоен!",
p37_done:"Ток в полупроводниках освоен!",
ch6_done:"Глава 6 пройдена!"
};
function loadProgress(){
try{
const s=localStorage.getItem('physics10_ch6_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
const a=localStorage.getItem('physics10_ch6_achievements');
if(a){ const p=JSON.parse(a); if(Array.isArray(p)) p.forEach(id=>STATE.achievements.set(id, ACH_LABELS[id]||id)); else 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('physics10_xp')||0); STATE.level=calcLevel(STATE.xp);
}catch(e){}
}
function saveProgress(){
try{
localStorage.setItem('physics10_ch6_progress', JSON.stringify(STATE.progress));
localStorage.setItem('physics10_ch6_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
localStorage.setItem('physics10_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]>=50) markParaRead(key);
}
const _markedRead=new Set();
let _pendingProgressBody=null, _progressTimer=null;
function _flushProgress(){
const body=_pendingProgressBody; _pendingProgressBody=null; if(!body) return;
const 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 _queueProgress(patch){ _pendingProgressBody=Object.assign(_pendingProgressBody||{},patch); if(_progressTimer) clearTimeout(_progressTimer); _progressTimer=setTimeout(_flushProgress, 600); }
function markLastPara(id){ _queueProgress({last_para:id}); }
function markParaRead(id){ if(_markedRead.has(id)) return; _markedRead.add(id); _queueProgress({mark_read:id}); }
window.addEventListener('beforeunload', _flushProgress);
function loadServerReadState(){
const tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok) return;
fetch('/api/textbooks/'+_TB_SLUG,{headers:{'Authorization':'Bearer '+tok}}).then(r=>r.ok?r.json():null).then(d=>{
if(!d||!d.progress) return;
(d.progress.read||[]).forEach(k=>{_markedRead.add(k); if((STATE.progress[k]||0)<50) STATE.progress[k]=100;});
saveProgress(); refreshProgressUI();
}).catch(()=>{});
}
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,'physics10-ch6-'+(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 refreshProgressUI(){
const total=Math.round(Object.values(STATE.progress).reduce((a,b)=>a+b,0)/TOTAL_PARAS);
const f=document.getElementById('hero-hp-fill'); if(f) f.style.width=total+'%';
const t=document.getElementById('hero-hp-text'); if(t) t.textContent=total+'% пройдено';
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)+'%'; });
const xpBadge=document.getElementById('hero-xp-badge');
if(xpBadge){ xpBadge.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:13px;height:13px"><polygon points="12 2 22 20 2 20"/></svg> Ур. '+STATE.level+' \xb7 '+(STATE.xp||0)+' XP'; }
if(STATE.current && document.getElementById('sidebar-content')){ try{ buildSidebar(STATE.current); }catch(e){} }
}
function achievement(id,text){
if(STATE.achievements.has(id)) return;
STATE.achievements.set(id, text||ACH_LABELS[id]||id); saveProgress();
const pop=document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent=text||ACH_LABELS[id]||id; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),3300); }
addXp(20,'ach-'+id);
}
function buildParaSelector(){
const g=document.getElementById('psel-grid'); g.innerHTML='';
PARAS.forEach(p=>{
const card=document.createElement('div');
card.className='psel-card'+(p.final?' final':'');
card.dataset.id=p.id; card.dataset.progCard=p.id;
card.innerHTML='<div class="psel-num">'+p.num+'</div><div class="psel-name">'+p.name+'</div><div class="psel-prog"><div class="psel-prog-fill"></div></div>';
card.addEventListener('click', ()=>goTo(p.id));
g.appendChild(card);
});
}
const BUILT=new Set();
const BUILDERS = { p34:()=>build_p34(), p35:()=>build_p35(), p36:()=>build_p36(), p37:()=>build_p37(), final6:()=>build_final6() };
function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } }
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) setTimeout(()=>renderMath(el), 0);
markLastPara(id);
}
const SIDEBARS = {
p34:{title:"Шпаргалка §34",rows:[["Носители","свободные электроны"],["$\\rho(T) = \\rho_0(1 + \\alpha t)$","зависимость от $T$"],["Сверхпров.","$T < T_c$, $\\rho = 0$"]]},
p35:{title:"Шпаргалка §35",rows:[["Электролит","раствор/расплав ионных в-в"],["$m = kIt$","1-й закон Фарадея"],["$k = M/(zF)$","эл.-хим. эквивалент"],["$F$","$F = 96485$ Кл/моль"]]},
p36:{title:"Шпаргалка §36",rows:[["Несам.","требует ионизатора"],["Самост.","тлеющий, искровой, дуговой, коронный"],["Плазма","газ из ионов и электронов"]]},
p37:{title:"Шпаргалка §37",rows:[["n-тип","примесь-донор, носители — электроны"],["p-тип","примесь-акцептор, носители — дырки"],["p-n","одностор. проводимость, диод"]]},
final6:{title:"Финал главы 6",rows:[["§§3437","теория главы 6"],["Награда","+50 XP"]]}
};
const TIPS=[
{sec:'p34',html:"В металлах носители — свободные электроны. $\\rho(T) = \\rho_0(1 + \\alpha t)$. Сверхпров.: $\\rho = 0$."},
{sec:'p35',html:"Электролиз: $m = kIt$ — 1-й закон Фарадея. $k = M/(zF)$, $F = 96485$ Кл/моль."},
{sec:'p36',html:"Самостоятельный разряд: тлеющий, искровой, дуговой, коронный. Плазма — ионизованный газ."},
{sec:'p37',html:"Полупроводники: n-тип (донор, электроны) и p-тип (акцептор, дырки). p-n переход — диод."},
{sec:'final6',html:"Финал главы 6 — интегрированные задачи по §§34–37. В разработке (Phase 6+)."}
];
function buildSidebar(id){
const box=document.getElementById('sidebar-content');
const sb=SIDEBARS[id]||SIDEBARS[PARAS[0].id];
let html='';
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;
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>';
html+='<div class="sidecard"><h4>'+sb.title+'</h4>';
sb.rows.forEach(([k,v])=>{ html+='<div class="sidecard-row"><b>'+k+'</b>'+(v?' \u2014 '+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,#fef3c7),var(--pri-soft));border-color:var(--warn,#f59e0b)"><h4 style="color:#92400e;display:flex;align-items:center;gap:6px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><polygon points="12,2 22,20 2,20"/></svg>Подсказка</h4><div class="sidecard-row" style="margin-bottom:0;font-size:.84rem;line-height:1.55">'+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(text=>{ html+='<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">&#10003; '+text+'</div>'; });
html+='</div>';
}
box.innerHTML=html;
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
}
function initTheme(){
const t=localStorage.getItem('physics10_ch6_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('physics10_ch6_theme', dark?'dark':'light');
document.getElementById('theme-lab').textContent=dark?'Светлая':'Тёмная';
});
}
function renderMath(root){ if(window.renderMathInElement){ try{ renderMathInElement(root, {delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false}); }catch(e){} } }
function feedback(elm, ok, text){ if(!elm) return; elm.className='feedback '+(ok?'ok':'fail'); elm.innerHTML=text||(ok?'&#10003; Верно!':'&#10007; Неверно'); elm.style.display='block'; try{renderMath(elm);}catch(e){} }
function fmt(n){ if(!isFinite(n)) return '?'; if(Number.isInteger(n)) return String(n); return Math.abs(n-Math.round(n))<1e-9?String(Math.round(n)):(+n.toFixed(6)).toString(); }
function ipow(base, exp){ let r=1; for(let i=0;i<Math.abs(exp);i++) r*=base; return exp<0 ? 1/r : r; }
function gcd(a,b){ a=Math.abs(a|0); b=Math.abs(b|0); while(b){ const t=b; b=a%b; a=t; } return a||1; }
function makeCard(kind, title, num, body){
const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно'};
return '<div class="card"><div class="card-header"><div class="card-icon '+kind+'">'+ICONS[kind]+'</div><div class="card-title">'+(labels[kind]||'')+(title&&title!==labels[kind]?' \xb7 '+title:'')+'</div>'+(num?'<div class="card-num">'+num+'</div>':'')+'</div><div class="card-body">'+body+'</div></div>';
}
function setupSorter(cfg){
const placed = {}; const pool = document.getElementById(cfg.poolId); const scope = document.querySelector(cfg.scopeSelector);
if(!pool||!scope) return {placed,render:()=>{},reset:()=>{}};
pool.classList.add('dnd-pool'); if(cfg.columnLayout) pool.classList.add('col');
let armed = null;
function buildChip(it,isPlaced){ const e=document.createElement('div'); e.className='dnd-chip'+(isPlaced?' placed':''); e.dataset.id=it.id; e.innerHTML='<span class="dnd-txt">'+it.html+'</span><span class="dnd-x" title="Убрать">\xd7</span>'; attach(e,it.id); return e; }
function attach(elm,itId){ let ghost=null,dragging=false,sx=0,sy=0; elm.addEventListener('pointerdown',ev=>{ if(ev.button!==undefined&&ev.button!==0) return;
ev.preventDefault(); if(ev.target.classList&&ev.target.classList.contains('dnd-x')){ ev.stopPropagation(); if(placed[itId]){delete placed[itId];render();}else if(armed===itId){armed=null;render();} return; } sx=ev.clientX;sy=ev.clientY; const r=elm.getBoundingClientRect(); const ox=ev.clientX-r.left,oy=ev.clientY-r.top; try{elm.setPointerCapture(ev.pointerId);}catch(e){} function onMove(e){ const dx=e.clientX-sx,dy=e.clientY-sy; if(!dragging&&Math.hypot(dx,dy)>8){ dragging=true; ghost=elm.cloneNode(true); ghost.classList.remove('armed'); ghost.style.cssText='position:fixed;z-index:9999;pointer-events:none;opacity:.9;transform:rotate(-2.5deg);box-shadow:0 14px 36px rgba(0,0,0,.32);width:'+r.width+'px;left:'+(e.clientX-ox)+'px;top:'+(e.clientY-oy)+'px'; document.body.appendChild(ghost); elm.classList.add('dragging'); } if(dragging&&ghost){ ghost.style.left=(e.clientX-ox)+'px';ghost.style.top=(e.clientY-oy)+'px'; const under=document.elementsFromPoint(e.clientX,e.clientY); scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); const tgt=under.find(n=>n.classList&&(n.classList.contains('drop-box')||n.classList.contains('dnd-pool'))); if(tgt)tgt.classList.add('over'); } } function onUp(e){ elm.removeEventListener('pointermove',onMove);elm.removeEventListener('pointerup',onUp);elm.removeEventListener('pointercancel',onUp);elm.classList.remove('dragging'); if(ghost){ghost.remove();ghost=null;} scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); if(dragging){ const under=document.elementsFromPoint(e.clientX,e.clientY); const box=under.find(n=>n.classList&&n.classList.contains('drop-box')); const pl=under.find(n=>n.classList&&n.classList.contains('dnd-pool')); if(box){const di=box.querySelector('[data-cat]');if(di){placed[itId]=di.dataset.cat;armed=null;render();return;}}else if(pl){delete placed[itId];armed=null;render();return;} }else{ if(placed[itId]){delete placed[itId];armed=null;render();}else{armed=(armed===itId)?null:itId;render();} } dragging=false; } elm.addEventListener('pointermove',onMove);elm.addEventListener('pointerup',onUp);elm.addEventListener('pointercancel',onUp); }); }
function attachBoxTaps(){ scope.querySelectorAll('.drop-box').forEach(box=>{ box.addEventListener('click',ev=>{ if(!armed)return; if(ev.target.closest('.dnd-chip'))return; const di=box.querySelector('[data-cat]'); if(di){placed[armed]=di.dataset.cat;armed=null;render();} }); }); }
function render(){ pool.innerHTML=''; cfg.items.forEach(it=>{if(placed[it.id])return;const c=buildChip(it,false);if(armed===it.id)c.classList.add('armed');pool.appendChild(c);}); cfg.cats.forEach(cat=>{const box=scope.querySelector('.drop-items[data-cat="'+cat+'"]');if(!box)return;box.innerHTML='';cfg.items.forEach(it=>{if(placed[it.id]!==cat)return;box.appendChild(buildChip(it,true));});}); if(window.renderMathInElement)try{renderMath(scope);}catch(_){} }
attachBoxTaps(); render();
return {placed,render,reset(){ for(const k in placed)delete placed[k];armed=null;render(); }};
}
/* === SVG-хелперы (axes2D, plotFunc, pointWithDrop, asymptote, snapToValue, геом.) === */
function axes2D(W, H, pad, xmin, xmax, ymin, ymax){
const ux = (W - 2*pad) / (xmax - xmin);
const uy = (H - 2*pad) / (ymax - ymin);
const toX = v => pad + (v - xmin) * ux;
const toY = v => H - pad - (v - ymin) * uy;
let g = '';
g += '<g stroke="#e5e7eb" stroke-width="1">';
for (let x = Math.ceil(xmin); x <= xmax; x++){
g += '<line x1="'+toX(x)+'" y1="'+pad+'" x2="'+toX(x)+'" y2="'+(H-pad)+'"/>';
}
for (let y = Math.ceil(ymin); y <= ymax; y++){
g += '<line x1="'+pad+'" y1="'+toY(y)+'" x2="'+(W-pad)+'" y2="'+toY(y)+'"/>';
}
g += '</g>';
const y0 = toY(0), x0 = toX(0);
g += '<line x1="'+pad+'" y1="'+y0+'" x2="'+(W-pad)+'" y2="'+y0+'" stroke="#0f172a" stroke-width="1.5"/>';
g += '<line x1="'+x0+'" y1="'+pad+'" x2="'+x0+'" y2="'+(H-pad)+'" stroke="#0f172a" stroke-width="1.5"/>';
g += '<text x="'+(W-pad+2)+'" y="'+(y0-4)+'" font-size="11" fill="#0f172a">x</text>';
g += '<text x="'+(x0+4)+'" y="'+(pad-2)+'" font-size="11" fill="#0f172a">y</text>';
g += '<g font-size="10" fill="#64748b">';
for (let x = Math.ceil(xmin); x <= xmax; x++){
if (x !== 0) g += '<text x="'+(toX(x)-3)+'" y="'+(y0+12)+'">'+x+'</text>';
}
for (let y = Math.ceil(ymin); y <= ymax; y++){
if (y !== 0) g += '<text x="'+(x0+4)+'" y="'+(toY(y)+3)+'">'+y+'</text>';
}
g += '<text x="'+(x0+4)+'" y="'+(y0+12)+'">0</text>';
g += '</g>';
return { content: g, toX, toY, ux, uy };
}
function plotFunc(f, xmin, xmax, toX, toY, color, N){
N = N || 200;
let d = '';
let prevValid = false;
for (let i = 0; i <= N; i++){
const x = xmin + (xmax - xmin) * i / N;
let y;
try { y = f(x); } catch(e){ y = NaN; }
if (!isFinite(y) || isNaN(y) || y < -1e4 || y > 1e4){ prevValid = false; continue; }
d += (prevValid ? ' L' : ' M') + toX(x).toFixed(2) + ',' + toY(y).toFixed(2);
prevValid = true;
}
return '<path d="'+d+'" stroke="'+color+'" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/>';
}
function pointWithDrop(x, fx, toX, toY, color, label){
const px = toX(x), py = toY(fx);
let s = '';
s += '<line x1="'+px+'" y1="'+py+'" x2="'+px+'" y2="'+toY(0)+'" stroke="'+color+'" stroke-width="1.2" stroke-dasharray="3 3" opacity=".7"/>';
s += '<line x1="'+px+'" y1="'+py+'" x2="'+toX(0)+'" y2="'+py+'" stroke="'+color+'" stroke-width="1.2" stroke-dasharray="3 3" opacity=".7"/>';
s += '<circle cx="'+px+'" cy="'+py+'" r="4.5" fill="'+color+'" stroke="#fff" stroke-width="2"/>';
if (label){
s += '<text x="'+(px+8)+'" y="'+(py-8)+'" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="'+color+'">'+label+'</text>';
}
return s;
}
function asymptote(orientation, value, toX, toY, xmin, xmax, ymin, ymax, color){
color = color || '#94a3b8';
if (orientation === 'h'){
const y = toY(value);
return '<line x1="'+toX(xmin)+'" y1="'+y+'" x2="'+toX(xmax)+'" y2="'+y+'" stroke="'+color+'" stroke-width="1.3" stroke-dasharray="6 4"/>';
} else {
const x = toX(value);
return '<line x1="'+x+'" y1="'+toY(ymin)+'" x2="'+x+'" y2="'+toY(ymax)+'" stroke="'+color+'" stroke-width="1.3" stroke-dasharray="6 4"/>';
}
}
function snapToValue(value, snapPoints, tolerance){
tolerance = tolerance || 0.1;
for (const sp of snapPoints){
if (Math.abs(value - sp) < tolerance) return sp;
}
return value;
}
function rightAngleMark(V, uIn, wIn, s){
s = s || 9;
const p1 = {x: V.x + s*uIn.x, y: V.y + s*uIn.y};
const c = {x: p1.x + s*wIn.x, y: p1.y + s*wIn.y};
const p2 = {x: V.x + s*wIn.x, y: V.y + s*wIn.y};
return p1.x+','+p1.y+' '+c.x+','+c.y+' '+p2.x+','+p2.y;
}
function angleArcAuto(V, uA, uB, R){
const sA = {x: V.x + R*uA.x, y: V.y + R*uA.y};
const eB = {x: V.x + R*uB.x, y: V.y + R*uB.y};
const cross = uA.x*uB.y - uA.y*uB.x;
const sweep = cross > 0 ? 1 : 0;
return 'M'+sA.x+','+sA.y+' A'+R+','+R+' 0 0,'+sweep+' '+eB.x+','+eB.y;
}
function unitVec(p1, p2){
const dx = p2.x - p1.x, dy = p2.y - p1.y;
const len = Math.sqrt(dx*dx + dy*dy) || 1;
return {x: dx/len, y: dy/len};
}
function deg2rad(d){ return d * Math.PI / 180; }
const ICONS = {
repeat:'<svg class="ic" viewBox="0 0 24 24"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',
theory:'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>',
algo:'<svg class="ic" viewBox="0 0 24 24"><polyline points="17 11 21 7 17 3"/><line x1="21" y1="7" x2="9" y2="7"/><polyline points="7 13 3 17 7 21"/><line x1="3" y1="17" x2="15" y2="17"/></svg>',
rule:'<svg class="ic" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>',
example:'<svg class="ic" viewBox="0 0 24 24"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 13c1 1 2 2 2 4h4c0-2 1-3 2-4a7 7 0 0 0-4-13z"/></svg>',
oral:'<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
};
function secNavFor(curId){
const idx = PARAS.findIndex(p => p.id === curId);
const prev = idx > 0 ? PARAS[idx-1].id : null;
const next = idx < PARAS.length - 1 ? PARAS[idx+1].id : null;
return secNav(prev, next);
}
function secNav(prev, next){
const NAMES = {p34:'\xA734',p35:'\xA735',p36:'\xA736',p37:'\xA737',final6:'Финал'};
let h='<div class="sec-nav">';
h+=prev?'<button class="btn" onclick="goTo(\''+prev+'\')"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> '+NAMES[prev]+'</button>':'<span></span>';
h+=next?'<button class="btn primary" onclick="goTo(\''+next+'\')">'+NAMES[next]+' <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>':'<span></span>';
h+='</div>'; return h;
}
function readButton(paraId){
const p = PARAS.find(x => x.id === paraId);
const labelTail = p && p.final ? 'финал' : (p ? p.num : '\xA7?');
return '<div style="margin-top:18px;display:flex;justify-content:center">'
+'<button class="btn primary" id="'+paraId+'-read-btn">'
+'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>'
+' Я прочитал — '+labelTail+' (+10 XP)'
+'</button></div>';
}
function wireReadBtn(paraId){
const btn = document.getElementById(paraId+'-read-btn'); if(!btn) return;
btn.addEventListener('click', ()=>{
addXp(10, paraId+'-read'); bumpProgress(paraId, 30);
btn.textContent='Прочитано! +10 XP'; btn.disabled=true; btn.style.opacity=.6;
const aId = paraId+'_done';
if(ACH_LABELS[aId]) achievement(aId);
});
}
/* ===== STUB BUILDERS — наполнение в Phase 1+ ===== */
function build_p34(){
const box = document.getElementById('p34-body');
let html = '';
/* THEORY 1 — Природа тока в металлах */
html += makeCard('theory', "Природа тока в металлах", "§34", `
<p>В <b>металлах</b> свободными носителями заряда являются <b>электроны проводимости</b> — внешние электроны атомов, не связанные с конкретным узлом решётки.</p>
<p style="margin-top:10px">Концентрация свободных электронов огромна: $n \\sim 10^{29}$ в м³.</p>
<p style="margin-top:10px"><b>Кристаллическая решётка</b> металла состоит из положительных ионов в узлах. Между ними движется «электронный газ» — почти свободные электроны.</p>
<p style="margin-top:10px"><b>Без электрического поля</b>: электроны движутся <b>хаотически</b> со скоростями $\\sim 10^5 - 10^6$ м/с. Средняя скорость направленного движения равна нулю — тока нет.</p>
<p style="margin-top:10px"><b>В электрическом поле $\\vec{E}$</b>: на хаотическое движение накладывается <b>дрейфовое</b> движение в сторону, противоположную $\\vec{E}$ (так как заряд электрона отрицательный). Средняя дрейфовая скорость очень мала: $v_{др} \\sim 10^{-3} - 10^{-5}$ м/с.</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px"><b>Парадокс.</b> Дрейф электронов очень медленный, но ток в проводнике включается «мгновенно» — электрическое поле в проводнике устанавливается со скоростью света $c \\approx 3\\cdot 10^8$ м/с.</p>
`);
/* THEORY 2 — Сопротивление и температура */
html += makeCard('rule', "Сопротивление и зависимость от температуры", "§34", `
<p><b>Сопротивление</b> однородного проводника:</p>
<p style="text-align:center;margin:8px 0">$$R = \\rho\\,\\dfrac{L}{S}$$</p>
<ul style="margin:6px 0 6px 22px">
<li>$\\rho$ — удельное сопротивление (Ом·м);</li>
<li>$L$ — длина проводника (м);</li>
<li>$S$ — площадь поперечного сечения (м²).</li>
</ul>
<p style="margin-top:10px"><b>Зависимость от температуры</b> для металлов — линейная:</p>
<p style="text-align:center;margin:8px 0">$$\\rho(t) = \\rho_0\\,(1 + \\alpha t)$$</p>
<p>где $\\rho_0$ — удельное сопротивление при $0°$C, $t$ — температура в $°$C, $\\alpha$ — <b>температурный коэффициент сопротивления</b> (К$^{-1}$).</p>
<p style="margin-top:10px"><b>Эталонные значения $\\alpha$</b>:</p>
<ul style="margin:6px 0 6px 22px">
<li>Медь: $\\alpha \\approx 0{,}0043$ К$^{-1}$;</li>
<li>Алюминий: $\\alpha \\approx 0{,}0042$ К$^{-1}$;</li>
<li>Железо: $\\alpha \\approx 0{,}0066$ К$^{-1}$;</li>
<li>Платина: $\\alpha \\approx 0{,}0039$ К$^{-1}$ — используется в термометрах сопротивления.</li>
</ul>
<p style="margin-top:10px">С нагревом сопротивление металлов <b>увеличивается</b>: атомы решётки сильнее колеблются и чаще «мешают» электронам дрейфовать.</p>
`);
/* THEORY 3 — Сверхпроводимость */
html += makeCard('example', "Сверхпроводимость", "§34", `
<p><b>Сверхпроводимость</b> — явление полного исчезновения сопротивления у некоторых металлов при температурах ниже <b>критической</b> $T_c$.</p>
<p style="margin-top:10px">Открыта в 1911 году для ртути ($T_c = 4{,}2$ К — близко к абсолютному нулю).</p>
<p style="margin-top:10px"><b>Критические температуры</b>:</p>
<ul style="margin:6px 0 6px 22px">
<li>Ртуть: $T_c = 4{,}2$ К;</li>
<li>Свинец: $T_c = 7{,}2$ К;</li>
<li>Ниобий: $T_c = 9{,}2$ К;</li>
<li>Высокотемпературные сверхпроводники (керамика YBa$_2$Cu$_3$O$_7$): $T_c \\approx 95$ К — выше точки кипения жидкого азота (77 К). Открыты в 1986, революция, Нобелевская премия.</li>
</ul>
<p style="margin-top:10px"><b>В сверхпроводнике ток может циркулировать бесконечно долго без потерь.</b></p>
<p style="margin-top:10px"><b>Применение:</b></p>
<ul style="margin:6px 0 6px 22px">
<li><b>Сверхмощные магниты</b> — МРТ, ускорители (в Большом адронном коллайдере все магниты сверхпроводящие);</li>
<li><b>Маглев-поезда</b> — левитация на сверхпроводящих магнитах;</li>
<li><b>Беспотерьная передача электроэнергии</b> — экспериментально для коротких линий.</li>
</ul>
`);
/* INTERACTIVE 1 — Симуляция дрейфа электронов */
html += `<div class="wg" id="p34-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Симуляция дрейфа электронов</div></div>
<div class="wg-help">При $U = 0$ — электроны движутся <b>хаотически</b>, тока нет. При $U > 0$ — на хаос накладывается медленный <b>дрейф</b> в сторону, противоположную $\\vec{E}$. Дрейф $\\Rightarrow$ ток.</div>
<div class="sliders">
<label>Напряжение $U$ (В): <b id="p34-iv1-UL">0.0</b><input type="range" id="p34-iv1-U" min="0" max="10" value="0" step="0.5"></label>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:8px;margin-top:8px">
<svg id="p34-iv1-svg" viewBox="0 0 380 240" width="100%" style="height:auto"></svg>
</div>
<div id="p34-iv1-out" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.95rem;line-height:1.7;text-align:center"></div>
</div>`;
/* INTERACTIVE 2 — Температурная зависимость */
html += `<div class="wg" id="p34-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Сопротивление: график $R(t)$</div></div>
<div class="wg-help">Для металлов: $R(t) = R_0(1 + \\alpha t)$ — прямая линия. Сверхпроводники имеют <b>скачок</b> до $R = 0$ при $T < T_c$.</div>
<div class="sliders">
<label>Материал: <b id="p34-iv2-ML">Медь</b><input type="range" id="p34-iv2-M" min="0" max="3" value="0" step="1"></label>
<label>$R_0$ при $0°$C (Ом): <b id="p34-iv2-RL">1.0</b><input type="range" id="p34-iv2-R" min="0.1" max="10" value="1" step="0.1"></label>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:8px;margin-top:8px">
<svg id="p34-iv2-svg" viewBox="0 0 380 260" width="100%" style="height:auto"></svg>
</div>
<div id="p34-iv2-out" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.95rem;line-height:1.7;text-align:center"></div>
</div>`;
/* INTERACTIVE 3 — Носители заряда в разных средах */
html += `<div class="wg" id="p34-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Кто переносит ток?</div></div>
<div class="wg-help">В каждой среде свои носители заряда — определи правильно.</div>
<div class="score-display"><span>Задача <b id="p34-iv3-i">1</b> / 6</span><span>Очки: <b id="p34-iv3-s">0</b> / 6</span></div>
<div id="p34-iv3-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div id="p34-iv3-opts" style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px"></div>
<div class="feedback" id="p34-iv3-fb"></div>
<div class="actions"><button class="btn" id="p34-iv3-restart">Начать заново</button></div>
</div>`;
/* INTERACTIVE 4 — Тренажёр сопротивления */
html += `<div class="wg" id="p34-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр: сопротивление и сверхпроводимость</div></div>
<div class="wg-help">5 задач. Допуск $\\pm 5\\%$. Формулы: $R = \\rho L/S$, $R(t) = R_0(1+\\alpha t)$.</div>
<div class="score-display"><span>Задача <b id="p34-iv4-i">1</b> / 5</span><span>Очки: <b id="p34-iv4-s">0</b> / 5</span></div>
<div id="p34-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div id="p34-iv4-form" style="display:flex;gap:8px;justify-content:center;margin-bottom:8px;flex-wrap:wrap">
<input type="number" id="p34-iv4-inp" step="any" style="padding:8px 10px;border:1px solid var(--border);border-radius:6px;width:140px;font-size:1rem">
<button class="btn primary" id="p34-iv4-go">Проверить</button>
</div>
<div class="feedback" id="p34-iv4-fb"></div>
<div class="actions"><button class="btn" id="p34-iv4-restart">Начать заново</button></div>
</div>`;
html += secNav(null, 'p35');
html += readButton('p34');
box.innerHTML = html;
renderMath(box);
/* IV1 — Дрейф электронов */
(function(){
const svg = document.getElementById('p34-iv1-svg');
const out = document.getElementById('p34-iv1-out');
const UI = document.getElementById('p34-iv1-U'), UL = document.getElementById('p34-iv1-UL');
const W = 380, H = 240;
// Решётка ионов: сетка
const ions = [];
for(let r=0; r<4; r++){
for(let c=0; c<7; c++){
ions.push({x: 40 + c*48, y: 50 + r*48});
}
}
// Электроны
const N = 22;
const els = [];
for(let k=0; k<N; k++){
els.push({
x: 30 + Math.random()*320,
y: 30 + Math.random()*180,
vx: (Math.random()-0.5)*1.8,
vy: (Math.random()-0.5)*1.8
});
}
let rafId = null;
let configsSeen = new Set(), _done = false;
function step(){
const U = +UI.value;
const drift = U * 0.18; // дрейфовая скорость "пиксели/кадр"
// обновим электроны: хаос + дрейф вправо (если U>0)
els.forEach(e => {
// случайные толчки от ионов
e.vx += (Math.random()-0.5)*0.45;
e.vy += (Math.random()-0.5)*0.45;
// ограничение
const sp = Math.hypot(e.vx, e.vy);
if(sp > 2.4){ e.vx *= 2.4/sp; e.vy *= 2.4/sp; }
e.x += e.vx + drift;
e.y += e.vy;
// отскок от границ
if(e.x < 16){ e.x = 364; }
if(e.x > 364){ e.x = 16; }
if(e.y < 16){ e.y = 16; e.vy = Math.abs(e.vy); }
if(e.y > 220){ e.y = 220; e.vy = -Math.abs(e.vy); }
});
draw();
rafId = requestAnimationFrame(step);
}
function draw(){
const U = +UI.value;
UL.textContent = U.toFixed(1);
let g = '';
g += '<rect x="0" y="0" width="'+W+'" height="'+H+'" fill="#fafafa"/>';
// рамка проводника
g += '<rect x="8" y="14" width="364" height="212" fill="none" stroke="#cbd5e1" stroke-width="1.4" rx="6"/>';
// подпись E
if(U > 0){
g += PHYS.drawArrow(40, 8, 90, 8, '#dc2626', 2, 8);
g += '<text x="100" y="12" font-family="JetBrains Mono,monospace" font-size="12" font-weight="700" fill="#dc2626">E</text>';
}
// ионы (большие красные +)
ions.forEach(io => {
g += '<circle cx="'+io.x+'" cy="'+io.y+'" r="7" fill="#fecaca" stroke="#dc2626" stroke-width="1.4"/>';
g += '<text x="'+io.x+'" y="'+(io.y+3.5)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="800" fill="#7f1d1d">+</text>';
});
// электроны
els.forEach(e => {
g += '<circle cx="'+e.x.toFixed(1)+'" cy="'+e.y.toFixed(1)+'" r="3.2" fill="#0891b2" stroke="#fff" stroke-width="0.8"/>';
// вектор скорости
if(U > 0){
const sx = e.x, sy = e.y;
const ex = sx + 6, ey = sy;
g += '<line x1="'+sx.toFixed(1)+'" y1="'+sy.toFixed(1)+'" x2="'+ex.toFixed(1)+'" y2="'+ey.toFixed(1)+'" stroke="#0891b2" stroke-width="1" opacity=".7"/>';
}
});
svg.innerHTML = g;
const vDrift = U > 0 ? (U * 0.0002).toFixed(4) : '0';
out.innerHTML = U === 0
? 'При $U = 0$ электроны движутся <b>хаотически</b> — тока нет.'
: '$U = '+U.toFixed(1)+'$ В $\\Rightarrow$ дрейф электронов вправо, $v_{др} \\sim '+vDrift+'$ м/с (примерная оценка).';
renderMath(out);
}
UI.addEventListener('input', ()=>{
configsSeen.add(UI.value);
if(!_done && configsSeen.size >= 4){ _done = true; addXp(15, 'p34-iv1'); bumpProgress('p34', 20); }
});
draw();
rafId = requestAnimationFrame(step);
})();
/* IV2 — R(t) график */
(function(){
const svg = document.getElementById('p34-iv2-svg');
const out = document.getElementById('p34-iv2-out');
const MI = document.getElementById('p34-iv2-M'), ML = document.getElementById('p34-iv2-ML');
const RI = document.getElementById('p34-iv2-R'), RL = document.getElementById('p34-iv2-RL');
const MATS = [
{ name:'Медь', alpha:0.0043, color:'#b45309', sc:false },
{ name:'Алюминий', alpha:0.0042, color:'#64748b', sc:false },
{ name:'Железо', alpha:0.0066, color:'#374151', sc:false },
{ name:'Свинец (сверхпр. при $T<7{,}2$ К)', alpha:0.0042, color:'#7c3aed', sc:true, Tc:7.2 }
];
let switched = new Set(), _done = false;
function draw(){
const m = MATS[Math.min(3, Math.max(0, +MI.value))];
const R0 = +RI.value;
ML.innerHTML = m.name;
RL.textContent = R0.toFixed(1);
renderMath(MI.parentNode);
// Оси: t от -50 до 500 °C; R от 0 до примерно R0*(1+alpha*500)
const Rmax = R0 * (1 + m.alpha * 500) * 1.1;
const Wd = 380, Hd = 260, pad = 38;
const tmin = -50, tmax = 500;
const ux = (Wd - 2*pad) / (tmax - tmin);
const uy = (Hd - 2*pad) / (Rmax - 0);
const toX = t => pad + (t - tmin) * ux;
const toY = R => Hd - pad - R * uy;
let g = '';
g += '<rect x="0" y="0" width="'+Wd+'" height="'+Hd+'" fill="#fafafa"/>';
// сетка
g += '<g stroke="#e5e7eb" stroke-width="1">';
for(let t=0; t<=500; t+=100){
const x = toX(t);
g += '<line x1="'+x+'" y1="'+pad+'" x2="'+x+'" y2="'+(Hd-pad)+'"/>';
}
g += '</g>';
// оси
g += '<line x1="'+pad+'" y1="'+toY(0)+'" x2="'+(Wd-pad)+'" y2="'+toY(0)+'" stroke="#0f172a" stroke-width="1.4"/>';
g += '<line x1="'+toX(0)+'" y1="'+pad+'" x2="'+toX(0)+'" y2="'+(Hd-pad)+'" stroke="#0f172a" stroke-width="1.4"/>';
g += '<text x="'+(Wd-pad+2)+'" y="'+(toY(0)-4)+'" font-size="11" fill="#0f172a">t, °C</text>';
g += '<text x="'+(toX(0)+4)+'" y="'+(pad-2)+'" font-size="11" fill="#0f172a">R, Ом</text>';
// tick labels
g += '<g font-size="10" fill="#64748b">';
for(let t=0; t<=500; t+=100){
g += '<text x="'+(toX(t)-3)+'" y="'+(toY(0)+12)+'">'+t+'</text>';
}
g += '<text x="'+(toX(0)+4)+'" y="'+(toY(R0)+3)+'">'+R0.toFixed(1)+'</text>';
g += '</g>';
// Линия R(t)
let path = '';
for(let i=0; i<=80; i++){
const t = tmin + (tmax - tmin)*i/80;
const Rv = R0 * (1 + m.alpha * t);
path += (i===0 ? 'M' : 'L') + toX(t).toFixed(1) + ',' + toY(Math.max(0,Rv)).toFixed(1) + ' ';
}
g += '<path d="'+path+'" stroke="'+m.color+'" stroke-width="2.4" fill="none"/>';
// Если сверхпроводник — вертикальный скачок до 0 при T=Tc
if(m.sc){
// Tc в °C
const tcC = m.Tc - 273.15;
// отметим линию
const xTc = toX(tcC);
if(xTc > pad && xTc < Wd - pad){
g += '<line x1="'+xTc+'" y1="'+toY(0)+'" x2="'+xTc+'" y2="'+toY(R0)+'" stroke="#dc2626" stroke-width="2.2" stroke-dasharray="4 3"/>';
g += '<text x="'+(xTc+4)+'" y="'+toY(R0*0.5)+'" font-size="10" fill="#dc2626">T_c</text>';
}
g += '<text x="'+(Wd/2)+'" y="'+(Hd-8)+'" text-anchor="middle" font-size="10" fill="#7c3aed">Слева от $T_c$ — сверхпроводимость: $R = 0$</text>';
}
// Точка R при t=100
const t100 = 100;
const R100 = R0 * (1 + m.alpha * t100);
g += '<circle cx="'+toX(t100)+'" cy="'+toY(R100)+'" r="4.5" fill="'+m.color+'" stroke="#fff" stroke-width="2"/>';
g += '<text x="'+(toX(t100)+8)+'" y="'+(toY(R100)-6)+'" font-family="JetBrains Mono,monospace" font-size="10" fill="'+m.color+'">R(100°C) = '+R100.toFixed(2)+'</text>';
svg.innerHTML = g;
out.innerHTML = '$\\alpha = '+m.alpha.toFixed(4)+'$ К$^{-1}$ &nbsp; $R(100°C) = '+R0.toFixed(2)+'\\cdot(1+'+m.alpha.toFixed(4)+'\\cdot 100) = '+R100.toFixed(3)+'$ Ом';
renderMath(out);
}
MI.addEventListener('input', ()=>{
switched.add(MI.value);
draw();
if(!_done && switched.size >= 3){ _done = true; addXp(15, 'p34-iv2'); bumpProgress('p34', 20); }
});
RI.addEventListener('input', draw);
draw();
})();
/* IV3 — Носители заряда */
(function(){
const OPTS = ['Электроны', 'Ионы', 'Электроны + ионы'];
const Q = [
{ q:'В <b>металлах</b> ток переносят…', ans:0, why:'Свободные электроны проводимости (~$10^{29}$ в м³). Ионы решётки неподвижны.' },
{ q:'В <b>электролитах</b> (раствор соли) ток переносят…', ans:1, why:'Положительные катионы и отрицательные анионы движутся к электродам.' },
{ q:'В <b>газах при электрическом разряде</b> ток переносят…', ans:2, why:'Электроны (ионизированные при разряде) и положительные ионы.' },
{ q:'В <b>вакуумной электронной лампе</b> ток переносят…', ans:0, why:'Только электроны, испускаемые горячим катодом (термоэлектронная эмиссия).' },
{ q:'В <b>сверхпроводнике</b> (металл при $T<T_c$) ток переносят…', ans:0, why:'Электроны, но <b>без сопротивления</b> — куперовские пары не рассеиваются на решётке.' },
{ q:'В <b>полупроводнике</b> ток переносят…', ans:2, why:'Электроны проводимости и «дырки» (положительные носители) — оба типа.' }
];
let i = 0, score = 0;
const qEl = document.getElementById('p34-iv3-q');
const oEl = document.getElementById('p34-iv3-opts');
const fb = document.getElementById('p34-iv3-fb');
const iEl = document.getElementById('p34-iv3-i');
const sEl = document.getElementById('p34-iv3-s');
function show(){
if(i >= Q.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
oEl.innerHTML = '';
if(score === Q.length){ addXp(15, 'p34-iv3'); bumpProgress('p34', 25); }
else if(score >= 4){ addXp(8, 'p34-iv3'); bumpProgress('p34', 15); }
return;
}
iEl.textContent = (i+1);
sEl.textContent = score;
qEl.innerHTML = Q[i].q;
oEl.innerHTML = OPTS.map((t,k) => '<button class="btn primary" data-v="'+k+'">'+t+'</button>').join('');
fb.style.display = 'none';
renderMath(qEl);
oEl.querySelectorAll('button').forEach(b => {
b.addEventListener('click', () => {
const v = +b.dataset.v;
if(v === Q[i].ans){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].why+' Дальше ▶'); }
else feedback(fb, false, '&#10007; Верно: '+OPTS[Q[i].ans]+'. '+Q[i].why+' Дальше ▶');
sEl.textContent = score;
oEl.querySelectorAll('button').forEach(x => x.disabled = true);
i++;
setTimeout(show, 1900);
});
});
}
document.getElementById('p34-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); });
show();
})();
/* IV4 — Тренажёр */
(function(){
const Q = [
{ q:'Медь: $\\rho = 1{,}7\\cdot 10^{-8}$ Ом·м. Провод $L = 10$ м, сечение $S = 1$ мм² $= 10^{-6}$ м². Найди $R$ (Ом).', ans:0.17, tol:0.01, why:'$R = \\rho L/S = 1{,}7\\cdot 10^{-8}\\cdot 10 / 10^{-6} = 0{,}17$ Ом.' },
{ q:'Медь: $R_0 = 1$ Ом при $0°$C, $\\alpha = 0{,}0043$ К$^{-1}$. Найди $R$ при $100°$C (Ом).', ans:1.43, tol:0.05, why:'$R = R_0(1 + \\alpha t) = 1\\cdot(1 + 0{,}0043\\cdot 100) = 1{,}43$ Ом.' },
{ q:'Сверхпроводимость — это явление, когда $R$… (1=максимально, 2=равно нулю, 3=пропорц. $T$). Введи номер.', ans:2, tol:0.1, why:'При $T<T_c$ сопротивление сверхпроводника <b>равно нулю</b>.' },
{ q:'Первая критическая температура сверхпроводимости ртути (в кельвинах). Введи число.', ans:4.2, tol:0.3, why:'Камерлинг-Оннес, 1911: $T_c({Hg}) = 4{,}2$ К.' },
{ q:'Алюминий ($\\alpha = 0{,}0042$ К$^{-1}$). $R_0 = 5$ Ом при $0°$C. Найди $R$ при $50°$C (Ом).', ans:6.05, tol:0.2, why:'$R = 5(1 + 0{,}0042\\cdot 50) = 5\\cdot 1{,}21 = 6{,}05$ Ом.' }
];
let i = 0, score = 0;
const qEl = document.getElementById('p34-iv4-q');
const fb = document.getElementById('p34-iv4-fb');
const iEl = document.getElementById('p34-iv4-i');
const sEl = document.getElementById('p34-iv4-s');
const inp = document.getElementById('p34-iv4-inp');
const bGo = document.getElementById('p34-iv4-go');
function show(){
if(i >= Q.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
inp.disabled = true; bGo.disabled = true;
if(score === Q.length){ addXp(15, 'p34-iv4'); bumpProgress('p34', 25); }
else if(score >= 3){ addXp(8, 'p34-iv4'); bumpProgress('p34', 15); }
return;
}
iEl.textContent = (i+1);
sEl.textContent = score;
qEl.innerHTML = Q[i].q;
fb.style.display = 'none';
inp.value = ''; inp.disabled = false; bGo.disabled = false; inp.focus();
renderMath(qEl);
}
function check(){
if(inp.disabled) return;
const v = parseFloat(inp.value.replace(',','.'));
if(!isFinite(v)){ feedback(fb, false, 'Введи число.'); return; }
const tol = Math.max(Q[i].tol, Math.abs(Q[i].ans)*0.05);
const ok = Math.abs(v - Q[i].ans) <= tol;
if(ok){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].why+' Дальше ▶'); }
else feedback(fb, false, '&#10007; Верно: '+Q[i].ans+'. '+Q[i].why+' Дальше ▶');
sEl.textContent = score;
inp.disabled = true; bGo.disabled = true;
i++;
setTimeout(show, 1900);
}
bGo.addEventListener('click', check);
inp.addEventListener('keydown', e => { if(e.key==='Enter') check(); });
document.getElementById('p34-iv4-restart').addEventListener('click', () => { i = 0; score = 0; inp.disabled=false; bGo.disabled=false; show(); });
show();
})();
wireReadBtn('p34');
}
function build_p35(){
const box = document.getElementById('p35-body');
let html = '';
/* THEORY 1 — Электролиты и ионная проводимость */
html += makeCard('theory', "Электролиты и ионная проводимость", "§35", `
<p><b>Электролиты</b> — вещества, проводящие электрический ток в растворе или расплаве за счёт движения ионов:</p>
<ul style="margin:6px 0 6px 22px">
<li>Растворы солей, кислот, щелочей в воде;</li>
<li>Расплавы солей.</li>
</ul>
<p style="margin-top:10px">В электролите присутствуют <b>свободные ионы</b> — продукт диссоциации молекул электролита:</p>
<ul style="margin:6px 0 6px 22px">
<li><b>Катионы</b> ($+$): Na$^+$, K$^+$, Cu$^{2+}$, Fe$^{2+}$, H$^+$ и др.;</li>
<li><b>Анионы</b> ($-$): Cl$^-$, SO$_4^{2-}$, NO$_3^-$, OH$^-$ и др.</li>
</ul>
<p style="margin-top:10px"><b>В электрическом поле</b> ионы движутся к электродам:</p>
<ul style="margin:6px 0 6px 22px">
<li>Катионы $(+)$ — к <b>катоду</b> $(-$ электрод);</li>
<li>Анионы $(-)$ — к <b>аноду</b> $(+$ электрод).</li>
</ul>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px"><b>Главное отличие от металлов:</b> в электролите переносится не только заряд, но и <b>вещество</b> — на электродах идут химические реакции. Это явление называется <b>электролизом</b>.</p>
`);
/* THEORY 2 — Законы Фарадея */
html += makeCard('rule', "Законы Фарадея для электролиза", "§35", `
<p><b>Первый закон Фарадея</b>: масса вещества, выделившегося на электроде, прямо пропорциональна заряду, прошедшему через электролит:</p>
<p style="text-align:center;margin:8px 0">$$m = k\\,I\\,t = k\\,q$$</p>
<ul style="margin:6px 0 6px 22px">
<li>$m$ — масса вещества (кг);</li>
<li>$I$ — сила тока (А);</li>
<li>$t$ — время (с);</li>
<li>$k$ — <b>электрохимический эквивалент</b> вещества (кг/Кл).</li>
</ul>
<p style="margin-top:10px"><b>Второй закон Фарадея</b>: электрохимический эквивалент пропорционален молярной массе и обратно пропорционален валентности:</p>
<p style="text-align:center;margin:8px 0">$$k = \\dfrac{M}{F\\,n}$$</p>
<ul style="margin:6px 0 6px 22px">
<li>$M$ — молярная масса (кг/моль);</li>
<li>$n$ — валентность иона;</li>
<li>$F = N_A\\,e \\approx 96\\,500$ Кл/моль — <b>постоянная Фарадея</b>.</li>
</ul>
<p style="margin-top:10px"><b>Объединённый закон Фарадея</b>:</p>
<p style="text-align:center;margin:8px 0">$$m = \\dfrac{M}{F\\,n}\\,I\\,t$$</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px"><b>Физический смысл $F$:</b> это заряд $\\sim 1$ моль однозарядных ионов, $F = N_A\\,e \\approx 6{,}022\\cdot 10^{23}\\cdot 1{,}6\\cdot 10^{-19} \\approx 96\\,500$ Кл.</p>
`);
/* THEORY 3 — Применение электролиза */
html += makeCard('example', "Применение электролиза", "§35", `
<p><b>Промышленные применения</b>:</p>
<ul style="margin:6px 0 6px 22px">
<li><b>Электролиз алюминия</b> — основной способ его получения из боксита. Огромные ванны рядом с электростанциями.</li>
<li><b>Электрометаллургия меди</b>: получение чистой меди электролизом раствора CuSO$_4$.</li>
<li><b>Производство хлора и каустической соды</b> — электролиз раствора NaCl.</li>
<li><b>Гальванопластика</b>: точные металлические копии скульптур, форм для печати — осаждение металла на форму.</li>
<li><b>Гальваностегия</b>: декоративные и защитные покрытия — хромирование, золочение, никелирование.</li>
<li><b>Зарядка аккумуляторов</b> — процесс, обратный разрядке (тоже электролиз).</li>
</ul>
<p style="margin-top:10px"><b>Пример расчёта.</b> Сколько меди ($M = 64$ г/моль, $n = 2$) выделится на катоде при $I = 5$ А за $t = 1$ ч?</p>
<p style="text-align:center;margin:8px 0">$m = \\dfrac{M I t}{F n} = \\dfrac{0{,}064 \\cdot 5 \\cdot 3600}{96\\,500 \\cdot 2} \\approx 5{,}97$ г</p>
<p style="margin-top:10px"><b>Серебро</b> $(M = 108$ г/моль, $n = 1)$ при тех же условиях:</p>
<p style="text-align:center;margin:8px 0">$m = \\dfrac{0{,}108 \\cdot 5 \\cdot 3600}{96\\,500 \\cdot 1} \\approx 20{,}15$ г — почти в 4 раза больше!</p>
`);
/* INTERACTIVE 1 — Симуляция электролиза */
html += `<div class="wg" id="p35-iv1">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Симуляция электролиза</div></div>
<div class="wg-help">Положительные катионы (красные) движутся к <b>катоду</b> (слева, $-$). Отрицательные анионы (синие) — к <b>аноду</b> (справа, $+$). Скорость пропорциональна току $I$.</div>
<div class="sliders">
<label>Сила тока $I$ (А): <b id="p35-iv1-IL">0.0</b><input type="range" id="p35-iv1-I" min="0" max="10" value="0" step="0.5"></label>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:9px;padding:8px;margin-top:8px">
<svg id="p35-iv1-svg" viewBox="0 0 380 280" width="100%" style="height:auto"></svg>
</div>
<div id="p35-iv1-out" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.95rem;line-height:1.7;text-align:center"></div>
</div>`;
/* INTERACTIVE 2 — Калькулятор электролиза */
html += `<div class="wg" id="p35-iv2">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор массы вещества при электролизе</div></div>
<div class="wg-help">Формула: $m = \\dfrac{M\\,I\\,t}{F\\,n}$, $F = 96\\,500$ Кл/моль.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;margin-bottom:10px">
<label style="display:flex;flex-direction:column;gap:4px;font-size:.92rem">Вещество:
<select id="p35-iv2-sub" style="padding:7px;border:1px solid var(--border);border-radius:6px">
<option value="0">Медь (Cu): M=64, n=2</option>
<option value="1">Серебро (Ag): M=108, n=1</option>
<option value="2">Алюминий (Al): M=27, n=3</option>
<option value="3">Железо (Fe): M=56, n=2</option>
<option value="4">Водород (H): M=1, n=1</option>
</select>
</label>
<label style="display:flex;flex-direction:column;gap:4px;font-size:.92rem">$I$ (А):<input type="number" id="p35-iv2-I" value="5" step="0.1" min="0" style="padding:7px;border:1px solid var(--border);border-radius:6px"></label>
<label style="display:flex;flex-direction:column;gap:4px;font-size:.92rem">$t$ (с):<input type="number" id="p35-iv2-t" value="3600" step="any" min="0" style="padding:7px;border:1px solid var(--border);border-radius:6px"></label>
</div>
<div class="actions"><button class="btn primary" id="p35-iv2-calc">Вычислить массу $m$</button></div>
<div id="p35-iv2-out" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.98rem;line-height:1.8;text-align:center;min-height:40px"></div>
</div>`;
/* INTERACTIVE 3 — Куда движется ион? */
html += `<div class="wg" id="p35-iv3">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Куда движется ион?</div></div>
<div class="wg-help">Катионы $(+)$ → к катоду $(-)$. Анионы $(-)$ → к аноду $(+)$.</div>
<div class="score-display"><span>Задача <b id="p35-iv3-i">1</b> / 6</span><span>Очки: <b id="p35-iv3-s">0</b> / 6</span></div>
<div id="p35-iv3-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.05rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div id="p35-iv3-opts" style="display:grid;grid-template-columns:1fr 1fr;gap:8px"></div>
<div class="feedback" id="p35-iv3-fb"></div>
<div class="actions"><button class="btn" id="p35-iv3-restart">Начать заново</button></div>
</div>`;
/* INTERACTIVE 4 — Тренажёр электролиза */
html += `<div class="wg" id="p35-iv4">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр: электролиз</div></div>
<div class="wg-help">5 задач. $F = 96\\,500$ Кл/моль. Допуск $\\pm 5\\%$.</div>
<div class="score-display"><span>Задача <b id="p35-iv4-i">1</b> / 5</span><span>Очки: <b id="p35-iv4-s">0</b> / 5</span></div>
<div id="p35-iv4-q" style="padding:14px;background:var(--sec-acc-soft);border-radius:10px;font-size:1.02rem;margin-bottom:10px;text-align:center;min-height:54px"></div>
<div id="p35-iv4-form" style="display:flex;gap:8px;justify-content:center;margin-bottom:8px;flex-wrap:wrap">
<input type="number" id="p35-iv4-inp" step="any" style="padding:8px 10px;border:1px solid var(--border);border-radius:6px;width:140px;font-size:1rem">
<button class="btn primary" id="p35-iv4-go">Проверить</button>
</div>
<div class="feedback" id="p35-iv4-fb"></div>
<div class="actions"><button class="btn" id="p35-iv4-restart">Начать заново</button></div>
</div>`;
html += secNav('p34', 'p36');
html += readButton('p35');
box.innerHTML = html;
renderMath(box);
/* IV1 — Симуляция электролиза */
(function(){
const svg = document.getElementById('p35-iv1-svg');
const out = document.getElementById('p35-iv1-out');
const II = document.getElementById('p35-iv1-I'), IL = document.getElementById('p35-iv1-IL');
const W = 380, H = 280;
// Ионы: красные катионы (+) и синие анионы (-)
const NCat = 12, NAn = 12;
const cats = [], ans = [];
for(let k=0; k<NCat; k++){
cats.push({ x: 80 + Math.random()*220, y: 80 + Math.random()*160, vy: (Math.random()-0.5)*1.0 });
}
for(let k=0; k<NAn; k++){
ans.push({ x: 80 + Math.random()*220, y: 80 + Math.random()*160, vy: (Math.random()-0.5)*1.0 });
}
let rafId = null;
let configs = new Set(), _done = false;
function step(){
const I = +II.value;
const v = I * 0.25;
cats.forEach(p => {
p.x -= v; // катионы влево (к катоду)
p.vy += (Math.random()-0.5)*0.4;
if(Math.abs(p.vy) > 1.4) p.vy *= 0.7;
p.y += p.vy;
if(p.x < 75){ p.x = 295; }
if(p.y < 80){ p.y = 80; p.vy = Math.abs(p.vy); }
if(p.y > 240){ p.y = 240; p.vy = -Math.abs(p.vy); }
});
ans.forEach(p => {
p.x += v; // анионы вправо (к аноду)
p.vy += (Math.random()-0.5)*0.4;
if(Math.abs(p.vy) > 1.4) p.vy *= 0.7;
p.y += p.vy;
if(p.x > 305){ p.x = 85; }
if(p.y < 80){ p.y = 80; p.vy = Math.abs(p.vy); }
if(p.y > 240){ p.y = 240; p.vy = -Math.abs(p.vy); }
});
draw();
rafId = requestAnimationFrame(step);
}
function draw(){
const I = +II.value;
IL.textContent = I.toFixed(1);
let g = '';
g += '<rect x="0" y="0" width="'+W+'" height="'+H+'" fill="#fafafa"/>';
// ванна с электролитом
g += '<rect x="60" y="65" width="260" height="195" rx="10" fill="#e0f2fe" stroke="#0891b2" stroke-width="2"/>';
g += '<text x="190" y="58" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#0f172a">Электролит (раствор)</text>';
// катод (слева, минус)
g += '<rect x="70" y="75" width="14" height="180" fill="#6b7280" stroke="#374151" stroke-width="1.4"/>';
g += '<text x="77" y="68" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="800" fill="#0891b2">К ('+''+')</text>';
// анод (справа, плюс)
g += '<rect x="296" y="75" width="14" height="180" fill="#6b7280" stroke="#374151" stroke-width="1.4"/>';
g += '<text x="303" y="68" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="13" font-weight="800" fill="#dc2626">А (+)</text>';
// батарея внизу
g += '<text x="190" y="276" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" fill="#64748b">Источник тока</text>';
g += PHYS.batteryEMF(190, 270, undefined, 'h');
// провода
g += PHYS.wire(77, 257, 77, 270);
g += PHYS.wire(77, 270, 175, 270);
g += PHYS.wire(205, 270, 303, 270);
g += PHYS.wire(303, 270, 303, 257);
// ионы — катионы (красные, +)
cats.forEach(p => {
g += '<circle cx="'+p.x.toFixed(1)+'" cy="'+p.y.toFixed(1)+'" r="6" fill="#fecaca" stroke="#dc2626" stroke-width="1.4"/>';
g += '<text x="'+p.x.toFixed(1)+'" y="'+(p.y+3).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" font-weight="800" fill="#7f1d1d">+</text>';
});
// анионы (синие, -)
ans.forEach(p => {
g += '<circle cx="'+p.x.toFixed(1)+'" cy="'+p.y.toFixed(1)+'" r="6" fill="#dbeafe" stroke="#1d4ed8" stroke-width="1.4"/>';
g += '<text x="'+p.x.toFixed(1)+'" y="'+(p.y+3).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="800" fill="#1e3a8a">'+''+'</text>';
});
// стрелка направления для катионов и анионов
if(I > 0){
g += PHYS.drawArrow(200, 50, 130, 50, '#dc2626', 1.6, 7);
g += '<text x="200" y="48" font-family="Inter,sans-serif" font-size="10" fill="#dc2626">катионы</text>';
g += PHYS.drawArrow(180, 30, 250, 30, '#1d4ed8', 1.6, 7);
g += '<text x="120" y="33" font-family="Inter,sans-serif" font-size="10" fill="#1d4ed8">анионы</text>';
}
svg.innerHTML = g;
out.innerHTML = I === 0
? 'При $I = 0$ ионы движутся хаотически (тока нет).'
: '$I = '+I.toFixed(1)+'$ А — катионы дрейфуют к <b>катоду</b> ($-$), анионы к <b>аноду</b> ($+$).';
renderMath(out);
}
II.addEventListener('input', ()=>{
configs.add(II.value);
if(!_done && configs.size >= 4){ _done = true; addXp(15, 'p35-iv1'); bumpProgress('p35', 20); }
});
draw();
rafId = requestAnimationFrame(step);
})();
/* IV2 — Калькулятор */
(function(){
const out = document.getElementById('p35-iv2-out');
const sub = document.getElementById('p35-iv2-sub');
const iI = document.getElementById('p35-iv2-I');
const iT = document.getElementById('p35-iv2-t');
const bGo = document.getElementById('p35-iv2-calc');
const SUBS = [
{ name:'Cu (медь)', M:0.064, n:2 },
{ name:'Ag (серебро)', M:0.108, n:1 },
{ name:'Al (алюминий)', M:0.027, n:3 },
{ name:'Fe (железо)', M:0.056, n:2 },
{ name:'H (водород)', M:0.001, n:1 }
];
const F = 96500;
let count = 0, _done = false;
function calc(){
const s = SUBS[+sub.value];
const I = +iI.value, t = +iT.value;
if(![I,t].every(isFinite) || I < 0 || t < 0){
out.innerHTML = '<b style="color:#dc2626">Проверь ввод: $I \\ge 0$, $t \\ge 0$.</b>';
renderMath(out);
return;
}
const m_kg = (s.M * I * t) / (F * s.n);
const m_g = m_kg * 1000;
let html = '';
html += '<b>'+s.name+'</b>: $M = '+(s.M*1000)+'$ г/моль, $n = '+s.n+'$<br>';
html += '$m = \\dfrac{M\\,I\\,t}{F\\,n} = \\dfrac{'+s.M+'\\cdot '+I+'\\cdot '+t+'}{'+F+'\\cdot '+s.n+'}$<br>';
html += '$m \\approx $ <b>'+m_g.toFixed(3)+' г</b> ($'+m_kg.toExponential(3)+'$ кг)';
out.innerHTML = html;
renderMath(out);
count++;
if(!_done && count >= 3){ _done = true; addXp(10, 'p35-iv2'); bumpProgress('p35', 15); }
}
bGo.addEventListener('click', calc);
[iI, iT].forEach(x => x.addEventListener('keydown', e => { if(e.key==='Enter') calc(); }));
sub.addEventListener('change', calc);
})();
/* IV3 — Куда движется ион */
(function(){
const OPTS = ['К катоду ()', 'К аноду (+)'];
const Q = [
{ q:'Ион меди Cu$^{2+}$ движется…', ans:0, why:'Катион (+) → к катоду ($-$). На катоде восстанавливается до Cu.' },
{ q:'Ион SO$_4^{2-}$ движется…', ans:1, why:'Анион ($-$) → к аноду (+).' },
{ q:'Ион натрия Na$^+$ движется…', ans:0, why:'Катион → к катоду.' },
{ q:'Ион хлора Cl$^-$ движется…', ans:1, why:'Анион → к аноду. На аноде окисляется до Cl$_2$.' },
{ q:'Ион водорода H$^+$ движется…', ans:0, why:'Катион → к катоду. На катоде восстанавливается до H$_2$.' },
{ q:'Ион гидроксила OH$^-$ движется…',ans:1, why:'Анион → к аноду. На аноде окисляется (выделяется O$_2$).' }
];
let i = 0, score = 0;
const qEl = document.getElementById('p35-iv3-q');
const oEl = document.getElementById('p35-iv3-opts');
const fb = document.getElementById('p35-iv3-fb');
const iEl = document.getElementById('p35-iv3-i');
const sEl = document.getElementById('p35-iv3-s');
function show(){
if(i >= Q.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
oEl.innerHTML = '';
if(score === Q.length){ addXp(15, 'p35-iv3'); bumpProgress('p35', 25); }
else if(score >= 4){ addXp(8, 'p35-iv3'); bumpProgress('p35', 15); }
return;
}
iEl.textContent = (i+1);
sEl.textContent = score;
qEl.innerHTML = Q[i].q;
oEl.innerHTML = OPTS.map((t,k) => '<button class="btn primary" data-v="'+k+'">'+t+'</button>').join('');
fb.style.display = 'none';
renderMath(qEl);
oEl.querySelectorAll('button').forEach(b => {
b.addEventListener('click', () => {
const v = +b.dataset.v;
if(v === Q[i].ans){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].why+' Дальше ▶'); }
else feedback(fb, false, '&#10007; Верно: '+OPTS[Q[i].ans]+'. '+Q[i].why+' Дальше ▶');
sEl.textContent = score;
oEl.querySelectorAll('button').forEach(x => x.disabled = true);
i++;
setTimeout(show, 1900);
});
});
}
document.getElementById('p35-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); });
show();
})();
/* IV4 — Тренажёр */
(function(){
const Q = [
{ q:'$I = 2$ А, $t = 30$ мин $= 1800$ с. Медь (Cu, $M = 64$ г/моль, $n = 2$), $F = 96\\,500$ Кл/моль. Найди $m$ (в <b>граммах</b>).', ans:1.19, tol:0.06, why:'$m = MIt/(Fn) = 64\\cdot 2\\cdot 1800/(96\\,500\\cdot 2) \\approx 1{,}19$ г.' },
{ q:'$I = 5$ А, $t = 1$ ч $= 3600$ с. Медь ($M=64$, $n=2$). Найди $m$ (г).', ans:5.97, tol:0.3, why:'$m = 64\\cdot 5\\cdot 3600/(96\\,500\\cdot 2) \\approx 5{,}97$ г.' },
{ q:'Серебро ($M = 108$ г/моль, $n = 1$). $I = 1$ А, $t = 3600$ с. Найди $m$ (г).', ans:4.03, tol:0.2, why:'$m = 108\\cdot 1\\cdot 3600/(96\\,500\\cdot 1) \\approx 4{,}03$ г.' },
{ q:'К какому электроду движутся <b>катионы</b>? (1 = анод, 2 = катод). Введи номер.', ans:2, tol:0.1, why:'Катионы $(+)$ движутся к катоду $(-)$.' },
{ q:'Постоянная Фарадея $F$ в Кл/моль (округлённое значение). Введи число.', ans:96500, tol:500, why:'$F = N_A \\cdot e \\approx 96\\,500$ Кл/моль.' }
];
let i = 0, score = 0;
const qEl = document.getElementById('p35-iv4-q');
const fb = document.getElementById('p35-iv4-fb');
const iEl = document.getElementById('p35-iv4-i');
const sEl = document.getElementById('p35-iv4-s');
const inp = document.getElementById('p35-iv4-inp');
const bGo = document.getElementById('p35-iv4-go');
function show(){
if(i >= Q.length){
qEl.innerHTML = '<b>Готово!</b> Результат: ' + score + ' / ' + Q.length;
inp.disabled = true; bGo.disabled = true;
if(score === Q.length){ addXp(15, 'p35-iv4'); bumpProgress('p35', 25); }
else if(score >= 3){ addXp(8, 'p35-iv4'); bumpProgress('p35', 15); }
return;
}
iEl.textContent = (i+1);
sEl.textContent = score;
qEl.innerHTML = Q[i].q;
fb.style.display = 'none';
inp.value = ''; inp.disabled = false; bGo.disabled = false; inp.focus();
renderMath(qEl);
}
function check(){
if(inp.disabled) return;
const v = parseFloat(inp.value.replace(',','.'));
if(!isFinite(v)){ feedback(fb, false, 'Введи число.'); return; }
const tol = Math.max(Q[i].tol, Math.abs(Q[i].ans)*0.05);
const ok = Math.abs(v - Q[i].ans) <= tol;
if(ok){ score++; feedback(fb, true, '&#10003; Верно! '+Q[i].why+' Дальше ▶'); }
else feedback(fb, false, '&#10007; Верно: '+Q[i].ans+'. '+Q[i].why+' Дальше ▶');
sEl.textContent = score;
inp.disabled = true; bGo.disabled = true;
i++;
setTimeout(show, 1900);
}
bGo.addEventListener('click', check);
inp.addEventListener('keydown', e => { if(e.key==='Enter') check(); });
document.getElementById('p35-iv4-restart').addEventListener('click', () => { i = 0; score = 0; inp.disabled=false; bGo.disabled=false; show(); });
show();
})();
wireReadBtn('p35');
}
function build_p36(){
const box = document.getElementById('p36-body');
let html = '';
html += makeCard('theory', "Ток в газах. Плазма", "§36", `
<p><b>Ток в газах. Плазма</b> — этот параграф в разработке (Phase 1+).</p>
<p>Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem">
<b>Phase 0:</b> создан скелет учебника. <b>Phase 6+:</b> наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
</p>
`);
html += secNav('p35', 'p37');
html += readButton('p36');
box.innerHTML = html;
renderMath(box);
wireReadBtn('p36');
}
function build_p37(){
const box = document.getElementById('p37-body');
let html = '';
html += makeCard('theory', "Ток в полупроводниках", "§37", `
<p><b>Ток в полупроводниках</b> — этот параграф в разработке (Phase 1+).</p>
<p>Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem">
<b>Phase 0:</b> создан скелет учебника. <b>Phase 6+:</b> наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
</p>
`);
html += secNav('p36', 'final6');
html += readButton('p37');
box.innerHTML = html;
renderMath(box);
wireReadBtn('p37');
}
function build_final6(){
const box = document.getElementById('final6-body');
let html = '';
html += makeCard('theory', "Финал главы 6", "★", `
<p><b>Финал главы 6</b> — этот параграф в разработке (Phase 1+).</p>
<p>Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.</p>
<p style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft);border-radius:9px;font-size:.92rem">
<b>Phase 0:</b> создан скелет учебника. <b>Phase 6+:</b> наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019).
</p>
`);
html += secNav('p37', null);
html += readButton('final6');
box.innerHTML = html;
renderMath(box);
wireReadBtn('final6');
}
/* ===== Search ===== */
const SEARCH_INDEX = (function(){
const arr=[];
PARAS.forEach(p=>arr.push({kind:'Параграф',title:p.num+' '+p.name,desc:p.sub||'',sec:p.id}));
return arr;
})();
function initSearch(){
const modal=document.getElementById('search-modal'),inp=document.getElementById('search-input'),out=document.getElementById('search-results'),btn=document.getElementById('search-btn');
if(!modal||!inp||!out) return;
let cur=0,rows=[];
function score(q,it){ const t=(it.title+' '+it.desc).toLowerCase(); if(t.includes(q)) return 100+(it.title.toLowerCase().startsWith(q)?50:0); let s=0; q.split(/\s+/).forEach(w=>{if(w&&t.includes(w))s+=10;}); return s; }
function rank(q){ q=q.trim().toLowerCase(); if(!q) return SEARCH_INDEX.slice(0,12); return SEARCH_INDEX.map(it=>({it,s:score(q,it)})).filter(x=>x.s>0).sort((a,b)=>b.s-a.s).slice(0,20).map(x=>x.it); }
function render(){ cur=0; if(!rows.length){out.innerHTML='<div class="search-empty">Ничего не найдено</div>';return;} out.innerHTML=rows.map((r,i)=>'<button class="search-row'+(i===0?' active':'')+'" data-i="'+i+'"><div class="sr-kind">'+r.kind+'</div><div class="sr-title">'+r.title+'</div>'+(r.desc?'<div class="sr-desc">'+(r.desc.length>90?r.desc.slice(0,90)+'…':r.desc)+'</div>':'')+'</button>').join(''); out.querySelectorAll('.search-row').forEach(b=>b.addEventListener('click',()=>{cur=+b.dataset.i;pick();})); }
function pick(){ const r=rows[cur]; if(!r) return; close(); goTo(r.sec); }
function move(d){ const items=out.querySelectorAll('.search-row'); if(!items.length) return; items[cur]&&items[cur].classList.remove('active'); cur=(cur+d+items.length)%items.length; items[cur].classList.add('active'); items[cur].scrollIntoView({block:'nearest'}); }
function open(){ modal.classList.add('show'); inp.value=''; rows=rank(''); render(); setTimeout(()=>inp.focus(),50); }
function close(){ modal.classList.remove('show'); }
btn&&btn.addEventListener('click',open);
modal.addEventListener('click',e=>{if(e.target===modal)close();});
inp.addEventListener('input',()=>{rows=rank(inp.value);render();});
inp.addEventListener('keydown',e=>{ if(e.key==='ArrowDown'){e.preventDefault();move(1);}else if(e.key==='ArrowUp'){e.preventDefault();move(-1);}else if(e.key==='Enter'){e.preventDefault();pick();}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 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 init(){
loadProgress(); initTheme(); initSidebarToggle(); initSearch();
buildParaSelector(); refreshProgressUI(); loadServerReadState(); goTo(PARAS[0].id);
setTimeout(()=>achievement('start'), 600);
if(window.LS&&window.LS.xp){
window.LS.xp.load().then(function(s){ if(s&&s.xp>STATE.xp){ STATE.xp=s.xp; STATE.level=calcLevel(STATE.xp); saveProgress(); refreshProgressUI(); if(STATE.current) buildSidebar(STATE.current); } });
}
}
document.addEventListener('DOMContentLoaded', init);
/* === PHYS10 POLISH JS === */
(function(){
function bumpScore(el){
if(!el) return;
el.classList.remove('bump');
void el.offsetWidth;
el.classList.add('bump');
setTimeout(function(){ try{ el.classList.remove('bump'); }catch(e){} }, 270);
}
window.__phys10BumpScore = bumpScore;
function observeScores(root){
root = root || document;
var nodes = root.querySelectorAll('.score-display b');
nodes.forEach(function(b){
if(b.__scoreObs) return;
b.__scoreObs = true;
var last = b.textContent;
try{
var mo = new MutationObserver(function(){
var nv = b.textContent;
if(nv !== last){ last = nv; bumpScore(b); }
});
mo.observe(b, {childList:true, characterData:true, subtree:true});
}catch(e){}
});
}
function rescanScores(){ try{ observeScores(document); }catch(e){} }
if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', rescanScores);
else rescanScores();
try{
var rootObs = new MutationObserver(function(muts){
var need = false;
for(var i=0;i<muts.length && !need;i++){
var m = muts[i];
for(var j=0;j<m.addedNodes.length;j++){
var n = m.addedNodes[j];
if(n.nodeType===1){
if(n.classList && n.classList.contains('score-display')) { need = true; break; }
if(n.querySelector && n.querySelector('.score-display b')) { need = true; break; }
}
}
}
if(need) rescanScores();
});
rootObs.observe(document.body, {childList:true, subtree:true});
}catch(e){}
function refreshDoneMarks(){
try{
if(typeof STATE === 'undefined' || !STATE.progress) return;
document.querySelectorAll('.psel-card').forEach(function(c){
var id = c.dataset.id || c.dataset.progCard;
if(!id) return;
var pct = +STATE.progress[id] || 0;
if(!c.querySelector('.psel-done')){
var s = document.createElement('span');
s.className = 'psel-done';
s.setAttribute('title','Прочитано');
s.innerHTML = '<svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>';
c.appendChild(s);
}
c.classList.toggle('done', pct >= 50);
});
}catch(e){}
}
try{
if(typeof window.refreshProgressUI === 'function'){
var _origRP = window.refreshProgressUI;
window.refreshProgressUI = function(){ var r = _origRP.apply(this, arguments); setTimeout(refreshDoneMarks, 0); return r; };
}
}catch(e){}
setTimeout(refreshDoneMarks, 600);
setTimeout(refreshDoneMarks, 1800);
window.addEventListener('focus', function(){ setTimeout(refreshDoneMarks, 200); });
document.addEventListener('click', function(e){
var card = e.target.closest && e.target.closest('.psel-card');
if(!card) return;
var id = card.dataset.id;
if(!id) return;
setTimeout(function(){
var sec = document.getElementById('sec-' + id);
if(sec) try{ sec.scrollIntoView({behavior:'smooth', block:'start'}); }catch(e){}
}, 60);
});
})();
</script>
</body>
</html>