Files
Learn_System/frontend/textbooks/physics8_optics.html
T
Maxim Dolgolyov dfe26a4771 fix(physics8): добавить /js/api.js в head — без него tracker молча отключается
Tracker проверяет 'LS.getToken()' перед каждым POST'ом. Без api.js
объект LS undefined, и tracker возвращает из syncToServer ничего не
делая. Поэтому в physics8_thermal/electro/optics прогресс не писался
вообще (ни last_para, ни mark_read).

Добавил <script src="/js/api.js" defer> перед xp.js во все 3 файла.

Chemistry-9 и physics-9 не затронуты — у них api.js уже подключён в
конце body перед tracker'ом.
2026-05-27 17:21:06 +03:00

3763 lines
252 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" id="root">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Физика 8 — Световые явления</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
<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"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/textbook-tracker.js" defer></script>
<script src="/js/textbook-xp-widget.js" defer></script>
<style>
/* ═══════════ ДИЗАЙН-ТОКЕНЫ v2 ═══════════ */
:root{
/* Палитра — 9 ступеней */
--pri-50:#faf5ff; --pri-100:#f3e8ff; --pri-200:#e9d5ff; --pri-300:#d8b4fe;
--pri-400:#c084fc; --pri-500:#a855f7; --pri-600:#9333ea; --pri-700:#7c3aed;
--pri-800:#6b21a8; --pri-900:#581c87;
--acc-300:#f9a8d4; --acc-400:#f472b6; --acc-500:#ec4899; --acc-600:#db2777; --acc-700:#be185d;
--pri:var(--pri-600); --acc:var(--acc-500);
/* Статусы */
--ok:#16a34a; --ok-bg:#dcfce7; --ok-border:#86efac;
--fail:#dc2626; --fail-bg:#fee2e2; --fail-border:#fca5a5;
--warn:#d97706; --warn-bg:#fef3c7;
/* Поверхности */
--bg:#faf5ff; --card:#fff;
--surface-1:#ffffff; --surface-2:#faf5ff; --surface-3:#f3e8ff;
--text:#1a1a2e; --muted:#64748b; --border:#e9d5ff;
--glass-bg:rgba(255,255,255,.65); --glass-border:rgba(255,255,255,.4);
/* Тени и свечение */
--sh:0 2px 10px rgba(147,51,234,.08);
--shadow-sm:0 1px 2px rgba(15,23,42,.06);
--shadow-md:0 4px 14px rgba(15,23,42,.08);
--shadow-lg:0 12px 32px rgba(15,23,42,.10);
--shadow-glow:0 0 24px rgba(147,51,234,.25);
--shadow-pop:0 8px 22px rgba(147,51,234,.16);
/* Радиусы */
--r-sm:8px; --r-md:12px; --r-lg:16px; --r-xl:22px; --r-full:999px;
/* Анимации */
--ease:cubic-bezier(.4,0,.2,1);
--ease-out:cubic-bezier(.16,1,.3,1);
--ease-bounce:cubic-bezier(.34,1.56,.64,1);
--dur-1:.16s; --dur-2:.22s; --dur-3:.36s; --dur-4:.56s;
}
html.dark{
--bg:#0f0a1f; --card:#1a0f2e;
--surface-1:#1a0f2e; --surface-2:#241640; --surface-3:#2e1d52;
--text:#f0e6ff; --muted:#a8a29e; --border:#4c1d95;
--glass-bg:rgba(26,15,46,.6); --glass-border:rgba(255,255,255,.08);
--ok:#22c55e; --ok-bg:rgba(34,197,94,.12); --ok-border:rgba(34,197,94,.3);
--fail:#f87171; --fail-bg:rgba(248,113,113,.12); --fail-border:rgba(248,113,113,.3);
--shadow-sm:0 1px 2px rgba(0,0,0,.4);
--shadow-md:0 4px 14px rgba(0,0,0,.5);
--shadow-lg:0 12px 32px rgba(0,0,0,.6);
--shadow-glow:0 0 28px rgba(192,132,252,.35);
--shadow-pop:0 8px 22px rgba(147,51,234,.4);
}
@media (prefers-reduced-motion: reduce){
*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Outfit',system-ui,sans-serif;background:var(--bg);color:var(--text);overflow-x:hidden}
::-webkit-scrollbar{width:5px;height:5px}
::-webkit-scrollbar-thumb{background:var(--border);border-radius:99px}
/* ═══════════ FLOATING BUTTONS ═══════════ */
.theme-btn{position:fixed;top:12px;right:12px;z-index:80;width:38px;height:38px;
border-radius:10px;background:rgba(147,51,234,.18);border:1px solid rgba(147,51,234,.3);
cursor:pointer;display:grid;place-items:center;font-size:1rem;
color:rgba(240,236,255,.8);box-shadow:0 2px 10px rgba(147,51,234,.2);transition:.18s}
.theme-btn:hover{background:rgba(147,51,234,.28);color:#d4a843;transform:scale(1.06)}
html.dark .theme-btn{background:rgba(147,51,234,.25);border-color:rgba(147,51,234,.4);color:#c084fc}
.ref-toggle{position:fixed;bottom:16px;right:16px;z-index:80;width:46px;height:46px;
border-radius:13px;background:var(--pri);color:#fff;border:none;cursor:pointer;
display:grid;place-items:center;font-size:1.1rem;
box-shadow:0 4px 16px rgba(147,51,234,.4);transition:transform .18s,box-shadow .18s}
.ref-toggle:hover{transform:scale(1.06) rotate(-4deg);box-shadow:0 8px 24px rgba(147,51,234,.55)}
/* ═══════════ POPUP СПРАВОЧНИК ═══════════ */
.ref-panel{position:fixed;bottom:72px;right:16px;z-index:75;width:300px;max-height:72vh;
overflow-y:auto;background:var(--card);border:1px solid var(--border);
border-radius:16px;padding:16px 18px;box-shadow:0 8px 32px rgba(0,0,0,.18);
display:none;font-size:.8rem;line-height:1.85;scrollbar-width:thin;
scrollbar-color:var(--border) transparent}
.ref-panel.show{display:block;animation:fadeUp .2s ease}
.ref-panel h3{font-size:.78rem;font-weight:800;color:var(--pri);margin:12px 0 5px;
text-transform:uppercase;letter-spacing:.08em}
.ref-panel h3:first-child{margin-top:0}
.ref-panel .rf{background:rgba(147,51,234,.06);border-radius:8px;padding:7px 12px;margin:3px 0;text-align:center;border:1px solid rgba(147,51,234,.1)}
html.dark .ref-panel .rf{background:rgba(147,51,234,.12)}
/* ═══════════ HDR ═══════════ */
.hdr{background:linear-gradient(135deg,#581c87 0%,#7c3aed 55%,#a855f7 100%);
color:#fff;padding:24px 20px 20px;text-align:center;position:relative;overflow:hidden}
.hdr::before{content:'';position:absolute;inset:0;opacity:.5;pointer-events:none;
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80' viewBox='0 0 140 80'><g fill='none' stroke='%23ffffff' stroke-width='1.2' opacity='0.18'><path d='M0 20 Q35 0 70 20 T140 20'/><path d='M0 40 Q35 20 70 40 T140 40'/><path d='M0 60 Q35 40 70 60 T140 60'/></g></svg>")}
.hdr h1{font-size:1.5rem;font-weight:900;position:relative}
.hdr p{font-size:.82rem;opacity:.82;margin-top:5px;position:relative}
@media(max-width:600px){.hdr h1{font-size:1.2rem}.hdr p{font-size:.74rem}}
/* ═══════════ LAYOUT ═══════════ */
.page-wrap{display:flex;min-height:calc(100vh - 90px)}
.sidebar{width:220px;flex-shrink:0;
background:linear-gradient(180deg,#2e1065 0%,#1e0a40 100%);
border-right:1px solid rgba(147,51,234,.2);
overflow-y:auto;overflow-x:hidden;
scrollbar-width:thin;scrollbar-color:rgba(147,51,234,.2) transparent}
.sidebar::-webkit-scrollbar{width:3px}
.sidebar::-webkit-scrollbar-thumb{background:rgba(147,51,234,.25);border-radius:99px}
html.dark .sidebar{background:linear-gradient(180deg,#1a0831 0%,#0f0520 100%);border-right-color:rgba(147,51,234,.15)}
.sb-brand{display:flex;align-items:center;gap:10px;padding:18px 14px 14px;
border-bottom:1px solid rgba(147,51,234,.2)}
.sb-logo{font-size:1.4rem;flex-shrink:0}
.sb-title{font-size:.9rem;font-weight:800;color:#f3e8ff;letter-spacing:-.02em;line-height:1.1}
.sb-sub{font-size:.55rem;color:rgba(200,160,255,.45);margin-top:2px;letter-spacing:.03em}
.sb-nav{padding:10px 8px 20px}
.sb-item{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:8px;
cursor:pointer;border:none;background:transparent;width:100%;text-align:left;
color:rgba(200,170,255,.68);font-size:.71rem;font-weight:700;font-family:inherit;
border-left:2.5px solid transparent;transition:.15s}
.sb-item:hover{background:rgba(147,51,234,.12);color:rgba(230,200,255,.9);border-left-color:rgba(168,85,247,.4)}
.sb-item.active{background:rgba(147,51,234,.22);color:#e9d5ff;border-left-color:#a855f7;box-shadow:inset 0 0 0 1px rgba(168,85,247,.12)}
.sb-item .sb-icon{font-size:.95rem;width:20px;text-align:center;flex-shrink:0;opacity:.65}
.sb-item.active .sb-icon{opacity:1}
.sb-item .sb-num{font-family:monospace;font-size:.65rem;color:rgba(168,85,247,.55);flex-shrink:0;min-width:26px}
.sb-item.active .sb-num{color:#c084fc}
.sb-item .sb-name{flex:1;line-height:1.3;white-space:normal;font-size:.7rem}
.sb-divider{height:1px;background:rgba(147,51,234,.18);margin:6px 8px}
.main-col{flex:1;min-width:0;overflow-x:hidden}
/* ═══════════ КОНТЕНТ ═══════════ */
.content-area{max-width:820px;margin:0 auto;padding:0 4px 40px}
.content{display:none;padding:20px 14px;animation:fadeUp .25s ease}
.content.active{display:block}
@keyframes fadeUp{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
/* ═══════════ АДАПТИВНОСТЬ ═══════════ */
@media(max-width:768px){
.page-wrap{flex-direction:column}
.sidebar{width:100%;border-right:none;border-bottom:1px solid rgba(147,51,234,.2)}
.sb-nav{display:flex;flex-wrap:nowrap;overflow-x:auto;padding:6px 8px;gap:2px;scrollbar-width:none}
.sb-nav::-webkit-scrollbar{display:none}
.sb-item{white-space:nowrap;flex-shrink:0;border-left:none;border-bottom:2.5px solid transparent;border-radius:0;padding:7px 10px;flex-direction:column;gap:3px;align-items:center;text-align:center;min-width:48px}
.sb-item:hover{border-left-color:transparent;border-bottom-color:rgba(168,85,247,.4)}
.sb-item.active{border-left-color:transparent!important;border-bottom-color:#a855f7;box-shadow:none}
.sb-item .sb-name{display:none}
.sb-item .sb-num{min-width:auto}
.sb-brand{padding:10px 14px 8px}
.sb-divider{display:none}
}
/* ═══════════ PARA-HERO ═══════════ */
.para-hero{border-radius:18px;padding:22px 24px;margin-bottom:22px;color:#fff;position:relative;overflow:hidden}
.para-hero::after{content:'';position:absolute;right:-30px;top:-30px;width:160px;height:160px;
border-radius:50%;background:rgba(255,255,255,.1);pointer-events:none}
.ph-num{font-size:.72rem;font-weight:700;opacity:.75;letter-spacing:.1em;text-transform:uppercase;margin-bottom:5px}
.ph-title{font-size:1.15rem;font-weight:900;line-height:1.3}
.ph-32{background:linear-gradient(135deg,#1a1a2e,#7c3aed,#a855f7)}
.ph-32::after{background:#e9d5ff}
.ph-33{background:linear-gradient(135deg,#0f172a,#0ea5e9,#7c3aed)}
.ph-33::after{background:#bae6fd}
.ph-34{background:linear-gradient(135deg,#1e1b4b,#4338ca,#818cf8)}
.ph-34::after{background:#c7d2fe}
.ph-35{background:linear-gradient(135deg,#312e81,#6366f1,#a5b4fc)}
.ph-35::after{background:#e0e7ff}
.ph-36{background:linear-gradient(135deg,#0c4a6e,#0891b2,#7c3aed)}
.ph-36::after{background:#cffafe}
.ph-37{background:linear-gradient(135deg,#4c1d95,#7c3aed,#f59e0b);color:#fff}
.ph-37::after{background:#fde68a}
.ph-38{background:linear-gradient(135deg,#7c3aed,#a855f7,#f59e0b)}
.ph-38::after{background:#fde68a}
.ph-39{background:linear-gradient(135deg,#064e3b,#059669,#7c3aed)}
.ph-39::after{background:#a7f3d0}
.ph-40{background:linear-gradient(135deg,#7c3aed,#6d28d9,#1e1b4b)}
.ph-40::after{background:#ede9fe}
/* para-badge colours */
.para-badge.b32{background:rgba(124,58,237,.13);color:#7c3aed}
.para-badge.b33{background:rgba(14,165,233,.13);color:#0369a1}
.para-badge.b34{background:rgba(67,56,202,.13);color:#4338ca}
.para-badge.b35{background:rgba(99,102,241,.13);color:#6366f1}
.para-badge.b36{background:rgba(8,145,178,.13);color:#0891b2}
.para-badge.b37{background:rgba(124,58,237,.13);color:#7c3aed}
.para-badge.b38{background:rgba(168,85,247,.13);color:#a855f7}
.para-badge.b39{background:rgba(5,150,105,.13);color:#059669}
.para-badge.b40{background:rgba(109,40,217,.13);color:#6d28d9}
/* ═══════════ ТЕОРИЯ ═══════════ */
.section-title{font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.14em;
color:var(--pri);display:flex;align-items:center;gap:8px;margin-bottom:16px}
.section-title::before{content:'';display:block;width:16px;height:2px;background:var(--pri);border-radius:1px}
.def-box{background:rgba(124,58,237,.05);border-left:4px solid var(--pri);border-radius:10px;
padding:12px 16px;margin-bottom:16px;font-size:.88rem;line-height:1.8}
html.dark .def-box{background:rgba(124,58,237,.09)}
.formula-box{background:var(--card);border:2px solid var(--border);border-radius:14px;
padding:16px 20px;margin-bottom:16px;box-shadow:var(--sh)}
.formula-box .main-f{font-size:1.05rem;font-weight:700;text-align:center;padding:10px;
background:rgba(124,58,237,.06);border-radius:8px;margin:8px 0}
html.dark .formula-box .main-f{background:rgba(124,58,237,.12)}
.info-row{display:flex;gap:10px;align-items:flex-start;padding:10px 14px;
background:var(--card);border:1px solid var(--border);border-radius:10px;margin-bottom:10px;font-size:.85rem;line-height:1.7}
.ovr-card{background:var(--card);border:1px solid var(--border);border-radius:14px;
padding:16px 18px;margin-bottom:14px;box-shadow:var(--sh)}
/* ═══════════ CANVAS ═══════════ */
canvas{width:100%;border-radius:10px;background:var(--card);display:block}
.ctrl-row{display:flex;align-items:center;gap:10px;margin:8px 0;flex-wrap:wrap;font-size:.83rem}
.slider-row{display:flex;align-items:center;gap:10px;margin:8px 0;font-size:.82rem;flex-wrap:wrap}
.slider-lbl{min-width:100px;font-weight:600;color:var(--text);flex-shrink:0}
.slider-val{min-width:72px;font-weight:800;color:var(--pri);font-family:monospace;font-size:.82rem}
input[type=range]{flex:1;min-width:100px;accent-color:var(--pri);cursor:pointer}
/* ═══════════ ЗАДАЧИ: ПИЛЮЛИ ═══════════ */
.para-pills{display:flex;flex-wrap:wrap;gap:6px;padding:14px;background:var(--card);
border-bottom:1px solid var(--border);border-radius:14px 14px 0 0;margin-bottom:0}
.para-pill{padding:6px 13px;border:2px solid var(--border);border-radius:9px;font-size:.72rem;
font-weight:700;cursor:pointer;white-space:nowrap;background:var(--card);color:var(--muted);transition:.16s}
.para-pill:hover{border-color:var(--pri);color:var(--pri)}
.para-pill.active{background:var(--pri);color:#fff;border-color:var(--pri)}
/* ═══════════ ЗАДАЧИ: ДВИЖОК ═══════════ */
.score-bar{display:flex;gap:10px;align-items:center;margin-bottom:12px;font-size:.85rem;font-weight:600;flex-wrap:wrap}
.chip{padding:5px 13px;border-radius:50px;display:inline-flex;align-items:center;gap:5px}
.chip-ok{background:var(--ok-bg);color:#166534}
html.dark .chip-ok{color:#86efac}
.chip-tot{background:var(--card);color:var(--muted);border:1px solid var(--border)}
.prog-wrap{width:100%;height:6px;background:var(--border);border-radius:3px;overflow:hidden;margin-bottom:14px}
.prog-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:3px;transition:width .4s}
.nav-dots{display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px}
.nav-dot{min-width:30px;height:30px;padding:0 6px;border-radius:7px;border:2px solid var(--border);
background:var(--card);font-size:.72rem;font-weight:700;cursor:pointer;display:grid;place-items:center;
transition:.15s;color:var(--muted);font-family:monospace}
.nav-dot:hover{border-color:var(--pri);color:var(--pri)}
.nav-dot.nd-cur{background:var(--pri);border-color:var(--pri);color:#fff}
.nav-dot.nd-ok{background:var(--ok-bg);border-color:var(--ok);color:#166534}
.nav-dot.nd-fail{background:var(--fail-bg);border-color:var(--fail);color:#991b1b}
.task-card{background:var(--card);border:1px solid var(--border);border-radius:14px;
padding:20px 22px;box-shadow:var(--sh);margin-bottom:12px}
.task-num{font-size:.72rem;font-weight:700;color:var(--acc);text-transform:uppercase;
letter-spacing:.06em;margin-bottom:6px}
.task-text{font-size:.96rem;font-weight:700;line-height:1.85;margin-bottom:14px}
.task-hint{font-size:.8rem;color:var(--muted);margin-bottom:12px;display:flex;align-items:flex-start;gap:6px}
.task-hint i{margin-top:2px;color:var(--warn);flex-shrink:0}
.ans-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.ans-inp{width:120px;padding:11px 10px;border:2px solid var(--border);border-radius:10px;
font-size:1.05rem;font-family:monospace;text-align:center;outline:none;
background:var(--card);color:var(--text);transition:.18s}
.ans-inp:focus{border-color:var(--pri);box-shadow:0 0 0 3px rgba(124,58,237,.12)}
.unit-lbl{font-size:.82rem;color:var(--muted);font-weight:600;white-space:nowrap}
.btn{padding:10px 18px;border:none;border-radius:10px;font-weight:700;font-size:.84rem;
cursor:pointer;transition:.18s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.btn:active{transform:scale(.96)}
.btn-pri{background:var(--pri);color:#fff}
.btn-pri:hover{filter:brightness(1.1)}
.btn-ghost{background:transparent;border:2px solid var(--border);color:var(--muted)}
.btn-ghost:hover{border-color:var(--pri);color:var(--pri)}
.btn-next{background:var(--ok);color:#fff}
.btn-next:hover{filter:brightness(1.1)}
.mcq-opts{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.opt-btn{width:100%;text-align:left;padding:11px 16px;border:2px solid var(--border);border-radius:10px;
background:var(--card);color:var(--text);font-size:.9rem;font-weight:500;cursor:pointer;
transition:.18s;line-height:1.5;font-family:inherit}
.opt-btn:hover:not(:disabled){border-color:var(--pri);background:rgba(124,58,237,.05)}
.opt-btn:disabled{cursor:default}
.opt-btn.mcq-cor{border-color:var(--ok)!important;background:var(--ok-bg)!important;color:#166534!important;font-weight:700}
.opt-btn.mcq-wrong{border-color:var(--fail)!important;background:var(--fail-bg)!important;color:#991b1b!important}
.feedback{padding:13px 18px;border-radius:11px;font-size:.87rem;font-weight:600;
display:none;line-height:1.7;margin-top:10px}
.feedback.show{display:block;animation:pop .25s ease}
.fb-ok{background:var(--ok-bg);color:#166534}
html.dark .fb-ok{color:#86efac}
.fb-fail{background:var(--fail-bg);color:#991b1b}
html.dark .fb-fail{color:#fca5a5}
@keyframes pop{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:scale(1)}}
.summary{background:var(--card);border:1px solid var(--border);border-radius:16px;
padding:28px;text-align:center;box-shadow:var(--sh);display:none}
.summary.show{display:block;animation:pop .35s ease}
.summary h2{font-size:1.2rem;font-weight:800;margin-bottom:8px}
.big-score{font-size:3.5rem;font-weight:900;color:var(--pri);line-height:1;margin:10px 0}
.sum-grade{color:var(--muted);font-size:.9rem;margin-bottom:20px}
.sum-btns{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}
/* ═══════════ СПРАВОЧНИК (legacy overrides removed — see floating buttons CSS above) ═══════════ */
/* #refToggle и #refPanel теперь управляются через .ref-toggle и .ref-panel */
.ref-body{padding:2px 0;font-size:.8rem;line-height:1.85}
.ref-body h3{font-size:.78rem;font-weight:800;color:var(--pri);margin:12px 0 5px;
text-transform:uppercase;letter-spacing:.08em}
.ref-body h3:first-child{margin-top:0}
.ref-body p{margin-bottom:6px;font-size:.78rem;color:var(--muted)}
.ref-tbl{width:100%;border-collapse:collapse;font-size:.78rem;margin:4px 0 10px}
.ref-tbl td{padding:4px 8px;border:1px solid var(--border)}
.ref-tbl tr:nth-child(odd) td{background:rgba(124,58,237,.04)}
/* ═══════════ PTAB ═══════════ */
[id^="ptab-"]{display:none;padding:14px}
/* ── Карточки формул ── */
.formula-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px}
@media(max-width:560px){.formula-grid{grid-template-columns:1fr}}
.fcard{background:var(--card);border:2px solid var(--border);border-radius:14px;padding:16px 18px;box-shadow:var(--sh);transition:transform .18s,box-shadow .18s}
.fcard:hover{transform:translateY(-2px);box-shadow:0 6px 22px rgba(124,58,237,.1)}
.fcard.highlight{border-color:var(--pri);background:linear-gradient(135deg,rgba(124,58,237,.04),rgba(249,115,22,.04))}
.fcard h3{font-size:.8rem;font-weight:700;color:var(--pri);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px}
.fcard .main-f{font-size:1.05rem;font-weight:700;text-align:center;margin:8px 0;padding:10px;background:rgba(124,58,237,.06);border-radius:9px}
.fcard p{font-size:.83rem;color:var(--muted);line-height:1.7;margin-top:6px}
.fcard ul{font-size:.83rem;color:var(--muted);line-height:1.8;padding-left:18px;margin-top:6px}
/* ── Интерактивные диаграммы ── */
.idiag{background:var(--card);border:2px solid var(--border);border-radius:14px;padding:16px 18px;margin:14px 0;box-shadow:var(--sh)}
.idiag h3{font-size:.79rem;font-weight:700;color:var(--pri);text-transform:uppercase;letter-spacing:.05em;margin-bottom:12px;display:flex;align-items:center;gap:6px}
.idiag-2col{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin:14px 0}
@media(max-width:560px){.idiag-2col{grid-template-columns:1fr}}
.idiag-result{background:rgba(124,58,237,.08);border-radius:10px;padding:10px 14px;margin-top:10px;font-size:.9rem;font-weight:700;text-align:center;letter-spacing:.02em;border:1px solid rgba(124,58,237,.15)}
.slider-lbl{min-width:90px;font-weight:600;color:var(--text);flex-shrink:0;font-size:.82rem}
.slider-val{min-width:72px;font-weight:800;color:var(--pri);font-size:.82rem;flex-shrink:0}
/* ── Запомни! ── */
.remember-box{background:linear-gradient(135deg,rgba(124,58,237,.06),rgba(124,58,237,.03));border:2px solid rgba(124,58,237,.3);border-radius:13px;padding:14px 17px;margin:16px 0}
.remember-box-title{font-weight:800;font-size:.82rem;color:#b91c1c;margin-bottom:8px;display:flex;align-items:center;gap:7px}
html.dark .remember-box{border-color:rgba(124,58,237,.4);background:rgba(124,58,237,.07)}
html.dark .remember-box-title{color:#fca5a5}
.remember-box ul,.remember-box p{font-size:.83rem;color:var(--text);line-height:1.9;margin:0}
.remember-box ul{padding-left:18px}
.remember-box li{margin-bottom:3px}
/* ── Частые ошибки ── */
.mistakes-box{background:linear-gradient(135deg,rgba(245,158,11,.06),rgba(251,191,36,.03));border:2px solid rgba(245,158,11,.35);border-radius:13px;padding:14px 17px;margin:16px 0}
.mistakes-box-title{font-weight:800;font-size:.82rem;color:#92400e;margin-bottom:8px;display:flex;align-items:center;gap:7px}
html.dark .mistakes-box-title{color:#fcd34d}
.mistakes-box ul{padding-left:18px;margin:0}
.mistakes-box li{font-size:.83rem;color:var(--text);line-height:1.9}
/* ── Объяснение по-человечески ── */
.student-box{background:linear-gradient(135deg,rgba(254,243,199,.7),rgba(255,237,213,.7));border:1.5px solid #f59e0b;border-radius:14px;padding:16px 18px;margin:16px 0;line-height:1.75}
html.dark .student-box{background:linear-gradient(135deg,rgba(120,80,0,.18),rgba(100,50,0,.18));border-color:#d97706}
.student-box-title{font-weight:800;font-size:.88rem;color:#92400e;margin-bottom:10px;display:flex;align-items:center;gap:7px}
html.dark .student-box-title{color:#fbbf24}
.student-box p{margin:0 0 9px;font-size:.84rem;color:var(--text)}
.student-box p:last-child{margin-bottom:0}
.student-box b{color:#92400e}
html.dark .student-box b{color:#fbbf24}
/* ── Инсайт ── */
.insight-box{background:linear-gradient(135deg,rgba(124,58,237,.07),rgba(249,115,22,.04));border:2px solid rgba(124,58,237,.22);border-radius:13px;padding:14px 17px;margin:16px 0}
.insight-title{font-weight:800;font-size:.82rem;color:var(--pri);margin-bottom:7px;display:flex;align-items:center;gap:7px}
.insight-box p{font-size:.83rem;color:var(--text);line-height:1.8;margin:0 0 6px}
/* ── Примеры из жизни ── */
.life-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin:14px 0}
.life-item{background:var(--card);border:1.5px solid var(--border);border-radius:12px;padding:12px 10px;text-align:center}
.life-item .li-icon{font-size:1.9rem;margin-bottom:5px}
.life-item .li-title{font-size:.79rem;font-weight:700;color:var(--text);margin-bottom:3px}
.life-item .li-desc{font-size:.71rem;color:var(--muted);line-height:1.55}
/* ── Иконки в сайдбаре ── */
.para-icon{margin-right:8px;display:inline-flex;align-items:center;vertical-align:-3px;flex-shrink:0}
/* ═══════════ REF-PANEL TABS ═══════════ */
.ref-tabs{display:flex;gap:0;border-bottom:2px solid var(--border);margin-bottom:16px}
.ref-tab-btn{flex:1;padding:10px 12px;border:none;background:transparent;cursor:pointer;font-size:.76rem;font-weight:700;color:var(--muted);transition:.18s;border-bottom:2px solid transparent;margin-bottom:-2px;font-family:inherit}
.ref-tab-btn:hover{color:var(--text)}
.ref-tab-btn.active{color:var(--pri);border-bottom-color:var(--pri)}
.ref-tab-content{display:none}
.ref-tab-content.active{display:block}
/* Formula table в ref-panel */
.ref-formula-table{width:100%;font-size:.73rem;margin:8px 0;border-collapse:collapse}
.ref-formula-table th,.ref-formula-table td{padding:7px 9px;border:1px solid var(--border);text-align:left;vertical-align:top}
.ref-formula-table th{background:rgba(147,51,234,.08);font-weight:700;color:var(--pri);position:sticky;top:0;z-index:1}
.ref-formula-table tr:nth-child(odd) td{background:rgba(147,51,234,.04)}
.ref-formula-table tr:nth-child(even) td{background:var(--card)}
html.dark .ref-formula-table th{background:rgba(147,51,234,.16)}
html.dark .ref-formula-table tr:nth-child(odd) td{background:rgba(147,51,234,.07)}
.ref-formula-table-wrap{max-height:65vh;overflow-y:auto}
/* ── Ключевые выводы ── */
.key-points{background:rgba(168,85,247,.08);border-left:4px solid #a855f7;border-radius:8px;padding:16px;margin:24px 0;box-shadow:var(--shadow-sm)}
.key-points-title{font-weight:800;font-size:.82rem;color:#a855f7;text-transform:uppercase;letter-spacing:.06em;margin-bottom:12px;display:flex;align-items:center;gap:7px}
.key-points-list{list-style:none;padding:0;margin:0}
.key-points-list li{font-size:.83rem;color:var(--text);line-height:1.8;margin-bottom:8px;padding-left:20px;position:relative}
.key-points-list li::before{content:'✓';position:absolute;left:0;color:#a855f7;font-weight:800}
html.dark .key-points{background:rgba(168,85,247,.12);border-left-color:#c084fc}
html.dark .key-points-title{color:#c084fc}
/* ── Para-hero доп. элементы ── */
.para-hero .ph-formula{display:inline-block;font-size:1rem;background:rgba(255,255,255,.17);border-radius:10px;padding:7px 16px;margin:2px 0 8px;font-weight:700;border:1px solid rgba(255,255,255,.22)}
.para-hero .ph-desc{font-size:.79rem;opacity:.87;line-height:1.65;margin-bottom:10px}
.para-hero .ph-tags{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.para-hero .ph-tag{background:rgba(255,255,255,.17);border:1px solid rgba(255,255,255,.25);border-radius:20px;padding:3px 11px;font-size:.7rem;font-weight:700}
.para-hero .ph-label{font-size:.7rem;font-weight:700;opacity:.75;letter-spacing:.1em;text-transform:uppercase;margin-bottom:5px}
.para-hero h2{font-size:1.12rem;font-weight:900;margin-bottom:8px;line-height:1.3}
/* ── Разделитель ── */
hr.divider{border:none;border-top:1px solid var(--border);margin:20px 0}
/* ── Шаги решения ── */
.sol-steps{list-style:none;padding:0;margin:8px 0}
.sol-steps li{display:flex;align-items:flex-start;gap:10px;margin-bottom:10px;font-size:.86rem;line-height:1.75}
.step-n{min-width:24px;height:24px;border-radius:50%;background:var(--pri);color:#fff;font-size:.69rem;font-weight:800;display:grid;place-items:center;margin-top:1px;flex-shrink:0}
/* ═══════════════════════════════════════════════ */
/* ═══════════ PRO MAX UPGRADE ═════════════════ */
/* ═══════════════════════════════════════════════ */
/* ── Body тонкий фоновый градиент ── */
body{background:radial-gradient(1200px 600px at 80% -10%,rgba(236,72,153,.08),transparent 60%),radial-gradient(900px 500px at -10% 30%,rgba(147,51,234,.07),transparent 55%),var(--bg);min-height:100vh}
html.dark body{background:radial-gradient(1200px 600px at 80% -10%,rgba(147,51,234,.20),transparent 60%),radial-gradient(900px 500px at -10% 30%,rgba(236,72,153,.10),transparent 55%),var(--bg)}
/* ── A5. Motion: появление секций ── */
.fx-rise{opacity:0;transform:translateY(18px);transition:opacity var(--dur-3) var(--ease-out),transform var(--dur-3) var(--ease-out)}
.fx-rise.is-in{opacity:1;transform:none}
.fx-stagger>*{opacity:0;transform:translateY(12px);transition:opacity var(--dur-3) var(--ease-out),transform var(--dur-3) var(--ease-out)}
.fx-stagger.is-in>*{opacity:1;transform:none}
.fx-stagger.is-in>*:nth-child(1){transition-delay:0ms}
.fx-stagger.is-in>*:nth-child(2){transition-delay:60ms}
.fx-stagger.is-in>*:nth-child(3){transition-delay:120ms}
.fx-stagger.is-in>*:nth-child(4){transition-delay:180ms}
.fx-stagger.is-in>*:nth-child(5){transition-delay:240ms}
.fx-stagger.is-in>*:nth-child(6){transition-delay:300ms}
/* ── A4. Типографика fluid + gradient ── */
.section-title{font-size:clamp(.68rem,.62rem + .25vw,.78rem)}
.fcard h3{font-size:clamp(.78rem,.72rem + .3vw,.92rem)}
.task-text{font-size:clamp(.92rem,.86rem + .35vw,1.05rem)}
.para-hero h2{font-size:clamp(1.1rem,.95rem + .8vw,1.5rem);background:linear-gradient(135deg,#fff,rgba(255,255,255,.78));-webkit-background-clip:text;background-clip:text;color:transparent;text-shadow:0 2px 18px rgba(0,0,0,.18)}
/* KaTeX inline подсветка */
.katex{font-size:1.02em}
.katex-html{padding:0 .15em;border-radius:5px;transition:background var(--dur-1) var(--ease)}
.def-box .katex-html:hover,.task-text .katex-html:hover,.fcard .katex-html:hover{background:rgba(147,51,234,.08)}
/* ── A2. Para-hero v2: SVG-узор + параллакс + glow ── */
.para-hero{box-shadow:var(--shadow-lg),0 0 50px rgba(147,51,234,.18);position:relative;isolation:isolate;transform:translateZ(0);transition:transform var(--dur-2) var(--ease)}
.para-hero::before{content:'';position:absolute;inset:0;z-index:-1;opacity:.32;mix-blend-mode:overlay;
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='80' viewBox='0 0 140 80'><g fill='none' stroke='%23ffffff' stroke-width='1.2' opacity='0.55'><path d='M0 20 Q35 0 70 20 T140 20'/><path d='M0 40 Q35 20 70 40 T140 40'/><path d='M0 60 Q35 40 70 60 T140 60'/></g></svg>")}
.para-hero::after{transition:transform .5s var(--ease-out);transform:translate(var(--phx,0),var(--phy,0))}
.para-hero:hover{transform:translateY(-2px)}
.para-hero:hover::after{transform:translate(var(--phx,0),var(--phy,0)) scale(1.1)}
.para-hero .ph-glow{position:absolute;left:-10%;bottom:-40%;width:60%;height:120%;background:radial-gradient(closest-side,rgba(255,255,255,.32),transparent);pointer-events:none;z-index:-1;animation:phPulse 4s ease-in-out infinite alternate}
@keyframes phPulse{from{opacity:.6;transform:scale(.92)}to{opacity:.95;transform:scale(1.06)}}
.ph-badge{position:absolute;top:14px;right:16px;background:rgba(255,255,255,.22);border:1px solid rgba(255,255,255,.4);border-radius:var(--r-full);padding:4px 10px;font-size:.68rem;font-weight:800;letter-spacing:.05em;backdrop-filter:blur(6px);z-index:1}
/* ── A3. Карточки формул v2 ── */
.fcard{transition:transform var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease);position:relative;overflow:hidden;backdrop-filter:blur(8px);background:linear-gradient(180deg,var(--card),color-mix(in srgb,var(--card) 96%,var(--pri-300)))}
.fcard::before{content:'';position:absolute;inset:0;background:radial-gradient(220px circle at var(--mx,50%) var(--my,0%),rgba(147,51,234,.10),transparent 60%);opacity:0;transition:opacity var(--dur-2) var(--ease);pointer-events:none}
.fcard:hover{transform:translateY(-3px) scale(1.005);box-shadow:var(--shadow-pop);border-color:var(--pri-400)}
.fcard:hover::before{opacity:1}
.fcard .main-f{transition:transform var(--dur-2) var(--ease-bounce)}
.fcard:hover .main-f{transform:scale(1.03)}
html.dark .fcard{background:linear-gradient(180deg,var(--card),color-mix(in srgb,var(--card) 92%,var(--pri-700)))}
/* Семантические бордеры для разных типов карточек */
.fcard.is-def{border-color:var(--pri-400)}
.fcard.is-law{border-color:#0891b2}
.fcard.is-formula{border-color:#a16207}
.fcard.is-rule{border-color:#7c3aed}
/* ── Кнопки v2: ripple + улучшенные ── */
.btn{transition:transform var(--dur-1) var(--ease-bounce),box-shadow var(--dur-2) var(--ease),filter var(--dur-2) var(--ease),background var(--dur-2) var(--ease);position:relative;overflow:hidden}
.btn-pri{background:linear-gradient(135deg,var(--pri-500),var(--pri-700));box-shadow:0 4px 14px rgba(147,51,234,.3)}
.btn-pri:hover{box-shadow:0 6px 20px rgba(147,51,234,.45);transform:translateY(-1px)}
.btn-next{background:linear-gradient(135deg,#16a34a,#15803d);box-shadow:0 4px 14px rgba(22,163,74,.3)}
.btn-next:hover{box-shadow:0 6px 20px rgba(22,163,74,.45);transform:translateY(-1px)}
.btn::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at var(--rx,50%) var(--ry,50%),rgba(255,255,255,.6),transparent 40%);opacity:0;transition:opacity var(--dur-3) var(--ease);pointer-events:none}
.btn.is-ripple::after{opacity:1;animation:rippleOut .55s var(--ease-out) forwards}
@keyframes rippleOut{from{opacity:.5;transform:scale(.4)}to{opacity:0;transform:scale(2.2)}}
/* ── Табы v2 ── */
.tab{transition:transform var(--dur-1) var(--ease),border-color var(--dur-1) var(--ease),background var(--dur-2) var(--ease),color var(--dur-2) var(--ease);position:relative}
.tab:hover{transform:translateY(-1px)}
.tab.active{box-shadow:0 4px 14px rgba(147,51,234,.32)}
.tab.active::after{content:'';position:absolute;left:50%;bottom:-9px;width:6px;height:6px;background:var(--pri);border-radius:50%;transform:translateX(-50%);box-shadow:0 0 8px var(--pri)}
/* Pills параграфов в задачах */
.para-pill{transition:all var(--dur-1) var(--ease)}
.para-pill:hover{transform:translateY(-1px);box-shadow:var(--shadow-sm)}
.para-pill.active{box-shadow:0 3px 10px rgba(147,51,234,.3)}
/* ── Nav-dots v2: пульс активного ── */
.nav-dot{transition:transform var(--dur-1) var(--ease),box-shadow var(--dur-2) var(--ease),background var(--dur-2) var(--ease)}
.nav-dot:hover{transform:scale(1.08)}
.nav-dot.nd-cur{box-shadow:0 0 0 4px rgba(147,51,234,.18),0 4px 12px rgba(147,51,234,.3);animation:dotPulse 2.4s ease-in-out infinite}
@keyframes dotPulse{0%,100%{box-shadow:0 0 0 4px rgba(147,51,234,.18),0 4px 12px rgba(147,51,234,.3)}50%{box-shadow:0 0 0 7px rgba(147,51,234,.08),0 4px 14px rgba(147,51,234,.4)}}
/* ── Task-card v2 ── */
.task-card{transition:box-shadow var(--dur-2) var(--ease);background:linear-gradient(180deg,var(--card),color-mix(in srgb,var(--card) 95%,var(--pri-300)))}
.task-card:focus-within{box-shadow:var(--shadow-pop),0 0 0 3px rgba(147,51,234,.15)}
.ans-inp{transition:border-color var(--dur-2) var(--ease),box-shadow var(--dur-2) var(--ease),transform var(--dur-1) var(--ease)}
.ans-inp:focus{transform:scale(1.02)}
/* ── Feedback v2: с иконкой и slide ── */
.feedback{border-left:4px solid transparent;backdrop-filter:blur(4px)}
.fb-ok{border-left-color:var(--ok);background:linear-gradient(135deg,var(--ok-bg),color-mix(in srgb,var(--ok-bg) 70%,transparent))}
.fb-fail{border-left-color:var(--fail);background:linear-gradient(135deg,var(--fail-bg),color-mix(in srgb,var(--fail-bg) 70%,transparent))}
/* ── Канвас-контейнер v2 ── */
.idiag{transition:border-color var(--dur-2) var(--ease),box-shadow var(--dur-2) var(--ease)}
.idiag:hover{border-color:var(--pri-400);box-shadow:var(--shadow-md)}
canvas{transition:filter var(--dur-2) var(--ease)}
/* Подпись под канвасом */
.cv-cap{font-size:.74rem;color:var(--muted);margin-top:8px;line-height:1.6;display:flex;align-items:flex-start;gap:6px}
.cv-cap i{color:var(--pri);margin-top:2px;flex-shrink:0}
/* ── Чипы значений интерактивов ── */
.val-chip{display:inline-flex;align-items:center;gap:5px;padding:4px 10px;border-radius:var(--r-full);background:rgba(147,51,234,.1);color:var(--pri-700);font-weight:800;font-family:monospace;font-size:.78rem;border:1px solid rgba(147,51,234,.2);transition:all var(--dur-1) var(--ease)}
html.dark .val-chip{color:var(--pri-300);background:rgba(147,51,234,.18);border-color:rgba(147,51,234,.3)}
/* ── C1. Sticky mini-TOC слева ── */
#miniToc{position:fixed;left:14px;top:130px;width:50px;z-index:55;display:none;flex-direction:column;gap:6px;max-height:calc(100vh - 180px);overflow-y:auto;padding:8px;background:var(--card);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow-md);scrollbar-width:none}
#miniToc::-webkit-scrollbar{display:none}
#miniToc .mt-item{display:grid;place-items:center;width:34px;height:34px;border-radius:var(--r-sm);font-size:.66rem;font-weight:800;color:var(--muted);background:transparent;border:1.5px solid var(--border);cursor:pointer;transition:all var(--dur-1) var(--ease);font-family:inherit;padding:0;flex-shrink:0}
#miniToc .mt-item:hover{color:var(--pri);border-color:var(--pri);transform:translateX(2px)}
#miniToc .mt-item.is-active{background:var(--pri);color:#fff;border-color:var(--pri);box-shadow:0 4px 10px rgba(147,51,234,.3)}
#miniToc .mt-divider{height:1px;background:var(--border);margin:4px 0;flex-shrink:0}
@media(min-width:1180px){#miniToc{display:flex}}
/* ── Скролл — плавный ── */
html{scroll-behavior:smooth}
/* ── Hint для канваса при касании/hover ── */
.cv-hint{position:absolute;top:8px;right:8px;background:rgba(0,0,0,.45);color:#fff;padding:3px 9px;border-radius:var(--r-full);font-size:.65rem;font-weight:700;pointer-events:none;backdrop-filter:blur(4px);letter-spacing:.04em;text-transform:uppercase;opacity:.9}
/* ── Hover на iconified элементах ── */
.life-item{transition:transform var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease),border-color var(--dur-2) var(--ease)}
.life-item:hover{transform:translateY(-3px);box-shadow:var(--shadow-md);border-color:var(--pri-300)}
.life-item .li-icon{transition:transform var(--dur-2) var(--ease-bounce)}
.life-item:hover .li-icon{transform:scale(1.15) rotate(-4deg)}
</style>
</head>
<body>
<!-- Floating: тема -->
<button class="theme-btn" id="themeBtn" title="Тема"><i class="fas fa-moon"></i></button>
<!-- Floating: справочник -->
<button class="ref-toggle" id="refToggle" title="Справочник"><i class="fas fa-book-open"></i></button>
<!-- Popup справочник -->
<div class="ref-panel" id="refPanel">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)">
<span style="font-size:.82rem;font-weight:800;color:var(--pri)"><i class="fas fa-book-open"></i> Справочник · §32–40</span>
<button onclick="document.getElementById('refPanel').classList.remove('show')"
style="background:none;border:none;cursor:pointer;color:var(--muted);font-size:1rem;line-height:1;padding:2px 4px;border-radius:5px" title="Закрыть"></button>
</div>
<!-- Вкладки -->
<div class="ref-tabs">
<button class="ref-tab-btn active" onclick="switchRefTab('para')">Параграф</button>
<button class="ref-tab-btn" onclick="switchRefTab('cheat')">Шпаргалка</button>
<button class="ref-tab-btn" onclick="switchRefTab('tasks')">Задачи</button>
</div>
<!-- Вкладка: Параграф -->
<div class="ref-tab-content active" id="reftab-para">
<div class="ref-body">
<h3>Скорость и распространение</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>$c = 3 \times 10^8$ м/с — скорость света в вакууме</div>
<div style="margin-top:4px">Вода: $v \approx 2{,}25 \times 10^8$ м/с; Стекло: $v \approx 2{,}00 \times 10^8$ м/с</div>
<div>Алмаз: $v \approx 1{,}24 \times 10^8$ м/с</div>
</div>
<h3>Отражение</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>$\gamma = \alpha$ (угол отражения = углу падения)</div>
<div>Зеркальное: параллельные → параллельные</div>
<div>Диффузное: рассеивается во все стороны</div>
</div>
<h3>Плоское зеркало</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>$l_1 = l_2$ (изображение на том же расстоянии за зеркалом)</div>
<div>Мнимое · прямое · равных размеров</div>
</div>
<h3>Преломление</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>$n = c/v$ (показатель преломления)</div>
<div>Плотнее среда → $\beta &lt; \alpha$</div>
<div>Менее плотная → $\beta &gt; \alpha$</div>
<div>$\alpha = 0°$ → преломления нет</div>
</div>
<h3>Линзы и оптическая сила</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>$D = 1/F$ [дптр]; $F$ [м]</div>
<div>Собирающая: $D &gt; 0$, $F &gt; 0$</div>
<div>Рассеивающая: $D &lt; 0$, $F &lt; 0$</div>
</div>
<h3>Изображения в линзах</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>$d &gt; 2F$ → действ., перевёрн., уменьш.</div>
<div>$F &lt; d &lt; 2F$ → действ., перевёрн., увелич.</div>
<div>$d &lt; F$ → мнимое, прямое, увелич. (лупа)</div>
<div>Рассеивающая → только мнимое, прямое, уменьш.</div>
</div>
<h3>Дефекты зрения</h3>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:10px">
<div>Близорукость: $D &lt; 0$ (рассеивающие очки)</div>
<div>Дальнозоркость: $D &gt; 0$ (собирающие очки)</div>
<div>Расстояние наилучшего видения: 25 см</div>
</div>
</div>
</div>
<!-- Вкладка: Шпаргалка -->
<div class="ref-tab-content" id="reftab-cheat">
<div style="font-size:.72rem;color:var(--muted);margin-bottom:8px">Все формулы §32–40 — сверь с параграфом</div>
<div class="ref-formula-table-wrap">
<table class="ref-formula-table">
<thead>
<tr><th>§</th><th>Формула</th><th>Описание</th><th>Ед.</th></tr>
</thead>
<tbody>
<tr><td>§32</td><td></td><td>Источники: тепловые и нетепловые</td><td></td></tr>
<tr><td>§33</td><td>$c = 3\times10^8\ \text{м/с}$</td><td>Скорость света в вакууме</td><td>м/с</td></tr>
<tr><td>§33</td><td>$t = l/c$</td><td>Время пробега света</td><td>с</td></tr>
<tr><td>§34</td><td>$\gamma = \alpha$</td><td>Закон отражения (угол отражения = углу падения)</td><td>°</td></tr>
<tr><td>§35</td><td>$l_1 = l_2$</td><td>Изображение в плоском зеркале: расстояния равны</td><td>м</td></tr>
<tr><td>§36</td><td>$n = \dfrac{c}{v}$</td><td>Абсолютный показатель преломления</td><td>б/р</td></tr>
<tr><td>§36</td><td>$\dfrac{\sin\alpha}{\sin\beta} = n$</td><td>Закон преломления (в/из воздуха)</td><td></td></tr>
<tr><td>§37</td><td>$D = \dfrac{1}{F}$</td><td>Оптическая сила линзы</td><td>дптр</td></tr>
<tr><td>§38</td><td>$\dfrac{1}{F} = \dfrac{1}{d} + \dfrac{1}{f}$</td><td>Формула тонкой линзы</td><td>м⁻¹</td></tr>
<tr><td>§38</td><td>$\Gamma = \dfrac{f}{d}$</td><td>Линейное увеличение линзы</td><td>б/р</td></tr>
<tr><td>§39</td><td>$D_{\text{глаз}} \approx 60\ \text{дптр}$</td><td>Оптическая сила нормального глаза</td><td>дптр</td></tr>
<tr><td>§39</td><td>$d_{\text{набл}} = 25\ \text{см}$</td><td>Расстояние наилучшего видения</td><td>см</td></tr>
<tr><td>§40</td><td>$D &lt; 0$</td><td>Близорукость: рассеивающие очки</td><td>дптр</td></tr>
<tr><td>§40</td><td>$D &gt; 0$</td><td>Дальнозоркость: собирающие очки</td><td>дптр</td></tr>
<tr><td>§40</td><td>$F = 1/D$</td><td>Фокусное расстояние очковой линзы</td><td>м</td></tr>
</tbody>
</table>
</div>
</div>
<!-- Вкладка: Задачи -->
<div class="ref-tab-content" id="reftab-tasks">
<div style="font-size:.72rem;color:var(--muted);margin-bottom:10px">Типовые задачи и подсказки к решению</div>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:8px">
<div style="font-weight:800;font-size:.76rem;color:var(--pri);margin-bottom:5px">§33 — Скорость света</div>
<div style="font-size:.76rem">Расстояние и время: $t = l/c$, $l = ct$</div>
<div style="font-size:.76rem;color:var(--muted)">Перевести км→м (умножить на 1000)</div>
</div>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:8px">
<div style="font-weight:800;font-size:.76rem;color:var(--pri);margin-bottom:5px">§34 — Отражение</div>
<div style="font-size:.76rem">Угол к нормали! $\varphi$ к поверхности → $\alpha = 90° - \varphi$</div>
<div style="font-size:.76rem;color:var(--muted)">Поворот зеркала на φ → луч повернётся на 2φ</div>
</div>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:8px">
<div style="font-weight:800;font-size:.76rem;color:var(--pri);margin-bottom:5px">§35 — Зеркало</div>
<div style="font-size:.76rem">$l_1 = l_2$; расстояние предмет–изображение = $2l$</div>
<div style="font-size:.76rem;color:var(--muted)">Скорость сближения с изображением = 2v</div>
</div>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:8px">
<div style="font-weight:800;font-size:.76rem;color:var(--pri);margin-bottom:5px">§37 — Оптическая сила</div>
<div style="font-size:.76rem">$D = 1/F$ [дптр], $F$ в метрах!</div>
<div style="font-size:.76rem;color:var(--muted)">$F$ в см: разделить на 100 для перевода в м</div>
</div>
<div style="background:rgba(124,58,237,.06);border-radius:9px;padding:10px 12px;margin-bottom:8px">
<div style="font-weight:800;font-size:.76rem;color:var(--pri);margin-bottom:5px">§38 — Формула линзы</div>
<div style="font-size:.76rem">$1/F = 1/d + 1/f$; $\Gamma = f/d$</div>
<div style="font-size:.76rem;color:var(--muted)">$d &gt; 2F$: уменьш.; $F &lt; d &lt; 2F$: увелич.; $d &lt; F$: лупа</div>
</div>
</div>
</div>
<!-- Шапка -->
<div class="hdr">
<h1><i class="fas fa-eye"></i> Физика 8 — Световые явления</h1>
<p>Свет &middot; Отражение &middot; Преломление &middot; Линзы &middot; Оптические приборы</p>
</div>
<!-- Двухколоночный layout -->
<div class="page-wrap">
<!-- Sidebar -->
<aside class="sidebar">
<div class="sb-brand">
<span class="sb-logo">🔭</span>
<div>
<span class="sb-title">Физика 8</span>
<span class="sb-sub">Световые явления · §32–40</span>
</div>
</div>
<nav class="sb-nav">
<button class="sb-item active" data-target="ref32">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="10" cy="10" r="4"/><line x1="10" y1="1" x2="10" y2="3"/><line x1="10" y1="17" x2="10" y2="19"/><line x1="1" y1="10" x2="3" y2="10"/><line x1="17" y1="10" x2="19" y2="10"/><line x1="3.5" y1="3.5" x2="5" y2="5"/><line x1="15" y1="15" x2="16.5" y2="16.5"/><line x1="16.5" y1="3.5" x2="15" y2="5"/><line x1="5" y1="15" x2="3.5" y2="16.5"/></svg></span>
<span class="sb-num">§32</span>
<span class="sb-name">Источники света</span>
</button>
<button class="sb-item" data-target="ref33">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M2 14 Q6 10 10 10 Q14 10 18 6"/><line x1="14" y1="6" x2="18" y2="6"/><line x1="18" y1="6" x2="18" y2="10"/></svg></span>
<span class="sb-num">§33</span>
<span class="sb-name">Скорость и прямолинейность</span>
</button>
<button class="sb-item" data-target="ref34">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><line x1="2" y1="14" x2="18" y2="14"/><line x1="10" y1="14" x2="10" y2="4" stroke-dasharray="2,2"/><path d="M3 4 L10 14"/><path d="M10 14 L17 4"/></svg></span>
<span class="sb-num">§34</span>
<span class="sb-name">Отражение света</span>
</button>
<button class="sb-item" data-target="ref35">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><line x1="10" y1="2" x2="10" y2="18"/><path d="M4 6 L10 10 L4 14" stroke-linecap="round"/><path d="M16 6 L10 10 L16 14" stroke-linecap="round" stroke-dasharray="2,2"/></svg></span>
<span class="sb-num">§35</span>
<span class="sb-name">Зеркала. Плоское зеркало</span>
</button>
<button class="sb-item" data-target="ref36">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><line x1="10" y1="2" x2="10" y2="18" stroke-dasharray="3,2"/><path d="M2 5 L10 10"/><path d="M10 10 L18 13"/><line x1="2" y1="10" x2="18" y2="10" stroke-opacity=".4"/></svg></span>
<span class="sb-num">§36</span>
<span class="sb-name">Преломление света</span>
</button>
<button class="sb-item" data-target="ref37">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><ellipse cx="10" cy="10" rx="3" ry="8"/><line x1="2" y1="10" x2="18" y2="10"/><line x1="2" y1="7" x2="7" y2="7"/><line x1="7" y1="7" x2="16" y2="10"/><line x1="2" y1="13" x2="7" y2="13"/><line x1="7" y1="13" x2="16" y2="10"/></svg></span>
<span class="sb-num">§37</span>
<span class="sb-name">Линзы. Оптическая сила</span>
</button>
<button class="sb-item" data-target="ref38">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><ellipse cx="10" cy="10" rx="3" ry="7"/><line x1="2" y1="10" x2="18" y2="10"/><line x1="3" y1="6" x2="10" y2="6"/><line x1="10" y1="6" x2="17" y2="9"/><line x1="3" y1="14" x2="10" y2="14"/><line x1="10" y1="14" x2="17" y2="11"/><circle cx="17" cy="10" r="2" fill="currentColor" stroke="none" opacity=".7"/></svg></span>
<span class="sb-num">§38</span>
<span class="sb-name">Изображения в линзах</span>
</button>
<button class="sb-item" data-target="ref39">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><ellipse cx="10" cy="10" rx="8" ry="6"/><circle cx="10" cy="10" r="2.5"/><circle cx="10" cy="10" r="1" fill="currentColor" stroke="none"/></svg></span>
<span class="sb-num">§39</span>
<span class="sb-name">Глаз как оптическая система</span>
</button>
<button class="sb-item" data-target="ref40">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="7" cy="11" r="3.5"/><circle cx="13" cy="11" r="3.5"/><line x1="10.5" y1="11" x2="10.5" y2="11"/><path d="M3.5 11 Q3 8 7 8"/><path d="M16.5 11 Q17 8 13 8"/><line x1="1" y1="11" x2="3.5" y2="11"/><line x1="16.5" y1="11" x2="19" y2="11"/><line x1="10" y1="8.5" x2="10" y2="7"/></svg></span>
<span class="sb-num">§40</span>
<span class="sb-name">Дефекты зрения. Очки</span>
</button>
<div class="sb-divider"></div>
<button class="sb-item" data-target="tasks">
<span class="para-icon"><svg viewBox="0 0 20 20" width="20" height="20" fill="none" stroke="currentColor" stroke-width="1.6"><rect x="4" y="2" width="12" height="16" rx="2"/><line x1="7" y1="7" x2="13" y2="7"/><line x1="7" y1="10" x2="13" y2="10"/><line x1="7" y1="13" x2="11" y2="13"/></svg></span>
<span class="sb-num"></span>
<span class="sb-name">Задачи</span>
</button>
</nav>
</aside>
<!-- Main content -->
<main class="main-col">
<div class="content-area">
<!-- §32 -->
<div class="content active" id="tab-ref32">
<div class="para-hero ph-32">
<div class="ph-label">§32 · Физика 8 кл</div>
<h2>Источники света</h2>
<div class="ph-desc">Тела, излучающие свет — источники. Тепловые (Солнце, лампа, свеча) и нетепловые (светлячки, лазер, флуоресценция). Точечный источник: размерами в условии задачи можно пренебречь.</div>
<div class="ph-tags">
<span class="ph-tag">☀️ тепловые и холодные</span>
<span class="ph-tag">🔦 точечный источник</span>
<span class="ph-tag">➡️ луч = линия света</span>
</div>
</div>
<div class="section-title"><i class="fas fa-sun"></i> §32. Источники света</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Виды источников</h3>
<div class="main-f" style="font-size:.85rem">тепловые · нетепловые (люминесцентные)</div>
<p><b>Тепловые:</b> тела, нагретые до высокой температуры → Солнце, лампа накаливания, пламя свечи.</p>
<p><b>Нетепловые:</b> светлячки, флуоресцеин, лазер — свечение без нагрева.</p>
<p><b>Точечный источник:</b> размерами в условии задачи можно пренебречь.</p>
</div>
<div class="fcard">
<h3>Луч света</h3>
<div class="main-f" style="font-size:.85rem">линия, вдоль которой распространяется свет</div>
<p>Лучи от точечного источника расходятся во все стороны.</p>
<p>Чем меньше отверстие — тем ближе пучок к идеальному лучу.</p>
<p>Большинство видимых нами тел мы видим благодаря <b>отражённому</b> от них свету.</p>
</div>
</div>
<div class="life-grid">
<div class="life-item"><div class="li-icon">☀️</div><div class="li-title">Солнце</div><div class="li-desc">Тепловой источник: температура поверхности ~6000°C → белый свет</div></div>
<div class="life-item"><div class="li-icon">🔦</div><div class="li-title">Лампа накаливания</div><div class="li-desc">Тепловой источник: нить нагрета током до ~2600°C</div></div>
<div class="life-item"><div class="li-icon">🐛</div><div class="li-title">Светлячок</div><div class="li-desc">Нетепловой (биолюминесценция): химическая реакция без нагрева</div></div>
<div class="life-item"><div class="li-icon">🔴</div><div class="li-title">Лазер</div><div class="li-desc">Нетепловой: когерентное монохроматическое излучение, применяется в медицине, связи</div></div>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>Источник света — тело, <b>само излучающее</b> свет (не отражённый).</li>
<li>Луна, книга, деревья — <b>не источники</b>: мы их видим в отражённом свете.</li>
<li>Точечный источник — упрощение задачи: его размером пренебрегаем.</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §32</div>
<ul class="key-points-list">
<li>Источник света — тело, которое само излучает свет (не отражённый): Солнце, лампа, свеча.</li>
<li>Тепловые источники светятся из-за нагрева; нетепловые (светлячки, лазер) — без нагрева.</li>
<li>Луч — линия, вдоль которой распространяется свет; идеальный луч — упрощение модели.</li>
<li>Точечный источник — источник, размерами которого в данной задаче можно пренебречь.</li>
<li>Большинство видимых предметов видны в отражённом свете — сами не являются источниками.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Точечный источник и лучи</div>
<div class="idiag">
<h3>☀️ Лучи от точечного источника</h3>
<canvas id="cv32" style="width:100%;height:240px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<div class="slider-row" style="flex:1;min-width:200px">
<span class="slider-lbl">Число лучей:</span>
<input type="range" id="sl32n" min="4" max="36" value="12" style="flex:1" oninput="lbl32n.textContent=this.value;upd32();">
<span class="slider-val"><span id="lbl32n">12</span></span>
</div>
<select id="sel32src" onchange="upd32()" style="padding:6px 10px;border-radius:8px;border:2px solid var(--border);background:var(--card);color:var(--text)">
<option value="point">Точечный источник</option>
<option value="wide">Протяжённый источник</option>
</select>
</div>
<p style="font-size:.78rem;color:var(--muted);margin-top:8px">Точечный источник излучает лучи равномерно во все стороны. Экран с отверстием выделяет один луч.</p>
</div>
</div>
<!-- §33 -->
<div class="content" id="tab-ref33">
<div class="para-hero ph-33">
<div class="ph-label">§33 · Физика 8 кл</div>
<h2>Скорость света. Прямолинейность</h2>
<div class="ph-formula">$c = 3 \times 10^8$ м/с</div>
<div class="ph-desc">Скорость света в вакууме — максимальная в природе. В оптически более плотных средах скорость меньше. В однородной среде свет распространяется прямолинейно → тень и полутень.</div>
<div class="ph-tags">
<span class="ph-tag">$c = 3 \times 10^8$ м/с</span>
<span class="ph-tag">🌫️ оптически плотные среды</span>
<span class="ph-tag">🌑 тень и полутень</span>
</div>
</div>
<div class="section-title"><i class="fas fa-bolt-lightning"></i> §33. Скорость света. Прямолинейность распространения</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Скорость света</h3>
<div class="main-f">$c = 3 \times 10^8$ м/с</div>
<p>Скорость света в вакууме — максимальная скорость в природе.</p>
<p>В среде: $v < c$. Чем <b>оптически плотнее</b> среда — тем медленнее.</p>
<table style="width:100%;font-size:.78rem;margin-top:6px;border-collapse:collapse">
<tr><td style="padding:2px 4px">Вода</td><td style="padding:2px 4px;font-weight:700">$2{,}25 \times 10^8$ м/с</td><td style="padding:2px 4px">Стекло</td><td style="padding:2px 4px;font-weight:700">$2{,}00 \times 10^8$ м/с</td></tr>
<tr><td style="padding:2px 4px">Алмаз</td><td style="padding:2px 4px;font-weight:700">$1{,}24 \times 10^8$ м/с</td></tr>
</table>
</div>
<div class="fcard">
<h3>Прямолинейность. Тень и полутень</h3>
<div class="main-f" style="font-size:.85rem">в однородной среде — прямолинейно</div>
<p>От <b>точечного</b> источника — только тень (чёткая граница).</p>
<p>От <b>протяжённого</b> — тень и полутень.</p>
<p>Солнечное затмение: Луна создаёт тень и полутень на Земле.</p>
</div>
</div>
<div class="idiag">
<h3>🌑 Тень и полутень от разных источников</h3>
<svg width="100%" viewBox="0 0 320 130" style="display:block">
<!-- Точечный источник -->
<text x="30" y="12" font-size="8.5" fill="#fbbf24" font-family="sans-serif" font-weight="bold">Точечный источник S</text>
<circle cx="20" cy="65" r="6" fill="#fbbf24"/>
<text x="20" y="69" font-size="7" fill="#1e1b4b" font-family="sans-serif" text-anchor="middle">S</text>
<!-- Предмет -->
<rect x="85" y="50" width="8" height="30" rx="2" fill="#475569"/>
<!-- Тень -->
<path d="M20,59 L85,50 L160,40 M20,71 L85,80 L160,90" stroke="rgba(251,191,36,0.4)" stroke-width="1" fill="none"/>
<rect x="160" y="40" width="12" height="50" rx="2" fill="rgba(15,23,42,0.9)" stroke="#334155" stroke-width="1"/>
<text x="166" y="100" font-size="7" fill="#94a3b8" font-family="sans-serif" text-anchor="middle">тень</text>
<!-- Протяжённый источник -->
<text x="185" y="12" font-size="8.5" fill="#f97316" font-family="sans-serif" font-weight="bold">Протяжённый источник</text>
<rect x="180" y="50" width="6" height="30" rx="2" fill="#f97316"/>
<!-- Предмет 2 -->
<rect x="240" y="52" width="7" height="26" rx="2" fill="#475569"/>
<!-- Тень+полутень -->
<path d="M180,50 L240,52 L300,45 M180,80 L240,78 L300,85" stroke="rgba(249,115,22,0.3)" stroke-width="1" fill="none"/>
<path d="M183,50 L240,52 L300,52 M183,80 L240,78 L300,78" stroke="rgba(249,115,22,0.2)" stroke-width="1" fill="none"/>
<rect x="300" y="45" width="12" height="40" rx="2" fill="rgba(15,23,42,0.9)"/>
<rect x="300" y="40" width="12" height="5" rx="1" fill="rgba(50,40,40,0.5)"/>
<rect x="300" y="85" width="12" height="5" rx="1" fill="rgba(50,40,40,0.5)"/>
<text x="306" y="108" font-size="6" fill="#94a3b8" font-family="sans-serif" text-anchor="middle">тень</text>
<text x="306" y="42" font-size="6" fill="#94a3b8" font-family="sans-serif" text-anchor="middle">полутень</text>
</svg>
</div>
<div class="insight-box">
<div class="insight-title"><i class="fas fa-lightbulb"></i> Мы смотрим в прошлое!</div>
<p>Свет от ближайшей к нам (после Солнца) звезды Проксима Центавра летит <b>4,2 года</b>. Свет от далёких галактик — <b>миллиарды лет</b>. Глядя на звёзды, мы видим, какими они были в момент испускания света — буквально «путешествие в прошлое».</p>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>$c = 3 \times 10^8$ м/с — скорость в вакууме; в среде — меньше.</li>
<li>Оптически более плотная среда: $v$ меньше — не путать с механической плотностью!</li>
<li>От точечного источника — только чёткая тень; от протяжённого — тень + полутень.</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §33</div>
<ul class="key-points-list">
<li>Скорость света в вакууме $c = 3\times10^8$ м/с — максимальная скорость в природе.</li>
<li>В оптически более плотной среде скорость меньше: $v &lt; c$ (вода: 2,25×10⁸; стекло: 2,00×10⁸ м/с).</li>
<li>В однородной среде свет распространяется прямолинейно — отсюда тени и полутени.</li>
<li>От точечного источника образуется только тень (чёткая граница); от протяжённого — тень и полутень.</li>
<li>Глядя на далёкие звёзды, мы видим их в прошлом: свет летит миллионы лет.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Тень и полутень</div>
<div class="idiag">
<h3>🌑 Наблюдай тень и полутень на экране</h3>
<canvas id="cv33" style="width:100%;height:260px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<select id="sel33src" onchange="upd33()" style="padding:6px 10px;border-radius:8px;border:2px solid var(--border);background:var(--card);color:var(--text)">
<option value="point">Точечный источник</option>
<option value="wide">Протяжённый источник</option>
</select>
<div class="slider-row" style="flex:1;min-width:180px">
<span class="slider-lbl">Размер предмета:</span>
<input type="range" id="sl33obj" min="10" max="60" value="30" style="flex:1" oninput="upd33();">
<span class="slider-val" id="lbl33obj">30</span>
</div>
</div>
</div>
</div>
<!-- §34 -->
<div class="content" id="tab-ref34">
<div class="para-hero ph-34">
<div class="ph-label">§34 · Физика 8 кл</div>
<h2>Отражение света</h2>
<div class="ph-formula">$\gamma = \alpha$</div>
<div class="ph-desc">Угол отражения равен углу падения. Падающий луч, отражённый и нормаль лежат в одной плоскости. Зеркальное отражение (гладкие) и диффузное (шероховатые).</div>
<div class="ph-tags">
<span class="ph-tag">$\gamma = \alpha$</span>
<span class="ph-tag">🪞 зеркальное</span>
<span class="ph-tag">⬜ диффузное</span>
</div>
</div>
<div class="section-title"><i class="fas fa-arrows-left-right"></i> §34. Отражение света</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Законы отражения</h3>
<div class="main-f">$\gamma = \alpha$</div>
<p>1. Угол отражения равен углу падения.</p>
<p>2. Падающий луч, отражённый и нормаль к поверхности лежат в <b>одной плоскости</b>.</p>
<p>$\alpha$ — угол падения (к нормали!), $\gamma$ — угол отражения.</p>
</div>
<div class="fcard">
<h3>Зеркальное и диффузное</h3>
<div class="main-f" style="font-size:.85rem">зеркальное · диффузное (рассеянное)</div>
<p><b>Зеркальное:</b> гладкая поверхность → параллельные лучи → параллельные (зеркало, вода).</p>
<p><b>Диффузное:</b> шероховатая → рассеивание во все стороны → поверхность видна с любой точки.</p>
<p>Именно благодаря диффузному отражению мы видим все матовые предметы вокруг!</p>
</div>
</div>
<div class="idiag-2col">
<div class="idiag">
<h3>📐 Закон отражения — схема</h3>
<svg width="100%" viewBox="0 0 200 120" style="display:block">
<!-- Зеркало -->
<line x1="10" y1="80" x2="190" y2="80" stroke="#64748b" stroke-width="2.5"/>
<rect x="10" y="80" width="180" height="6" fill="rgba(99,102,241,0.3)"/>
<!-- Нормаль -->
<line x1="100" y1="80" x2="100" y2="15" stroke="#94a3b8" stroke-width="1.5" stroke-dasharray="4,3"/>
<text x="106" y="20" font-size="8" fill="#94a3b8" font-family="sans-serif">нормаль</text>
<!-- Падающий луч -->
<line x1="40" y1="20" x2="100" y2="80" stroke="#ef4444" stroke-width="2.5"/>
<polygon points="100,80 90,60 96,62" fill="#ef4444"/>
<text x="52" y="25" font-size="8" fill="#ef4444" font-family="sans-serif">падающий</text>
<!-- Отражённый луч -->
<line x1="100" y1="80" x2="160" y2="20" stroke="#3b82f6" stroke-width="2.5"/>
<polygon points="160,20 150,40 156,38" fill="#3b82f6"/>
<text x="140" y="25" font-size="8" fill="#3b82f6" font-family="sans-serif">отражённый</text>
<!-- Дуги углов -->
<path d="M100,60 A20,20 0 0,0 85,70" stroke="#ef4444" stroke-width="1.5" fill="none"/>
<text x="72" y="62" font-size="9" fill="#ef4444" font-family="sans-serif" font-weight="bold">α</text>
<path d="M100,60 A20,20 0 0,1 115,70" stroke="#3b82f6" stroke-width="1.5" fill="none"/>
<text x="116" y="62" font-size="9" fill="#3b82f6" font-family="sans-serif" font-weight="bold">γ</text>
<!-- Формула -->
<text x="100" y="110" text-anchor="middle" font-size="10" fill="#a855f7" font-family="sans-serif" font-weight="bold">γ = α</text>
</svg>
</div>
<div class="idiag">
<h3>🪞 Зеркальное vs диффузное</h3>
<svg width="100%" viewBox="0 0 200 120" style="display:block">
<!-- Зеркальное -->
<text x="50" y="12" text-anchor="middle" font-size="8.5" fill="#94a3b8" font-family="sans-serif">Зеркальное</text>
<line x1="10" y1="60" x2="90" y2="60" stroke="#6366f1" stroke-width="2"/>
<!-- параллельные лучи падают -->
<line x1="15" y1="35" x2="30" y2="60" stroke="#fbbf24" stroke-width="1.5"/>
<line x1="40" y1="30" x2="50" y2="60" stroke="#fbbf24" stroke-width="1.5"/>
<line x1="65" y1="35" x2="70" y2="60" stroke="#fbbf24" stroke-width="1.5"/>
<!-- параллельные лучи отражаются -->
<line x1="30" y1="60" x2="15" y2="35" stroke="#3b82f6" stroke-width="1.5" transform="scale(-1,1) translate(-90,0)"/>
<line x1="30" y1="60" x2="45" y2="35" stroke="#3b82f6" stroke-width="1.5"/>
<line x1="50" y1="60" x2="65" y2="35" stroke="#3b82f6" stroke-width="1.5"/>
<line x1="70" y1="60" x2="85" y2="35" stroke="#3b82f6" stroke-width="1.5"/>
<!-- Диффузное -->
<text x="150" y="12" text-anchor="middle" font-size="8.5" fill="#94a3b8" font-family="sans-serif">Диффузное</text>
<line x1="110" y1="65" x2="190" y2="65" stroke="#78716c" stroke-width="2"/>
<!-- Волнистость шероховатой -->
<path d="M110,65 Q120,62 130,65 Q140,68 150,65 Q160,62 170,65 Q180,68 190,65" stroke="#92400e" stroke-width="1.5" fill="none"/>
<!-- лучи рассеиваются -->
<line x1="140" y1="65" x2="115" y2="40" stroke="#f97316" stroke-width="1" opacity=".7"/>
<line x1="145" y1="65" x2="130" y2="35" stroke="#f97316" stroke-width="1" opacity=".7"/>
<line x1="150" y1="65" x2="150" y2="30" stroke="#f97316" stroke-width="1" opacity=".7"/>
<line x1="155" y1="65" x2="170" y2="35" stroke="#f97316" stroke-width="1" opacity=".7"/>
<line x1="160" y1="65" x2="185" y2="40" stroke="#f97316" stroke-width="1" opacity=".7"/>
<text x="150" y="100" text-anchor="middle" font-size="7.5" fill="#94a3b8" font-family="sans-serif">видна с любой стороны</text>
</svg>
</div>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>Углы $\alpha$ и $\gamma$ отсчитываются от <b>нормали</b>, а не от поверхности!</li>
<li>Свойство обратимости: если пустить луч обратно по отражённому — он пойдёт по падающему.</li>
<li>Зеркальное отражение: блестящие поверхности (зеркало, вода, полированный металл).</li>
<li>Диффузное: матовые поверхности (бумага, стены, снег, кожа) — видны с любой точки.</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §34</div>
<ul class="key-points-list">
<li>Закон отражения: угол отражения равен углу падения ($\gamma = \alpha$). Углы — к нормали!</li>
<li>Падающий луч, отражённый луч и нормаль лежат в одной плоскости.</li>
<li>Зеркальное отражение: гладкая поверхность → параллельные лучи остаются параллельными.</li>
<li>Диффузное отражение: шероховатая поверхность → лучи рассеиваются во все стороны → предмет виден с любой точки.</li>
<li>Поворот зеркала на угол φ вызывает поворот отражённого луча на 2φ.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Закон отражения (Pro Max, мышью!)</div>
<div class="idiag">
<h3>🪞 Двигай мышью — лазер падает в точку курсора, отражение строится автоматически</h3>
<canvas id="cv34" style="width:100%;height:280px;border-radius:12px;background:#0f172a;cursor:crosshair;display:block;touch-action:none"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<button class="btn btn-ghost" type="button" onclick="reset34()" style="padding:6px 14px;font-size:.78rem">🔄 Сброс</button>
<select id="sel34type" onchange="upd34()" style="padding:6px 10px;border-radius:8px;border:2px solid var(--border);background:var(--card);color:var(--text)">
<option value="mirror">Зеркальное отражение</option>
<option value="diffuse">Диффузное отражение</option>
</select>
<span class="val-chip" id="chip34a">α = 35°</span>
<span class="val-chip" id="chip34b" style="background:rgba(34,197,94,.12);color:#16a34a;border-color:rgba(34,197,94,.3)">β = 35° ✓</span>
</div>
<div class="cv-cap"><i class="fas fa-mouse-pointer"></i> Двигай мышью над канвасом — наблюдай закон отражения: угол падения $\alpha$ = углу отражения $\gamma$. Кнопка «Сброс» вернёт луч под 45°.</div>
<div class="idiag-result" id="res34">$\alpha = 35°$ → $\gamma = 35°$ (закон отражения)</div>
</div>
</div>
<!-- §35 -->
<div class="content" id="tab-ref35">
<div class="para-hero ph-35">
<div class="ph-label">§35 · Физика 8 кл</div>
<h2>Зеркала. Изображение в плоском зеркале</h2>
<div class="ph-formula">$l_1 = l_2$</div>
<div class="ph-desc">Изображение в плоском зеркале: мнимое, прямое, равных размеров, на том же расстоянии за зеркалом. Вогнутые — собирают, выпуклые — рассеивают.</div>
<div class="ph-tags">
<span class="ph-tag">🪞 мнимое и прямое</span>
<span class="ph-tag">$l_1 = l_2$</span>
<span class="ph-tag">🔭 вогнутые и выпуклые</span>
</div>
</div>
<div class="section-title"><i class="fas fa-clone"></i> §35. Зеркала. Изображение в плоском зеркале</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Изображение в плоском зеркале</h3>
<div class="main-f">$l_1 = l_2$</div>
<p>Изображение: <b>мнимое</b> (за зеркалом), <b>прямое</b>, <b>равных размеров</b>.</p>
<p>Расстояние от предмета до зеркала = расстоянию от изображения до зеркала.</p>
<p>Образовано пересечением <b>продолжений</b> отражённых лучей — световой энергии за зеркалом нет!</p>
</div>
<div class="fcard">
<h3>Вогнутое и выпуклое зеркала</h3>
<div class="main-f" style="font-size:.85rem">вогнутое → сходящееся · выпуклое → расходящееся</div>
<p><b>Вогнутое:</b> собирает параллельные лучи в фокусе — телескопы, прожекторы, зубные зеркала врача.</p>
<p><b>Выпуклое:</b> даёт широкий обзор — автомобильные зеркала заднего вида, зеркала безопасности в магазинах.</p>
</div>
</div>
<div class="insight-box">
<div class="insight-title"><i class="fas fa-lightbulb"></i> Почему «правое» становится «левым»?</div>
<p>Зеркало не переворачивает право–лево физически. Оно разворачивает изображение по оси, перпендикулярной его плоскости. Когда вы смотрите в зеркало, <b>вы видите себя повёрнутым на 180° вокруг вертикальной оси</b>. Поднятая правая рука кажется «левой», потому что для сравнения вы мысленно разворачиваете зеркальную копию — и получается «зеркальный двойник».</p>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>Мнимое изображение — фотоплёнка в той точке ничего не запишет (энергии там нет).</li>
<li>Расстояние до зеркала: $l_1 = l_2$ — изображение «симметрично» предмету.</li>
<li>Скорость изображения = скорости предмета; при сближении с зеркалом — скорость сближения с изображением вдвое больше.</li>
</ul>
</div>
<div class="life-grid">
<div class="life-item"><div class="li-icon">🚗</div><div class="li-title">Зеркало заднего вида</div><div class="li-desc">Выпуклое зеркало — широкий угол обзора, изображение уменьшенное</div></div>
<div class="life-item"><div class="li-icon">🔭</div><div class="li-title">Телескоп-рефлектор</div><div class="li-desc">Вогнутое зеркало собирает свет далёких звёзд в фокусе</div></div>
<div class="life-item"><div class="li-icon">🦷</div><div class="li-title">Зубное зеркало</div><div class="li-desc">Вогнутое — увеличивает изображение для осмотра зубов</div></div>
<div class="life-item"><div class="li-icon">🏪</div><div class="li-title">Зеркало безопасности</div><div class="li-desc">Выпуклое в углу магазина — широкий обзор для охраны</div></div>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §35</div>
<ul class="key-points-list">
<li>Изображение в плоском зеркале: мнимое (за зеркалом), прямое, равных размеров, $l_1 = l_2$.</li>
<li>Мнимое — образовано продолжениями отражённых лучей; на экране не получить.</li>
<li>Расстояние предмет–изображение = $2l_1$; скорость сближения с изображением = $2v$.</li>
<li>Вогнутое зеркало собирает параллельные лучи в фокусе (телескопы, прожекторы).</li>
<li>Выпуклое зеркало рассеивает лучи, даёт широкий обзор (зеркала заднего вида, магазины).</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Изображение в плоском зеркале</div>
<div class="idiag">
<h3>🪞 Перемещай предмет — изображение строится автоматически</h3>
<canvas id="cv35" style="width:100%;height:280px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<div class="slider-row" style="flex:1;min-width:200px">
<span class="slider-lbl">Расстояние до зеркала $l_1$:</span>
<input type="range" id="sl35d" min="30" max="200" value="100" style="flex:1" oninput="lbl35d.textContent=this.value+' усл.ед.';upd35();">
<span class="slider-val"><span id="lbl35d">100 усл.ед.</span></span>
</div>
<label style="font-size:.82rem;display:flex;align-items:center;gap:6px;cursor:pointer">
<input type="checkbox" id="chk35rays" onchange="upd35()" checked> Показать лучи
</label>
</div>
<div class="idiag-result" id="res35">$l_1 = l_2 = 100$ усл.ед. Изображение мнимое, прямое, равных размеров.</div>
</div>
</div>
<!-- §36 -->
<div class="content" id="tab-ref36">
<div class="para-hero ph-36">
<div class="ph-label">§36 · Физика 8 кл</div>
<h2>Преломление света</h2>
<div class="ph-desc">При переходе в оптически более плотную среду: $\beta < \alpha$. В менее плотную: $\beta > \alpha$. Падающий и преломлённый лучи лежат в одной плоскости с нормалью.</div>
<div class="ph-tags">
<span class="ph-tag">💧 оптическая плотность</span>
<span class="ph-tag">↗ $\beta < \alpha$ (плотнее)</span>
<span class="ph-tag">↘ $\beta > \alpha$ (менее плотно)</span>
</div>
</div>
<div class="section-title"><i class="fas fa-layer-group"></i> §36. Преломление света</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Законы преломления</h3>
<div class="main-f" style="font-size:.82rem">плотнее → $\beta < \alpha$ · менее плотная → $\beta > \alpha$</div>
<p>1. Падающий и преломлённый лучи лежат в одной плоскости с нормалью к границе раздела.</p>
<p>2. При переходе в <b>оптически более плотную</b> среду: $\beta < \alpha$.</p>
<p>3. При переходе в <b>менее плотную</b>: $\beta > \alpha$.</p>
<p>4. При $\alpha = 0°$ преломления нет.</p>
</div>
<div class="fcard">
<h3>Оптическая плотность среды</h3>
<div class="main-f" style="font-size:.82rem">чем плотнее — тем медленнее свет</div>
<table style="width:100%;font-size:.78rem;border-collapse:collapse;margin-top:6px">
<tr style="background:rgba(124,58,237,.08)"><th style="padding:3px 5px;border:1px solid var(--border)">Среда</th><th>$v$, $\times 10^8$ м/с</th><th>Плотнее воздуха?</th></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">Воздух</td><td style="text-align:center">≈3,0</td><td style="text-align:center"></td></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">Вода</td><td style="text-align:center">2,25</td><td style="text-align:center;color:#7c3aed"></td></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">Стекло</td><td style="text-align:center">2,0</td><td style="text-align:center;color:#7c3aed">✓✓</td></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">Алмаз</td><td style="text-align:center">1,24</td><td style="text-align:center;color:#7c3aed">✓✓✓</td></tr>
</table>
</div>
</div>
<div class="life-grid">
<div class="life-item"><div class="li-icon">🏊</div><div class="li-title">Ноги «короче» в воде</div><div class="li-desc">Лучи от ног преломляются на границе вода→воздух: $\beta > \alpha$ → мнимое изображение выше реального</div></div>
<div class="life-item"><div class="li-icon">🌅</div><div class="li-title">Мираж</div><div class="li-desc">Слои воздуха разной температуры — разной оптической плотности → лучи искривляются</div></div>
<div class="life-item"><div class="li-icon">💎</div><div class="li-title">Блеск алмаза</div><div class="li-desc">Очень высокая оптическая плотность → сильное преломление → полное внутреннее отражение → блеск</div></div>
<div class="life-item"><div class="li-icon">🔭</div><div class="li-title">Оптоволокно</div><div class="li-desc">Полное внутреннее отражение: свет «скачет» внутри стеклянной нити — передача данных</div></div>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>Оптическая плотность ≠ механической плотности (скипидар оптически плотнее воды, хотя легче).</li>
<li>При $\alpha = 0°$ (перпендикулярное падение) — преломления нет, луч идёт прямо.</li>
<li>Мнимое изображение дна водоёма — выше реального (поэтому дно «кажется мельче»).</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §36</div>
<ul class="key-points-list">
<li>При переходе в оптически более плотную среду: $\beta &lt; \alpha$ (луч «прижимается» к нормали).</li>
<li>В менее плотную: $\beta &gt; \alpha$ (луч «отходит» от нормали).</li>
<li>Показатель преломления: $n = c/v$ — чем плотнее среда, тем больше $n$.</li>
<li>При $\alpha = 0°$ (перпендикулярное падение) преломления нет — луч идёт прямо.</li>
<li>Оптическая плотность ≠ механической: скипидар оптически плотнее воды, хотя легче.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Преломление на границе сред</div>
<div class="idiag">
<h3>💧 Меняй угол и среды — наблюдай преломление</h3>
<canvas id="cv36" style="width:100%;height:270px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<div class="slider-row" style="flex:1;min-width:180px">
<span class="slider-lbl">Угол падения $\alpha$:</span>
<input type="range" id="sl36a" min="0" max="80" value="40" style="flex:1" oninput="lbl36a.textContent=this.value+'°';upd36();">
<span class="slider-val"><span id="lbl36a">40°</span></span>
</div>
<select id="sel36med" onchange="upd36()" style="padding:6px 10px;border-radius:8px;border:2px solid var(--border);background:var(--card);color:var(--text)">
<option value="water">Воздух → Вода (n=1,33)</option>
<option value="glass">Воздух → Стекло (n=1,50)</option>
<option value="diamond">Воздух → Алмаз (n=2,42)</option>
<option value="rev_water">Вода → Воздух (n=0,75)</option>
</select>
</div>
<div class="idiag-result" id="res36">$\alpha = 40°$; среда: вода (n=1,33); $\beta \approx 29°$</div>
</div>
</div>
<!-- §37 -->
<div class="content" id="tab-ref37">
<div class="para-hero ph-37">
<div class="ph-label">§37 · Физика 8 кл</div>
<h2>Линзы. Оптическая сила линзы</h2>
<div class="ph-formula">$D = 1/F$</div>
<div class="ph-desc">Собирающая линза: параллельные лучи сходятся в фокусе ($D > 0$). Рассеивающая: расходятся ($D < 0$). Оптическая сила $D = 1/F$ [дптр].</div>
<div class="ph-tags">
<span class="ph-tag">$D = 1/F$ [дптр]</span>
<span class="ph-tag">⊕ собирающая $D > 0$</span>
<span class="ph-tag">⊖ рассеивающая $D < 0$</span>
</div>
</div>
<div class="section-title"><i class="fas fa-circle-half-stroke"></i> §37. Линзы. Оптическая сила линзы</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Оптическая сила линзы</h3>
<div class="main-f">$D = 1/F$</div>
<p>$D$ — оптическая сила [дптр]; $F$ — фокусное расстояние [м].</p>
<p><b>Собирающая:</b> $D > 0$, $F > 0$ — параллельные лучи сходятся в фокусе.</p>
<p><b>Рассеивающая:</b> $D < 0$, $F < 0$ параллельные лучи расходятся (продолжения сходятся в мнимом фокусе).</p>
</div>
<div class="fcard">
<h3>Фокус и главная оптическая ось</h3>
<div class="main-f" style="font-size:.85rem">главный фокус $F$ · оптический центр $O$</div>
<p><b>Главная оптическая ось</b> — прямая через центры кривизны поверхностей.</p>
<p><b>Оптический центр $O$</b> — луч через него не меняет направления.</p>
<p><b>Фокус $F$</b> — точка, где пересекаются лучи, параллельные оси (у собирающей — действительный; у рассеивающей — мнимый).</p>
</div>
</div>
<div class="idiag">
<h3>📊 Примеры оптической силы</h3>
<table style="width:100%;border-collapse:collapse;font-size:.8rem">
<thead><tr style="background:rgba(124,58,237,.08)"><th style="padding:6px 8px;border:1px solid var(--border)">Устройство</th><th style="padding:6px 8px;border:1px solid var(--border)">$D$, дптр</th><th style="padding:6px 8px;text-align:left;border:1px solid var(--border)">Применение</th></tr></thead>
<tr><td style="padding:5px 8px;border:1px solid var(--border)">Лупа</td><td style="padding:5px 8px;border:1px solid var(--border);text-align:center;font-weight:700;color:#059669">+5 … +20</td><td style="padding:5px 8px;border:1px solid var(--border)">Часовщик, исследования</td></tr>
<tr style="background:rgba(124,58,237,.03)"><td style="padding:5px 8px;border:1px solid var(--border)">Нормальный глаз</td><td style="padding:5px 8px;border:1px solid var(--border);text-align:center;font-weight:700;color:#0369a1">≈ 60</td><td style="padding:5px 8px;border:1px solid var(--border)">Роговица + хрусталик</td></tr>
<tr><td style="padding:5px 8px;border:1px solid var(--border)">Очки при близорукости</td><td style="padding:5px 8px;border:1px solid var(--border);text-align:center;font-weight:700;color:#dc2626">1 … 6</td><td style="padding:5px 8px;border:1px solid var(--border)">Рассеивающие линзы</td></tr>
<tr style="background:rgba(124,58,237,.03)"><td style="padding:5px 8px;border:1px solid var(--border)">Очки при дальнозоркости</td><td style="padding:5px 8px;border:1px solid var(--border);text-align:center;font-weight:700;color:#059669">+1 … +4</td><td style="padding:5px 8px;border:1px solid var(--border)">Собирающие линзы</td></tr>
</table>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>$D = 1/F$: чем меньше $F$ — тем больше $D$ — тем сильнее линза.</li>
<li>У собирающей линзы середина <b>толще краёв</b>; у рассеивающей — тоньше.</li>
<li>Луч через оптический центр не преломляется; луч параллельно оси — через фокус.</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §37</div>
<ul class="key-points-list">
<li>Оптическая сила линзы: $D = 1/F$ [дптр]; $F$ — фокусное расстояние в метрах.</li>
<li>Собирающая линза: $D &gt; 0$, $F &gt; 0$; середина толще краёв.</li>
<li>Рассеивающая линза: $D &lt; 0$, $F &lt; 0$; края толще середины.</li>
<li>Луч через оптический центр O не преломляется; луч || оси — проходит через фокус F.</li>
<li>Чем меньше $F$ — тем больше $D$ — тем сильнее линза преломляет.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Фокус и оптическая сила</div>
<div class="idiag">
<h3>🔍 Параллельные лучи через линзу</h3>
<canvas id="cv37" style="width:100%;height:240px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<div class="slider-row" style="flex:1;min-width:200px">
<span class="slider-lbl">Фокусное расстояние $F$:</span>
<input type="range" id="sl37F" min="-200" max="200" step="10" value="80" style="flex:1" oninput="lbl37F.textContent=this.value+' усл.';upd37();">
<span class="slider-val"><span id="lbl37F">80 усл.</span></span>
</div>
</div>
<div class="idiag-result" id="res37">$F = 80$ усл.; $D = 12{,}5$ дптр (собирающая)</div>
</div>
</div>
<!-- §38 -->
<div class="content" id="tab-ref38">
<div class="para-hero ph-38">
<div class="ph-label">§38 · Физика 8 кл</div>
<h2>Построение изображений в тонких линзах</h2>
<div class="ph-desc">$d > 2F$: действит., перевёрн., уменьш. $F < d < 2F$: действит., перевёрн., увелич. $d < F$: мнимое, прямое, увелич. (лупа). Рассеивающая только мнимое, прямое, уменьш.</div>
<div class="ph-tags">
<span class="ph-tag">🔍 лупа: $d < F$</span>
<span class="ph-tag">📷 $d > 2F$: уменьш.</span>
<span class="ph-tag">✏️ два луча → изображение</span>
</div>
</div>
<div class="section-title"><i class="fas fa-drafting-compass"></i> §38. Построение изображений в тонких линзах</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Типы изображений в собирающей линзе</h3>
<div class="main-f" style="font-size:.78rem">два луча строят изображение</div>
<table style="width:100%;font-size:.78rem;border-collapse:collapse;margin-top:6px">
<tr style="background:rgba(124,58,237,.08)"><th style="padding:3px 5px;border:1px solid var(--border)">Положение</th><th style="padding:3px 5px;border:1px solid var(--border)">Изображение</th></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">$d > 2F$</td><td style="padding:3px 5px;border:1px solid var(--border)">действ., перевёрн., уменьш.</td></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">$d = 2F$</td><td style="padding:3px 5px;border:1px solid var(--border)">действ., перевёрн., равное</td></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">$F < d < 2F$</td><td style="padding:3px 5px;border:1px solid var(--border)">действ., перевёрн., увелич.</td></tr>
<tr><td style="padding:3px 5px;border:1px solid var(--border)">$d < F$ (лупа)</td><td style="padding:3px 5px;border:1px solid var(--border)">мнимое, прямое, увелич.</td></tr>
</table>
</div>
<div class="fcard">
<h3>Два главных луча</h3>
<div class="main-f" style="font-size:.82rem">✦ параллельный → через $F$ · ✦ через $O$</div>
<p><b>Луч 1:</b> параллельно главной оси → после линзы идёт через фокус $F$.</p>
<p><b>Луч 2:</b> через оптический центр $O$ → не меняет направления.</p>
<p>Пересечение (или продолжений) этих лучей = изображение точки.</p>
<p><b>Рассеивающая</b> → всегда: мнимое, прямое, уменьшенное.</p>
</div>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>Действительное изображение — можно спроецировать на экран (лучи реально пересекаются).</li>
<li>Мнимое — только продолжения лучей пересекаются; экраном не поймаешь, но видно в линзу.</li>
<li>Все действительные изображения — <b>перевёрнутые</b>; все мнимые — <b>прямые</b>.</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §38</div>
<ul class="key-points-list">
<li>Два главных луча строят изображение: 1) || оси → через F'; 2) через оптический центр O.</li>
<li>$d &gt; 2F$: действительное, перевёрнутое, уменьшенное (фотоаппарат, глаз).</li>
<li>$F &lt; d &lt; 2F$: действительное, перевёрнутое, увеличенное (проектор).</li>
<li>$d &lt; F$: мнимое, прямое, увеличенное (лупа); $1/F = 1/d + 1/f$; $\Gamma = f/d$.</li>
<li>Рассеивающая линза — всегда мнимое, прямое, уменьшенное при любом положении предмета.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Оптический стол Pro Max (тяни предмет!)</div>
<div class="idiag">
<h3>🔬 Drag-and-drop: тяни стрелку-предмет или саму линзу — три луча и изображение строятся в реальном времени</h3>
<canvas id="cv38" style="width:100%;height:320px;border-radius:12px;background:#0f172a;cursor:grab;display:block;touch-action:none"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<div class="slider-row" style="flex:1;min-width:200px">
<span class="slider-lbl">Фокусное расстояние F:</span>
<input type="range" id="sl38F" min="30" max="120" value="70" style="flex:1" oninput="lbl38F.textContent=this.value+' усл.';upd38();">
<span class="slider-val"><span id="lbl38F">70 усл.</span></span>
</div>
<select id="sel38type" onchange="upd38()" style="padding:6px 10px;border-radius:8px;border:2px solid var(--border);background:var(--card);color:var(--text)">
<option value="conv">Собирающая линза</option>
<option value="div">Рассеивающая линза</option>
</select>
<label style="font-size:.82rem;display:flex;align-items:center;gap:6px;cursor:pointer">
<input type="checkbox" id="chk38r3" checked onchange="upd38()"> Луч 3 (через F)
</label>
<button class="btn btn-ghost" type="button" onclick="reset38()" style="padding:6px 14px;font-size:.78rem">🔄 Сброс</button>
</div>
<div style="margin-top:8px;display:flex;flex-wrap:wrap;gap:8px;align-items:center">
<span class="val-chip" id="chip38lens">1/F = 1/d + 1/f</span>
<span class="val-chip" id="chip38mag" style="background:rgba(34,197,94,.12);color:#16a34a;border-color:rgba(34,197,94,.3)">Γ = h'/h = 1.00</span>
<span class="val-chip" id="chip38type" style="background:rgba(249,115,22,.12);color:#c2410c;border-color:rgba(249,115,22,.3)">действ., перевёрн.</span>
</div>
<div style="margin-top:8px">
<div class="slider-row">
<span class="slider-lbl">Положение предмета d:</span>
<input type="range" id="sl38d" min="15" max="280" value="160" style="flex:1" oninput="lbl38d.textContent=this.value+' усл.';upd38();">
<span class="slider-val"><span id="lbl38d">160 усл.</span></span>
</div>
</div>
<div class="cv-cap"><i class="fas fa-hand-pointer"></i> Тяни мышью: за стрелку-предмет — двигаешь d; за линзу — двигаешь её по оси (изменяется d). Слайдер F меняет фокус. Луч 1 || оси → через F'. Луч 2 → через оптический центр. Луч 3 → через F → || оси.</div>
<div class="idiag-result" id="res38">Перемести предмет слайдером ↓ или потяни за объект на canvas</div>
</div>
</div>
<!-- §39 -->
<div class="content" id="tab-ref39">
<div class="para-hero ph-39">
<div class="ph-label">§39 · Физика 8 кл</div>
<h2>Глаз как оптическая система</h2>
<div class="ph-desc">Роговица + хрусталик = собирающая система. Аккомодация: хрусталик меняет кривизну → фокусирует на сетчатку. Расстояние наилучшего видения 25 см.</div>
<div class="ph-tags">
<span class="ph-tag">👁️ сетчатка = экран</span>
<span class="ph-tag">⚙️ аккомодация</span>
<span class="ph-tag">📏 $d_{\text{набл}} = 25$ см</span>
</div>
</div>
<div class="section-title"><i class="fas fa-eye"></i> §39. Глаз как оптическая система</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Строение глаза</h3>
<div class="main-f" style="font-size:.82rem">роговица · хрусталик · сетчатка</div>
<p><b>Роговица</b> + хрусталик + стекловидное тело = собирающая линза ($D \approx 60$ дптр).</p>
<p><b>Сетчатка</b> — «экран»: на ней образуется действительное, перевёрнутое, уменьшенное изображение.</p>
<p><b>Зрачок</b> — регулирует количество света, поступающего в глаз.</p>
</div>
<div class="fcard">
<h3>Аккомодация глаза</h3>
<div class="main-f" style="font-size:.85rem">хрусталик меняет кривизну → меняет $F$</div>
<p>Мышцы глаза изменяют форму хрусталика:</p>
<ul style="font-size:.83rem;color:var(--muted);padding-left:16px;line-height:1.9;margin-top:4px">
<li><b>Близкий предмет</b>: хрусталик выпуклее → $F$↓ → $D$↑</li>
<li><b>Далёкий предмет</b>: хрусталик уплощается → $F$↑ → $D$↓</li>
</ul>
<p>Расстояние наилучшего видения: <b>25 см</b> (при котором глаз работает без напряжения).</p>
</div>
</div>
<div class="idiag">
<h3>👁 Схема строения глаза</h3>
<svg width="100%" viewBox="0 0 300 140" style="display:block">
<!-- Глазное яблоко -->
<ellipse cx="170" cy="70" rx="65" ry="55" fill="rgba(255,240,220,0.08)" stroke="#a78bfa" stroke-width="2"/>
<!-- Склера -->
<ellipse cx="170" cy="70" rx="65" ry="55" fill="none" stroke="#64748b" stroke-width="1.5" stroke-dasharray="3,3"/>
<!-- Роговица -->
<path d="M108,55 Q95,70 108,85" stroke="#38bdf8" stroke-width="3" fill="none"/>
<text x="82" y="48" font-size="7.5" fill="#38bdf8" font-family="sans-serif">роговица</text>
<!-- Зрачок/радужка -->
<circle cx="118" cy="70" r="12" fill="rgba(59,130,246,0.2)" stroke="#3b82f6" stroke-width="1.5"/>
<circle cx="118" cy="70" r="5" fill="#1e293b" stroke="#0369a1" stroke-width="1"/>
<text x="100" y="97" font-size="7" fill="#94a3b8" font-family="sans-serif">зрачок</text>
<!-- Хрусталик -->
<path d="M128,55 Q145,70 128,85" stroke="#fbbf24" stroke-width="3" fill="rgba(251,191,36,0.1)"/>
<path d="M132,55 Q118,70 132,85" stroke="#fbbf24" stroke-width="2" fill="none"/>
<text x="130" y="48" font-size="7.5" fill="#fbbf24" font-family="sans-serif">хрусталик</text>
<!-- Стекловидное тело -->
<text x="170" y="75" text-anchor="middle" font-size="7" fill="rgba(148,163,184,0.6)" font-family="sans-serif">стекл. тело</text>
<!-- Сетчатка -->
<path d="M220,35 Q240,70 220,105" stroke="#22c55e" stroke-width="3" fill="none"/>
<text x="240" y="60" font-size="7.5" fill="#22c55e" font-family="sans-serif">сетчатка</text>
<!-- Зрительный нерв -->
<line x1="234" y1="70" x2="255" y2="70" stroke="#94a3b8" stroke-width="2"/>
<text x="260" y="74" font-size="7" fill="#94a3b8" font-family="sans-serif">нерв</text>
<!-- Лучи -->
<line x1="20" y1="50" x2="108" y2="55" stroke="rgba(251,191,36,0.5)" stroke-width="1.5"/>
<line x1="20" y1="90" x2="108" y2="85" stroke="rgba(251,191,36,0.5)" stroke-width="1.5"/>
<!-- После преломления → к сетчатке -->
<line x1="132" y1="57" x2="225" y2="85" stroke="rgba(59,130,246,0.6)" stroke-width="1.5"/>
<line x1="132" y1="83" x2="225" y2="55" stroke="rgba(59,130,246,0.6)" stroke-width="1.5"/>
<!-- Предмет -->
<line x1="20" y1="40" x2="20" y2="100" stroke="#fbbf24" stroke-width="2.5"/>
<polygon points="20,38 16,50 24,50" fill="#fbbf24"/>
<text x="12" y="115" font-size="7.5" fill="#fbbf24" font-family="sans-serif">предмет</text>
<!-- Изображение на сетчатке -->
<text x="218" y="30" font-size="7" fill="#22c55e" font-family="sans-serif">изображение</text>
<text x="218" y="40" font-size="7" fill="#22c55e" font-family="sans-serif">(перевёрнутое)</text>
</svg>
</div>
<div class="insight-box">
<div class="insight-title"><i class="fas fa-lightbulb"></i> Мозг «видит», а не глаз!</div>
<p>На сетчатке образуется перевёрнутое изображение — но мы всё видим «правильно». Это потому что <b>мозг</b> обрабатывает сигналы и строит зрительный образ. Новорождённые поначалу видят мир перевёрнутым — мозгу нужно время, чтобы «научиться» правильно интерпретировать сигналы.</p>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li>Глаз = короткофокусная собирающая линза $D \approx 60$ дптр.</li>
<li>Изображение на сетчатке: действительное, перевёрнутое, уменьшенное.</li>
<li>Аккомодация позволяет видеть чётко на разных расстояниях (25 см … ∞).</li>
<li>Чтение при плохом освещении и с близкого расстояния утомляет хрусталик!</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §39</div>
<ul class="key-points-list">
<li>Оптическая система глаза: роговица + хрусталик ≈ собирающая линза $D \approx 60$ дптр.</li>
<li>На сетчатке образуется действительное, перевёрнутое, уменьшенное изображение.</li>
<li>Аккомодация: хрусталик меняет кривизну → изменяет $F$ → фокусирует предметы с разных расстояний.</li>
<li>Расстояние наилучшего видения: 25 см — при нём глаз работает без напряжения.</li>
<li>Мозг «видит», а не глаз: мозг переворачивает перевёрнутое изображение сетчатки.</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Аккомодация глаза</div>
<div class="idiag">
<h3>👁 Меняй расстояние — хрусталик меняет форму</h3>
<canvas id="cv39" style="width:100%;height:240px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<div class="slider-row" style="flex:1;min-width:200px">
<span class="slider-lbl">Расстояние до предмета:</span>
<input type="range" id="sl39d" min="15" max="200" value="50" style="flex:1" oninput="lbl39d.textContent=this.value+' см';upd39();">
<span class="slider-val"><span id="lbl39d">50 см</span></span>
</div>
</div>
<div class="idiag-result" id="res39">Предмет на 50 см: хрусталик слегка выпуклый</div>
</div>
</div>
<!-- §40 -->
<div class="content" id="tab-ref40">
<div class="para-hero ph-40">
<div class="ph-label">§40 · Физика 8 кл</div>
<h2>Дефекты зрения. Очки</h2>
<div class="ph-desc">Близорукость: фокус перед сетчаткой → рассеивающие очки ($D < 0$). Дальнозоркость: фокус за сетчаткой собирающие очки ($D > 0$).</div>
<div class="ph-tags">
<span class="ph-tag">👓 близорукость → $D < 0$</span>
<span class="ph-tag">🔍 дальнозоркость → $D > 0$</span>
<span class="ph-tag">🎯 лазерная коррекция</span>
</div>
</div>
<div class="section-title"><i class="fas fa-glasses"></i> §40. Дефекты зрения. Очки</div>
<div class="formula-grid">
<div class="fcard highlight">
<h3>Близорукость (миопия)</h3>
<div class="main-f" style="font-size:.85rem">фокус перед сетчаткой → рассеивающие очки $D < 0$</div>
<p>Причина: глазное яблоко вытянуто или хрусталик слишком сильно преломляет.</p>
<p>Дальние предметы — размыто. Ближние — чётко.</p>
<p><b>Коррекция:</b> рассеивающие линзы ($D < 0$) сдвигают фокус назад на сетчатку.</p>
</div>
<div class="fcard">
<h3>Дальнозоркость (гиперметропия)</h3>
<div class="main-f" style="font-size:.85rem">фокус за сетчаткой → собирающие очки $D > 0$</div>
<p>Причина: хрусталик потерял эластичность (у пожилых) или глаз укороченный.</p>
<p>Ближние предметы — размыто. Дальние — лучше.</p>
<p><b>Коррекция:</b> собирающие линзы ($D > 0$) сдвигают фокус вперёд — на сетчатку.</p>
</div>
</div>
<div class="idiag">
<h3>📊 Как читать рецепт на очки</h3>
<table style="width:100%;border-collapse:collapse;font-size:.8rem">
<thead><tr style="background:rgba(124,58,237,.08)"><th style="padding:6px 8px;border:1px solid var(--border)">Запись в рецепте</th><th style="padding:6px 8px;border:1px solid var(--border)">Тип линз</th><th style="padding:6px 8px;border:1px solid var(--border)">Дефект</th><th style="padding:6px 8px;border:1px solid var(--border)">$F$ линз</th></tr></thead>
<tr><td style="padding:5px 8px;border:1px solid var(--border)">2,0 дптр</td><td style="padding:5px 8px;border:1px solid var(--border);color:#dc2626;font-weight:700">рассеивающие</td><td style="padding:5px 8px;border:1px solid var(--border)">близорукость</td><td style="padding:5px 8px;border:1px solid var(--border)">50 см</td></tr>
<tr style="background:rgba(124,58,237,.03)"><td style="padding:5px 8px;border:1px solid var(--border)">+2,5 дптр</td><td style="padding:5px 8px;border:1px solid var(--border);color:#059669;font-weight:700">собирающие</td><td style="padding:5px 8px;border:1px solid var(--border)">дальнозоркость</td><td style="padding:5px 8px;border:1px solid var(--border)">+40 см</td></tr>
<tr><td style="padding:5px 8px;border:1px solid var(--border)">5,0 дптр</td><td style="padding:5px 8px;border:1px solid var(--border);color:#dc2626;font-weight:700">рассеивающие</td><td style="padding:5px 8px;border:1px solid var(--border)">сильная близор.</td><td style="padding:5px 8px;border:1px solid var(--border)">20 см</td></tr>
<tr style="background:rgba(124,58,237,.03)"><td style="padding:5px 8px;border:1px solid var(--border)">+1,0 дптр</td><td style="padding:5px 8px;border:1px solid var(--border);color:#059669;font-weight:700">собирающие</td><td style="padding:5px 8px;border:1px solid var(--border)">слаб. дальнозорк.</td><td style="padding:5px 8px;border:1px solid var(--border)">+100 см</td></tr>
</table>
</div>
<div class="insight-box">
<div class="insight-title"><i class="fas fa-lightbulb"></i> Как определить дефект без прибора</div>
<p>Возьмите очки и поднесите к строчке текста: <b>собирающие (дальнозоркость)</b> — буквы увеличатся; <b>рассеивающие (близорукость)</b> — уменьшатся. Или поднесите к источнику света — собирающие дают яркое пятно (фокус), рассеивающие — нет.</p>
</div>
<div class="life-grid">
<div class="life-item"><div class="li-icon">📱</div><div class="li-title">Смартфон и близорукость</div><div class="li-desc">Длительное чтение с малого расстояния → постоянное напряжение хрусталика → близорукость у детей</div></div>
<div class="life-item"><div class="li-icon">👴</div><div class="li-title">Старческая дальнозоркость</div><div class="li-desc">После 40 лет хрусталик теряет эластичность → не может стать достаточно выпуклым для чтения</div></div>
<div class="life-item"><div class="li-icon">🔬</div><div class="li-title">Лазерная коррекция</div><div class="li-desc">Лазером изменяют кривизну роговицы → меняют оптическую силу → коррекция без очков</div></div>
<div class="life-item"><div class="li-icon">💎</div><div class="li-title">Контактные линзы</div><div class="li-desc">Тонкая линза прямо на роговице — полная свобода от очков, широкое поле зрения</div></div>
</div>
<div class="remember-box">
<div class="remember-box-title"><i class="fas fa-exclamation-circle"></i> Запомни!</div>
<ul>
<li><b>Близорукость</b>: $D < 0$ () рассеивающие. Фокус перед сетчаткой.</li>
<li><b>Дальнозоркость</b>: $D > 0$ (+) → собирающие. Фокус за сетчаткой.</li>
<li>$F = 1/D$ [м] — фокусное расстояние линз очков.</li>
<li>Близорукий может в старости обрести нормальное зрение: потеря упругости хрусталика компенсирует его изначальную «выпуклость».</li>
</ul>
</div>
<div class="key-points">
<div class="key-points-title">🔑 Главное в §40</div>
<ul class="key-points-list">
<li>Близорукость: фокус перед сетчаткой → дальние предметы размыты → рассеивающие очки ($D &lt; 0$).</li>
<li>Дальнозоркость: фокус за сетчаткой → ближние предметы размыты → собирающие очки ($D &gt; 0$).</li>
<li>$F = 1/D$ [м] — фокусное расстояние линз очков; знак определяет тип коррекции.</li>
<li>Лазерная коррекция: лазер меняет кривизну роговицы — навсегда исправляет оптическую силу.</li>
<li>Рассеивающие линзы уменьшают видимые предметы; собирающие — увеличивают (тест без прибора).</li>
</ul>
</div>
<div class="section-title"><i class="fas fa-play-circle"></i> Интерактив — Дефекты зрения и коррекция</div>
<div class="idiag">
<h3>👓 Выбери дефект — надень очки — наблюдай исправление</h3>
<canvas id="cv40" style="width:100%;height:260px;border-radius:12px;background:#0f172a;display:block"></canvas>
<div class="ctrl-row" style="display:flex;flex-wrap:wrap;gap:10px;margin-top:12px;align-items:center">
<select id="sel40def" onchange="upd40()" style="padding:6px 10px;border-radius:8px;border:2px solid var(--border);background:var(--card);color:var(--text)">
<option value="normal">Нормальное зрение</option>
<option value="myopia">Близорукость (миопия)</option>
<option value="hyperopia">Дальнозоркость (гиперметропия)</option>
</select>
<label style="font-size:.82rem;display:flex;align-items:center;gap:7px;cursor:pointer">
<input type="checkbox" id="chk40glasses" onchange="upd40()"> 👓 Надеть очки
</label>
<div class="slider-row" style="flex:1;min-width:180px">
<span class="slider-lbl">D очков:</span>
<input type="range" id="sl40D" min="-6" max="6" step="0.5" value="-2" style="flex:1" oninput="lbl40D.textContent=(+this.value>0?'+':'')+this.value+' дптр';upd40();">
<span class="slider-val"><span id="lbl40D">-2 дптр</span></span>
</div>
</div>
<div class="idiag-result" id="res40">Нормальное зрение: лучи фокусируются точно на сетчатку</div>
</div>
</div>
<!-- ЗАДАЧИ -->
<div class="content" id="tab-tasks">
<div class="para-pills">
<button class="para-pill active" data-para="p32" onclick="setParaTab('p32')">§32 Источники</button>
<button class="para-pill" data-para="p33" onclick="setParaTab('p33')">§33 Скорость света</button>
<button class="para-pill" data-para="p34" onclick="setParaTab('p34')">§34 Отражение</button>
<button class="para-pill" data-para="p35" onclick="setParaTab('p35')">§35 Зеркала</button>
<button class="para-pill" data-para="p36" onclick="setParaTab('p36')">§36 Преломление</button>
<button class="para-pill" data-para="p37" onclick="setParaTab('p37')">§37 Линзы</button>
<button class="para-pill" data-para="p38" onclick="setParaTab('p38')">§38 Изображения</button>
<button class="para-pill" data-para="p39" onclick="setParaTab('p39')">§39 Глаз</button>
<button class="para-pill" data-para="p40" onclick="setParaTab('p40')">§40 Дефекты зрения</button>
<button class="para-pill" data-para="hard" onclick="setParaTab('hard')">⚡ Сложные</button>
</div>
<!-- ptab-p32 -->
<div id="ptab-p32">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp32">0</span></div>
<div class="chip chip-tot"><span id="curp32">0</span>&nbsp;/&nbsp;<span id="maxp32">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p32')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp32" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp32"></div>
<div id="taskAreap32"></div>
<div class="feedback" id="fbp32"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp32" onclick="nextTask('p32')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump32">
<h2>§32 — готово!</h2>
<div class="big-score" id="sumScorep32">0/5</div>
<div class="sum-grade" id="sumGradep32"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p32')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p33')">→ §33</button>
</div>
</div>
</div>
<!-- ptab-p33 -->
<div id="ptab-p33">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp33">0</span></div>
<div class="chip chip-tot"><span id="curp33">0</span>&nbsp;/&nbsp;<span id="maxp33">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p33')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp33" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp33"></div>
<div id="taskAreap33"></div>
<div class="feedback" id="fbp33"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp33" onclick="nextTask('p33')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump33">
<h2>§33 — готово!</h2>
<div class="big-score" id="sumScorep33">0/5</div>
<div class="sum-grade" id="sumGradep33"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p33')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p34')">→ §34</button>
</div>
</div>
</div>
<!-- ptab-p34 -->
<div id="ptab-p34">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp34">0</span></div>
<div class="chip chip-tot"><span id="curp34">0</span>&nbsp;/&nbsp;<span id="maxp34">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p34')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp34" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp34"></div>
<div id="taskAreap34"></div>
<div class="feedback" id="fbp34"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp34" onclick="nextTask('p34')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump34">
<h2>§34 — готово!</h2>
<div class="big-score" id="sumScorep34">0/8</div>
<div class="sum-grade" id="sumGradep34"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p34')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p35')">→ §35</button>
</div>
</div>
</div>
<!-- ptab-p35 -->
<div id="ptab-p35">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp35">0</span></div>
<div class="chip chip-tot"><span id="curp35">0</span>&nbsp;/&nbsp;<span id="maxp35">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p35')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp35" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp35"></div>
<div id="taskAreap35"></div>
<div class="feedback" id="fbp35"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp35" onclick="nextTask('p35')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump35">
<h2>§35 — готово!</h2>
<div class="big-score" id="sumScorep35">0/6</div>
<div class="sum-grade" id="sumGradep35"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p35')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p36')">→ §36</button>
</div>
</div>
</div>
<!-- ptab-p36 -->
<div id="ptab-p36">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp36">0</span></div>
<div class="chip chip-tot"><span id="curp36">0</span>&nbsp;/&nbsp;<span id="maxp36">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p36')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp36" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp36"></div>
<div id="taskAreap36"></div>
<div class="feedback" id="fbp36"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp36" onclick="nextTask('p36')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump36">
<h2>§36 — готово!</h2>
<div class="big-score" id="sumScorep36">0/7</div>
<div class="sum-grade" id="sumGradep36"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p36')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p37')">→ §37</button>
</div>
</div>
</div>
<!-- ptab-p37 -->
<div id="ptab-p37">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp37">0</span></div>
<div class="chip chip-tot"><span id="curp37">0</span>&nbsp;/&nbsp;<span id="maxp37">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p37')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp37" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp37"></div>
<div id="taskAreap37"></div>
<div class="feedback" id="fbp37"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp37" onclick="nextTask('p37')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump37">
<h2>§37 — готово!</h2>
<div class="big-score" id="sumScorep37">0/5</div>
<div class="sum-grade" id="sumGradep37"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p37')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p38')">→ §38</button>
</div>
</div>
</div>
<!-- ptab-p38 -->
<div id="ptab-p38">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp38">0</span></div>
<div class="chip chip-tot"><span id="curp38">0</span>&nbsp;/&nbsp;<span id="maxp38">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p38')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp38" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp38"></div>
<div id="taskAreap38"></div>
<div class="feedback" id="fbp38"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp38" onclick="nextTask('p38')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump38">
<h2>§38 — готово!</h2>
<div class="big-score" id="sumScorep38">0/6</div>
<div class="sum-grade" id="sumGradep38"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p38')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p39')">→ §39</button>
</div>
</div>
</div>
<!-- ptab-p39 -->
<div id="ptab-p39">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp39">0</span></div>
<div class="chip chip-tot"><span id="curp39">0</span>&nbsp;/&nbsp;<span id="maxp39">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p39')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp39" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp39"></div>
<div id="taskAreap39"></div>
<div class="feedback" id="fbp39"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp39" onclick="nextTask('p39')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump39">
<h2>§39 — готово!</h2>
<div class="big-score" id="sumScorep39">0/4</div>
<div class="sum-grade" id="sumGradep39"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p39')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('p40')">→ §40</button>
</div>
</div>
</div>
<!-- ptab-p40 -->
<div id="ptab-p40">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okp40">0</span></div>
<div class="chip chip-tot"><span id="curp40">0</span>&nbsp;/&nbsp;<span id="maxp40">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('p40')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="progp40" style="width:0%"></div></div>
<div class="nav-dots" id="navDotsp40"></div>
<div id="taskAreap40"></div>
<div class="feedback" id="fbp40"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnp40" onclick="nextTask('p40')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sump40">
<h2>§40 — готово!</h2>
<div class="big-score" id="sumScorep40">0/5</div>
<div class="sum-grade" id="sumGradep40"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('p40')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
<button class="btn btn-ghost" onclick="setParaTab('hard')">→ ⚡ Сложные</button>
</div>
</div>
</div>
<!-- ptab-hard -->
<div id="ptab-hard">
<div class="score-bar">
<div class="chip chip-ok"><i class="fas fa-check"></i>&nbsp;<span id="okhard">0</span></div>
<div class="chip chip-tot"><span id="curhard">0</span>&nbsp;/&nbsp;<span id="maxhard">0</span></div>
<button class="btn btn-ghost" onclick="resetTasks('hard')" style="padding:6px 13px;font-size:.74rem"><i class="fas fa-rotate-right"></i> Заново</button>
</div>
<div class="prog-wrap"><div class="prog-fill" id="proghard" style="width:0%"></div></div>
<div class="nav-dots" id="navDotshard"></div>
<div id="taskAreahard"></div>
<div class="feedback" id="fbhard"></div>
<div style="display:flex;gap:10px;margin-top:10px;justify-content:flex-end">
<button class="btn btn-next" id="nextBtnhard" onclick="nextTask('hard')" style="display:none"><i class="fas fa-arrow-right"></i> Следующее</button>
</div>
<div class="summary" id="sumhard">
<h2>Сложные — готово!</h2>
<div class="big-score" id="sumScorehard">0/7</div>
<div class="sum-grade" id="sumGradehard"></div>
<div class="sum-btns">
<button class="btn btn-pri" onclick="resetTasks('hard')"><i class="fas fa-rotate-right"></i> Ещё раз</button>
</div>
</div>
</div>
</div><!-- /tab-tasks -->
</div><!-- /content-area -->
</main>
</div><!-- /page-wrap -->
<script>
// ═══════════════════════════════════════
// ДАННЫЕ ЗАДАЧ
// ═══════════════════════════════════════
var TASKS_P32 = [
{q:"Что такое источник света?",opts:["Любое тело","Тело, само излучающее свет (не отражённый)","Зеркало, отражающее лучи","Тело, поглощающее весь свет"],a:1,ex:"Источник света — тело, которое САМО излучает свет. Луна, книга, стена — не источники (они отражают свет Солнца или ламп)."},
{q:"Какие из перечисленных источников являются тепловыми?",opts:["Светлячок, северное сияние","Лампа накаливания, Солнце, пламя свечи","Флуоресцентная краска, лазер","Гнилая древесина, флюоресцеин"],a:1,ex:"Тепловые источники: нагреваются до высокой температуры и начинают светиться (Солнце, лампа накаливания, свеча). Нетепловые светятся за счёт химических реакций или флуоресценции."},
{q:"В каком случае источник света можно считать точечным?",opts:["Всегда, если он маленький","Когда его размерами в конкретных условиях задачи можно пренебречь","Только если это звезда","Когда он находится далеко от экрана"],a:1,ex:"Понятие точечного источника — это упрощение. Звезды — точечные источники для нас (очень далеко). Лампа — точечный для большого экрана, но не для ближнего листа бумаги."},
{q:"Что такое луч света?",opts:["Пучок параллельных волн","Линия, вдоль которой распространяется свет","Световая волна между двумя телами","Полоса освещённости"],a:1,ex:"Луч — это линия, вдоль которой распространяется световая энергия. Реально получить идеальный луч (с нулевым поперечным сечением) невозможно, но малое отверстие даёт хорошее приближение."},
{q:"Большинство окружающих нас тел мы видим благодаря...",opts:["Собственному свечению тел","Отражённому от них свету","Теплу, которое они излучают","Магнитному полю"],a:1,ex:"Луна, книга, деревья, люди — сами не светятся. Мы их видим потому, что они отражают свет Солнца или ламп. Только тела-источники (лампы, экраны) мы видим благодаря их собственному свету."}
];
var TASKS_P33 = [
{q:"Можно ли имея точечный источник, экран и непрозрачный предмет получить только тень (без полутени)?",opts:["Нет, всегда будет полутень","Да — от точечного источника образуется только тень, без полутени","Только если экран очень близко","Только при маленьком предмете"],a:1,ex:"От точечного источника — только тень (чётко очерченная). Полутень образуется только от протяжённого источника (два и более точечных источника или большой источник)."},
{q:"Сколько времени идёт свет от Солнца до Земли? Расстояние $l = 1{,}49 \\times 10^8$ км. $c = 3 \\times 10^8$ м/с.",hint:"$t = l/c$; перевести км → м",unit:"с",a:497,ex:"$l = 1{,}49 \\times 10^{11}$ м; $t = 1{,}49 \\times 10^{11} / 3 \\times 10^8 \\approx 497$ с $\\approx 8{,}3$ мин"},
{q:"Почему астрономы говорят: «Мы изучаем прошлое звёзд»?",opts:["Потому что звёзды очень старые","Свет от далёких звёзд летит миллионы лет: мы видим не нынешнее состояние, а то, каким оно было в момент излучения","Потому что телескопы дают перевёрнутое изображение","Звёзды уже погасли, мы видим их историю в записях"],a:1,ex:"Расстояние до ближайших звёзд — световые годы. Свет от звезды летит к нам миллионы лет. Глядя на звезду, мы видим её состояние миллионы лет назад — это буквальное «путешествие в прошлое»."},
{q:"На какой высоте над поверхностью воды в бассейне глубиной $h = 3{,}9$ м нужно повесить лампочку, чтобы свет шёл в воде и воздухе одинаковое время? $v_\\text{воды} = 2{,}25 \\times 10^8$ м/с.",hint:"$t = h/v_\\text{воды} = h_\\text{возд}/c$; $h_\\text{возд} = h \\cdot c/v_\\text{воды}$",unit:"м",a:5.2,ex:"$t_\\text{воды} = 3{,}9 / 2{,}25 \\times 10^8$; $h_\\text{возд} = 3{,}9 \\times 3/2{,}25 = 5{,}2$ м"},
{q:"Почему руки хирурга, освещаемые сверху несколькими светильниками, не дают на «операционном поле» тень?",opts:["Потому что хирург держит руки высоко","Несколько источников со стороны дают перекрывающиеся тени — в зоне операции нет полной тени (только полутени от каждого)","Хирурги носят перчатки, которые прозрачны для хирургических ламп","Операционные лампы — лазерные и не дают теней"],a:1,ex:"Несколько источников с разных сторон — тени от каждого перекрываются. В «операционном поле» остаётся зона полутени (частично освещается от другого светильника). Полная тень не образуется."}
];
var TASKS_P34 = [
{q:"Под каким углом отражается луч, упавший перпендикулярно на зеркало? А упавший под углом $\\varphi = 60°$ к поверхности зеркала?",opts:["0° и 60°","0° и 30° (угол к нормали, а не к поверхности)","90° и 60°","0° и 90°"],a:1,ex:"При $\\alpha = 0°$ (перпендикулярно) → $\\gamma = 0°$ (луч уходит обратно). При $\\varphi = 60°$ к поверхности → $\\alpha = 90° - 60° = 30°$ к нормали → $\\gamma = 30°$."},
{q:"Почему поверхность классной доски должна быть матовой?",opts:["Матовая поверхность прочнее","Матовая поверхность даёт диффузное отражение → её видно с любого места в классе","Зеркальная доска была бы слишком яркой","Из матового материала дешевле делать"],a:1,ex:"Зеркальная доска отражает свет лишь в одном направлении — с большинства мест в классе её не видно. Матовая (диффузная) отражает во все стороны → видна с любой позиции."},
{q:"Зеркально или диффузно отражает свет поверхность Луны?",opts:["Зеркально — она блестит как зеркало","Диффузно — её видно с любой стороны Земли в ночном небе","Луна сама светится, не отражает","Зависит от фазы Луны"],a:1,ex:"Луна видна из любой точки Земли — это признак диффузного отражения. Если бы Луна отражала зеркально, её можно было бы видеть только в одном месте (как блик на воде)."},
{q:"Луч падающий и отражённый образуют угол $\\varphi = 70°$. Чему равен угол падения?",hint:"Угол между падающим и отражённым = $\\alpha + \\gamma = 2\\alpha$",unit:"°",a:35,ex:"$\\varphi = \\alpha + \\gamma = 2\\alpha = 70°$; $\\alpha = 35°$."},
{q:"Солнечные лучи образуют с горизонтом угол $\\varphi = 38°$. Как расположить зеркало, чтобы осветить дно колодца? Под каким углом к горизонту?",hint:"$\\sigma = (90° - \\varphi)/2 = (90° - 38°)/2$",unit:"°",a:26,ex:"Нормаль к зеркалу — биссектриса угла между падающим ($52°$ к нормали горизонта) и вертикалью вниз ($0°$). $\\sigma = (90° - 38°)/2 = 26°$ к горизонту."},
{q:"На какой угол повернётся отражённый луч, если зеркало повернуть на $\\varphi = 10°$ (направление падающего луча не меняется)?",hint:"Отражённый луч поворачивается на $2\\varphi$",unit:"°",a:20,ex:"При повороте зеркала на $\\varphi$ нормаль поворачивается на $\\varphi$, следовательно, отражённый луч поворачивается на $2\\varphi = 20°$."},
{q:"Почему отражение Луны на поверхности озера, покрытого рябью, кажется удлинённым?",opts:["Луна имеет вытянутую форму","Рябь создаёт наклонные зеркальные поверхности, каждая из которых отражает луч под разным углом — в глаз попадают лучи из широкой полосы","Водяные волны усиливают свет","Это иллюзия из-за расстояния"],a:1,ex:"На спокойной воде лишь малый участок зеркально отражает Луну в глаз. На ряби — множество наклонных поверхностей с разными углами, каждая отражает луч в глаз — в итоге полоса бликов."},
{q:"Угол между падающим и отражённым лучами $\\delta = 30°$. Каким станет угол отражения, если угол падения увеличится на $\\varphi = 5°$?",hint:"Исходно $2\\alpha = \\delta$; новый $\\alpha' = \\alpha + \\varphi$; новый $\\delta' = 2\\alpha'$",unit:"°",a:20,ex:"$\\alpha = 15°$; $\\alpha' = 20°$; $\\delta' = 2 \\times 20° = 40°$."}
];
var TASKS_P35 = [
{q:"Почему изображение предмета в плоском зеркале называют мнимым?",opts:["Потому что мы его придумываем","Оно образуется пересечением не самих лучей, а их продолжений — в точку за зеркалом свет не попадает","Оно размытое и нечёткое","Его видно только под определённым углом"],a:1,ex:"Мнимое изображение образуется продолжениями отражённых лучей (за зеркалом). Реальные лучи за зеркало не проходят — световой энергии там нет. Фотоплёнка, помещённая в точку изображения, ничего не запишет."},
{q:"Картина висит на стене перед плоским зеркалом на расстоянии $l = 3{,}0$ м. Чему равно расстояние между картиной и её изображением?",hint:"Изображение находится за зеркалом на $l = 3{,}0$ м; расстояние = $2l$",unit:"м",a:6.0,ex:"Изображение в зеркале — на расстоянии $l = 3{,}0$ м за зеркалом. Расстояние картина → изображение = $l + l = 6{,}0$ м."},
{q:"Расстояние между свечой и её изображением в зеркале увеличилось на $\\Delta l = 40$ см. На сколько и в каком направлении передвинули свечу?",hint:"$l_\\text{свеча-изображение} = 2l$; если увеличилось на 40 → свеча отдалилась на $40/2$",unit:"см",a:20,ex:"$\\Delta(2l) = 40$ см → $\\Delta l = 20$ см. Свечу отдвинули от зеркала на 20 см."},
{q:"Плоское зеркало приблизили к свече на $\\Delta l = 15$ см. На сколько и как изменилось расстояние между свечой и её изображением?",hint:"При сближении зеркала на $\\Delta l$, расстояние меняется на $2\\Delta l$",unit:"см",a:30,ex:"Зеркало приближается к свече на 15 см → изображение тоже приближается на 15 см. Суммарное расстояние уменьшается на $2 \\times 15 = 30$ см."},
{q:"Мальчик движется к зеркалу со скоростью $v = 2{,}0$ м/с. С какой скоростью он приближается к своему изображению?",hint:"Изображение тоже движется к зеркалу с той же скоростью → скорость сближения = $2v$",unit:"м/с",a:4.0,ex:"Изображение удалено от зеркала на $l$. Мальчик идёт к зеркалу: $l$ уменьшается с v=2. Изображение приближается с той же v=2. Скорость сближения мальчик–изображение = $2v = 4{,}0$ м/с."},
{q:"Почему в изображении предмета в плоском зеркале правое и левое меняются местами, а верх и низ — нет?",opts:["Это иллюзия","Зеркало переворачивает только по одной оси: поворот вокруг вертикальной оси меняет лево/право, но не верх/низ","Зеркало тяжёлое снизу","Так устроен наш глаз"],a:1,ex:"Плоское зеркало делает мнимое изображение симметричным — разворот на 180° вокруг зеркальной плоскости. При стандартном расположении (вертикальное зеркало) — ось симметрии вертикальна → лево/право меняется, верх/низ — нет."}
];
var TASKS_P36 = [
{q:"Какое явление происходит со световым лучом на границе раздела двух сред?",opts:["Только отражение","Только преломление","Частично отражается, частично преломляется (меняет направление при переходе)","Луч полностью поглощается"],a:2,ex:"На границе раздела сред всегда происходит и отражение, и преломление. При $\\alpha = 0°$ нет преломления, но есть частичное отражение. В быту мы видим оба эффекта: например, в оконном стекле одновременно отражение и прозрачность."},
{q:"Луч из воздуха падает на воду, стекло и алмаз под одним углом. В какой среде угол преломления наибольший?",opts:["В воде (наименее плотная из трёх)","В алмазе (наиболее плотный)","В стекле (средняя плотность)","Одинаковый во всех"],a:0,ex:"Чем оптически плотнее среда → тем меньше угол преломления $\\beta$. Вода — наименее плотная из трёх → $\\beta$ наибольший. Алмаз — наиболее плотный → $\\beta$ наименьший."},
{q:"Почему ноги человека, зашедшего в воду, кажутся короче?",opts:["Вода уменьшает размеры","Луч от ног преломляется при переходе вода→воздух ($\\beta > \\alpha$) → наблюдатель видит ноги как бы ближе к поверхности","Давление воды сжимает ноги","Это оптическая иллюзия мозга"],a:1,ex:"Лучи от ног идут из воды (оптически плотная) в воздух (менее плотная) → $\\beta > \\alpha$. Наблюдатель, видя расходящиеся лучи, «продолжает» их прямолинейно — мнимое изображение ног оказывается выше реального."},
{q:"Почему дно водоёма кажется более близким, чем есть на самом деле?",opts:["Дно отражает свет","Лучи от дна при выходе из воды в воздух преломляются ($\\beta > \\alpha$) → мнимое изображение дна выше реального","Вода преломляет предметы иначе","Это из-за освещения"],a:1,ex:"Лучи из более плотной среды (вода) в менее плотную (воздух): $\\beta > \\alpha$. Наблюдатель воспринимает лучи как пришедшие по прямой → видимое дно кажется ближе, чем реальное."},
{q:"Почему, находясь в лодке, трудно попасть острогой (копьём) в рыбу, плавающую вблизи дна?",opts:["Острога тупая","Из-за преломления: реальная рыба глубже и в стороне от мнимого изображения, в которое целишься","Вода отклоняет острогу","Рыба быстро уплывает"],a:1,ex:"Охотник видит мнимое изображение рыбы (из-за преломления при выходе лучей из воды). Реальная рыба — глубже и ближе к охотнику. Целясь в изображение, промажешь. Нужно целиться «ниже» изображения."},
{q:"Луч падает из воздуха под углом $\\alpha = 0°$ (перпендикулярно к границе раздела). Преломится ли он?",opts:["Да, всегда преломляется","Нет: при $\\alpha = 0°$ луч не меняет направления","Преломляется на 90°","Зависит от среды"],a:1,ex:"При нормальном падении ($\\alpha = 0°$) луч не испытывает преломления — продолжает идти по той же прямой (хотя скорость меняется). Закон преломления: при $\\alpha = 0°$ → $\\beta = 0°$."},
{q:"Два мальчика: один под водой, другой на берегу, оценивают высоту Солнца над горизонтом. Кому Солнце кажется выше?",opts:["Мальчику на берегу","Мальчику под водой — лучи от Солнца при входе в воду преломляются, $\\beta < \\alpha$ → Солнце кажется выше горизонта","Одинаково","Зависит от погоды"],a:1,ex:"Лучи Солнца переходят из воздуха (менее плотная) в воду (более плотная) → $\\beta < \\alpha$. Мальчик под водой видит Солнце под меньшим углом к нормали → Солнце кажется поднятым выше горизонта."}
];
var TASKS_P37 = [
{q:"Вычислите оптическую силу линзы с фокусным расстоянием $F = 20$ см.",hint:"$D = 1/F$; перевести в метры",unit:"дптр",a:5,ex:"$F = 0{,}20$ м; $D = 1/0{,}20 = 5$ дптр"},
{q:"Вычислите оптическую силу линзы с фокусным расстоянием $F = -10$ см.",hint:"$D = 1/F$; рассеивающая → $D < 0$",unit:"дптр",a:-10,ex:"$F = -0{,}10$ м; $D = 1/(-0{,}10) = -10$ дптр. Отрицательная оптическая сила — рассеивающая линза."},
{q:"Вычислите фокусное расстояние линзы с оптической силой $D = 2{,}5$ дптр.",hint:"$F = 1/D$",unit:"см",a:40,ex:"$F = 1/2{,}5 = 0{,}40$ м = 40 см"},
{q:"Вычислите фокусное расстояние линзы $D = -20$ дптр.",hint:"$F = 1/D$; отрицательное $F$ — рассеивающая",unit:"см",a:-5,ex:"$F = 1/(-20) = -0{,}05$ м = $-5$ см. Рассеивающая линза с мнимым фокусом."},
{q:"Какая из двух одинаковых по размеру линз имеет меньшее фокусное расстояние и большую оптическую силу?",opts:["Та, у которой поверхности менее выпуклые (плоские)","Та, у которой поверхности более выпуклые (толще в середине)","Обе одинаковы","Зависит от материала, а не от формы"],a:1,ex:"Более выпуклая поверхность сильнее преломляет лучи → меньше $F$ → больше $D$. Менее выпуклая → больше $F$ → меньше $D$. Линза 1 на рис. 267a преломляет лучи сильнее, чем линза 2."}
];
var TASKS_P38 = [
{q:"При каком условии собирающая линза даёт уменьшенное действительное изображение?",opts:["$d < F$","$d > 2F$","$F < d < 2F$","$d = F$"],a:1,ex:"При $d > 2F$: изображение действительное, перевёрнутое, уменьшенное (фотоаппарат, глаз). При $d = 2F$: равное предмету. При $F < d < 2F$: увеличенное действительное."},
{q:"Что происходит с лучами, выходящими из собирающей линзы, если предмет находится в фокусе ($d = F$)?",opts:["Сходятся в точке за линзой","Расходятся","Выходят параллельным пучком — изображение на бесконечности","Отражаются обратно"],a:2,ex:"При $d = F$ лучи после линзы выходят параллельно — изображение на бесконечности. Это используется в прожекторах и лупах: источник в фокусе → параллельный пучок."},
{q:"Свеча находится на расстоянии $d = 20$ см от линзы, изображение — на расстоянии $f = 60$ см. Во сколько раз размеры изображения отличаются от свечи? Чему равна оптическая сила линзы?",hint:"Увеличение $k = f/d$; $1/F = 1/d + 1/f$; $D = 1/F$",unit:"дптр",a:6.67,tol:0.05,ex:"$k = 60/20 = 3$ раза (увеличено). $1/F = 1/20 + 1/60 = 4/60$; $F = 15$ см = $0{,}15$ м; $D = 1/0{,}15 \\approx 6{,}7$ дптр"},
{q:"Какие изображения даёт рассеивающая линза?",opts:["Действительные, перевёрнутые","Мнимые, прямые, уменьшенные — всегда","Зависит от расстояния до предмета","Только увеличенные"],a:1,ex:"Рассеивающая линза даёт только мнимые, прямые, уменьшенные изображения при любом расстоянии до предмета. Лучи после рассеивающей линзы расходятся — пересекаются только их продолжения."},
{q:"В каком устройстве используют принцип: предмет находится между фокусом и линзой ($d < F$)?",opts:["Фотоаппарат","Лупа: даёт мнимое, прямое, увеличенное изображение","Прожектор","Объектив телескопа"],a:1,ex:"Лупа — собирающая линза. При $d < F$ получаем мнимое, прямое, увеличенное изображение. Часовщик рассматривает детали часов через лупу — его глаз видит мнимое увеличенное изображение."},
{q:"Изображение свечи в собирающей линзе оказалось уменьшенным и перевёрнутым. Где расположена свеча относительно линзы?",opts:["Между F и линзой ($d < F$)","Между F и 2F","За двойным фокусом ($d > 2F$)","В фокусе"],a:2,ex:"Уменьшенное и перевёрнутое → действительное, т.к. перевёрнутые всегда действительные. Уменьшенное действительное → $d > 2F$. При $F < d < 2F$ было бы увеличенное."}
];
var TASKS_P39 = [
{q:"Какую роль в создании зрительного образа играет оптическая система глаза?",opts:["Определяет цвет предметов","Создаёт действительное, перевёрнутое изображение на сетчатке","Фильтрует вредное излучение","Усиливает яркость изображения"],a:1,ex:"Роговица + водянистая влага + хрусталик + стекловидное тело = собирающая система. Создаёт действительное, перевёрнутое, уменьшенное изображение на сетчатке. Мозг переворачивает обратно."},
{q:"Что такое аккомодация глаза?",opts:["Привыкание к темноте","Изменение кривизны хрусталика для фокусировки на предметах разного расстояния","Расширение зрачка","Движение глазного яблока"],a:1,ex:"Аккомодация: хрусталик изменяет свою кривизну с помощью мышц. При приближении предмета — хрусталик становится более выпуклым ($F$ уменьшается). При удалении — уплощается ($F$ увеличивается). Всегда изображение остаётся на сетчатке."},
{q:"Какое изображение предмета создаётся на сетчатке глаза?",opts:["Прямое и увеличенное","Действительное, перевёрнутое, уменьшенное","Мнимое и увеличенное","Мнимое и прямое"],a:1,ex:"На сетчатке образуется действительное (реальные лучи сходятся), перевёрнутое (как в любой собирающей линзе при $d > 2F$), уменьшенное изображение. Мозг его «переворачивает» обратно."},
{q:"Что происходит с хрусталиком при переводе взгляда с близкого предмета на далёкий?",opts:["Хрусталик становится более выпуклым","Хрусталик уплощается — фокусное расстояние увеличивается","Хрусталик разрушается","Зрачок закрывается"],a:1,ex:"Для далёкого предмета: нужно большее фокусное расстояние $F$. Хрусталик уплощается — мышцы расслабляются, $F$ растёт. Для близкого: мышцы сжимают хрусталик — $F$ уменьшается."}
];
var TASKS_P40 = [
{q:"В чём суть дефекта зрения «близорукость»?",opts:["Хрусталик потерял прозрачность","Изображение удалённых предметов фокусируется перед сетчаткой, а не на ней","Сетчатка не чувствительна к цвету","Зрачок не реагирует на свет"],a:1,ex:"Близорукость (миопия): глазное яблоко вытянуто или хрусталик слишком сильно преломляет — изображение дальних предметов фокусируется перед сетчаткой. Ближние видны чётко, дальние — размыто."},
{q:"Почему в глазу дальнозоркого человека изображение близких предметов размытое?",opts:["Дальнозоркий не может смотреть близко","Хрусталик слишком плоский — при максимальном напряжении мышц всё равно не может собрать лучи от близкого предмета на сетчатку: фокус за ней","Сетчатка слишком мала","Зрачок слишком маленький"],a:1,ex:"Дальнозоркость: хрусталик потерял эластичность — даже при максимальном напряжении мышц $F$ слишком велико. Лучи от близкого предмета сошлись бы за сетчаткой → изображение размытое."},
{q:"Можно ли, не прикасаясь к очкам, определить, каким дефектом зрения обладает их владелец?",opts:["Нет, только у окулиста","Да: рассеивающие линзы (− дптр) уменьшают предметы → близорукость; собирающие (+ дптр) увеличивают → дальнозоркость","Только по цвету стёкол","По форме оправы"],a:1,ex:"Посмотрите сквозь очки на что-нибудь: рассеивающие (близорукость) уменьшают предметы. Собирающие (дальнозоркость) увеличивают. Или поднесите к источнику света: рассеивающие не дают фокуса, собирающие — дают."},
{q:"На рецепте написано: «Очки +2,5 дптр». Для какого дефекта зрения и каково фокусное расстояние линз?",hint:"$F = 1/D$",unit:"см",a:40,ex:"$D = +2{,}5$ дптр > 0 → собирающая линза → дальнозоркость. $F = 1/2{,}5 = 0{,}40$ м = 40 см."},
{q:"Почему к старости у близорукого с детства человека зрение может стать нормальным?",opts:["Глаза сами вылечиваются","С возрастом хрусталик теряет эластичность — уплощается. Близорукий видел близко, теперь хрусталик не так сильно преломляет → фокус смещается на сетчатку","Зрение улучшается от упражнений","Это невозможно"],a:1,ex:"Близорукость: хрусталик слишком выпуклый → фокус перед сетчаткой. С возрастом хрусталик уплощается (дальнозоркость). Два дефекта частично компенсируют друг друга → зрение приближается к норме."}
];
var TASKS_HARD = [
{para:"§33",q:"Тонкий непрозрачный диск диаметром $d = 30$ см. Источник на расстоянии $L = 4{,}0$ м от экрана. На экране тень диаметром $D = 1{,}2$ м. Расстояние от источника до диска?",hint:"Из подобия треугольников: $D/d = L/a$; $a = dL/D$",unit:"м",a:1.0,ex:"$a = dL/D = 0{,}30 \\times 4{,}0/1{,}2 = 1{,}0$ м"},
{para:"§33",q:"Длина тени дуба $l_{\\text{д}} = 2{,}0$ м (высота дуба $h_{\\text{д}} = 6{,}0$ м). Найти высоту берёзы, если длина её тени $l_{\\text{б}} = 2{,}6$ м.",hint:"Подобие: $h/l = \\text{const}$ для всех предметов",unit:"м",a:7.8,ex:"$h_{\\text{б}} = h_{\\text{д}} \\times l_{\\text{б}}/l_{\\text{д}} = 6{,}0 \\times 2{,}6/2{,}0 = 7{,}8$ м"},
{para:"§33",q:"Столбик высотой $h_{\\text{с}} = 80$ см отбрасывает тень длиной $l_{\\text{с}} = 40$ см. Яблоня — тень $l_{\\text{я}} = 2{,}6$ м. Высота яблони?",hint:"$h_{\\text{я}}/l_{\\text{я}} = h_{\\text{с}}/l_{\\text{с}}$",unit:"м",a:5.2,ex:"$h_{\\text{я}} = h_{\\text{с}} \\times l_{\\text{я}}/l_{\\text{с}} = 0{,}80 \\times 2{,}6/0{,}40 = 5{,}2$ м"},
{para:"§34",q:"Мальчик движется к зеркалу со скоростью $v = 2{,}0$ м/с. С какой скоростью он приближается к своему изображению?",hint:"Скорость сближения = $v_\\text{мальчик} + v_\\text{изображения} = 2v$",unit:"м/с",a:4.0,ex:"Изображение тоже движется к зеркалу с $v$. Скорость сближения = $2v = 4{,}0$ м/с."},
{para:"§37",q:"Свеча на расстоянии $d = 30$ см от линзы, изображение на экране на расстоянии $f = 60$ см. Какая это линза? Каково фокусное расстояние? Как увеличение?",hint:"$1/F = 1/d + 1/f$; $k = f/d$",unit:"дптр",a:5.0,ex:"Собирающая (изображение на экране = действительное). $1/F = 1/30 + 1/60 = 3/60$; $F = 20$ см; $D = 5$ дптр; $k = 60/30 = 2$ раза."},
{para:"§38",q:"С помощью собирающей линзы на экране получили изображение, увеличенное в 3 раза, расположенное на расстоянии $f = 36$ см от линзы. Расстояние до предмета и оптическая сила?",hint:"$k = f/d = 3$; $d = f/3$; затем $1/F = 1/d + 1/f$",unit:"дптр",a:11,tol:0.05,ex:"$d = 36/3 = 12$ см; $1/F = 1/12 + 1/36 = 4/36$; $F = 9$ см; $D = 1/0{,}09 \\approx 11$ дптр"},
{para:"§40",q:"Врач выписал очки $D = -2{,}5$ дптр. Какой дефект зрения? Каково фокусное расстояние?",hint:"$D < 0$ → рассеивающая → близорукость; $F = 1/D$",unit:"см",a:-40,ex:"$D < 0$ → близорукость (рассеивающие очки). $F = 1/(-2{,}5) = -0{,}40$ м = $-40$ см."}
];
// ═══════════════════════════════════════
// ПУЛЫ И СОСТОЯНИЯ
// ═══════════════════════════════════════
var POOLS = {
p32:TASKS_P32, p33:TASKS_P33, p34:TASKS_P34, p35:TASKS_P35, p36:TASKS_P36,
p37:TASKS_P37, p38:TASKS_P38, p39:TASKS_P39, p40:TASKS_P40, hard:TASKS_HARD
};
function mkState(pool) {
return {idx:0, answered:false, results:Array(pool.length).fill(null), selections:Array(pool.length).fill(null)};
}
var STATE = {
p32:mkState(TASKS_P32), p33:mkState(TASKS_P33), p34:mkState(TASKS_P34),
p35:mkState(TASKS_P35), p36:mkState(TASKS_P36), p37:mkState(TASKS_P37),
p38:mkState(TASKS_P38), p39:mkState(TASKS_P39), p40:mkState(TASKS_P40),
hard:mkState(TASKS_HARD)
};
// ═══════════════════════════════════════
// KaTeX рендеринг
// ═══════════════════════════════════════
function doRender(el) {
if (!window.renderMathInElement) return;
renderMathInElement(el, {
delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],
throwOnError:false
});
}
// ═══════════════════════════════════════
// ПЕРЕКЛЮЧАТЕЛЬ ПАРАГРАФОВ
// ═══════════════════════════════════════
function setParaTab(para) {
['p1','p2','p3','p4','p5','p6','p7','p8','p9','p10','p11','hard'].forEach(function(p) {
var el = document.getElementById('ptab-'+p);
if (el) el.style.display = (p===para) ? 'block' : 'none';
document.querySelectorAll('.para-pill[data-para="'+p+'"]').forEach(function(b) {
b.classList.toggle('active', p===para);
});
});
}
// ═══════════════════════════════════════
// НАВИГАЦИЯ
// ═══════════════════════════════════════
function renderNav(sec) {
var pool = POOLS[sec], s = STATE[sec];
var el = document.getElementById('navDots'+sec);
if (!el) return;
el.innerHTML = pool.map(function(_, i) {
var cls = 'nav-dot';
if (i===s.idx) cls += ' nd-cur';
else if (s.results[i]===true) cls += ' nd-ok';
else if (s.results[i]===false) cls += ' nd-fail';
return '<button class="'+cls+'" onclick="goToTask(\''+sec+'\','+i+')" title="Задача '+(i+1)+'">'+(i+1)+'</button>';
}).join('');
}
function goToTask(sec, idx) {
var s = STATE[sec];
s.idx = idx;
s.answered = s.results[idx]!==null;
renderTask(sec);
}
// ═══════════════════════════════════════
// ОТРИСОВКА ЗАДАЧИ
// ═══════════════════════════════════════
function renderTask(sec) {
var pool = POOLS[sec], s = STATE[sec];
var area = document.getElementById('taskArea'+sec);
var fb = document.getElementById('fb'+sec);
document.getElementById('sum'+sec).classList.remove('show');
var q = pool[s.idx];
var done = s.results[s.idx]!==null;
s.answered = done;
var isMcq = !!q.opts;
// Бейдж параграфа для раздела hard
var paraBadge = q.para ? '<span style="display:inline-flex;align-items:center;padding:2px 8px;background:rgba(124,58,237,.12);color:var(--pri);border-radius:6px;font-size:.68rem;font-weight:800;margin-left:7px">'+q.para+'</span>' : '';
if (isMcq) {
var selIdx = s.selections[s.idx];
area.innerHTML = '<div class="task-card">' +
'<div class="task-num">Задача '+(s.idx+1)+' из '+pool.length+' · Тест'+paraBadge+'</div>' +
'<div class="task-text">'+q.q+'</div>' +
'<div class="mcq-opts">' +
q.opts.map(function(opt, i) {
var cls = 'opt-btn';
if (done) {
if (i===q.a) cls += ' mcq-cor';
else if (i===selIdx) cls += ' mcq-wrong';
}
return '<button class="'+cls+'" id="mcqOpt'+sec+'_'+i+'" '+
'onclick="'+(done?'':'selectMcq(\''+sec+'\','+i+')')+'" '+
(done?'disabled':'')+'>'+
'<span style="font-weight:800;margin-right:6px">'+String.fromCharCode(65+i)+'.</span>'+opt+
'</button>';
}).join('') +
'</div></div>';
} else {
area.innerHTML = '<div class="task-card">' +
'<div class="task-num">Задача '+(s.idx+1)+' из '+pool.length+paraBadge+'</div>' +
'<div class="task-text">'+q.q+'</div>' +
'<div class="task-hint"><i class="fas fa-lightbulb"></i><span>'+q.hint+'</span></div>' +
'<div class="ans-row">' +
'<label style="font-weight:700;font-size:.88rem">Ответ:</label>' +
'<input class="ans-inp" type="text" id="ainp'+sec+'" placeholder="?" autocomplete="off"' +
(done?' disabled style="border-color:var(--'+(s.results[s.idx]?'ok':'fail')+')"':'')+'>'+
'<span class="unit-lbl">'+q.unit+'</span>' +
(done?'':'<button class="btn btn-pri" onclick="checkNum(\''+sec+'\')"><i class="fas fa-check"></i> Проверить</button>') +
'</div></div>';
}
if (done) {
var ok = s.results[s.idx];
fb.className = 'feedback show '+(ok?'fb-ok':'fb-fail');
if (isMcq) {
fb.innerHTML = ok
? '✓ Верно!&ensp;'+(q.ex||'')
: '✗ Неверно. Правильный ответ: <strong>'+q.opts[q.a]+'</strong>&ensp;'+(q.ex||'');
} else {
fb.innerHTML = ok
? '✓ Верно!&ensp;'+q.ex
: '✗ Неверно. Правильный ответ: <strong>'+q.a+'&nbsp;'+q.unit+'</strong>&ensp;'+q.ex;
}
document.getElementById('nextBtn'+sec).style.display = 'inline-flex';
doRender(fb);
} else {
fb.className = 'feedback';
document.getElementById('nextBtn'+sec).style.display = 'none';
}
updateScoreBar(sec);
renderNav(sec);
doRender(area);
if (!done && !isMcq) {
var inp = document.getElementById('ainp'+sec);
setTimeout(function(){ if(inp) inp.focus(); }, 80);
if (inp) inp.addEventListener('keydown', function(e){ if(e.key==='Enter') checkNum(sec); });
}
}
// ═══════════════════════════════════════
// ПРОВЕРКА MCQ
// ═══════════════════════════════════════
function selectMcq(sec, i) {
var s = STATE[sec];
if (s.answered) return;
var pool = POOLS[sec], q = pool[s.idx];
var ok = (i===q.a);
s.results[s.idx] = ok;
s.selections[s.idx] = i;
s.answered = true;
updateScoreBar(sec);
renderNav(sec);
q.opts.forEach(function(_, j) {
var btn = document.getElementById('mcqOpt'+sec+'_'+j);
if (!btn) return;
btn.disabled = true;
if (j===q.a) btn.classList.add('mcq-cor');
else if (j===i && !ok) btn.classList.add('mcq-wrong');
});
var fb = document.getElementById('fb'+sec);
fb.className = 'feedback show '+(ok?'fb-ok':'fb-fail');
fb.innerHTML = ok
? '✓ Верно!&ensp;'+(q.ex||'')
: '✗ Неверно. Правильный ответ: <strong>'+q.opts[q.a]+'</strong>&ensp;'+(q.ex||'');
doRender(fb);
document.getElementById('nextBtn'+sec).style.display = 'inline-flex';
if (s.results.every(function(r){ return r!==null; })) {
setTimeout(function(){ showSummary(sec); }, 2200);
}
}
// ═══════════════════════════════════════
// ПРОВЕРКА ЧИСЛОВЫХ
// ═══════════════════════════════════════
function checkNum(sec) {
var s = STATE[sec];
if (s.answered) return;
var pool = POOLS[sec], q = pool[s.idx];
var inp = document.getElementById('ainp'+sec);
var fb = document.getElementById('fb'+sec);
var val = inp.value.trim().replace(',','.');
var num = parseFloat(val);
if (!val || isNaN(num)) {
fb.className = 'feedback show fb-fail';
fb.innerHTML = 'Введите числовой ответ!';
return;
}
s.answered = true;
var tol = (q.tol !== undefined) ? q.tol : 0.03;
var ok = (q.a===0) ? (Math.abs(num)<0.05) : (Math.abs((num-q.a)/q.a)<tol);
s.results[s.idx] = ok;
updateScoreBar(sec);
renderNav(sec);
inp.disabled = true;
inp.style.borderColor = ok ? 'var(--ok)' : 'var(--fail)';
fb.className = 'feedback show '+(ok?'fb-ok':'fb-fail');
fb.innerHTML = ok
? '✓ Верно!&ensp;'+q.ex
: '✗ Неверно. Правильный ответ: <strong>'+q.a+'&nbsp;'+q.unit+'</strong>&ensp;'+q.ex;
doRender(fb);
document.getElementById('nextBtn'+sec).style.display = 'inline-flex';
if (s.results.every(function(r){ return r!==null; })) {
setTimeout(function(){ showSummary(sec); }, 2200);
}
}
// ═══════════════════════════════════════
// СЛЕДУЮЩАЯ / СБРОС
// ═══════════════════════════════════════
function nextTask(sec) {
var pool = POOLS[sec], s = STATE[sec];
var next = -1;
for (var i=s.idx+1; i<pool.length; i++) {
if (s.results[i]===null) { next=i; break; }
}
if (next===-1) {
for (var j=0; j<s.idx; j++) {
if (s.results[j]===null) { next=j; break; }
}
}
if (next===-1) { showSummary(sec); return; }
s.idx = next;
s.answered = false;
renderTask(sec);
}
function resetTasks(sec) {
STATE[sec] = mkState(POOLS[sec]);
document.getElementById('sum'+sec).classList.remove('show');
renderTask(sec);
}
// ═══════════════════════════════════════
// SCORE BAR
// ═══════════════════════════════════════
function updateScoreBar(sec) {
var pool = POOLS[sec], s = STATE[sec];
var okCnt = s.results.filter(function(r){ return r===true; }).length;
var doneCnt = s.results.filter(function(r){ return r!==null; }).length;
document.getElementById('ok'+sec).textContent = okCnt;
document.getElementById('cur'+sec).textContent = doneCnt;
document.getElementById('max'+sec).textContent = pool.length;
document.getElementById('prog'+sec).style.width = (doneCnt/pool.length*100)+'%';
}
// ═══════════════════════════════════════
// SUMMARY
// ═══════════════════════════════════════
function showSummary(sec) {
var pool = POOLS[sec], s = STATE[sec];
document.getElementById('prog'+sec).style.width = '100%';
document.getElementById('sum'+sec).classList.add('show');
var okCnt = s.results.filter(function(r){ return r===true; }).length;
document.getElementById('sumScore'+sec).textContent = okCnt+' / '+pool.length;
var p = okCnt/pool.length;
document.getElementById('sumGrade'+sec).textContent =
p>=.9 ? 'Отлично — тема освоена!' :
p>=.75 ? 'Хорошо! Разбери пропущенные задачи.' :
p>=.5 ? 'Неплохо. Повтори формулы и попробуй ещё раз.' :
'Прочитай теорию и реши снова.';
}
// ═══════════════════════════════════════
// ПЕРЕКЛЮЧАТЕЛЬ ПАРАГРАФОВ
// ═══════════════════════════════════════
function setParaTab(para) {
['p32','p33','p34','p35','p36','p37','p38','p39','p40','hard'].forEach(function(p) {
var el = document.getElementById('ptab-'+p);
if (el) el.style.display = (p===para) ? 'block' : 'none';
document.querySelectorAll('.para-pill[data-para="'+p+'"]').forEach(function(b) {
b.classList.toggle('active', p===para);
});
});
}
// ═══════════════════════════════════════
// ЗАГЛУШКИ ИНТЕРАКТИВОВ
// ═══════════════════════════════════════
var anim32Id=null,anim33Id=null,anim34Id=null,anim35Id=null,anim36Id=null,anim37Id=null,anim38Id=null,anim39Id=null,anim40Id=null;
function upd32() {
var cv = document.getElementById('cv32');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 240;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var sel = document.getElementById('sel32src');
var isWide = sel && sel.value === 'wide';
var n = parseInt((document.getElementById('sl32n') || {}).value) || 12;
var sources = isWide ?
[{x: W*0.22, y: H/2-20}, {x: W*0.22, y: H/2}, {x: W*0.22, y: H/2+20}] :
[{x: W*0.22, y: H/2}];
var screenX = W * 0.55;
var holeY = H / 2, holeH = 8;
ctx.fillStyle = '#475569';
ctx.fillRect(screenX - 3, 10, 6, holeY - holeH - 10);
ctx.fillRect(screenX - 3, holeY + holeH, 6, H - holeY - holeH - 10);
var hues = ['rgba(251,191,36,', 'rgba(249,115,22,', 'rgba(239,68,68,'];
sources.forEach(function(src, si) {
var hue = hues[si] || hues[0];
for (var i = 0; i < n; i++) {
var angle = (i / n) * Math.PI * 2;
var dx = Math.cos(angle), dy = Math.sin(angle);
var len = Math.min(W, H) * 0.8;
var tScreen = (screenX - src.x) / (dx || 0.001);
var yAtScreen = src.y + dy * tScreen;
var throughHole = Math.abs(yAtScreen - holeY) < holeH && dx > 0;
var alpha = throughHole ? 0.9 : 0.15;
ctx.strokeStyle = hue + alpha + ')';
ctx.lineWidth = throughHole ? 1.8 : 0.8;
ctx.beginPath();
ctx.moveTo(src.x, src.y);
if (throughHole) {
ctx.lineTo(src.x + dx * len, src.y + dy * len);
} else {
if (dx > 0 && tScreen > 0 && tScreen < len) {
ctx.lineTo(screenX, yAtScreen);
} else {
ctx.lineTo(src.x + dx * len, src.y + dy * len);
}
}
ctx.stroke();
}
var grd = ctx.createRadialGradient(src.x, src.y, 0, src.x, src.y, 18);
grd.addColorStop(0, 'rgba(251,191,36,0.9)');
grd.addColorStop(1, 'rgba(251,191,36,0)');
ctx.fillStyle = grd;
ctx.beginPath(); ctx.arc(src.x, src.y, 18, 0, Math.PI * 2); ctx.fill();
ctx.fillStyle = '#fff'; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText(isWide ? 'S' + (si+1) : 'S', src.x, src.y + 4);
});
ctx.fillStyle = '#94a3b8'; ctx.font = '9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('Источник', W * 0.22, H - 10);
ctx.fillText('Экран с отверстием', screenX, H - 10);
ctx.fillText('→ луч', W * 0.78, H/2 - 15);
}
function startAnim32() { upd32(); }
function upd33() {
var cv = document.getElementById('cv33');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 260;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var sel = document.getElementById('sel33src');
var isWide = sel && sel.value === 'wide';
var objH = parseInt((document.getElementById('sl33obj') || {}).value) || 30;
var lbl = document.getElementById('lbl33obj');
if (lbl) lbl.textContent = objH;
var srcX = W * 0.12, srcYC = H / 2;
var srcSize = isWide ? 30 : 3;
var objX = W * 0.45, objYC = H / 2;
var scrX = W * 0.82;
if (isWide) {
var grd = ctx.createLinearGradient(srcX-3, srcYC-srcSize, srcX+3, srcYC+srcSize);
grd.addColorStop(0, '#fbbf24'); grd.addColorStop(0.5, '#fff'); grd.addColorStop(1, '#fbbf24');
ctx.fillStyle = grd;
ctx.fillRect(srcX - 4, srcYC - srcSize, 8, srcSize * 2);
} else {
var sg = ctx.createRadialGradient(srcX, srcYC, 0, srcX, srcYC, 12);
sg.addColorStop(0, 'rgba(255,255,200,1)'); sg.addColorStop(1, 'rgba(251,191,36,0)');
ctx.fillStyle = sg;
ctx.beginPath(); ctx.arc(srcX, srcYC, 12, 0, Math.PI * 2); ctx.fill();
}
ctx.fillStyle = '#fbbf24'; ctx.font = '9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('S', srcX, srcYC + 4);
ctx.fillStyle = '#64748b';
ctx.fillRect(objX - 5, objYC - objH/2, 10, objH);
var srcYTop = srcYC - srcSize, srcYBot = srcYC + srcSize;
var objYTop = objYC - objH/2, objYBot = objYC + objH/2;
var shadowTopY = srcYTop + (objYTop - srcYTop) * (scrX - srcX) / (objX - srcX);
var shadowBotY = srcYBot + (objYBot - srcYBot) * (scrX - srcX) / (objX - srcX);
var penumbraTopY = srcYBot + (objYTop - srcYBot) * (scrX - srcX) / (objX - srcX);
var penumbraBotY = srcYTop + (objYBot - srcYTop) * (scrX - srcX) / (objX - srcX);
ctx.fillStyle = '#1e293b'; ctx.fillRect(scrX - 3, 10, 6, H - 20);
ctx.strokeStyle = '#475569'; ctx.lineWidth = 1;
ctx.strokeRect(scrX - 3, 10, 6, H - 20);
if (isWide) {
ctx.fillStyle = 'rgba(251,191,36,0.2)';
ctx.fillRect(scrX + 3, Math.min(penumbraTopY, shadowTopY), 14, Math.abs(shadowTopY - penumbraTopY));
ctx.fillStyle = 'rgba(15,23,42,0.95)';
ctx.fillRect(scrX + 3, shadowTopY, 14, shadowBotY - shadowTopY);
ctx.fillStyle = 'rgba(251,191,36,0.2)';
ctx.fillRect(scrX + 3, shadowBotY, 14, Math.abs(penumbraBotY - shadowBotY));
ctx.fillStyle = '#94a3b8'; ctx.font = '7px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('полутень', scrX + 18, penumbraTopY + 6);
ctx.fillText('тень', scrX + 18, (shadowTopY + shadowBotY) / 2 + 3);
ctx.fillText('полутень', scrX + 18, penumbraBotY - 3);
} else {
ctx.fillStyle = 'rgba(15,23,42,0.95)';
ctx.fillRect(scrX + 3, shadowTopY, 14, shadowBotY - shadowTopY);
ctx.fillStyle = '#94a3b8'; ctx.font = '7px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('тень', scrX + 18, (shadowTopY + shadowBotY) / 2 + 3);
}
ctx.strokeStyle = 'rgba(251,191,36,0.5)'; ctx.lineWidth = 1; ctx.setLineDash([4,3]);
ctx.beginPath(); ctx.moveTo(srcX, srcYTop); ctx.lineTo(objX, objYTop); ctx.lineTo(scrX, shadowTopY); ctx.stroke();
ctx.beginPath(); ctx.moveTo(srcX, srcYBot); ctx.lineTo(objX, objYBot); ctx.lineTo(scrX, shadowBotY); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#94a3b8'; ctx.font = '9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('Источник', srcX, H - 8);
ctx.fillText('Предмет', objX, H - 8);
ctx.fillText('Экран', scrX, H - 8);
}
function startAnim33() { upd33(); }
// ── cv34: Pro Max закон отражения (мышь-лазер) ──
var alpha34 = 35; // текущий угол падения (0..85), хранится глобально
function reset34() { alpha34 = 45; upd34(); }
function upd34() {
var cv = document.getElementById('cv34');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 280;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var sel = document.getElementById('sel34type');
var isDiffuse = sel && sel.value === 'diffuse';
var alpha = Math.max(0, Math.min(85, alpha34|0));
var alphaRad = alpha * Math.PI / 180;
var mirrorY = H * 0.72, mirrorX = W / 2;
var rayLen = Math.min(W * 0.42, mirrorY - 20);
// фоновая сетка-«стол»
ctx.strokeStyle = 'rgba(148,163,184,0.06)'; ctx.lineWidth = 1;
for (var gx = 0; gx < W; gx += 24) { ctx.beginPath(); ctx.moveTo(gx, 0); ctx.lineTo(gx, H); ctx.stroke(); }
for (var gy = 0; gy < H; gy += 24) { ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(W, gy); ctx.stroke(); }
// зеркало
if (!isDiffuse) {
var grd = ctx.createLinearGradient(40, mirrorY, W-40, mirrorY);
grd.addColorStop(0, 'rgba(167,139,250,0.05)');
grd.addColorStop(0.5, 'rgba(167,139,250,0.55)');
grd.addColorStop(1, 'rgba(167,139,250,0.05)');
ctx.fillStyle = grd; ctx.fillRect(40, mirrorY, W - 80, 5);
ctx.strokeStyle = '#a78bfa'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(40, mirrorY); ctx.lineTo(W - 40, mirrorY); ctx.stroke();
// штриховка снизу — обозначение «обратной стороны»
ctx.strokeStyle = 'rgba(167,139,250,0.45)'; ctx.lineWidth = 1.2;
for (var hx = 50; hx < W - 40; hx += 10) {
ctx.beginPath(); ctx.moveTo(hx, mirrorY + 5); ctx.lineTo(hx - 6, mirrorY + 13); ctx.stroke();
}
} else {
ctx.strokeStyle = '#a78bfa'; ctx.lineWidth = 2;
ctx.beginPath();
for (var sx = 40; sx < W - 40; sx += 10) {
ctx.moveTo(sx, mirrorY + (sx % 20 === 0 ? -3 : 3));
ctx.lineTo(sx + 10, mirrorY + (sx % 20 === 0 ? 3 : -3));
}
ctx.stroke();
}
// нормаль (пунктир)
ctx.strokeStyle = 'rgba(203,213,225,0.6)'; ctx.lineWidth = 1.5;
ctx.setLineDash([6, 5]);
ctx.beginPath(); ctx.moveTo(mirrorX, 12); ctx.lineTo(mirrorX, mirrorY + 28); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#cbd5e1'; ctx.font = '10px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('нормаль', mirrorX + 6, 22);
// падающий луч с лазерным glow
var incStartX = mirrorX - Math.sin(alphaRad) * rayLen;
var incStartY = mirrorY - Math.cos(alphaRad) * rayLen;
ctx.strokeStyle = 'rgba(251,191,36,0.25)'; ctx.lineWidth = 7;
ctx.beginPath(); ctx.moveTo(incStartX, incStartY); ctx.lineTo(mirrorX, mirrorY); ctx.stroke();
ctx.strokeStyle = '#fbbf24'; ctx.lineWidth = 2.5;
ctx.beginPath(); ctx.moveTo(incStartX, incStartY); ctx.lineTo(mirrorX, mirrorY); ctx.stroke();
// лазер-указка
var lpw = 14, lph = 9;
ctx.save();
ctx.translate(incStartX, incStartY);
ctx.rotate(Math.atan2(mirrorY - incStartY, mirrorX - incStartX));
ctx.fillStyle = '#1e293b'; ctx.strokeStyle = '#ef4444'; ctx.lineWidth = 1.5;
ctx.fillRect(-lpw, -lph/2, lpw, lph); ctx.strokeRect(-lpw, -lph/2, lpw, lph);
ctx.fillStyle = '#ef4444';
ctx.beginPath(); ctx.arc(0, 0, 2.5, 0, Math.PI*2); ctx.fill();
ctx.restore();
ctx.fillStyle = '#fcd34d'; ctx.font = 'bold 10px sans-serif'; ctx.textAlign = 'right';
ctx.fillText('падающий', incStartX - 18, incStartY - 4);
if (!isDiffuse) {
var refEndX = mirrorX + Math.sin(alphaRad) * rayLen;
var refEndY = mirrorY - Math.cos(alphaRad) * rayLen;
ctx.strokeStyle = 'rgba(96,165,250,0.25)'; ctx.lineWidth = 7;
ctx.beginPath(); ctx.moveTo(mirrorX, mirrorY); ctx.lineTo(refEndX, refEndY); ctx.stroke();
ctx.strokeStyle = '#60a5fa'; ctx.lineWidth = 2.5;
ctx.beginPath(); ctx.moveTo(mirrorX, mirrorY); ctx.lineTo(refEndX, refEndY); ctx.stroke();
// стрелка на конце
var aDx = refEndX - mirrorX, aDy = refEndY - mirrorY, aL = Math.sqrt(aDx*aDx + aDy*aDy) || 1;
var ux = aDx/aL, uy = aDy/aL;
ctx.fillStyle = '#60a5fa';
ctx.beginPath();
ctx.moveTo(refEndX, refEndY);
ctx.lineTo(refEndX - ux*10 + uy*6, refEndY - uy*10 - ux*6);
ctx.lineTo(refEndX - ux*10 - uy*6, refEndY - uy*10 + ux*6);
ctx.fill();
ctx.fillStyle = '#93c5fd'; ctx.font = 'bold 10px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('отражённый', refEndX + 6, refEndY - 4);
// дуги углов α и β
var arcR = Math.min(50, rayLen * 0.45);
ctx.strokeStyle = '#fbbf24'; ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(mirrorX, mirrorY, arcR, -Math.PI/2 - alphaRad, -Math.PI/2); ctx.stroke();
ctx.fillStyle = '#fbbf24'; ctx.font = 'bold 13px sans-serif'; ctx.textAlign = 'center';
var alA = mirrorX - Math.sin(alphaRad/2)*(arcR+12);
var alB = mirrorY - Math.cos(alphaRad/2)*(arcR+12);
ctx.fillText('α=' + alpha + '°', alA, alB + 4);
ctx.strokeStyle = '#60a5fa'; ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(mirrorX, mirrorY, arcR, -Math.PI/2, -Math.PI/2 + alphaRad); ctx.stroke();
ctx.fillStyle = '#60a5fa'; ctx.font = 'bold 13px sans-serif'; ctx.textAlign = 'center';
var blA = mirrorX + Math.sin(alphaRad/2)*(arcR+12);
var blB = mirrorY - Math.cos(alphaRad/2)*(arcR+12);
ctx.fillText('β=' + alpha + '°', blA, blB + 4);
} else {
for (var di = 0; di < 11; di++) {
var dAngle = ((di / 10) * Math.PI - Math.PI/2) * 0.92;
var dX = mirrorX + Math.sin(dAngle) * rayLen * 0.85;
var dY = mirrorY - Math.cos(dAngle) * rayLen * 0.85;
var alpha2 = 0.25 + 0.55 * Math.abs(Math.cos(dAngle));
ctx.strokeStyle = 'rgba(96,165,250,' + alpha2 + ')';
ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(mirrorX, mirrorY); ctx.lineTo(dX, dY); ctx.stroke();
}
ctx.fillStyle = '#94a3b8'; ctx.font = '9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('Лучи рассеиваются во все стороны', mirrorX, mirrorY + 45);
}
// точка падения — «искорка»
ctx.fillStyle = 'rgba(251,191,36,0.85)';
ctx.beginPath(); ctx.arc(mirrorX, mirrorY, 4, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = 'rgba(251,191,36,0.25)';
ctx.beginPath(); ctx.arc(mirrorX, mirrorY, 9, 0, Math.PI*2); ctx.fill();
// chips
var cA = document.getElementById('chip34a');
var cB = document.getElementById('chip34b');
if (cA) cA.textContent = 'α = ' + alpha + '°';
if (cB) {
if (isDiffuse) {
cB.textContent = 'диффузное';
cB.style.background = 'rgba(148,163,184,.15)';
cB.style.color = '#64748b';
cB.style.borderColor = 'rgba(148,163,184,.3)';
} else {
cB.textContent = 'β = ' + alpha + '° ✓';
cB.style.background = 'rgba(34,197,94,.12)';
cB.style.color = '#16a34a';
cB.style.borderColor = 'rgba(34,197,94,.3)';
}
}
var res = document.getElementById('res34');
if (res) res.innerHTML = isDiffuse
? 'Диффузное отражение: лучи расходятся во все стороны'
: '$\\alpha = ' + alpha + '°$ → $\\beta = ' + alpha + '°$ (закон отражения)';
if (window.doRender && res) doRender(res);
}
// Mouse / touch drag для cv34: курсор задаёт точку — угол α определяется автоматически
(function() {
function setup34() {
var cv = document.getElementById('cv34');
if (!cv) return;
function update(e) {
var rect = cv.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
var W = cv.offsetWidth, H = cv.offsetHeight || 280;
var mirrorY = H * 0.72, mirrorX = W / 2;
// вектор от точки падения к курсору
var dx = x - mirrorX, dy = mirrorY - y; // dy > 0, если выше зеркала
if (dy < 4) dy = 4;
var a = Math.atan2(dx, dy) * 180 / Math.PI;
// ограничим |α| <= 85
a = Math.max(-85, Math.min(85, a));
alpha34 = Math.abs(Math.round(a));
upd34();
}
var down = false;
cv.addEventListener('mousemove', function(e) { update(e); });
cv.addEventListener('mousedown', function(e) { down = true; update(e); });
cv.addEventListener('mouseup', function() { down = false; });
cv.addEventListener('touchstart', function(e) {
if (e.touches.length) { update(e.touches[0]); e.preventDefault(); }
}, {passive:false});
cv.addEventListener('touchmove', function(e) {
if (e.touches.length) { update(e.touches[0]); e.preventDefault(); }
}, {passive:false});
cv.addEventListener('touchend', function() {});
}
if (document.readyState === 'complete') setup34();
else window.addEventListener('load', setup34);
})();
function upd35() {
var cv = document.getElementById('cv35');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 280;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var l1 = parseInt((document.getElementById('sl35d') || {}).value) || 100;
var showRays = document.getElementById('chk35rays') && document.getElementById('chk35rays').checked;
var mirrorX = W / 2;
var scale = (W * 0.35) / 200;
var objX = mirrorX - l1 * scale;
var imgX = mirrorX + l1 * scale;
var objH = 60, objYbase = H * 0.72, objYtop = objYbase - objH;
var mg = ctx.createLinearGradient(mirrorX-3, 20, mirrorX+3, H-20);
mg.addColorStop(0, 'rgba(167,139,250,0.1)');
mg.addColorStop(0.5, 'rgba(167,139,250,0.5)');
mg.addColorStop(1, 'rgba(167,139,250,0.1)');
ctx.fillStyle = mg; ctx.fillRect(mirrorX - 3, 20, 6, H - 40);
ctx.strokeStyle = '#a78bfa'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(mirrorX, 20); ctx.lineTo(mirrorX, H - 20); ctx.stroke();
ctx.fillStyle = '#a78bfa'; ctx.font = '9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('Зеркало', mirrorX, H - 8);
ctx.strokeStyle = '#fbbf24'; ctx.lineWidth = 3;
ctx.beginPath(); ctx.moveTo(objX, objYbase); ctx.lineTo(objX, objYtop); ctx.stroke();
ctx.fillStyle = '#fbbf24';
ctx.beginPath(); ctx.moveTo(objX, objYtop - 10); ctx.lineTo(objX - 6, objYtop + 2); ctx.lineTo(objX + 6, objYtop + 2); ctx.fill();
ctx.fillStyle = '#fbbf24'; ctx.font = 'bold 9px sans-serif';
ctx.fillText('Предмет', objX, objYbase + 16);
ctx.fillText('S', objX, objYtop - 14);
ctx.strokeStyle = 'rgba(147,197,253,0.6)'; ctx.lineWidth = 2; ctx.setLineDash([5, 4]);
ctx.beginPath(); ctx.moveTo(imgX, objYbase); ctx.lineTo(imgX, objYtop); ctx.stroke();
ctx.fillStyle = 'rgba(147,197,253,0.5)';
ctx.beginPath(); ctx.moveTo(imgX, objYtop - 10); ctx.lineTo(imgX - 6, objYtop + 2); ctx.lineTo(imgX + 6, objYtop + 2); ctx.fill();
ctx.setLineDash([]);
ctx.fillStyle = '#93c5fd'; ctx.font = 'bold 9px sans-serif';
ctx.fillText("Изображение S'", imgX, objYbase + 16);
ctx.fillStyle = 'rgba(147,197,253,0.7)'; ctx.font = '8px sans-serif';
ctx.fillText("(мнимое)", imgX, objYbase + 28);
ctx.strokeStyle = '#475569'; ctx.lineWidth = 1; ctx.setLineDash([3, 3]);
ctx.beginPath(); ctx.moveTo(objX, H * 0.85); ctx.lineTo(mirrorX, H * 0.85); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#ef4444'; ctx.font = 'bold 10px sans-serif';
ctx.fillText('l₁ = ' + l1, (objX + mirrorX) / 2, H * 0.85 - 4);
ctx.strokeStyle = '#475569'; ctx.lineWidth = 1; ctx.setLineDash([3, 3]);
ctx.beginPath(); ctx.moveTo(mirrorX, H * 0.85); ctx.lineTo(imgX, H * 0.85); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#3b82f6'; ctx.font = 'bold 10px sans-serif';
ctx.fillText('l₂ = ' + l1, (mirrorX + imgX) / 2, H * 0.85 - 4);
if (showRays) {
var eyeX = W * 0.88, eyeY = H * 0.35;
ctx.strokeStyle = 'rgba(251,191,36,0.7)'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(objX, objYtop); ctx.lineTo(mirrorX, objYtop); ctx.stroke();
ctx.beginPath(); ctx.moveTo(mirrorX, objYtop); ctx.lineTo(eyeX, eyeY); ctx.stroke();
ctx.setLineDash([4, 3]);
ctx.strokeStyle = 'rgba(147,197,253,0.5)';
ctx.beginPath(); ctx.moveTo(mirrorX, objYtop); ctx.lineTo(imgX, objYtop); ctx.stroke();
ctx.setLineDash([]);
var r2mirY = objYtop + 20;
ctx.strokeStyle = 'rgba(251,191,36,0.7)'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(objX, objYtop); ctx.lineTo(mirrorX, r2mirY); ctx.stroke();
ctx.beginPath(); ctx.moveTo(mirrorX, r2mirY); ctx.lineTo(eyeX, eyeY); ctx.stroke();
ctx.setLineDash([4, 3]);
ctx.strokeStyle = 'rgba(147,197,253,0.5)';
ctx.beginPath(); ctx.moveTo(mirrorX, r2mirY); ctx.lineTo(imgX, r2mirY - (r2mirY - objYtop)); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#22c55e'; ctx.font = '16px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('👁', eyeX, eyeY + 6);
}
var res = document.getElementById('res35');
if (res) res.textContent = 'l₁ = l₂ = ' + l1 + ' усл.ед. | Изображение: мнимое, прямое, равных размеров.';
}
function upd36() {
var cv = document.getElementById('cv36');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 270;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var alpha = parseInt((document.getElementById('sl36a') || {}).value) || 40;
var sel = document.getElementById('sel36med');
var medStr = sel ? sel.value : 'water';
var nMap = {water:1.33, glass:1.5, diamond:2.42, rev_water:0.75};
var labMap = {water:'Воздух → Вода (n=1,33)', glass:'Воздух → Стекло (n=1,5)', diamond:'Воздух → Алмаз (n=2,42)', rev_water:'Вода → Воздух (n=0,75)'};
var colMap = {water:'rgba(14,165,233,0.3)', glass:'rgba(167,139,250,0.25)', diamond:'rgba(251,191,36,0.2)', rev_water:'rgba(14,165,233,0.15)'};
var n = nMap[medStr] || 1.33;
var alphaRad = alpha * Math.PI / 180;
var sinBeta = Math.sin(alphaRad) / n;
var beta = Math.asin(Math.min(1, sinBeta)) * 180 / Math.PI;
var betaRad = Math.asin(Math.min(1, sinBeta));
var totalInternalReflection = sinBeta > 1;
var boundY = H / 2;
var cx = W / 2;
// Media backgrounds
ctx.fillStyle = 'rgba(15,23,42,0.6)'; ctx.fillRect(0, 0, W, boundY);
ctx.fillStyle = colMap[medStr]; ctx.fillRect(0, boundY, W, H - boundY);
// Boundary line
ctx.strokeStyle = 'rgba(167,139,250,0.6)'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(0, boundY); ctx.lineTo(W, boundY); ctx.stroke();
// Labels
ctx.fillStyle = '#94a3b8'; ctx.font = '9px sans-serif'; ctx.textAlign = 'left';
ctx.fillText(medStr === 'rev_water' ? 'Вода' : 'Воздух', 8, boundY - 8);
ctx.fillText(medStr === 'rev_water' ? 'Воздух' : medStr === 'water' ? 'Вода' : medStr === 'glass' ? 'Стекло' : 'Алмаз', 8, boundY + 18);
// Normal
ctx.strokeStyle = 'rgba(148,163,184,0.4)'; ctx.lineWidth = 1.5; ctx.setLineDash([6, 4]);
ctx.beginPath(); ctx.moveTo(cx, 20); ctx.lineTo(cx, H - 20); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle = '#64748b'; ctx.font = '9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('нормаль', cx + 40, 30);
var rayLen = Math.min(W, H) * 0.38;
// Incident ray
var incSX = cx - Math.sin(alphaRad) * rayLen;
var incSY = boundY - Math.cos(alphaRad) * rayLen;
ctx.strokeStyle = '#ef4444'; ctx.lineWidth = 2.5;
ctx.beginPath(); ctx.moveTo(incSX, incSY); ctx.lineTo(cx, boundY); ctx.stroke();
// Arrow
var dx = cx-incSX, dy = boundY-incSY, dl = Math.sqrt(dx*dx+dy*dy);
var mx = cx-dx/dl*12, my = boundY-dy/dl*12;
ctx.fillStyle='#ef4444'; ctx.beginPath();
ctx.moveTo(cx,boundY); ctx.lineTo(mx+dy/dl*5,my-dx/dl*5); ctx.lineTo(mx-dy/dl*5,my+dx/dl*5); ctx.fill();
// Reflected ray
var refEX = cx + Math.sin(alphaRad) * rayLen * 0.6;
var refEY = boundY - Math.cos(alphaRad) * rayLen * 0.6;
ctx.strokeStyle = 'rgba(239,68,68,0.5)'; ctx.lineWidth = 1.5; ctx.setLineDash([4,3]);
ctx.beginPath(); ctx.moveTo(cx, boundY); ctx.lineTo(refEX, refEY); ctx.stroke();
ctx.setLineDash([]);
// Refracted ray
if (!totalInternalReflection) {
var refRX = cx + Math.sin(betaRad) * rayLen;
var refRY = boundY + Math.cos(betaRad) * rayLen;
ctx.strokeStyle = '#3b82f6'; ctx.lineWidth = 2.5;
ctx.beginPath(); ctx.moveTo(cx, boundY); ctx.lineTo(refRX, refRY); ctx.stroke();
ctx.fillStyle='#3b82f6'; ctx.beginPath();
var dx2=refRX-cx,dy2=refRY-boundY,dl2=Math.sqrt(dx2*dx2+dy2*dy2);
var rx=refRX-dx2/dl2*12,ry=refRY-dy2/dl2*12;
ctx.moveTo(refRX,refRY); ctx.lineTo(rx+dy2/dl2*5,ry-dx2/dl2*5); ctx.lineTo(rx-dy2/dl2*5,ry+dx2/dl2*5); ctx.fill();
} else {
ctx.fillStyle = '#fbbf24'; ctx.font = 'bold 10px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('⚠️ Полное внутреннее отражение!', cx, boundY + 40);
}
// Angle arcs & labels
var arcR = 40;
if (alpha > 0) {
ctx.strokeStyle = '#ef4444'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.arc(cx, boundY, arcR, -Math.PI/2-alphaRad, -Math.PI/2); ctx.stroke();
ctx.fillStyle = '#fca5a5'; ctx.font = 'bold 11px sans-serif'; ctx.textAlign = 'right';
ctx.fillText('α=' + alpha + '°', cx - Math.sin(alphaRad/2)*arcR - 4, boundY - Math.cos(alphaRad/2)*arcR);
if (!totalInternalReflection && beta > 0.5) {
ctx.strokeStyle = '#3b82f6'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.arc(cx, boundY, arcR, Math.PI/2, Math.PI/2+betaRad); ctx.stroke();
ctx.fillStyle = '#93c5fd'; ctx.font = 'bold 11px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('β=' + beta.toFixed(1) + '°', cx + Math.sin(betaRad/2)*arcR + 4, boundY + Math.cos(betaRad/2)*arcR);
}
}
var res = document.getElementById('res36');
if (res) {
if (totalInternalReflection) {
res.textContent = 'α=' + alpha + '° | Полное внутреннее отражение! (sin α > n²)';
} else {
res.innerHTML = '$\\alpha = ' + alpha + '°$; $n = ' + n + '$; $\\beta \\approx ' + beta.toFixed(1) + '°$ (' + (n>1?'β < α':'β > α') + ' — ' + (n>1?'более плотная среда':'менее плотная среда') + ')';
if (window.doRender) doRender(res);
}
}
}
function upd37() {
var cv = document.getElementById('cv37');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 240;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var F = parseInt((document.getElementById('sl37F') || {}).value) || 80;
if (F === 0) F = 1;
var lx = W / 2, ly = H / 2;
var scale = W * 0.3 / 200;
var Fpx = F * scale;
// Optical axis
ctx.strokeStyle = 'rgba(148,163,184,0.3)'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(0, ly); ctx.lineTo(W, ly); ctx.stroke();
// Lens
var lensH = H * 0.55;
var isConv = F > 0;
ctx.strokeStyle = isConv ? '#a78bfa' : '#f97316'; ctx.lineWidth = 3;
if (isConv) {
// Biconvex
ctx.beginPath();
ctx.moveTo(lx, ly - lensH/2);
ctx.quadraticCurveTo(lx + 18, ly, lx, ly + lensH/2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(lx, ly - lensH/2);
ctx.quadraticCurveTo(lx - 18, ly, lx, ly + lensH/2);
ctx.stroke();
} else {
// Biconcave
ctx.beginPath();
ctx.moveTo(lx, ly - lensH/2);
ctx.quadraticCurveTo(lx - 18, ly, lx, ly + lensH/2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(lx, ly - lensH/2);
ctx.quadraticCurveTo(lx + 18, ly, lx, ly + lensH/2);
ctx.stroke();
}
// Arrows on lens symbol
ctx.strokeStyle = isConv ? '#a78bfa' : '#f97316'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(lx, ly - lensH/2); ctx.lineTo(lx, ly + lensH/2); ctx.stroke();
ctx.fillStyle = isConv ? '#a78bfa' : '#f97316';
if (isConv) {
ctx.beginPath(); ctx.moveTo(lx, ly - lensH/2); ctx.lineTo(lx-5,ly-lensH/2+10); ctx.lineTo(lx+5,ly-lensH/2+10); ctx.fill();
ctx.beginPath(); ctx.moveTo(lx, ly + lensH/2); ctx.lineTo(lx-5,ly+lensH/2-10); ctx.lineTo(lx+5,ly+lensH/2-10); ctx.fill();
} else {
ctx.beginPath(); ctx.moveTo(lx, ly - lensH/2); ctx.lineTo(lx-5,ly-lensH/2-2); ctx.lineTo(lx-5,ly-lensH/2+12); ctx.fill();
ctx.beginPath(); ctx.moveTo(lx, ly + lensH/2); ctx.lineTo(lx-5,ly+lensH/2+2); ctx.lineTo(lx-5,ly+lensH/2-12); ctx.fill();
}
// Focal points
var f1x = lx - Math.abs(Fpx), f2x = lx + Math.abs(Fpx);
if (F < 0) { f1x = lx + Math.abs(Fpx); f2x = lx - Math.abs(Fpx); }
[f1x, f2x].forEach(function(fx) {
ctx.fillStyle = '#fbbf24';
ctx.beginPath(); ctx.arc(fx, ly, 5, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = '#fbbf24'; ctx.font = 'bold 11px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('F', fx, ly - 10);
});
// Parallel rays → converge/diverge at F
var nRays = 7;
for (var ri = 0; ri < nRays; ri++) {
var ry = ly - lensH/2 + lensH * ri / (nRays - 1);
var startX = 15;
// Incident ray
ctx.strokeStyle = 'rgba(251,191,36,0.8)'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(startX, ry); ctx.lineTo(lx, ry); ctx.stroke();
if (isConv) {
// Refracted ray converges to F
ctx.strokeStyle = 'rgba(59,130,246,0.8)'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(lx, ry); ctx.lineTo(f2x, ly); ctx.stroke();
// Continue past F
var extX = W - 10;
var extY = ly + (extX - f2x) * (ly - ry) / (f2x - lx);
ctx.strokeStyle = 'rgba(59,130,246,0.3)'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(f2x, ly); ctx.lineTo(Math.min(extX, W-5), extY); ctx.stroke();
} else {
// Refracted ray diverges; extension passes through F (on same side)
var fFarX = lx - Fpx; // мнимый фокус (ближе к источнику для рассеивающей)
var dirX = lx - fFarX, dirY = ry - ly; // direction from F to point on lens
var len = Math.sqrt(dirX*dirX + dirY*dirY);
ctx.strokeStyle = 'rgba(59,130,246,0.8)'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(lx, ry); ctx.lineTo(lx + dirX/len*200, ry + dirY/len*200); ctx.stroke();
// Dashed continuation to мнимый фокус
ctx.strokeStyle = 'rgba(147,197,253,0.4)'; ctx.lineWidth = 1; ctx.setLineDash([4,3]);
ctx.beginPath(); ctx.moveTo(lx, ry); ctx.lineTo(fFarX, ly); ctx.stroke();
ctx.setLineDash([]);
}
}
// Labels
ctx.fillStyle = isConv ? '#a78bfa' : '#f97316'; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText(isConv ? 'Собирающая' : 'Рассеивающая', lx, ly - lensH/2 - 8);
var D = F !== 0 ? (1000 / F).toFixed(1) : '∞';
var res = document.getElementById('res37');
if (res) res.textContent = 'F = ' + F + ' усл.; D = 1000/' + F + ' = ' + D + ' дптр (' + (isConv ? 'собирающая' : 'рассеивающая') + ')';
}
// ── cv38: Pro Max тонкая линза (drag предмет + линза, формула, увеличение) ──
var obj38d = 160;
var lensPos38 = 0.55; // линза по центру (доля W); можно тянуть мышью
function reset38() {
lensPos38 = 0.55;
var slF = document.getElementById('sl38F'); if (slF) { slF.value = 70; var lf = document.getElementById('lbl38F'); if (lf) lf.textContent = '70 усл.'; }
var slD = document.getElementById('sl38d'); if (slD) { slD.value = 160; var ld = document.getElementById('lbl38d'); if (ld) ld.textContent = '160 усл.'; }
var sel = document.getElementById('sel38type'); if (sel) sel.value = 'conv';
var chk = document.getElementById('chk38r3'); if (chk) chk.checked = true;
upd38();
}
function upd38() {
var cv = document.getElementById('cv38');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 320;
cv.width = Math.round(W * dpr); cv.height = Math.round(H * dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0, 0, W, H);
var Fval = parseInt((document.getElementById('sl38F') || {}).value) || 70;
var dval = parseInt((document.getElementById('sl38d') || {}).value) || 160;
var selT = document.getElementById('sel38type');
var isDiv = selT && selT.value === 'div';
var showR3 = !!(document.getElementById('chk38r3') && document.getElementById('chk38r3').checked);
// Масштаб: scl пикселей на единицу
var scl = (W * 0.38) / 300;
var Fpx = Fval * scl;
var dpx = dval * scl;
// Геометрия
var lx = W * lensPos38, ly = H / 2;
// удержим линзу с зазорами под предмет
lx = Math.max(W * 0.32, Math.min(W * 0.78, lx));
var f1x = lx - Fpx; // передний фокус F (слева)
var f2x = lx + Fpx; // задний фокус F' (справа)
var objX = lx - dpx;
var objH = Math.min(72, H * 0.26);
var Ay = ly - objH; // кончик предмета (выше оси)
// Формула линзы: 1/F = 1/d + 1/f → f
var Feff = isDiv ? -Fval : Fval;
var fImg, isInf=false;
// 1/Feff = 1/d + 1/f → f = d*F/(d-F)
var denom = dval - Feff;
if (Math.abs(denom) < 0.01) { fImg = 1e9; isInf = true; }
else fImg = Feff * dval / denom;
var Gamma = -fImg / dval; // линейное увеличение (- = перевёрнутое)
var fpx = fImg * scl;
var imgX = lx + fpx;
var imgYtip = ly - Gamma * objH;
var isReal = fImg > 0.5 && isFinite(fImg);
var isVirt = fImg < -0.5 && isFinite(fImg);
// === Сетка-«стол» ===
ctx.strokeStyle = 'rgba(148,163,184,0.05)'; ctx.lineWidth = 1;
for (var gx = 0; gx < W; gx += 30) { ctx.beginPath(); ctx.moveTo(gx,0); ctx.lineTo(gx,H); ctx.stroke(); }
for (var gy = 0; gy < H; gy += 30) { ctx.beginPath(); ctx.moveTo(0,gy); ctx.lineTo(W,gy); ctx.stroke(); }
// === Фоновая зона: подсветка области (внутри F / между F и 2F / за 2F) ===
if (!isDiv) {
var zc = dpx < Fpx ? 'rgba(124,58,237,0.07)' : dpx < 2*Fpx ? 'rgba(249,115,22,0.05)' : 'rgba(34,197,94,0.05)';
ctx.fillStyle = zc; ctx.fillRect(0, 0, lx - 1, H);
ctx.fillStyle = '#475569'; ctx.font = '8.5px sans-serif'; ctx.textAlign = 'left';
var zoneL = dpx < Fpx ? 'd < F: мнимое, прямое, увелич.' :
dpx < 2*Fpx ? 'F < d < 2F: действ., перевёрн., увелич.' :
'd > 2F: действ., перевёрн., уменьш.';
ctx.fillText(zoneL, 8, 14);
}
// === Главная оптическая ось ===
ctx.strokeStyle = 'rgba(148,163,184,0.35)'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(0,ly); ctx.lineTo(W,ly); ctx.stroke();
ctx.fillStyle = '#94a3b8'; ctx.font = '9px sans-serif'; ctx.textAlign = 'right';
ctx.fillText('главная оптическая ось', W - 6, ly - 4);
// стрелка оси справа
ctx.fillStyle = 'rgba(148,163,184,0.6)';
ctx.beginPath(); ctx.moveTo(W - 2, ly); ctx.lineTo(W - 9, ly - 3); ctx.lineTo(W - 9, ly + 3); ctx.fill();
// === Фокусы F и F' и точки 2F ===
function fmark(fx, lbl, primary) {
var a = primary ? 0.95 : 0.7;
ctx.fillStyle = 'rgba(251,191,36,' + a + ')';
ctx.beginPath(); ctx.arc(fx, ly, 5, 0, Math.PI*2); ctx.fill();
ctx.strokeStyle = 'rgba(15,23,42,0.7)'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.arc(fx, ly, 5, 0, Math.PI*2); ctx.stroke();
ctx.fillStyle = 'rgba(251,191,36,0.95)';
ctx.font = 'bold 11px sans-serif'; ctx.textAlign = 'center';
ctx.fillText(lbl, fx, ly - 12);
}
fmark(f1x, 'F', true);
fmark(f2x, "F'", true);
// точки 2F
[lx - 2*Fpx, lx + 2*Fpx].forEach(function(tf) {
ctx.fillStyle = 'rgba(251,191,36,0.35)';
ctx.beginPath(); ctx.arc(tf, ly, 3, 0, Math.PI*2); ctx.fill();
ctx.fillStyle = 'rgba(251,191,36,0.55)'; ctx.font = '8px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('2F', tf, ly - 8);
});
// === Линза (двояковыпуклая для собирающей, двояковогнутая для рассеивающей) ===
var lc = isDiv ? '#f97316' : '#a78bfa';
var lH = H * 0.42;
// тело линзы (овал/линза-фигура)
ctx.save();
if (!isDiv) {
// двояковыпуклая
var grdL = ctx.createLinearGradient(lx-12, 0, lx+12, 0);
grdL.addColorStop(0, 'rgba(167,139,250,0.06)');
grdL.addColorStop(0.5, 'rgba(167,139,250,0.28)');
grdL.addColorStop(1, 'rgba(167,139,250,0.06)');
ctx.fillStyle = grdL;
ctx.beginPath();
ctx.moveTo(lx, ly - lH/2);
ctx.quadraticCurveTo(lx + 18, ly, lx, ly + lH/2);
ctx.quadraticCurveTo(lx - 18, ly, lx, ly - lH/2);
ctx.fill();
ctx.strokeStyle = lc; ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(lx, ly - lH/2);
ctx.quadraticCurveTo(lx + 18, ly, lx, ly + lH/2);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(lx, ly - lH/2);
ctx.quadraticCurveTo(lx - 18, ly, lx, ly + lH/2);
ctx.stroke();
// стрелки-указатели «собирающая» (двусторонние)
ctx.fillStyle = lc;
ctx.beginPath(); ctx.moveTo(lx, ly-lH/2-3); ctx.lineTo(lx-5,ly-lH/2+7); ctx.lineTo(lx+5,ly-lH/2+7); ctx.fill();
ctx.beginPath(); ctx.moveTo(lx, ly+lH/2+3); ctx.lineTo(lx-5,ly+lH/2-7); ctx.lineTo(lx+5,ly+lH/2-7); ctx.fill();
} else {
// двояковогнутая
ctx.fillStyle = 'rgba(249,115,22,0.18)';
ctx.beginPath();
ctx.moveTo(lx - 10, ly - lH/2);
ctx.lineTo(lx + 10, ly - lH/2);
ctx.quadraticCurveTo(lx, ly, lx + 10, ly + lH/2);
ctx.lineTo(lx - 10, ly + lH/2);
ctx.quadraticCurveTo(lx, ly, lx - 10, ly - lH/2);
ctx.fill();
ctx.strokeStyle = lc; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(lx-10,ly-lH/2); ctx.lineTo(lx+10,ly-lH/2); ctx.stroke();
ctx.beginPath(); ctx.moveTo(lx-10,ly+lH/2); ctx.lineTo(lx+10,ly+lH/2); ctx.stroke();
ctx.beginPath(); ctx.moveTo(lx-10,ly-lH/2); ctx.quadraticCurveTo(lx, ly, lx-10, ly+lH/2); ctx.stroke();
ctx.beginPath(); ctx.moveTo(lx+10,ly-lH/2); ctx.quadraticCurveTo(lx, ly, lx+10, ly+lH/2); ctx.stroke();
// стрелки-указатели «рассеивающая»
ctx.fillStyle = lc;
ctx.beginPath(); ctx.moveTo(lx-10,ly-lH/2); ctx.lineTo(lx-14,ly-lH/2+8); ctx.lineTo(lx-6,ly-lH/2+8); ctx.fill();
ctx.beginPath(); ctx.moveTo(lx+10,ly-lH/2); ctx.lineTo(lx+14,ly-lH/2+8); ctx.lineTo(lx+6,ly-lH/2+8); ctx.fill();
}
ctx.restore();
// оптический центр O
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(lx, ly, 3, 0, Math.PI*2); ctx.fill();
ctx.strokeStyle = lc; ctx.lineWidth = 1;
ctx.beginPath(); ctx.arc(lx, ly, 3, 0, Math.PI*2); ctx.stroke();
ctx.fillStyle = lc; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'left';
ctx.fillText('O', lx + 6, ly + 12);
ctx.fillStyle = lc; ctx.font = 'bold 9px sans-serif'; ctx.textAlign = 'center';
ctx.fillText(isDiv ? 'Рассеивающая' : 'Собирающая', lx, ly - lH/2 - 12);
// hint «drag»
ctx.fillStyle = 'rgba(255,255,255,0.35)'; ctx.font = '8px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('⇔ drag', lx, ly + lH/2 + 12);
// === Предмет AB (стрелка ↑) ===
ctx.strokeStyle = '#fbbf24'; ctx.lineWidth = 3;
ctx.beginPath(); ctx.moveTo(objX, ly); ctx.lineTo(objX, Ay); ctx.stroke();
ctx.fillStyle = '#fbbf24';
ctx.beginPath(); ctx.moveTo(objX, Ay - 10); ctx.lineTo(objX - 6, Ay + 2); ctx.lineTo(objX + 6, Ay + 2); ctx.fill();
// drag-«ручка» — кружок на кончике
ctx.fillStyle = 'rgba(251,191,36,0.85)';
ctx.beginPath(); ctx.arc(objX, Ay - 4, 6, 0, Math.PI*2); ctx.fill();
ctx.strokeStyle = '#fff'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(objX, Ay - 4, 6, 0, Math.PI*2); ctx.stroke();
ctx.fillStyle = '#fbbf24'; ctx.font = 'bold 10px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('B', objX, Ay - 14);
ctx.fillStyle = '#fbbf24'; ctx.font = 'bold 10px sans-serif'; ctx.textAlign = 'center';
ctx.fillText('A', objX, ly + 14);
ctx.fillStyle = '#94a3b8'; ctx.font = '8.5px sans-serif';
ctx.fillText('d=' + dval, objX, ly + 26);
// === ТРАССИРОВКА ЛУЧЕЙ ===
var EDGE = W + 40;
function yAt(x1,y1,x2,y2,toX) {
if (Math.abs(x2-x1) < 0.001) return y1;
return y1 + (y2-y1)*(toX-x1)/(x2-x1);
}
function seg(x1,y1,x2,y2,col,dsh,lw) {
if (isNaN(y1)||isNaN(y2)) return;
ctx.strokeStyle = col; ctx.lineWidth = lw||1.8;
ctx.setLineDash(dsh ? [5,4] : []);
ctx.beginPath(); ctx.moveTo(x1,y1); ctx.lineTo(x2,y2); ctx.stroke();
ctx.setLineDash([]);
}
var Ax = objX;
// ── ЛУЧ 1 (красный): || оси → через F' ──
seg(Ax, Ay, lx, Ay, '#ef4444');
if (!isDiv) {
if (isReal) {
var r1iy = yAt(lx,Ay,f2x,ly,imgX);
seg(lx, Ay, imgX, r1iy, '#ef4444');
seg(imgX, r1iy, EDGE, yAt(lx,Ay,f2x,ly,EDGE), 'rgba(239,68,68,0.18)', false, 1);
} else if (isVirt) {
seg(lx, Ay, EDGE, yAt(lx,Ay,f2x,ly,EDGE), '#ef4444');
seg(lx, Ay, imgX, yAt(lx,Ay,f2x,ly,imgX), 'rgba(239,68,68,0.45)', true, 1.5);
} else {
seg(lx, Ay, EDGE, yAt(lx,Ay,f2x,ly,EDGE), '#ef4444');
}
} else {
// рассеивающая: после линзы луч расходится, как из F (того, что слева)
var r1slope = (Ay - ly) / (lx - f1x + 0.001);
var r1ey = Ay + r1slope * (EDGE - lx);
seg(lx, Ay, EDGE, r1ey, '#ef4444');
if (isVirt) seg(lx, Ay, imgX, yAt(f1x,ly,lx,Ay,imgX), 'rgba(239,68,68,0.45)', true, 1.5);
}
// ── ЛУЧ 2 (зелёный): через оптический центр O — без преломления ──
seg(Ax, Ay, lx, ly, '#22c55e');
if (isReal) {
var r2iy = yAt(Ax,Ay,lx,ly,imgX);
seg(lx, ly, imgX, r2iy, '#22c55e');
seg(imgX, r2iy, EDGE, yAt(Ax,Ay,lx,ly,EDGE), 'rgba(34,197,94,0.18)', false, 1);
} else if (isVirt) {
seg(lx, ly, EDGE, yAt(Ax,Ay,lx,ly,EDGE), '#22c55e');
seg(lx, ly, imgX, yAt(Ax,Ay,lx,ly,imgX), 'rgba(34,197,94,0.45)', true, 1.5);
} else {
seg(lx, ly, EDGE, yAt(Ax,Ay,lx,ly,EDGE), '#22c55e');
}
// ── ЛУЧ 3 (оранжевый): через F → после линзы || оси ──
if (showR3 && !isDiv && dpx > Fpx * 0.05) {
var r3yL = yAt(Ax, Ay, f1x, ly, lx);
seg(Ax, Ay, lx, r3yL, '#f97316');
if (isReal) {
seg(lx, r3yL, imgX, r3yL, '#f97316');
seg(imgX, r3yL, EDGE, r3yL, 'rgba(249,115,22,0.18)', false, 1);
} else if (isVirt) {
seg(lx, r3yL, EDGE, r3yL, '#f97316');
seg(lx, r3yL, imgX, r3yL, 'rgba(249,115,22,0.45)', true, 1.5);
} else {
seg(lx, r3yL, EDGE, r3yL, '#f97316');
}
}
// === Изображение A'B' (сплошное действ. / пунктир мнимое) ===
if (!isInf && Math.abs(fpx) < W*1.2 && Math.abs(imgYtip-ly) < H*0.98) {
var ic = isReal ? '#3b82f6' : 'rgba(147,197,253,0.85)';
ctx.strokeStyle = ic; ctx.lineWidth = isReal ? 3 : 2;
if (isVirt) ctx.setLineDash([5,4]);
ctx.beginPath(); ctx.moveTo(imgX, ly); ctx.lineTo(imgX, imgYtip); ctx.stroke();
ctx.fillStyle = ic;
var ad = (imgYtip < ly) ? -1 : 1;
ctx.beginPath();
ctx.moveTo(imgX, imgYtip + ad*10);
ctx.lineTo(imgX - 6, imgYtip - ad*2);
ctx.lineTo(imgX + 6, imgYtip - ad*2);
ctx.fill();
ctx.setLineDash([]);
ctx.fillStyle = ic; ctx.font = 'bold 10px sans-serif'; ctx.textAlign = 'center';
ctx.fillText("B'", imgX, imgYtip + (ad < 0 ? -8 : 18));
ctx.fillText("A'", imgX, ly + (ad < 0 ? 14 : -6));
ctx.fillStyle = '#94a3b8'; ctx.font = '8.5px sans-serif';
ctx.fillText("f=" + Math.round(fImg), imgX, ly + (ad < 0 ? 26 : -18));
}
// === Подписи d, f под осью (от линзы) ===
ctx.strokeStyle = 'rgba(251,191,36,0.5)'; ctx.lineWidth = 1; ctx.setLineDash([3,3]);
ctx.beginPath(); ctx.moveTo(objX, ly + 30); ctx.lineTo(lx, ly + 30); ctx.stroke();
ctx.setLineDash([]);
// === Чипы: формула линзы, увеличение, тип ===
var cLens = document.getElementById('chip38lens');
var cMag = document.getElementById('chip38mag');
var cType = document.getElementById('chip38type');
if (cLens) {
if (isInf) cLens.textContent = 'd = F → 1/F = 1/d + 0 → f = ∞';
else {
// 1/F = 1/d + 1/f → подставим числа
var fR = Math.round(fImg);
cLens.textContent = '1/' + Feff + ' = 1/' + dval + ' + 1/' + fR;
}
}
if (cMag) {
if (isInf) {
cMag.textContent = "Γ → ∞";
} else {
var absG = Math.abs(Gamma);
cMag.textContent = "Γ = f/d = " + absG.toFixed(2);
// зелёный/синий/серый — увеличение/уменьшение/равное
if (absG > 1.05) { cMag.style.background='rgba(34,197,94,.12)'; cMag.style.color='#16a34a'; cMag.style.borderColor='rgba(34,197,94,.3)'; }
else if (absG < 0.95) { cMag.style.background='rgba(59,130,246,.12)'; cMag.style.color='#1d4ed8'; cMag.style.borderColor='rgba(59,130,246,.3)'; }
else { cMag.style.background='rgba(148,163,184,.15)'; cMag.style.color='#475569'; cMag.style.borderColor='rgba(148,163,184,.3)'; }
}
}
if (cType) {
var t1 = isReal ? 'действ.' : (isVirt ? 'мнимое' : '∞');
var t2 = Gamma < 0 ? 'перевёрн.' : 'прямое';
cType.textContent = t1 + ', ' + t2;
}
// === Текстовый результат ===
var res = document.getElementById('res38');
if (res) {
if (isInf) {
res.textContent = 'd = F = ' + Fval + ' → лучи параллельны, изображение на ∞';
} else {
var t1r = isReal ? 'действительное' : 'мнимое';
var t2r = Gamma < 0 ? 'перевёрнутое' : 'прямое';
var absG2 = Math.abs(Gamma);
var t3r = absG2 > 1.05 ? 'увеличенное' : absG2 < 0.95 ? 'уменьшенное' : 'равное';
res.textContent = 'd=' + dval + ', F=' + Feff + ' → f=' + Math.round(fImg) + ' | ' + t1r + ', ' + t2r + ', ' + t3r + ' (Γ=' + absG2.toFixed(2) + ')';
}
}
}
// Mouse / touch drag для cv38: за стрелку-предмет или за линзу
(function() {
var dragging38 = null; // 'obj' | 'lens' | null
function setup38() {
var cv = document.getElementById('cv38');
if (!cv) return;
function pick(e) {
var rect = cv.getBoundingClientRect();
var x = e.clientX - rect.left, y = e.clientY - rect.top;
var W = cv.offsetWidth, H = cv.offsetHeight || 320;
var ly = H / 2;
var lx = Math.max(W*0.32, Math.min(W*0.78, W * lensPos38));
var scl = (W * 0.38) / 300;
var dval = parseInt((document.getElementById('sl38d')||{}).value) || 160;
var objX = lx - dval * scl;
// приоритет — предмет (если рядом по x), иначе линза
if (Math.abs(x - objX) < 22) return {mode: 'obj', x: x, y: y, W: W, lx: lx, scl: scl};
if (Math.abs(x - lx) < 18) return {mode: 'lens', x: x, y: y, W: W, lx: lx, scl: scl};
return null;
}
function move(e) {
if (!dragging38) return;
var rect = cv.getBoundingClientRect();
var x = e.clientX - rect.left;
var W = cv.offsetWidth;
if (dragging38 === 'lens') {
lensPos38 = Math.max(0.32, Math.min(0.78, x / W));
} else if (dragging38 === 'obj') {
var lx = Math.max(W*0.32, Math.min(W*0.78, W * lensPos38));
var scl = (W * 0.38) / 300;
var d = Math.round(Math.max(10, Math.min(300, (lx - x) / scl)));
var sl = document.getElementById('sl38d');
if (sl) {
sl.value = d;
var lb = document.getElementById('lbl38d');
if (lb) lb.textContent = d + ' усл.';
}
}
upd38();
}
cv.addEventListener('mousedown', function(e) {
var p = pick(e);
if (p) { dragging38 = p.mode; cv.style.cursor = 'grabbing'; move(e); }
});
cv.addEventListener('mousemove', function(e) {
if (dragging38) { move(e); return; }
var p = pick(e);
cv.style.cursor = p ? 'grab' : 'crosshair';
});
cv.addEventListener('mouseup', function() { dragging38 = null; cv.style.cursor = 'grab'; });
cv.addEventListener('mouseleave', function() { dragging38 = null; cv.style.cursor = 'grab'; });
cv.addEventListener('touchstart', function(e) {
if (!e.touches.length) return;
var p = pick(e.touches[0]);
if (p) { dragging38 = p.mode; move(e.touches[0]); e.preventDefault(); }
}, {passive:false});
cv.addEventListener('touchmove', function(e) {
if (dragging38 && e.touches.length) { move(e.touches[0]); e.preventDefault(); }
}, {passive:false});
cv.addEventListener('touchend', function() { dragging38 = null; });
}
if (document.readyState === 'complete') setup38();
else window.addEventListener('load', setup38);
})();
function upd39() {
var cv = document.getElementById('cv39');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 240;
cv.width = Math.round(W*dpr); cv.height = Math.round(H*dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr,0,0,dpr,0,0);
ctx.fillStyle = '#0f172a'; ctx.fillRect(0,0,W,H);
var d = parseInt((document.getElementById('sl39d')||{}).value)||50;
// Normalize: 15cm → max bulge; 200cm → flat
var bulge = Math.max(3, 22 - (d - 15) * 19 / 185);
var lensAccom = bulge; // more bulge = shorter F
var ey = H/2, ex = W * 0.55;
var eyeRx = W * 0.18, eyeRy = H * 0.38;
// Eye outline
ctx.strokeStyle = '#a78bfa'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.ellipse(ex, ey, eyeRx, eyeRy, 0, 0, Math.PI*2); ctx.stroke();
ctx.fillStyle = 'rgba(124,58,237,0.05)'; ctx.fill();
// Cornea (left side, fixed)
ctx.strokeStyle = '#38bdf8'; ctx.lineWidth = 2.5;
ctx.beginPath();
ctx.moveTo(ex - eyeRx, ey - 22);
ctx.quadraticCurveTo(ex - eyeRx - 12, ey, ex - eyeRx, ey + 22);
ctx.stroke();
// Lens (variable bulge for accommodation)
var lx = ex - eyeRx + 28;
ctx.strokeStyle = '#fbbf24'; ctx.lineWidth = 2.5;
ctx.beginPath();
ctx.moveTo(lx, ey - 20);
ctx.quadraticCurveTo(lx + lensAccom, ey, lx, ey + 20);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(lx + 8, ey - 20);
ctx.quadraticCurveTo(lx + 8 - lensAccom, ey, lx + 8, ey + 20);
ctx.stroke();
ctx.fillStyle = 'rgba(251,191,36,0.12)';
ctx.beginPath();
ctx.moveTo(lx, ey-20); ctx.quadraticCurveTo(lx+lensAccom, ey, lx, ey+20);
ctx.lineTo(lx+8, ey+20); ctx.quadraticCurveTo(lx+8-lensAccom, ey, lx+8, ey-20); ctx.fill();
// Retina (right side)
ctx.strokeStyle = '#22c55e'; ctx.lineWidth = 2.5;
ctx.beginPath();
ctx.moveTo(ex + eyeRx - 5, ey - 30);
ctx.quadraticCurveTo(ex + eyeRx + 8, ey, ex + eyeRx - 5, ey + 30);
ctx.stroke();
// Optical axis
ctx.strokeStyle = 'rgba(148,163,184,0.2)'; ctx.lineWidth=1;
ctx.beginPath(); ctx.moveTo(0,ey); ctx.lineTo(W,ey); ctx.stroke();
// Object (left)
var objX = ex - eyeRx - Math.min(W*0.35, d*2.2);
if (objX < 10) objX = 10;
ctx.strokeStyle = '#fbbf24'; ctx.lineWidth=2.5;
ctx.beginPath(); ctx.moveTo(objX, ey); ctx.lineTo(objX, ey-30); ctx.stroke();
ctx.fillStyle='#fbbf24';
ctx.beginPath(); ctx.moveTo(objX,ey-36); ctx.lineTo(objX-4,ey-26); ctx.lineTo(objX+4,ey-26); ctx.fill();
ctx.font='8px sans-serif'; ctx.textAlign='center'; ctx.fillStyle='#fbbf24';
ctx.fillText(d + ' см', objX, ey+16);
// Rays converge on retina
var retinaX = ex + eyeRx - 5;
ctx.strokeStyle = 'rgba(59,130,246,0.7)'; ctx.lineWidth=1.5;
ctx.beginPath(); ctx.moveTo(objX, ey-28); ctx.lineTo(lx+4, ey-15); ctx.lineTo(retinaX, ey + (d<50?12:d<100?5:0)); ctx.stroke();
ctx.beginPath(); ctx.moveTo(objX, ey+2); ctx.lineTo(lx+4, ey+10); ctx.lineTo(retinaX, ey - (d<50?12:d<100?5:0)); ctx.stroke();
// Labels
ctx.fillStyle='#38bdf8'; ctx.font='8px sans-serif'; ctx.textAlign='center';
ctx.fillText('роговица', ex-eyeRx-3, ey-eyeRy+14);
ctx.fillStyle='#fbbf24';
ctx.fillText('хрусталик', lx+4, ey-22);
ctx.fillStyle='#22c55e';
ctx.fillText('сетчатка', retinaX+22, ey);
ctx.fillStyle = d<25 ? '#ef4444' : d>150 ? '#22c55e' : '#fbbf24';
ctx.font='bold 9px sans-serif'; ctx.textAlign='center';
ctx.fillText(d<25 ? '⚠️ Очень близко — напряжение!' : d<50 ? 'Хрусталик выпуклый (F мал)' : d<120 ? 'Хрусталик средний' : 'Хрусталик плоский (F велик)', W/2, H-10);
var res=document.getElementById('res39');
if(res) res.textContent = 'Расстояние: ' + d + ' см | хрусталик ' + (d<40?'сильно выпуклый, D↑':d<80?'нормальный':'плоский, D↓');
}
function startAnim39() { upd39(); }
function upd40() {
var cv = document.getElementById('cv40');
if (!cv || cv.offsetWidth === 0) return;
var dpr = window.devicePixelRatio || 1;
var W = cv.offsetWidth, H = cv.offsetHeight || 260;
cv.width = Math.round(W*dpr); cv.height = Math.round(H*dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr,0,0,dpr,0,0);
ctx.fillStyle='#0f172a'; ctx.fillRect(0,0,W,H);
var sel=document.getElementById('sel40def');
var defect=sel?sel.value:'normal';
var glasses=document.getElementById('chk40glasses')&&document.getElementById('chk40glasses').checked;
var Dgl=parseFloat((document.getElementById('sl40D')||{}).value)||-2;
var ey=H/2, ex=W*0.62, eyeRx=W*0.16, eyeRy=H*0.32;
// Defect offsets: where focus actually lands
var focusOffset = defect==='myopia' ? -eyeRx*0.25 : defect==='hyperopia' ? eyeRx*0.25 : 0;
if (glasses) {
// Glasses correct the focus
var correction = -Dgl * eyeRx * 0.06;
focusOffset = Math.max(-eyeRx*0.3, Math.min(eyeRx*0.3, focusOffset + correction));
}
var retinaX = ex + eyeRx - 8;
var focusX = retinaX + focusOffset;
// Eye outline
ctx.strokeStyle='#a78bfa'; ctx.lineWidth=2;
ctx.beginPath(); ctx.ellipse(ex,ey,eyeRx,eyeRy,0,0,Math.PI*2); ctx.stroke();
// Shape of eye (myopia = elongated)
if (defect==='myopia') {
ctx.strokeStyle='rgba(239,68,68,0.4)'; ctx.lineWidth=1.5; ctx.setLineDash([4,3]);
ctx.beginPath(); ctx.ellipse(ex+4,ey,eyeRx+6,eyeRy,0,0,Math.PI*2); ctx.stroke();
ctx.setLineDash([]);
}
// Glasses (if worn)
if (glasses) {
var glassX = ex - eyeRx - 25;
var gColor = Dgl<0 ? '#f97316' : '#22c55e';
ctx.strokeStyle=gColor; ctx.lineWidth=2.5;
// Simple lens representation
if (Dgl < 0) {
ctx.beginPath(); ctx.moveTo(glassX, ey-18); ctx.quadraticCurveTo(glassX-8,ey,glassX,ey+18); ctx.stroke();
ctx.beginPath(); ctx.moveTo(glassX+6, ey-18); ctx.quadraticCurveTo(glassX+14,ey,glassX+6,ey+18); ctx.stroke();
} else {
ctx.beginPath(); ctx.moveTo(glassX, ey-18); ctx.quadraticCurveTo(glassX+10,ey,glassX,ey+18); ctx.stroke();
ctx.beginPath(); ctx.moveTo(glassX+6, ey-18); ctx.quadraticCurveTo(glassX-4,ey,glassX+6,ey+18); ctx.stroke();
}
ctx.fillStyle=gColor; ctx.font='8px sans-serif'; ctx.textAlign='center';
ctx.fillText((Dgl>0?'+':'')+Dgl+' дптр', glassX+3, ey+28);
}
// Cornea/lens (simplified)
var lx = ex - eyeRx + 12;
ctx.strokeStyle='#fbbf24'; ctx.lineWidth=2.5;
ctx.beginPath();
ctx.moveTo(lx,ey-18); ctx.quadraticCurveTo(lx+10,ey,lx,ey+18); ctx.stroke();
ctx.beginPath();
ctx.moveTo(lx+8,ey-18); ctx.quadraticCurveTo(lx-2,ey,lx+8,ey+18); ctx.stroke();
// Retina
ctx.strokeStyle='#22c55e'; ctx.lineWidth=2.5;
ctx.beginPath();
ctx.moveTo(retinaX, ey-eyeRy+8);
ctx.quadraticCurveTo(retinaX+6,ey,retinaX,ey+eyeRy-8);
ctx.stroke();
// Rays converging to focusX
var nR=5;
for(var ri=0;ri<nR;ri++) {
var ry = ey-20 + ri*10;
var atFocus = focusX;
// Color: green=on retina, red=not
var onRetina = Math.abs(focusX - retinaX) < 8;
ctx.strokeStyle = onRetina ? 'rgba(34,197,94,0.8)' : ri%2===0?'rgba(59,130,246,0.7)':'rgba(239,68,68,0.6)';
ctx.lineWidth=1.5;
ctx.beginPath(); ctx.moveTo(ex-eyeRx-40, ry); ctx.lineTo(lx+4,ry);
// After lens → converge to focus
ctx.lineTo(atFocus, ey);
// If focus behind retina — continue
if (atFocus > retinaX+2) {
ctx.setLineDash([3,3]);
ctx.lineTo(atFocus+40, ey + (ey-ry));
ctx.setLineDash([]);
}
ctx.stroke();
}
// Focus dot
var focusColor = Math.abs(focusX - retinaX) < 8 ? '#22c55e' : '#ef4444';
ctx.fillStyle=focusColor;
ctx.beginPath(); ctx.arc(focusX,ey,6,0,Math.PI*2); ctx.fill();
ctx.fillStyle='#fff'; ctx.font='8px sans-serif'; ctx.textAlign='center';
ctx.fillText('F', focusX, ey+4);
// Status text
var onR = Math.abs(focusX - retinaX) < 10;
var statusColor = onR ? '#22c55e' : '#ef4444';
ctx.fillStyle=statusColor; ctx.font='bold 10px sans-serif'; ctx.textAlign='center';
ctx.fillText(onR ? '✓ Фокус на сетчатке — чёткое зрение' :
focusX < retinaX ? '✗ Фокус перед сетчаткой — размыто (близорукость)' :
'✗ Фокус за сетчаткой — размыто (дальнозоркость)', W/2, H-12);
// Labels
ctx.fillStyle='#fbbf24'; ctx.font='8px sans-serif'; ctx.textAlign='center';
ctx.fillText('линза', lx+4, ey+30);
ctx.fillStyle='#22c55e'; ctx.fillText('сетчатка', retinaX+22, ey-eyeRy+5);
var res=document.getElementById('res40');
if(res) res.textContent = (defect==='normal'?'Норма':(defect==='myopia'?'Близорукость':'Дальнозоркость')) +
(glasses?' + очки '+Dgl+' дптр':'') + (onR?' → фокус на сетчатке ✓':' → фокус не на сетчатке ✗');
}
function startAnim40() { upd40(); }
// ═══════════════════════════════════════
// ИНИЦИАЛИЗАЦИЯ
// ═══════════════════════════════════════
document.addEventListener('DOMContentLoaded', function() {
// тема
if (localStorage.getItem('phys8_o_theme')==='dark') document.documentElement.classList.add('dark');
document.getElementById('themeBtn').onclick = function() {
document.documentElement.classList.toggle('dark');
var isDark = document.documentElement.classList.contains('dark');
localStorage.setItem('phys8_o_theme', isDark?'dark':'light');
this.querySelector('i').className = isDark ? 'fas fa-sun' : 'fas fa-moon';
};
// Установить начальную иконку темы
(function(){
var isDark = document.documentElement.classList.contains('dark');
var ic = document.querySelector('#themeBtn i');
if(ic) ic.className = isDark ? 'fas fa-sun' : 'fas fa-moon';
})();
// sidebar навигация
var tabFnsO = {
'ref32': function(){ setTimeout(function(){ if(typeof startAnim32==='function' && !anim32Id) startAnim32(); }, 60); },
'ref33': function(){ setTimeout(function(){ if(typeof startAnim33==='function' && !anim33Id) startAnim33(); }, 60); },
'ref34': function(){ setTimeout(function(){ if(typeof upd34==='function') upd34(); }, 60); },
'ref35': function(){ setTimeout(function(){ if(typeof upd35==='function') upd35(); }, 60); },
'ref36': function(){ setTimeout(function(){ if(typeof upd36==='function') upd36(); }, 60); },
'ref37': function(){ setTimeout(function(){ if(typeof upd37==='function') upd37(); }, 60); },
'ref38': function(){ setTimeout(function(){ if(typeof upd38==='function') upd38(); }, 60); },
'ref39': function(){ setTimeout(function(){ if(typeof startAnim39==='function' && !anim39Id) startAnim39(); }, 60); },
'ref40': function(){ setTimeout(function(){ if(typeof startAnim40==='function' && !anim40Id) startAnim40(); }, 60); }
};
function activateSection(target) {
document.querySelectorAll('.sb-item').forEach(function(b){ b.classList.remove('active'); });
document.querySelectorAll('.content').forEach(function(c){ c.classList.remove('active'); });
var btn = document.querySelector('.sb-item[data-target="'+target+'"]');
if(btn) btn.classList.add('active');
var cont = document.getElementById('tab-'+target);
if(cont) cont.classList.add('active');
if(tabFnsO[target]) tabFnsO[target]();
// Прокрутить main-col вверх
var mc = document.querySelector('.main-col');
if(mc) mc.scrollTop = 0;
else window.scrollTo({top:0,behavior:'smooth'});
}
document.querySelectorAll('.sb-item').forEach(function(btn) {
btn.onclick = function() {
activateSection(this.dataset.target);
};
});
// переключение вкладок ref-panel
window.switchRefTab = function(name) {
document.querySelectorAll('.ref-tab-btn').forEach(function(b){ b.classList.remove('active'); });
document.querySelectorAll('.ref-tab-content').forEach(function(c){ c.classList.remove('active'); });
var btn = document.querySelector('.ref-tab-btn[onclick*="\''+name+'\'"]');
if (btn) btn.classList.add('active');
var cont = document.getElementById('reftab-'+name);
if (cont) cont.classList.add('active');
// render KaTeX в шпаргалке при первом открытии
if (name === 'cheat' && cont && !cont.dataset.katexDone) {
cont.dataset.katexDone = '1';
if (window.renderMathInElement) renderMathInElement(cont, {
delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],
throwOnError:false
});
}
};
// refPanel (popup)
var refRendered = false;
document.getElementById('refToggle').onclick = function(e) {
e.stopPropagation();
var panel = document.getElementById('refPanel');
panel.classList.toggle('show');
if (!refRendered && panel.classList.contains('show')) {
refRendered = true;
if (window.renderMathInElement) renderMathInElement(panel, {
delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],
throwOnError:false
});
}
};
// Закрытие при клике вне панели
document.addEventListener('click', function(e) {
var panel = document.getElementById('refPanel');
var toggle = document.getElementById('refToggle');
if(panel && panel.classList.contains('show') && !panel.contains(e.target) && e.target !== toggle) {
panel.classList.remove('show');
}
});
// задачи — инит
['p32','p33','p34','p35','p36','p37','p38','p39','p40','hard'].forEach(function(sec) {
renderTask(sec);
});
setParaTab('p32');
// KaTeX
if (window.renderMathInElement) {
renderMathInElement(document.body, {
delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],
throwOnError:false
});
}
// первоначальный запуск
setTimeout(function(){ startAnim32(); }, 200);
// ═══════════ PRO MAX UPGRADE ИНИЦИАЛИЗАЦИЯ ═══════════
initProMaxUpgrade();
});
// ═══════════════════════════════════════
// PRO MAX UPGRADE: инфра motion + UX
// ═══════════════════════════════════════
function initProMaxUpgrade(){
// 0. Авто-инжекция ph-glow и ph-badge в каждый hero
document.querySelectorAll('.para-hero').forEach(function(hero, i){
if(!hero.querySelector('.ph-glow')){
var g = document.createElement('span');
g.className = 'ph-glow';
hero.appendChild(g);
}
if(!hero.querySelector('.ph-badge')){
// определить номер § из class ph-N
var n = '';
hero.classList.forEach(function(c){ var m=/^ph-(\d+)$/.exec(c); if(m) n='§'+m[1]; });
if(!n) n='§'+(i+1);
var b = document.createElement('div');
b.className = 'ph-badge';
b.innerHTML = '<i class="fas fa-bookmark" style="font-size:.6rem;margin-right:4px"></i>'+n;
hero.appendChild(b);
}
});
// 1. IntersectionObserver — fade-up для секций при скролле
try{
var io = new IntersectionObserver(function(entries){
entries.forEach(function(e){
if(e.isIntersecting){ e.target.classList.add('is-in'); io.unobserve(e.target); }
});
},{threshold:.12,rootMargin:'0px 0px -40px 0px'});
document.querySelectorAll('.content > *').forEach(function(el){
// не трогаем para-hero — у него своя анимация
if(el.classList.contains('para-hero')) return;
el.classList.add('fx-rise');
io.observe(el);
});
document.querySelectorAll('.formula-grid, .life-grid, .idiag-2col').forEach(function(el){
el.classList.add('fx-stagger');
io.observe(el);
});
}catch(_){/* no-op */}
// 2. Mousemove параллакс на ::after шар у hero
document.querySelectorAll('.para-hero').forEach(function(hero){
hero.addEventListener('mousemove', function(e){
var r = hero.getBoundingClientRect();
var dx = (e.clientX - r.left - r.width/2) / r.width;
var dy = (e.clientY - r.top - r.height/2) / r.height;
hero.style.setProperty('--phx', (dx*12).toFixed(2)+'px');
hero.style.setProperty('--phy', (dy*8).toFixed(2)+'px');
});
});
// 3. Карточки формул: glow-курсор
document.querySelectorAll('.fcard').forEach(function(card){
card.addEventListener('mousemove', function(e){
var r = card.getBoundingClientRect();
card.style.setProperty('--mx', ((e.clientX-r.left)/r.width*100)+'%');
card.style.setProperty('--my', ((e.clientY-r.top)/r.height*100)+'%');
});
});
// 4. Ripple на всех кнопках
document.addEventListener('click', function(e){
var btn = e.target.closest('.btn, .para-pill, .opt-btn, .sb-item');
if(!btn) return;
var r = btn.getBoundingClientRect();
btn.style.setProperty('--rx', ((e.clientX-r.left)/r.width*100)+'%');
btn.style.setProperty('--ry', ((e.clientY-r.top)/r.height*100)+'%');
btn.classList.remove('is-ripple');
// reflow
void btn.offsetWidth;
btn.classList.add('is-ripple');
setTimeout(function(){ btn.classList.remove('is-ripple'); }, 600);
});
// 5. Mini-TOC: нет (заменено sidebar)
// buildMiniToc() — no-op
// 6. Chapter progress — нет (заменено sidebar)
}
// buildMiniToc, markMiniTocActive, updateChapterProgress — заменены sidebar, no-op
function buildMiniToc(){ /* no-op */ }
function markMiniTocActive(t){ /* no-op */ }
function updateChapterProgress(){ /* no-op */ }
// ═══ B1. setupCanvas — утилита для новых интерактивов ═══
function setupCanvas(id, opts){
opts = opts || {};
var cv = document.getElementById(id);
if(!cv) return null;
var dpr = Math.min(window.devicePixelRatio||1, 2);
function resize(){
var W = cv.offsetWidth, H = cv.offsetHeight || (opts.height||220);
cv.width = Math.round(W*dpr); cv.height = Math.round(H*dpr);
var ctx = cv.getContext('2d');
ctx.setTransform(dpr,0,0,dpr,0,0);
return {ctx:ctx, W:W, H:H};
}
var rid = null, paused = false, lastFrame = 0;
var io = null;
if(opts.draw){
var loop = function(now){
if(paused){ rid=null; return; }
var dt = lastFrame ? (now-lastFrame)/1000 : 0.016;
lastFrame = now;
var dims = resize();
opts.draw(dims.ctx, dims.W, dims.H, dt, now);
rid = requestAnimationFrame(loop);
};
// auto-pause when off-screen
try{
io = new IntersectionObserver(function(entries){
entries.forEach(function(e){
if(e.isIntersecting){
if(!rid){ paused=false; lastFrame=0; rid=requestAnimationFrame(loop); }
} else {
paused=true; if(rid){cancelAnimationFrame(rid); rid=null;}
}
});
},{threshold:.05});
io.observe(cv);
}catch(_){}
// initial
paused=false; lastFrame=0; rid=requestAnimationFrame(loop);
} else if(opts.onResize){
var dims = resize();
opts.onResize(dims.ctx, dims.W, dims.H);
}
window.addEventListener('resize', function(){ if(opts.onResize){ var d=resize(); opts.onResize(d.ctx,d.W,d.H);} });
return {
canvas:cv,
stop:function(){ paused=true; if(rid){cancelAnimationFrame(rid); rid=null;} if(io)io.disconnect(); }
};
}
</script>
</body>
</html>