/* FORMA — client logic. All data stays in this browser (localStorage). */ (function () { "use strict"; var $ = function (s) { return document.querySelector(s); }; var $$ = function (s) { return Array.prototype.slice.call(document.querySelectorAll(s)); }; // ---------- i18n ---------- var I18N = { ru: { menu: "МЕНЮ", nav_home: "Обзор", nav_train: "Тренировки", nav_health: "Здоровье", nav_coach: "ИИ помощник", cTA: "Спросить ИИ", profile_name: "А", profile_name_lbl: "Мой профиль", profile_sub: "Бесплатный план", hi: "Привет, Айгерим", sub: "Маленький шаг сегодня — сильная привычка завтра.", date: "25 сентября", kpi_streak: "Серия", streak_unit: "дня", kpi_streak_d: "к прошлой неделе", kpi_min: "Активность", min_unit: "мин", kpi_min_d: "за эту неделю", kpi_water: "Вода", water_add: "+ добавить стакан", kpi_weight: "Последний вес", kg: "кг", kpi_weight_d: "обновлено сегодня", wk_eb: "Сегодня · 22 мин · 6 упражнений", wk_title: "Сильные ноги", wk_desc: "Уверенный темп и забота о теле. Без оборудования, в комфортном ритме.", wk_min: "22 мин", wk_ex: "6 упражнений", wk_lvl: "Средний", start: "Начать тренировку →", week: "Эта неделя", week_count: "3 / 5 дней", week_goal: "Недельная цель", week_done: "1 / 3", d_mo: "Пн", d_tu: "Вт", d_we: "Ср", d_th: "Чт", d_fr: "Пт", d_sa: "Сб", d_su: "Вс", recent: "Последняя активность", all: "Все тренировки →", a1: "Кардио без прыжков", a1s: "Вчера · 18 мин · Выполнено", a2: "Растяжка всего тела", a2s: "Вторник · 12 мин · Выполнено", cTA_t: "Твой цифровой напарник", cTA_p: "Подскажу, как начать, подскажу технику упражнений и подберу тренировку под твой ритм, настроение и свободное время.", tr_t: "Тренировки", tr_s: "Программа на неделю — выбирай, что подходит сегодня.", tr_chip: "4 программы", h_t: "Здоровье", h_s: "Записывай показатели и наблюдай за изменениями со временем.", hm_t: "Вес и параметры тела", w_lbl: "Вес, кг", h_lbl: "Рост, см", waist_lbl: "Обхват талии, см (необязательно)", local: "Данные — только в этом браузере.", hm_save: "Сохранить", bmi_note: "ИМТ — лишь один из ориентиров и не учитывает состав тела, возраст и другие особенности. Обсудите личные показатели со специалистом.", bmi_lbl: "ИМТ · ориентировочный показатель, не диагноз", wt_t: "Изменение веса", wt_s: "Твои записи за последние недели.", lb_t: "Анализы и самочувствие", metric: "Показатель", testo: "Тестостерон", ferritin: "Ферритин", vitd: "Витамин D", other: "Другой", val: "Результат", unit: "Единицы измерения", labdate: "Дата анализа", lb_add: "Добавить результат", lb_h: "Ваши записи", empty: "Пока нет записей — добавьте первый результат.", lb_note: "Референсные значения зависят от лаборатории, метода, пола, возраста и времени сдачи. Мы не диагностируем гормональные нарушения. Сверь результат с бланком и обсуди его с врачом.", ai_t: "ИИ помощник", ai_s: "Расскажи, что тебе нужно — подберём идею для следующего шага.", ai_online: "Онлайн", ai_on: "Отвечает мгновенно", hi_msg: "Привет! Я помогу выбрать тренировку, подскажу технику и составлю план на неделю. Как ты себя сегодня чувствуешь?", s1: "15-минутная тренировка", s2: "Войти в ритм", s3: "Лёгкая растяжка", ph: "Напиши сообщение…", ai_disc: "ИИ может ошибаться. Ответы не заменяют консультацию врача или тренера. При боли остановись; при недомогании обратись к специалисту.", ex_start: "Начать →", ex_prog: "Упражнение {n} из {total}", ex_title: "{name}", ex_pause: "Пауза", ex_resume: "Продолжить", ex_next: "Далее →", toast_done: "Поздравляем! Вы отработали {name}.", toast_pause: "Пауза", toast_save: "Сохранено", toast_add: "Добавлено", ex_done: "Упражнение выполнено", ex_end: "Завершить тренировку", workouts: [ ["Сила ног и ягодиц", "Начальный · 15 мин", "Мягко включаем мышцы нижней части тела.", ["Приседания у стула", "Ягодичный мост", "Подъёмы на носки"]], ["Всё тело за 15 минут", "Средний · 15 мин", "Короткий круг, когда день расписан по минутам.", ["Отжимания от стены", "Обратные выпады", "Планка на коленях"]], ["Кардио без прыжков", "Лёгкий · 12 мин", "Поддержим пульс, не нагружая суставы.", ["Шаги на месте", "Бокс без прыжков", "Шаг в сторону"]], ["Вечерняя растяжка", "Мобильность · 10 мин", "Расслабимся и мягко потянёмся перед сном.", ["Кошка-корова", "Поворот лёжа", "Растяжка бёдер"]] ] }, kz: { menu: "МӘЗІР", nav_home: "Шолу", nav_train: "Жаттығулар", nav_health: "Денсаулық", nav_coach: "AI көмекші", cTA: "AI-дан сұрау", profile_name: "Ә", profile_name_lbl: "Менің профилім", profile_sub: "Тегін жоспар", hi: "Сәлем, Әйгерім", sub: "Бүгінгі кішкентай қадам — ертеңгі жақсы әдет.", date: "25 қыркүйек", kpi_streak: "Серия", streak_unit: "күн", kpi_streak_d: "өткен аптамен салыстырғанда", kpi_min: "Белсенділік", min_unit: "мин", kpi_min_d: "осы аптада", kpi_water: "Су", water_add: "+ бір стақан қосу", kpi_weight: "Соңғы салмақ", kg: "кг", kpi_weight_d: "бүгін жаңартылды", wk_eb: "Бүгін · 22 мин · 6 жаттығу", wk_title: "Мықты аяқтар", wk_desc: "Бірқалыпты қарқын және өзіңе қамқорлық. Жабдықсыз, ыңғайлы ритмде.", wk_min: "22 мин", wk_ex: "6 жаттығу", wk_lvl: "Орташа", start: "Бастау →", week: "Осы апта", week_count: "3 / 5 күн", week_goal: "Апталық мақсат", week_done: "1 / 3", d_mo: "Дс", d_tu: "Сс", d_we: "Ср", d_th: "Бс", d_fr: "Жм", d_sa: "Сб", d_su: "Жс", recent: "Соңғы белсенділік", all: "Барлық жаттығулар →", a1: "Секірусіз кардио", a1s: "Кеше · 18 мин · Аяқталды", a2: "Бүкіл денені созу", a2s: "Сейсенбі · 12 мин · Аяқталды", cTA_t: "Сенің цифрлық көмекшің", cTA_p: "Қалай бастарыңды айтып, техника көрсетіп, жаттығу ұсынамын — ритміңе, көңіл күйіңе және бос уақытыңа сай.", tr_t: "Жаттығулар", tr_s: "Апталық бағдарлама — бүгін өзіңе сай келетінін таңда.", tr_chip: "4 бағдарлама", h_t: "Денсаулық", h_s: "Көрсеткіштерді жазып, өзгерістерді бақыла.", hm_t: "Салмақ және дене өлшемдері", w_lbl: "Салмақ, кг", h_lbl: "Бой, см", waist_lbl: "Бел айналымы, см (міндетті емес)", local: "Деректер — тек осы браузерде.", hm_save: "Сақтау", bmi_note: "ДСИ — тек бір бағдар, ол дене құрамын, жасты және басқа ерекшеліктерді ескермейді. Жеке көрсеткіштерді маманмен талқыла.", bmi_lbl: "ДСИ · шамамен көрсеткіш, диагноз емес", wt_t: "Салмақ өзгерісі", wt_s: "Соңғы аптадағы жазбаларың.", lb_t: "Талдаулар мен көңіл күй", metric: "Көрсеткіш", testo: "Тестостерон", ferritin: "Ферритин", vitd: "D дәрумені", other: "Басқа", val: "Нәтиже", unit: "Өлшем бірлігі", labdate: "Талдау күні", lb_add: "Нәтижені қосу", lb_h: "Сенің жазбаларың", empty: "Алдымен жазба жоқ — бірінші нәтижені қос.", lb_note: "Қалыпты аралық зертханаға, әдіске, жынысқа, жасқа және тапсыру уақытына байланысты. Біз гормондық бұзылыстарды анықтамаймыз. Нәтижені зертхана парағымен салыстырып, дәрігермен талқыла.", ai_t: "AI көмекші", ai_s: "Не қажет екенін айт — келесі қадамға идея тауып беремін.", ai_online: "Онлайн", ai_on: "Бірден жауап береді", hi_msg: "Сәлем! Жаттығу таңдауға, техника түсіндіруге немесе апталық жоспар құруға көмектесемін. Бүгін өзіңді қалай сезініп тұрсың?", s1: "15-минуттық жаттығу", s2: "Ритмге кіру", s3: "Жеңіл созылу", ph: "Хабарлама жаз…", ai_disc: "AI қателесуі мүмкін. Жауаптар дәрігердің немесе білікті жаттықтырушының кеңесін алмастырмайды. Ауырса тоқта; жайсыздық сезінсең маманға жүгін.", ex_start: "Бастау →", ex_prog: "Жаттығу {n} / {total}", ex_title: "{name}", ex_pause: "Үзіліс", ex_resume: "Жалғастыру", ex_next: "Келесі →", toast_done: "Құттықтаймыз! {name} орындалды.", toast_pause: "Үзіліс", toast_save: "Сақталды", toast_add: "Қосылды", ex_done: "Жаттығу аяқталды", ex_end: "Жаттығуды аяқтау", workouts: [ ["Аяқ пен бөксе", "Бастаушы · 15 мин", "Төменгі дене бұлшықеттерін біртіндеп белсендіреміз.", ["Орындыққа отырып-тұру", "Жамбас көтеру", "Башпайға көтерілу"]], ["15 минутта бүкіл дене", "Орташа · 15 мин", "Күн қарбалас кездегі қысқа жаттығу.", ["Қабырғадан итерілу", "Кері адым", "Тіземен планка"]], ["Секірусіз кардио", "Жеңіл · 12 мин", "Жүрек соғуын жиілетеміз, буынға жүктеме қоймай.", ["Орнында жүру", "Секірмей бокс", "Жанға қадам"]], ["Кешкі созылу", "Икемділік · 10 мин", "Ұйқы алдында босаңсып, денеңді соз.", ["Мысық-сиыр", "Жатып бұрылу", "Жамбас созу"]] ] }, en: { menu: "MENU", nav_home: "Overview", nav_train: "Workouts", nav_health: "Health", nav_coach: "AI coach", cTA: "Ask the AI", profile_name: "A", profile_name_lbl: "My profile", profile_sub: "Free plan", hi: "Hi, Aigerim", sub: "A small step today builds a strong habit tomorrow.", date: "Sep 25", kpi_streak: "Streak", streak_unit: "days", kpi_streak_d: "from last week", kpi_min: "Activity", min_unit: "min", kpi_min_d: "this week", kpi_water: "Water", water_add: "+ add a glass", kpi_weight: "Latest weight", kg: "kg", kpi_weight_d: "updated today", wk_eb: "Today · 22 min · 6 exercises", wk_title: "Strong legs", wk_desc: "Steady pace and care for your body. No equipment, at a comfortable rhythm.", wk_min: "22 min", wk_ex: "6 exercises", wk_lvl: "Medium", start: "Start workout →", week: "This week", week_count: "3 / 5 days", week_goal: "Weekly goal", week_done: "1 / 3", d_mo: "Mo", d_tu: "Tu", d_we: "We", d_th: "Th", d_fr: "Fr", d_sa: "Sa", d_su: "Su", recent: "Recent activity", all: "All workouts →", a1: "Low-impact cardio", a1s: "Yesterday · 18 min · Complete", a2: "Full-body stretch", a2s: "Tuesday · 12 min · Complete", cTA_t: "Your digital partner", cTA_p: "I'll help you start, show exercise technique and suggest a workout for your pace, mood and schedule.", tr_t: "Workouts", tr_s: "A weekly program — pick what suits you today.", tr_chip: "4 programs", h_t: "Health", h_s: "Log your measurements and watch how they change over time.", hm_t: "Weight and body measurements", w_lbl: "Weight, kg", h_lbl: "Height, cm", waist_lbl: "Waist, cm (optional)", local: "Your data stays in this browser only.", hm_save: "Save", bmi_note: "BMI is one rough screening measure and does not account for body composition, age or individual factors. Discuss personal measurements with a health professional.", bmi_lbl: "BMI · an estimate, not a diagnosis", wt_t: "Weight trend", wt_s: "Your entries from recent weeks.", lb_t: "Lab results and wellbeing", metric: "Marker", testo: "Testosterone", ferritin: "Ferritin", vitd: "Vitamin D", other: "Other", val: "Result", unit: "Units", labdate: "Test date", lb_add: "Add result", lb_h: "Your records", empty: "No records yet — add your first result.", lb_note: "Reference ranges vary by lab, method, sex, age and time of day. We do not diagnose hormone conditions. Compare your result with the lab report and discuss with a clinician.", ai_t: "AI coach", ai_s: "Tell me what you need — I'll find an idea for your next step.", ai_online: "Online", ai_on: "Replies instantly", hi_msg: "Hi! I can help pick a workout, show the technique and build a weekly plan. How are you feeling today?", s1: "15-minute workout", s2: "Build a routine", s3: "Gentle stretching", ph: "Write a message…", ai_disc: "AI can make mistakes. Answers don't replace a clinician's or qualified trainer's advice. Stop if you feel pain; speak to a professional if you feel unwell.", ex_start: "Start →", ex_prog: "Exercise {n} of {total}", ex_title: "{name}", ex_pause: "Pause", ex_resume: "Resume", ex_next: "Next →", toast_done: "Nice work! You completed {name}.", toast_pause: "Paused", toast_save: "Saved", toast_add: "Added", ex_done: "Exercise complete", ex_end: "Finish workout", workouts: [ ["Legs & glutes", "Beginner · 15 min", "Ease your lower-body muscles into movement.", ["Chair squats", "Glute bridge", "Calf raises"]], ["Full body in 15", "Medium · 15 min", "A short circuit for your busiest days.", ["Wall push-ups", "Reverse lunges", "Knee plank"]], ["Low-impact cardio", "Easy · 12 min", "Keep the pulse up without loading the joints.", ["March in place", "No-jump boxing", "Side steps"]], ["Evening stretch", "Mobility · 10 min", "Unwind and stretch gently before bed.", ["Cat-cow", "Supine twist", "Hip stretch"]] ] } }; var EX_NAMES = { ru: ["Приседания у стула", "Ягодичный мост", "Подъёмы на носки", "Отжимания от стены", "Обратные выпады", "Планка на коленях", "Шаги на месте", "Бокс без прыжков", "Шаг в сторону", "Кошка-корова", "Поворот лёжа", "Растяжка бёдер"], kz: ["Орындыққа отырып-тұру", "Жамбас көтеру", "Башпайға көтерілу", "Қабырғадан итерілу", "Кері адым", "Тіземен планка", "Орнында жүру", "Секірмей бокс", "Жанға қадам", "Мысық-сиыр", "Жатып бұрылу", "Жамбас созу"], en: ["Chair squats", "Glute bridge", "Calf raises", "Wall push-ups", "Reverse lunges", "Knee plank", "March in place", "No-jump boxing", "Side steps", "Cat-cow", "Supine twist", "Hip stretch"] }; var CHAT = { ru: { plan: "Отличный выбор — начнём с короткой тренировки. Попробуй круг: 30 сек приседаний у стула, 30 сек шагов на месте, 30 сек отжиманий от стены, 30 сек ягодичного моста. Сделай 2–3 круга в комфортном темпе.", stretch: "Мягкая растяжка без боли: кошка-корова, наклоны таза лёжа и спокойное дыхание. Держи 20–30 секунд. Остановись, если почувствуешь боль.", routine: "Для начала — 3 короткие тренировки в неделю с днями отдыха между ними. Чередуй лёгкое кардио, упражнения на всё тело и растяжку. Начни с 10–15 минут и добавляй время постепенно.", default: "Хорошая идея — начать в комфортном темпе. Могу предложить короткую тренировку без оборудования, план на неделю или упражнения на растяжку. Что тебе ближе?" }, kz: { plan: "Жақсы таңдау — қысқа жаттығудан бастайық. Шеңбер жаса: 30 сек орындыққа отырып-тұру, 30 сек орнында жүру, 30 сек қабырғадан итерілу, 30 сек жамбас көтеру. Өзіңе ыңғайлы темпте 2–3 айналым.", stretch: "Ауырсынусыз жеңіл созылу: мысық-сиыр, жатып жамбас қозғау және баяу тыныс алу. 20–30 секунд ұста. Ауырса тоқта.", routine: "Бастау үшін аптасына 3 қысқа жаттығу және арасына демалыс күндерін қос. Жеңіл кардио, бүкіл дене және созылуды кезектестір. 10–15 минуттан баста.", default: "Жақсы идея — ыңғайлы темптен бастау. Жабдықсыз жаттығу, апталық жоспар немесе созылуды ұсынамын. Қайсысы керек?" }, en: { plan: "Great — let's start with a short circuit: 30s chair squats, 30s marching in place, 30s wall push-ups, 30s glute bridges. Repeat for 2–3 rounds at a comfortable pace.", stretch: "Gentle, pain-free mobility: cat-cow, lying pelvic tilts and slow breathing. Hold 20–30s each. Stop if you feel pain.", routine: "For a start: three short workouts a week with rest days between. Alternate light cardio, full-body strength and stretching. Begin with 10–15 minutes and build up gradually.", default: "A good place to start is a comfortable pace. I can suggest an equipment-free workout, a weekly plan or some mobility exercises. Which sounds useful?" } }; // ---------- state ---------- var lang = localStorage.getItem("formaLang") || "ru"; var t = function (key, data) { var s = (I18N[lang] && I18N[lang][key]) || I18N.ru[key] || key; if (data) Object.keys(data).forEach(function (k) { s = s.replace("{" + k + "}", data[k]); }); return s; }; // ---------- toast ---------- var toastStack = $("#toasts"); function toast(msg, tone) { if (!toastStack) return; var el = document.createElement("div"); el.className = "kt-ai-toast"; if (tone) el.setAttribute("data-tone", tone); el.textContent = msg; toastStack.appendChild(el); setTimeout(function () { el.remove(); }, 2600); } // ---------- navigation ---------- var current = "home"; function go(page) { if (!page) return; current = page; $$(".kt-ai-page").forEach(function (p) { p.style.display = (p.getAttribute("data-page") === page) ? "block" : "none"; }); $$(".kt-ai-nav-item").forEach(function (b) { b.setAttribute("data-active", b.getAttribute("data-page") === page ? "true" : "false"); }); var crumb = $("#crumb"); if (crumb) crumb.textContent = navLabel(page); if (page === "home") renderHomeExercise(); if (page === "health") { calcBmi(); renderLabs(); drawChart(); } window.scrollTo(0, 0); } function navLabel(page) { return t("nav_" + page); } $$("[data-page]").forEach(function (el) { el.addEventListener("click", function (e) { var p = el.getAttribute("data-page"); if (el.classList.contains("kt-ai-nav-item") || el.classList.contains("kt-ai-link") || el.tagName === "BUTTON") go(p); }); }); // ---------- language ---------- var langSel = $("#lang"); if (langSel) langSel.addEventListener("change", function (e) { lang = e.target.value; localStorage.setItem("formaLang", lang); applyLanguage(); }); function applyLanguage() { document.documentElement.lang = (lang === "kz") ? "kk" : lang; if (langSel) langSel.value = lang; $$("[data-i]").forEach(function (el) { var key = el.getAttribute("data-i"); var val = I18N[lang][key]; if (val != null) el.innerHTML = val; }); var ph = $("#chatText"); if (ph) ph.placeholder = t("ph"); renderTrainGrid(); renderHomeExercise(); renderLabs(); drawChart(); var crumb = $("#crumb"); if (crumb) crumb.textContent = navLabel(current); } // ---------- home today-exercise card ---------- function renderHomeExercise() { var w = I18N[lang].workouts[0]; var card = $("#homeExCard"); if (!card) return; $("#homeExBadgeTx").textContent = w[1]; $("#homeExTitle").textContent = w[0]; $("#homeExDesc").textContent = w[2]; var list = $("#homeExList"); list.innerHTML = ""; w[3].forEach(function (name, i) { var d = document.createElement("div"); d.className = "form-ex"; d.innerHTML = "
" + w[2] + "
" + "