diff --git a/frontend/textbooks/algebra_11_hub.html b/frontend/textbooks/algebra_11_hub.html
index c6e813b..2097ac2 100644
--- a/frontend/textbooks/algebra_11_hub.html
+++ b/frontend/textbooks/algebra_11_hub.html
@@ -127,6 +127,73 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
.fin-placeholder{padding:24px 18px;background:linear-gradient(135deg,var(--pri-soft),rgba(94,234,212,.08));border:1.5px dashed var(--pri);border-radius:14px;text-align:center;color:var(--text)}
.fin-placeholder h3{font-family:'Outfit',sans-serif;color:var(--pri-d);margin-bottom:8px;font-size:1.1rem}
.fin-placeholder p{color:var(--muted);font-size:.92rem;line-height:1.55}
+
+.fin-section-title{font-family:'Outfit',sans-serif;font-size:1.18rem;font-weight:800;color:var(--text);margin:8px 0 14px;letter-spacing:-.005em;display:flex;align-items:center;gap:9px}
+.fin-section-title svg{width:20px;height:20px;stroke:var(--pri);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
+
+/* CHEAT SHEET */
+.cheat-grid{display:grid;grid-template-columns:1fr;gap:14px;margin-bottom:28px}
+@media(min-width:680px){.cheat-grid{grid-template-columns:1fr 1fr}}
+@media(min-width:1000px){.cheat-grid{grid-template-columns:repeat(3,1fr)}}
+.cheat-card{border:1.5px solid var(--border);border-radius:13px;padding:14px 16px;background:var(--card);position:relative;overflow:hidden}
+.cheat-card::before{content:'';position:absolute;left:0;top:0;bottom:0;width:4px}
+.cheat-card.c1::before{background:linear-gradient(180deg,var(--ch1),var(--ch1-d))}
+.cheat-card.c2::before{background:linear-gradient(180deg,var(--ch2),var(--ch2-d))}
+.cheat-card.c3::before{background:linear-gradient(180deg,var(--ch3),var(--ch3-d))}
+.cheat-head{display:flex;align-items:center;gap:9px;margin-bottom:9px;padding-left:6px}
+.cheat-badge{font-size:.7rem;font-weight:800;padding:2px 8px;border-radius:99px;color:#fff;letter-spacing:.05em;text-transform:uppercase}
+.cheat-card.c1 .cheat-badge{background:var(--ch1)}
+.cheat-card.c2 .cheat-badge{background:var(--ch2)}
+.cheat-card.c3 .cheat-badge{background:var(--ch3)}
+.cheat-title{font-weight:800;color:var(--text);font-size:.98rem}
+.cheat-list{list-style:none;padding-left:6px;margin:0}
+.cheat-list li{padding:6px 0;border-bottom:1px dashed var(--border);font-size:.92rem;line-height:1.5;color:var(--text)}
+.cheat-list li:last-child{border-bottom:0}
+
+/* BOSS PROGRESS */
+.boss-overall-bar{background:linear-gradient(135deg,rgba(13,148,136,.08),rgba(94,234,212,.06));border:1px solid var(--border);border-radius:12px;padding:13px 16px;margin:6px 0 18px;display:flex;gap:14px;align-items:center;flex-wrap:wrap}
+.boss-overall-bar .lab{font-weight:700;font-size:.95rem;color:var(--text);min-width:200px}
+.boss-overall-bar .bar{flex:1;min-width:160px;height:9px;background:rgba(13,148,136,.14);border-radius:5px;overflow:hidden}
+.boss-overall-bar .fill{height:100%;background:linear-gradient(90deg,var(--pri),#5eead4,#f59e0b);transition:width .5s;border-radius:5px}
+
+/* BOSS CARDS */
+.boss-card{background:var(--card);border:2px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;transition:border-color .35s,box-shadow .35s,transform .2s}
+.boss-card.solved{border-color:#10b981;box-shadow:0 0 0 3px rgba(16,185,129,.18)}
+.boss-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
+.boss-tag{font-size:.7rem;font-weight:800;padding:3px 9px;border-radius:99px;background:rgba(13,148,136,.14);color:var(--pri-d);letter-spacing:.04em;text-transform:uppercase}
+html.dark .boss-tag{color:#5eead4}
+.boss-title{font-family:'Outfit',sans-serif;font-weight:800;color:var(--text);font-size:1.02rem;flex:1;min-width:0}
+.boss-q{padding:12px 14px;background:rgba(13,148,136,.06);border-radius:10px;font-size:.96rem;line-height:1.55;margin-bottom:10px;color:var(--text)}
+.boss-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
+.boss-input{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);font-family:'JetBrains Mono',monospace;width:130px;text-align:center;font-size:.95rem;transition:border-color .15s}
+.boss-input:focus{outline:0;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-soft)}
+.boss-btn{padding:8px 16px;border-radius:9px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:700;font-size:.88rem;cursor:pointer;font-family:inherit;transition:background .15s,border-color .15s,transform .1s}
+.boss-btn:hover{background:var(--pri-soft);border-color:var(--pri)}
+.boss-btn:active{transform:scale(.96)}
+.boss-btn.primary{background:linear-gradient(135deg,var(--pri),#0891b2);color:#fff;border-color:transparent}
+.boss-btn.primary:hover{filter:brightness(1.08)}
+.boss-fb{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none;line-height:1.45}
+.boss-fb.ok{display:block;background:#d1fae5;color:#065f46;border-left:4px solid #10b981}
+.boss-fb.fail{display:block;background:#fee2e2;color:#7f1d1d;border-left:4px solid #dc2626}
+html.dark .boss-fb.ok{background:rgba(16,185,129,.18);color:#a7f3d0}
+html.dark .boss-fb.fail{background:rgba(220,38,38,.18);color:#fecaca}
+.boss-hint-txt{margin-top:8px;padding:9px 13px;background:rgba(245,158,11,.12);border-left:3px solid #f59e0b;border-radius:6px;font-size:.86rem;color:var(--text);display:none;line-height:1.5}
+.boss-hint-txt.show{display:block}
+
+/* FINAL CTA */
+.final-cta{margin-top:24px;padding:18px 20px;border-radius:14px;background:linear-gradient(135deg,#fef3c7,#fde68a);border:1.5px solid #fbbf24;display:none;align-items:center;gap:14px;flex-wrap:wrap}
+.final-cta.show{display:flex}
+html.dark .final-cta{background:linear-gradient(135deg,rgba(245,158,11,.18),rgba(217,119,6,.15));border-color:#d97706}
+.final-cta-icon{width:48px;height:48px;border-radius:12px;background:linear-gradient(135deg,#fbbf24,#f59e0b);display:flex;align-items:center;justify-content:center;flex-shrink:0}
+.final-cta-icon svg{width:28px;height:28px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
+.final-cta-txt{flex:1;min-width:180px}
+.final-cta-title{font-weight:800;color:#92400e;font-size:1.05rem;font-family:'Outfit',sans-serif}
+html.dark .final-cta-title{color:#fde68a}
+.final-cta-sub{font-size:.86rem;color:#78350f;margin-top:2px}
+html.dark .final-cta-sub{color:#fcd34d}
+.final-cta-btn{padding:10px 18px;border-radius:10px;background:linear-gradient(135deg,var(--pri),#0891b2);color:#fff;text-decoration:none;font-weight:800;font-size:.9rem;display:inline-flex;align-items:center;gap:7px;transition:filter .15s}
+.final-cta-btn:hover{filter:brightness(1.1)}
+.final-cta-btn svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
@@ -243,9 +310,77 @@ main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
-
-
В разработке (Phase 4)
-
Итоговая шпаргалка и набор интегрированных боссов по всем 10 параграфам будут добавлены в Phase 4. Сейчас доступны главы 1–3 в режиме skeleton.
+
+
+
+
+
+ Гл. 1
+ Обобщение степени
+
+
+ - $a^{m/n} = \sqrt[n]{a^m}$
+ - Свойства: $a^p \cdot a^q = a^{p+q}$, $(a^p)^q = a^{pq}$, $(ab)^p = a^p b^p$
+ - $y = x^\alpha$ — 6 типов в зависимости от $\alpha$
+ - $\log_a b = c \Leftrightarrow a^c = b$
+ - Осн. тождество: $a^{\log_a b} = b$
+
+
+
+
+ Гл. 2
+ Показательная функция
+
+
+ - $y = a^x$, $a > 0, a \ne 1$. $D = \mathbb{R}$, $E = (0; +\infty)$
+ - $a > 1$ — возрастает, $0 < a < 1$ — убывает
+ - $a^{f(x)} = a^{g(x)} \Leftrightarrow f(x) = g(x)$
+ - Методы: одно осн., замена ($t = a^x > 0$), однород., граф.
+ - Нер-ва: знак сохр. при $a > 1$, меняется при $a < 1$
+
+
+
+
+ Гл. 3
+ Логарифмическая функция
+
+
+ - $\log_a (bc) = \log_a b + \log_a c$, $\log_a \dfrac{b}{c} = \log_a b - \log_a c$
+ - $\log_a b^n = n \log_a b$, $\log_a b = \dfrac{\log_c b}{\log_c a}$
+ - $y = \log_a x$: $D = (0; +\infty)$, $E = \mathbb{R}$, обр. к $a^x$
+ - Уравнения и нер-ва: ВСЕГДА учитываем ОДЗ ($f(x) > 0$)
+ - $a > 1$ — знак сохр., $0 < a < 1$ — меняется
+
+
+
+
+
+
+ 7 интегрированных боссов
+
+
+
+
Боссов побеждено: 0 / 7
+
+
+
+
+
+
+
+
+
Курс Алгебра 11 пройден!
+
Вы прошли всю итоговую проверку курса. +50 XP, ачивка «Магистр алгебры 11» получена.
+
+
+ К каталогу учебников
+
+
@@ -354,6 +489,264 @@ function renderProgress(children) {
}
}
+/* COURSE FINAL — lazy bosses */
+var FIN_BOSS_KEY = 'algebra11_course_bosses';
+
+var FIN_BOSSES = [
+ {
+ n: 1,
+ title: 'Степень + Логарифм',
+ tag: 'Гл. 1',
+ q: 'Вычислите: $4^{\\log_2 5}$.',
+ hint: '$4 = 2^2$, поэтому $4^{\\log_2 5} = 2^{2 \\log_2 5} = 2^{\\log_2 25}$.',
+ ans: 25,
+ step: '1'
+ },
+ {
+ n: 2,
+ title: 'Показательное уравнение через замену',
+ tag: 'Гл. 2',
+ q: 'Решите $4^x - 3 \\cdot 2^x + 2 = 0$. Найдите
сумму корней.',
+ hint: 'Замена $t = 2^x$: $t^2 - 3t + 2 = 0$. Найдите $t_1, t_2$, затем $x_1, x_2$.',
+ ans: 1,
+ step: '1'
+ },
+ {
+ n: 3,
+ title: 'Логарифмическое неравенство с ОДЗ',
+ tag: 'Гл. 3',
+ q: 'Решите $\\log_{1/2} (x - 1) > -2$. Какое
наибольшее целое $x$ удовлетворяет?',
+ hint: 'ОДЗ: $x > 1$. $-2 = \\log_{1/2} 4$. При $a < 1$ знак меняется: $x - 1 < 4$.',
+ ans: 4,
+ step: '1'
+ },
+ {
+ n: 4,
+ title: 'Свойства логарифмов',
+ tag: 'Гл. 3',
+ q: 'Упростите $\\log_2 48 - \\log_2 3$.',
+ hint: 'Разность логарифмов = логарифм частного: $\\log_2 \\dfrac{48}{3} = \\log_2 16$.',
+ ans: 4,
+ step: '1'
+ },
+ {
+ n: 5,
+ title: 'Графический синтез',
+ tag: 'Гл. 2 + Гл. 3',
+ q: 'Сколько решений имеет уравнение $2^x = 6 - x$?',
+ hint: '$y = 2^x$ возрастает, $y = 6 - x$ убывает. При $x = 2$: $4 = 4$ ✓. Пересечение возр. и убыв. графиков.',
+ ans: 1,
+ step: '1'
+ },
+ {
+ n: 6,
+ title: 'Логарифмирование показательного',
+ tag: 'Гл. 2 + Гл. 3',
+ q: 'Решите $5^{2x} = 7$. Введите $x$ в виде десятичной дроби (округлите до сотых, допуск 0.05).',
+ hint: '$2x = \\log_5 7 = \\dfrac{\\lg 7}{\\lg 5} \\approx \\dfrac{0{,}845}{0{,}699}$. Затем $x = \\dfrac{\\log_5 7}{2}$.',
+ ans: 0.60,
+ tol: 0.05,
+ step: '0.01'
+ },
+ {
+ n: 7,
+ title: 'Магистр функций',
+ tag: 'синтез всех 3 глав',
+ q: 'При каком целом $a$ функция $y = (5 - a)^x$ возрастает на $\\mathbb{R}$? Введите
наибольшее такое целое $a$ из множества $\\{1, 2, 3, 4\\}$.',
+ hint: 'Для возрастания $y = b^x$ нужно $b > 1$, т.е. $5 - a > 1 \\Rightarrow a < 4$.',
+ ans: 3,
+ step: '1'
+ }
+];
+
+function loadFinBossState(){
+ try { return JSON.parse(localStorage.getItem(FIN_BOSS_KEY) || '{}') || {}; }
+ catch(e) { return {}; }
+}
+function saveFinBossState(s){
+ try { localStorage.setItem(FIN_BOSS_KEY, JSON.stringify(s)); } catch(e){}
+}
+
+function finRenderKatex(root){
+ if (typeof window.renderMathInElement !== 'function') return;
+ try {
+ window.renderMathInElement(root, {
+ delimiters: [
+ {left: '$$', right: '$$', display: true},
+ {left: '$', right: '$', display: false}
+ ],
+ throwOnError: false
+ });
+ } catch(e){}
+}
+
+function updateFinBossBar(state){
+ var won = 0;
+ for (var k in state) if (state[k]) won++;
+ var lab = document.getElementById('fin-boss-lab');
+ var fill = document.getElementById('fin-boss-fill');
+ if (lab) lab.textContent = 'Боссов побеждено: ' + won + ' / ' + FIN_BOSSES.length;
+ if (fill) fill.style.width = Math.round(won * 100 / FIN_BOSSES.length) + '%';
+ return won;
+}
+
+function maybeUnlockMaster(state){
+ if (localStorage.getItem(FIN_ACH_KEY) === '1') return;
+ var won = 0;
+ for (var k in state) if (state[k]) won++;
+ if (won < FIN_BOSSES.length) return;
+
+ localStorage.setItem(FIN_ACH_KEY, '1');
+
+ /* +50 XP */
+ var xp = parseInt(localStorage.getItem('algebra11_xp') || '0', 10) || 0;
+ localStorage.setItem('algebra11_xp', String(xp + 50));
+
+ /* trigger global XP system if available */
+ try {
+ if (window.LS && typeof window.LS.addXp === 'function') {
+ window.LS.addXp(50, 'algebra11-master');
+ } else if (typeof window.addXp === 'function') {
+ window.addXp(50, 'algebra11-master');
+ }
+ } catch(e){}
+
+ /* confetti */
+ try { if (typeof window.confetti === 'function') window.confetti({particleCount: 160, spread: 90, origin: {y: .6}}); } catch(e){}
+
+ /* light up ach-strip */
+ var strip = document.getElementById('ach-strip');
+ var sub = document.getElementById('ach-sub');
+ if (strip) strip.classList.add('lit');
+ if (sub) sub.textContent = 'Выполнено! Вы — Магистр алгебры 11.';
+
+ /* show CTA */
+ var cta = document.getElementById('final-cta');
+ if (cta) cta.classList.add('show');
+
+ /* refresh XP badge */
+ var xpBadge = document.getElementById('hero-xp-badge');
+ if (xpBadge) {
+ var newXp = parseInt(localStorage.getItem('algebra11_xp') || '0', 10) || 0;
+ xpBadge.style.display = '';
+ xpBadge.textContent = newXp + ' XP';
+ }
+}
+
+function buildFinBoss(b, state){
+ var solvedClass = state[b.n] ? ' solved' : '';
+ var step = b.step || '1';
+ var displayAns = (typeof b.ans === 'number' && step !== '1') ? b.ans.toFixed(2) : b.ans;
+ return '
'
+ + '
'
+ + '' + b.tag + ''
+ + 'Босс ' + b.n + '. ' + b.title + ''
+ + '
'
+ + '
' + b.q + '
'
+ + '
'
+ + ''
+ + ''
+ + ''
+ + '
'
+ + '
' + b.hint + '
'
+ + '
' + (state[b.n] ? 'Победа! +15 XP. Босс уже повержен.' : '') + '
'
+ + '
';
+}
+
+function bindFinBoss(b){
+ var state = loadFinBossState();
+ var goBtn = document.getElementById('fin-boss-' + b.n + '-go');
+ var hintBtn = document.getElementById('fin-boss-' + b.n + '-hint');
+ var inp = document.getElementById('fin-boss-' + b.n + '-inp');
+ var fb = document.getElementById('fin-boss-' + b.n + '-fb');
+ var hintTx = document.getElementById('fin-boss-' + b.n + '-hinttxt');
+ var card = document.getElementById('fin-boss-' + b.n + '-card');
+ if (!goBtn) return;
+
+ if (hintBtn) hintBtn.addEventListener('click', function(){
+ if (hintTx) hintTx.classList.toggle('show');
+ });
+
+ if (state[b.n]) return; /* already solved */
+
+ goBtn.addEventListener('click', function(){
+ var v = parseFloat((inp.value || '').replace(',', '.'));
+ if (isNaN(v)) {
+ fb.className = 'boss-fb fail';
+ fb.textContent = 'Введите число.';
+ return;
+ }
+ var tol = (typeof b.tol === 'number') ? b.tol : 1e-9;
+ if (Math.abs(v - b.ans) < tol) {
+ fb.className = 'boss-fb ok';
+ fb.textContent = 'Победа! +15 XP. Босс повержен.';
+ card.classList.add('solved');
+ goBtn.disabled = true;
+ inp.disabled = true;
+
+ var s = loadFinBossState();
+ if (!s[b.n]) {
+ s[b.n] = true;
+ saveFinBossState(s);
+
+ /* +15 XP */
+ var xp = parseInt(localStorage.getItem('algebra11_xp') || '0', 10) || 0;
+ localStorage.setItem('algebra11_xp', String(xp + 15));
+ try {
+ if (window.LS && typeof window.LS.addXp === 'function') window.LS.addXp(15, 'fin-boss-' + b.n);
+ else if (typeof window.addXp === 'function') window.addXp(15, 'fin-boss-' + b.n);
+ } catch(e){}
+
+ var xpBadge = document.getElementById('hero-xp-badge');
+ if (xpBadge) {
+ var nXp = parseInt(localStorage.getItem('algebra11_xp') || '0', 10) || 0;
+ xpBadge.style.display = '';
+ xpBadge.textContent = nXp + ' XP';
+ }
+
+ updateFinBossBar(s);
+ maybeUnlockMaster(s);
+ }
+ } else {
+ fb.className = 'boss-fb fail';
+ fb.textContent = 'Не то. Перепроверь решение и попробуй снова.';
+ }
+ });
+
+ inp.addEventListener('keydown', function(e){
+ if (e.key === 'Enter') { e.preventDefault(); goBtn.click(); }
+ });
+}
+
+var FIN_BOSSES_RENDERED = false;
+function renderFinBosses(){
+ if (FIN_BOSSES_RENDERED) return;
+ var cont = document.getElementById('fin-bosses-container');
+ if (!cont) return;
+ var state = loadFinBossState();
+ var html = '';
+ for (var i = 0; i < FIN_BOSSES.length; i++) html += buildFinBoss(FIN_BOSSES[i], state);
+ cont.innerHTML = html;
+ for (var j = 0; j < FIN_BOSSES.length; j++) bindFinBoss(FIN_BOSSES[j]);
+
+ var wrap = document.getElementById('course-final');
+ finRenderKatex(wrap);
+
+ updateFinBossBar(state);
+
+ /* if already mastered: show CTA */
+ if (localStorage.getItem(FIN_ACH_KEY) === '1') {
+ var cta = document.getElementById('final-cta');
+ if (cta) cta.classList.add('show');
+ var strip = document.getElementById('ach-strip');
+ var sub = document.getElementById('ach-sub');
+ if (strip) strip.classList.add('lit');
+ if (sub) sub.textContent = 'Выполнено! Вы — Магистр алгебры 11.';
+ }
+
+ FIN_BOSSES_RENDERED = true;
+}
+
/* FINAL ACCORDION */
(function bindFinalAccordion(){
var head = document.getElementById('final-head');
@@ -364,6 +757,10 @@ function renderProgress(children) {
var willOpen = !wrap.classList.contains('open');
wrap.classList.toggle('open');
head.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
+ if (willOpen) {
+ renderFinBosses();
+ finRenderKatex(wrap);
+ }
}
head.addEventListener('click', toggle);
@@ -372,6 +769,16 @@ function renderProgress(children) {
});
})();
+/* sync ach-strip + CTA on load if already mastered */
+(function syncMasterOnLoad(){
+ if (localStorage.getItem(FIN_ACH_KEY) === '1') {
+ var strip = document.getElementById('ach-strip');
+ var sub = document.getElementById('ach-sub');
+ if (strip) strip.classList.add('lit');
+ if (sub) sub.textContent = 'Выполнено! Вы — Магистр алгебры 11.';
+ }
+})();
+
function loadProgress() {
if (typeof window.LS === 'undefined' || typeof window.LS.api !== 'function') {
renderProgress([]);