§9 Босс 2: в условии было h=12 см, но правильный ответ S=10
требует h=8 см. Подправлены число в условии и подсказка.
§11 Теорема Пифагора:
- Card 11.1: 'квадраты на сторонах' были нарисованы как тонкие
прямоугольники (140×20 и 20×100). Заменены на настоящие квадраты
80×80 (a²) и 60×60 (b²). ViewBox увеличен до 200×255.
- Интерактив 1 (слайдер катетов): sqAh=min(40,ax*0.4) и sqBw=min(40,bx*0.4)
давали прямоугольники, не квадраты. Теперь квадраты ax×ax и bx×bx
с динамическим viewBox.
§12 Босс 3: в объекте задачи ans=144, но проверка использовала
correct[2]=62 — противоречие. Исправлено ans=62 + чистая подсказка.
Final2 Босс 1: маркер прямого угла в основании высоты H был
ориентирован неправильно (вертикально вниз). Пересчитан через
единичные векторы вдоль BC и перпендикуляра.
Всего проверено 21 SVG, исправлено 5. Остальные §10, §13, §14, §15 — OK.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
§9 Треугольники с общей высотой: SVG draggable с общей стороной AB и
двумя вершинами C/D на параллельной прямой, live S₁/S₂=a₁/a₂,
анимация-доказательство, калькулятор, тренажёр, босс.
§10 Медиана и площади: SVG draggable треугольник с медианой AM делит
на 2 равновеликих, отдельная визуализация всех 3 медиан → 6 равновеликих
треугольников с центроидом G, доказательство, калькулятор, тренажёр, босс.
§11 Теорема Пифагора (ключевая): слайдеры катетов с квадратами a², b², c²
на сторонах, анимация доказательства через квадрат (a+b)², калькулятор
(a,b→c; c,a→b; диагональ прямоугольника), DnD-сортировщик пифагоровых
троек (3-4-5, 5-12-13, 6-8-10, 7-24-25, 9-12-15), тренажёр, босс (5 задач).
File: 3998 → 5118 LOC. 11 of 15 §§ Главы 2 готовы.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
§5 Draggable трапеция:
- Высота теперь рисуется как вертикальная пунктирная линия В СЕРЕДИНЕ
трапеции от верхнего основания до нижнего (с прямым углом у основания),
а не уходит вертикально вверх от вершины A вне фигуры
- Жёлтый drag-handle для h перенесён в вершину D (верх-лево) — тащишь
её вертикально и высота меняется. Синий drag-handle для b остался в C.
- Добавлены подписи всех вершин ABCD точками и Unbounded-буквами
- Подсказки в углу SVG что какой цвет означает
§5 Пошаговое доказательство:
- Полностью переписана геометрия с КОРРЕКТНЫМ поворотом на 180°
вокруг середины M боковой стороны BC (формула P'=2M-P)
- Раньше копия трапеции уходила за пределы viewBox (y=-20)
- Теперь 4 шага: трапеция → поворот вокруг M → параллелограмм ABD'A' →
половина = трапеция, формула S=½(a+b)h
§8 Прямые углы:
- Card 8.1: треугольник A(20,150) B(220,150) C(92,54) — НАСТОЯЩИЙ
прямоугольный 3-4-5 с h_c=ab/c (раньше координаты не давали 90° в C)
- Card 8.2: оба треугольника теперь корректные прямоугольные с прямыми
углами на правильных вершинах
- Card 8.3: треугольник 6-8-10, маркер прямого угла в H пересчитан
через единичные векторы H→C и H→A (раньше показывал не то направление)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Системный аудит 62 статических SVG в теоретических карточках выявил
2 мелких косяка:
Ch1 §10 (квадрат, карточка 10.2): не хватало прямоугольных меток в
двух верхних углах — у квадрата были обозначены только нижние.
Добавлены маркеры в (68,24) и (168,24).
Ch2 §2 (прямоугольник, карточка 2.2 — периметр): на верхней стороне
у стрелки была ссылка marker-end='url(#a2)', но сам marker #a2 в SVG
не определён → битая ссылка. Убрана для консистентности с остальными
тремя сторонами.
KaTeX-форматирование: проверено во всех 24 buildP-функциях обеих глав —
везде используются корректные $...$ / $$...$$ / \[...\] делиметры.
Конвертаций не потребовалось.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Было:
- 5.1: высота нарисована из вершины (некорректно как иллюстрация
'расстояние между параллельными сторонами')
- 5.2: координаты треугольников ABD/BCD и диагонали указывали на точки
ВНЕ трапеции (диагональ заканчивалась в (215,30) вместо вершины D=(65,30))
- 5.3: то же — высота из вершины
Стало:
- Высота — вертикальная пунктирная линия в середине трапеции от верхнего
основания до нижнего, с прямым углом
- Все вершины ABCD подписаны и отмечены точками
- В 5.2 диагональ BD корректно проведена, треугольники ABD/BCD точно
совпадают с половинами трапеции, добавлены подписи S₁=½ah, S₂=½bh
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Было: продолжение рисовалось от next-vertex назад через v, дуга центрировалась
у next-vertex с углом из произвольного направления — углы отображались
неправильно (не у тех вершин, не в тех направлениях).
Стало: для каждой вершины v вычисляются prev/next, направления u=(v-prev)/|·|
(входящая сторона), w=(next-v)/|·| (исходящая). Продолжение u рисуется от v
дальше. Дуга — сектор у v от u-направления до w-направления, sweep
определяется через знак векторного произведения (u×w). Подпись угла —
по биссектрисе дуги на радиусе Rlabel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drag (12 SVG-интерактивов): pointermove/pointerup/pointercancel слушались на
самом vertex-элементе. При выходе курсора за пределы маленького круга drag
обрывался — отсюда эффект 'нажал, чуть-чуть потянулось, и всё'. Перенесены
на window — теперь работают как нативный drag.
§7 (Прямоугольник): info-карточка показывала 'AC = BD' с одним значением.
Теперь две отдельные карточки AC и BD + индикатор равенства (зелёная плашка
'Диагонали равны' / красная 'Не равны' с Δ).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
В функции drawProof пошагового доказательства §4 использовалась переменная
cy без определения (была только cx). Это приводило к ReferenceError при
вызове buildP4, и из-за throw в ensureBuilt секция §4 не открывалась
при клике на карточку в селекторе параграфов.
Проверено: все 17 параграфов главы (p1-p16, final1) теперь строятся без ошибок.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Часть 1: 9 mini-cards с формулами всех 16 параграфов (KaTeX).
Часть 2: интерактивная SVG-карта иерархии четырёхугольников
(клик по узлу — подсветка свойств).
Часть 3: 7 интегрированных боссов (по 10 XP):
- Босс 1: многоугольник из суммы углов 1620°
- Босс 2: параллелограмм через треугольник ABD
- Босс 3: средние линии прямоугольника → ромб
- Босс 4: ромб 60° → диагонали (Пифагор)
- Босс 5: теорема Фалеса, 3 подзадачи
- Босс 6: треугольник 12-16-20 — средняя линия + медиана + центроид
- Босс 7: равнобедренная трапеция 20/8/10
Часть 4: при победе над всеми — achievement 'Мастер многоугольников Главы 1',
+50 XP бонус, confetti, кнопка перехода к Главе 2.
File: 5194 → 5558 LOC. Глава 1 полностью наполнена.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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'ом.
После переименования slug algebra-8 → algebra-8-ch1 (миграция 014) Глава 1
продолжала POSTить прогресс под старым именем 'algebra-8', который теперь
указывает на hub-строку. Эффект: paragraphs_read и last_para уходили в
hub-row, а каталог хабов их игнорировал (агрегирует только children).
Фикс:
- algebra_8.html: _TB_SLUG = 'algebra-8-ch1'
- migration 016: union перенос ошибочно записанного прогресса из hub в
ch1; очистка hub-row. Идемпотентно (NOT EXISTS guard).
Проверено: после миграции у user 2 paragraphs_read='["p1"]' живёт в
ch1-row, hub-row пуста.
Другие учебники проверены — корректно:
- ch2/ch3 уже использовали правильные slug
- chemistry-9, physics-9, physics8_* подключены через textbook-tracker
- algebra_8_hub.html и physics_8.html — хабы без tracker (правильно)
A. textbook-tracker.js: первый клик по .para-pill теперь автоматически
помечает параграф как прочитанный. «Прочитано» = «открыто». Сразу
даёт осмысленный счётчик для chemistry-9 и physics-9 в каталоге.
Slug fallback: physics8_* → physics-8-* (корректный слаг).
B. Физика 8 — миграция 015:
- 3 children: physics-8-thermal / electro / optics с parent_slug
- parent физики-8 обновлён: para_count=40, описание трёх разделов
- sub-файлы получили textbook-tracker.js + правильный слаг
- physics_8.html переписана в стиле algebra_8_hub: 3 цветные
карточки, агрегированный прогресс, ачивка «Эксперт физики 8»
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- migration 014: parent_slug column + algebra-8 hub row +
rename old algebra-8 → algebra-8-ch1 (progress сохраняется
через стабильный textbook_id=3)
- backend/routes/textbooks.js: GET / фильтрует parent_slug IS NULL;
aggregated progress для хабов; новый GET /:slug/children
- algebra_8_hub.html: новая хаб-страница с 3 карточками глав,
hero с общим прогрессом, XP-бейдж, ссылки на главы
- algebra_8/ch2/ch3: кнопки cross-chapter заменены на
одну «К алгебре 8» в шапке
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- js/textbook-xp-widget.js: shared модуль (monkey-patch addXp +
para-pill auto-award для учебников без addXp)
- physics8_thermal/electro/optics: добавлены теги /js/xp.js и
/js/textbook-xp-widget.js — теперь все 74 addXp-хука пробрасываются
в глобальный gamification (через self-award endpoint с дебаунсом)
- chemistry_9 + physics_9: те же теги. Каждый первый клик по
.para-pill даёт +5 XP в систему (без правок 23000 LOC)
- Изначальный XP в учебниках не теряется — localStorage остаётся
кешем, сервер — источник правды
§ Финал главы 3:
- BOSS ARENA: 7 боссов (5–7 заданий каждый, иконки <>, ±, [], ∩, ∪, 1/x, ★):
· §13 Хранитель сравнения — свойства, транзитивность, смена знака
· §14 Алхимик границ — оценки x+y, x-y, xy
· §15 Архитектор промежутков — линейные неравенства, запись
· §16 Дирижёр пересечений — системы и совокупности
· §17 Мастер параболы — квадратные, D, корни
· §18 Властелин ОДЗ — дробно-рац., выколотые точки
· ★ Чемпион неравенств (финал) — 7 заданий из всей главы
- Универсальный движок select / yesno / input, HP-бар, состояние в localStorage
- Сертификат «Чемпион неравенств» при всех 7 победах
Увлекательная математика (3 факта):
- Почему меняется знак при умножении на отрицательное
- Кто придумал знаки $<$ и $>$ (Хэрриот, 1631)
- Неравенство Коши (a+b)/2 ≥ √(ab)
Финальная практика — генератор 5 типов задач (линейные, оценка,
системы, квадратные, ОДЗ). Серия из 5 = достижение.
algebra_8.html: добавлена ссылка «Глава 3 →» в шапке.
§ 17 «Квадратные неравенства. Метод интервалов»:
- Теория: парабола, метод интервалов, правило знаков
- INTERACT 1: SVG-парабола + слайдеры a, b, c с цветовой раскраской
на оси: зелёные зоны = выражение > 0, красные = < 0. Корни как
точки. Внизу — текстовый анализ (D, корни, решение для >0 и <0).
- INTERACT 2: Пошаговый решатель — D, корни, знаки, ответ
(4-5 шагов с обработкой D<0 и D=0)
- INTERACT 3: Тренажёр 6 квадратных (multiple-choice)
- INTERACT 4: Drag-сопоставление (a, D, направление неравенства) →
тип ответа: вне корней / между / R / пусто
- INTERACT 5: «Где плюс, где минус?» — кликаем по 3 интервалам
параболы x²−4x+3, ставим знаки. Победа = +, -, +.
§ 18 «Дробно-рациональные»:
- Теория: f/g ≷ 0, выколотые точки знаменателя, алгоритм
- INTERACT 1: Пошаговый решатель (x-a)/(x-b) ≥ 0 с учётом a vs b
(включая случай a == b)
- INTERACT 2: Тренажёр 6 неравенств (multiple-choice)
- INTERACT 3: Найди ОДЗ — 5 выражений, вводим запрещённые точки
- INTERACT 4: Drag «закрашена/выколота» — 8 ситуаций
Раньше: алгебра 1 и 2 главы хранили прогресс только в localStorage,
поэтому каталог /textbooks показывал 0/N прочитано и кнопку 'Открыть'
даже после активной работы с учебником.
Теперь обе главы шлют POST /api/textbooks/:slug/progress:
- markLastPara(id) — при каждом goTo(); сервер запоминает last_para,
каталог показывает кнопку 'Продолжить'.
- markParaRead(id) — когда STATE.progress[key] первый раз ≥ 50%
(внутрипараграфный прогресс достаточен); сервер добавляет id в
paragraphs_read[], каталог показывает '1/7 прочитано'.
- Дебаунс 600мс — несколько быстрых переходов схлопываются в один POST.
- keepalive:true + beforeunload-flush, чтобы последний переход не
потерялся при закрытии вкладки.
- loadServerReadState() при init() — если на другом устройстве уже
прочитаны параграфы, локальный STATE.progress поднимается до 100%
для них (визуально совпадает с каталогом).
Slug: 'algebra-8' для ch1, 'algebra-8-ch2' для ch2.
- backend: POST /api/gamification/self-award (rate-limited, validated)
- frontend/js/xp.js: load/add/flush/on клиент, ~150 LOC, дебаунс 300мс,
keepalive fetch на unload/visibilitychange hidden
- algebra_8.html и algebra_8_ch2.html: XP_LEVELS заменён на единую
формулу с сервером; addXp/loadProgress подключены к window.LS.xp
- При первой загрузке: merge max(local, server); далее сервер — источник
правды
Раньше: каждая глава хранила XP отдельно (algebra8_ch1_xp +
algebra8_ch2_xp), формулы уровня были разные (дискретная таблица в
ch1, формула sqrt в ch2), визуально XP-карты различались.
Теперь:
- Один ключ localStorage: 'algebra8_xp' для обеих глав.
- При первой загрузке (в любой главе) — single-shot миграция:
если новый ключ отсутствует, суммирует старые ch1 + ch2 и
сохраняет под единый ключ. Старые ключи не удаляются (на всякий).
- Единая таблица уровней XP_LEVELS = [0, 50, 120, 220, 350, 520,
740, 1000, 1300, 1700, 2200] (11 уровней, MAX = Ур. 11).
- Единые функции calcLevel(xp) и _xpForLevel(lv).
- XP-карта в сайдбаре главы 2 теперь идентична главе 1:
градиент acc→pri-soft, .xp-card-title, .xp-bar, .xp-fill, .xp-nums.
- Hero badge «★ Ур. N · NN XP» добавлен в hero обоих глав.
- addXp в ch2: при повышении уровня — popup с номером уровня + confetti.
- addXp в ch1: refreshProgressUI вызывается, чтобы обновлять hero
badge сразу после начисления.
- SIDEBARS.final2: убрал stub 'будет в Wave 4', добавил 5 строк по
финалу (7 боссов, типы заданий, награда, практика, серия).
- XP card в сайдбаре: уровень (Lv N), текущий XP, прогресс-бар до
следующего уровня, остаток XP. Формула: Lv = floor(sqrt(xp/50)).
- XP badge в hero (рядом с прогрессом): жёлто-розовая пилюля
«★ Lv N · NN XP», обновляется при каждом addXp.
- TIPS: 7 советов (по одному на каждый §+финал). В сайдбаре отдельная
карточка «Подсказка» с жёлтым градиентом — контекстная под текущий
параграф.
- refreshProgressUI: после изменения XP пересобирает сайдбар, чтобы
карточки опыта/совета оставались актуальными.
Универсальный хелпер setupSorter(cfg) с pointer-events:
- desktop: тащим карточку → подсветка целевого ящика → отпускаем = поставлено
- touch / mobile: тап по карточке (становится "armed") → тап по ящику = поставлено
- × кнопка на placed-чипе → возврат в pool
- drop за пределы ящика на сам pool тоже возвращает чип
- threshold 8px — клик не превращается в drag случайно
Стили: .dnd-chip с cursor:grab/active grabbing, .armed shadow,
.dragging opacity, .drop-box.over подсветка с лёгким scale.
Применено к:
- § 7 INT 2 (полное / неполное / не квадратное) — 8 уравнений
- § 10 INT 5 (раскладывается / не раскладывается) — 8 трёхчленов
- § 11 INT 5 (движение / работа / числа / геометрия) — 8 задач,
columnLayout:true для длинных текстов
Старые «лесенки кнопок Полн./Неполн./Не квадр.» удалены — теперь
один-клик-затем-один-клик или drag. § 12 INT 4 оставлен как
<select> (другой паттерн: одна метка для нескольких уравнений).
Три «пошаговых» решателя дампили все шаги сразу при первом клике.
Переписаны на прогрессивное раскрытие:
- § 8 INT 5 «Пошаговый решатель» (квадратное)
- § 10 INT 2 «Пошаговый разлагатель»
- § 12 INT 1 «Решатель биквадратного»
Паттерн: Старт → шаги собираются в массив, idx=0 → Дальше (1/N) →
каждый шаг — отдельный блок с border-left и fadeIn. По окончании —
кнопка «Готово», начисление достижения и confetti. Кнопка «Сначала»
сбрасывает к Старту.
Ещё: § 8 INT 4 — $D = b^2 - 4ac$ показывался буквально с долларами,
потому что использовался textContent + renderMath на чужом элементе.
Заменено на innerHTML + renderMath на правильный узел.
- Слайдеры (.sliders label): убран flex-direction:column, который раскладывал
KaTeX-span / '=' / <b> / <input> на 4 строки. Теперь label = block,
всё на одной строке, slider — на следующей.
- .wg-help: вместо мелкого курсива — полноценный hint-box с жёлтым
градиентом, левой полосой и круглым «?» слева. Совпадает по визуалу
с главой 1.
- Шпаргалка: добавлена кнопка «Шпаргалка» в шапке, на узких экранах
(≤980px) col-side превращается в выезжающий справа drawer с
backdrop'ом, открывается по кнопке/закрывается по клику вне или Esc.
- initSidebarToggle() вызывается из init().
1. §1 «Извлечение в столбик» — пошаговая анимация
- Поле ввода числа + пресеты 1296/2916/7744
- Async-функция clStart() рендерит классическое 'деление в столбик'
- JetBrains Mono шрифт, подсветка текущей грани цветом секции
- Поясняющий текст для каждого шага рядом
- При остатке 0: confetti + 15 XP + ачивка 'col-root'
- Для нецелых корней — корректно показывает остаток
2. §4 «Сравнение через квадраты» — визуальное доказательство
- 5 пар: 3√2 vs 2√3, 4√3 vs 3√5, √17 vs 4, ...
- SVG с двумя анимированно растущими квадратами (transform scale 0→1, spring)
- Победитель — бейдж в верхней части
- Под квадратами: (3√2)² = 18 > 12 = (2√3)²
3. §5 «Эйлеровы диаграммы» — альтернатива линейной визуализации
- 4 слайдера для границ A и B
- Два эллипса (pink/blue) с пересечением
- Режимы: 'Показать ∪' (золотой контур), '∩' (зелёная штриховка), 'Оба'
- Дополняет существующую линейную визуализацию
4. §6 «Решатель систем 3+ неравенств» — расширен с 2 до 5
- Динамический контейнер #sys-list с массивом _sysRows
- Кнопка '+ Добавить неравенство' (до 5)
- Кнопка '×' удаляет (кроме первой)
- SVG-прямая динамически масштабируется под N строк
- Совместимость с sysMode/solveLin сохранена
Старая версия: два статичных прямоугольника бок о бок (синий a×b и розовый √(ab)×√(ab)) с текстовым описанием. Зритель не видел РАВЕНСТВА площадей.
Новая версия — настоящее визуальное доказательство:
- Один большой SVG-канвас (600×280) с двумя зонами и стрелкой между ними
- Слева: прямоугольник a×b из единичных клеток (синих). Каждая клетка отдельный <rect> (всего a·b штук)
- Справа: пунктирная рамка квадрата √(ab)×√(ab) (заполнится анимацией)
- При нажатии 'Анимировать':
* Шаг 1: волна подсветки клеток жёлтым по очереди (20мс задержка)
* Шаг 2: клетки 'летят' (CSS transition 550мс на x/y) к новой позиции в квадрате,
меняя цвет с синего на розовый
* Шаг 3: финальная пульсация + KaTeX-формула с числами и бейдж 'Доказано!'
- KaTeX-формула под канвасом обновляется живо: $\sqrt{a·b}$ = ... + $\sqrt{a}·\sqrt{b}$ = ...
- 'Сбросить' возвращает в исходное положение
Бонус: для непрямого квадрата (a·b не точный квадрат) анимация всё равно работает, клетки плотно укладываются в столбцы по ceil(√ab), визуально показывая что суммарная площадь одинакова.
1. KaTeX: в config delimiters добавлены '\['/'\]' (display) и '\('/'\)' (inline) во всех 6 местах вызова renderMathInElement. Раньше initFracIrr использовал \[…\] в template literal — выводилось raw LaTeX. Теперь рендерится математически.
2. «Упрости √» переделан с нуля:
Было: непонятный drag-and-drop с пустой drop-zone и техническим хинтом
Стало: явный вопрос 'Выберите точный квадрат, который делит подкоренное'
- Карточки кандидатов крупные (с подписью "= N²" под числом)
- Не делит → красная тряска + объяснение
- Делит но не максимальный → жёлтое предупреждение
- Максимальный квадрат → зелёная анимация pop + пошаговый вывод KaTeX:
√72 = √(36·2) = √36·√2 = 6√2
- confetti + XP +8
- Кнопка 'Подсказка' даёт намёк
- На правильном ответе остальные карточки блокируются
Было: 3 уровня (i%3) × 12px — близко стоящие √2 √3 √5 π √15 наложились друг на друга.
Стало:
- Точки сортируются по координате
- Для каждой подписи ищется минимальный уровень БЕЗ перекрытия с уже размещёнными (с учётом ширины метки ~44px и шкалы в пикселях)
- До 9 уровней по 20px вверх от оси
- От подписи к точке идёт тонкая линия-выноска (0.45 opacity)
- Box-shadow на метках для разделения если плотно
Также: ось перемещена с y=60 на y=100 — больше места сверху для уровней. Контейнер 120 → 140px высоты.
Было: два изолированных блока (квадрат и линия), связь неявная.
Стало: конвейер из трёх шагов со стрелками:
[x] →(возвести в квадрат)→ [x² с площадью квадрата] →(извлечь корень)→ [|x|]
Ключевое улучшение: ползунок теперь от -8 до +8. При отрицательном x:
- площадь всё равно положительная (x²)
- корень даёт |x|, не x
- формула снизу подсвечивается янтарным предупреждением 'это |x| ≠ x'
Под конвейером: живая формула KaTeX типа 'x = 3 → x² = 9 → √9 = 3 ✓'. При отрицательном x текст явно показывает: 'x = -3 → x² = 9 → √9 = 3 ≠ -3 → это |x| = 3'.
Мобайл: вертикальная компоновка со стрелками вниз.
Было: elm.textContent = text — '✓ √72 = 6√2' выводилось буквально, а не как '✓ √72 = 6√2'.
Стало: elm.innerHTML = text — entities и теги <b> теперь рендерятся как ожидалось.
Затронуты места где feedback() получал HTML-entities: §4 dragSimp, §3 matchCheck, и др. где успех содержал '✓'.
Сначала пробовали left:105% — лежало на правом соседе.
Затем top:calc(100%+8px) — лежало на нижнем ряду.
Третий вариант (intelligent positioning) был бы over-engineered. Проще — выпилить вообще: карточки и так показывают название и % прогресса (круговой), темы видны в самом параграфе после клика.
Удалено:
- <div class='psel-card-preview'> из innerHTML карточек
- CSS правила .psel-card-preview, .psel-preview-* (оставлен display:none!important на случай если в скриптах ещё ссылается на класс)
Главная причина почему «Существует или нет?» (§1) не работал:
В buildP1 setTimeout цепочка была:
initRing() → initCalc() → initSquares() → initExists() → initDual()
initSquares() — функция-не-существует (игра запускается по кнопке через squaresStart). ReferenceError рушил цепочку, поэтому initExists() и initDual() НЕ ВЫЗЫВАЛИСЬ → у dropzones не было event-listeners для drag/click → drag-and-drop не работал.
Та же проблема была в §2 с initRationality() — функция отсутствует, riStart() запускает игру по клику.
Исправил обе цепочки.