/* GreenRoot app: i18n engine, nav, counters, reveal, chat, career, mood, charts, form */ (function(){ "use strict"; /* ---------- safe storage ---------- */ var store = (function(){ try{ var s=window.localStorage; s.setItem("__gr","1"); s.removeItem("__gr"); return s; }catch(e){ return null; } })(); /* ---------- language ---------- */ var lang = "en"; var saved = store ? store.getItem("gr-lang") : null; if (saved && ["en","fa","tr"].indexOf(saved)>-1) lang = saved; else { var nav3 = (navigator.language||""); if (nav3.indexOf("fa")===0) lang = "fa"; else if (nav3.indexOf("tr")===0) lang = "tr"; } function t(k){ var d = I18N[lang] || I18N.en; if (d[k]!==undefined) return d[k]; if (I18N.en[k]!==undefined) return I18N.en[k]; return ""; } function fmt(n){ return n.toLocaleString("en-US"); } var raf = (window.requestAnimationFrame ? function(f){ return window.requestAnimationFrame(f); } : function(f){ return setTimeout(function(){ f(Date.now()); }, 16); }); function safe(fn){ try{ fn(); }catch(e){ if (window.console) console.warn("GreenRoot init:", e); } } function mergeTr(){ var X = window.GR_EXTRA_TR; if (!X) return; CHAT_GREETING.tr = X.greeting; CHAT_FALLBACK.tr = X.fallback; X.chips.forEach(function(c){ var dst = CHAT_CHIPS.find(function(x){ return x.id===c.id; }); if (dst) dst.tr = c.tr; }); Object.keys(X.intents).forEach(function(id){ var dst = CHAT_INTENTS.find(function(x){ return x.id===id; }); if (dst) dst.r.tr = X.intents[id]; }); Object.keys(X.career||{}).forEach(function(job){ var s = X.career[job], d = CAREER_PLANS[job]; if (d){ d.title.tr=s.title; d.s1.tr=s.s1; d.s2.tr=s.s2; d.s3.tr=s.s3; d.story.tr=s.story; } }); } function applyLang(){ document.documentElement.lang = lang; document.documentElement.dir = (lang==="fa") ? "rtl" : "ltr"; document.querySelectorAll("[data-i18n]").forEach(function(el){ el.innerHTML = t(el.getAttribute("data-i18n")); }); document.querySelectorAll("[data-i18n-ph]").forEach(function(el){ el.setAttribute("placeholder", t(el.getAttribute("data-i18n-ph"))); }); document.querySelectorAll(".lang-sw .lang").forEach(function(b){ b.classList.toggle("on", b.getAttribute("data-lang")===lang); }); /* COP31 countdown */ var days = Math.max(0, Math.ceil((new Date(2026,10,9) - new Date())/86400000)); document.querySelectorAll("[data-cop-days]").forEach(function(elm){ elm.textContent = t("cop.countdown").replace("{d}", days); }); var page = document.body.getAttribute("data-page"); if (page && t("title."+page)) document.title = t("title."+page); var cs = document.getElementById("chatShellDir"); if (page==="ai") renderChips(); applyChatDir(); if (page==="dashboard" && document.getElementById("chartMonthly")) initDashboard(); var file = (page === "home" ? "index" : page) + ".html"; document.querySelectorAll(".links a").forEach(function(a){ a.classList.toggle("active", a.getAttribute("href") === file); }); } function setLang(l){ lang = l; if (store) try{ store.setItem("gr-lang", l); }catch(e){} safe(applyLang); } document.addEventListener("DOMContentLoaded", function(){ safe(mergeTr); safe(applyLang); document.querySelectorAll(".lang-sw .lang").forEach(function(b){ b.addEventListener("click", function(){ setLang(b.getAttribute("data-lang")); }); }); /* burger */ var nav = document.getElementById("nav"); var burger = document.getElementById("burger"); if (burger && nav){ burger.addEventListener("click", function(){ nav.classList.toggle("open"); }); nav.querySelectorAll(".links a").forEach(function(a){ a.addEventListener("click", function(){ nav.classList.remove("open"); }); }); } /* footer year */ document.querySelectorAll("#year").forEach(function(el){ el.textContent = new Date().getFullYear(); }); /* reveal on scroll */ var rvs = document.querySelectorAll(".rv"); if ("IntersectionObserver" in window){ var io = new IntersectionObserver(function(entries){ entries.forEach(function(e){ if (e.isIntersecting){ e.target.classList.add("in"); io.unobserve(e.target); } }); }, {threshold:.12}); rvs.forEach(function(el){ io.observe(el); }); } else { rvs.forEach(function(el){ el.classList.add("in"); }); } /* animated counters */ function runCounter(el){ var target = parseFloat(el.getAttribute("data-count"))||0; var pre = el.getAttribute("data-prefix")||"", suf = el.getAttribute("data-suffix")||""; var dur = 1500, t0 = null; function step(ts){ if(!t0) t0 = ts; var p = Math.min((ts-t0)/dur, 1); var eased = 1 - Math.pow(1-p, 3); el.textContent = pre + fmt(Math.round(target*eased)) + suf; if (p<1) raf(step); } raf(step); } var counters = document.querySelectorAll("[data-count]"); if ("IntersectionObserver" in window){ var cio = new IntersectionObserver(function(entries){ entries.forEach(function(e){ if (e.isIntersecting){ safe(function(){ runCounter(e.target); }); cio.unobserve(e.target); } }); }, {threshold:.4}); counters.forEach(function(el){ cio.observe(el); }); } else { counters.forEach(function(el){ safe(function(){ runCounter(el); }); }); } /* page inits */ var page = document.body.getAttribute("data-page"); safe(function(){ if (page==="ai") initAI(); if (page==="dashboard") initDashboard(); if (page==="join") initJoin(); }); }); /* ============================================================ Raha chat (AI page) ============================================================ */ var CHAT_INTENTS = [ { id:"crisis", kw:["suicide","kill myself","overdose","end it","خودکشی","اوردوز","مردن","تموم کنم","نابود","intihar","aşırı doz","bitirmek istiyorum"], r:{ en:"I'm really glad you told me. Please reach a human right now:\n• Your local emergency number (DE: 112 · IR: 123)\n• Iran addiction hotline: 09628\n• Your GreenRoot counselor — number is on your card.\nYou are not alone, and this moment will pass. Stay with me — then call.", fa:"خیلی خوشحالم که گفتی. لطفاً همین حالا به یک انسان وصل شو:\n• شمارهٔ اورژانس محلی (آلمان: ۱۱۲ · ایران: ۱۲۳)\n• خط اعتیاد ایران: ۰۹۶۲۸\n• شمارهٔ مشاور گرین‌روت روی کارتت هست.\nتنها نیستی و این لحظه رد می‌شود. با من بمون — بعد زنگ بزن." } }, { id:"craving", kw:["craving","crave","urge","relapse now","using again","هوس","کشش","میل","لغزش","مصرف","kriz","canım çekti","kullanmak istiyorum"], r:{ en:"Craving noticed — that's already a win. Let's ride the wave:\n1. Put the thought on a 10-minute timer.\n2. 4-7-8 breathing ×3 with me: in 4… hold 7… out 8…\n3. Walk toward a crew member or call your buddy.\nCravings peak and pass — usually under 20 minutes. I'm staying right here.", fa:"هوس رو شنیدم — همین که گفتی یعنی یک برد. موج رو سوار بشیم:\n۱. فکر رو روی تایمر ۱۰ دقیقه‌ای بذار.\n۲. سه بار تنفس ۴-۷-۸ با من: دم ۴… نگه ۷… بازدم ۸…\n۳. برو سمت یکی از اعضای تیم یا به همراهت زنگ بزن.\nهوس اوج می‌گیره و رد می‌شه — معمولاً زیر ۲۰ دقیقه. من همین‌جام." } }, { id:"mood", kw:["sad","depress","low","lonely","tired","empty","anxious","غم","افسر","تنها","خسته","حالم","اضطراب","نگران","mutsuz","yalnızım","kötüyüm","yorgunum","kaygılı"], r:{ en:"Thanks for telling me. Low days are data, not failure.\n• Today's shift is optional — rest is treatment too.\n• Want me to draft a message to your counselor?\n• One small thing: water, window, 5 slow breaths. That's enough for now.", fa:"ممنون که گفتی. روزهای پایین، داده‌ان نه شکست.\n• شیفت امروز اختیاریه — استراحت هم بخشی از درمانه.\n• برات یک پیام برای مشاورت بنویسم؟\n• یک کار کوچک: آب، پنجره، ۵ نفس آروم. فعلاً همین کافیه." } }, { id:"career", kw:["job","career","work again","cv","resume","interview","شغل","کار","رزومه","مصاحبه","حرفه","kariyer","meslek","mülakat","özgeçmiş"], r:{ en:"Career rewind is my favourite topic 💼 Your plan has 3 steps: skill map → paid refresh role inside the program → placement with a partner employer.\nTell me your old job — driver, nurse, accountant, mechanic, teacher, cook — or try the Career rewind demo below the chat.", fa:"بازگشت شغلی موضوع موردعلاقه‌ام هست 💼 طرحت ۳ قدم داره: نقشهٔ مهارت → نقشِ تمرینیِ حقوق‌دار در برنامه → قرارگیری در یک کارفرمای شریک.\nشغل قبلیت رو بگو — راننده، پرستار، حسابدار، مکانیک، معلم، آشپز — یا دموی «بازگشت شغلی» زیر چت رو امتحان کن." } }, { id:"balance", kw:["token","balance","reward","point","wallet","توکن","موجودی","پاداش","امتیاز","کیف","jeton","bakiye","cüzdan"], r:{ en:"Token balance: 340 🪙\n• This week: +60 (3 shifts)\n• Available rewards: bus pass (40) · phone credit (25) · welding course (220)\nTip: set a goal in the wallet — goals roughly double follow-through.", fa:"موجودی توکن: 340 🪙\n• این هفته: +60 (۳ شیفت)\n• پاداش‌های موجود: کارت اتوبوس (40) · شارژ (25) · دورهٔ جوشکاری (220)\nپیشنهاد: در کیف، یک هدف بذار — هدف‌گذاری پیگیری رو تقریباً دوبرابر می‌کنه." } }, { id:"schedule", kw:["schedule","shift","time","plan","when","برنامه","شیفت","ساعت","کی","وقت","vardiya","bu hafta"], r:{ en:"This week's plan:\n• Mon / Wed / Fri 08:00 — cleanup shift (meet at the depot)\n• Tue 17:00 — group therapy\n• Thu 16:00 — Raha session + skills class\nRain plan: indoor sorting line. Missed a day? It happens — tell your mentor, your place is safe.", fa:"برنامهٔ این هفته:\n• دوشنبه / چهارشنبه / جمعه 08:00 — شیفت پاک‌سازی (قرار مقابل انبار)\n• سه‌شنبه 17:00 — گروه‌درمانی\n• پنجشنبه 16:00 — جلسهٔ رها + کلاس مهارت\nبرنامهٔ بارونی: خط جداسازی سرپوشیده. یه روز جا موندی؟ پیش میاد — به مربیت بگو، جایگاهت محفوظه." } }, { id:"trash", kw:["trash","waste","recycl","collect","زباله","بازیافت","جمع","çöp","atık"], r:{ en:"Today's crews collected 214 kg: 96 kg PET · 41 kg metal · 52 kg paper · 25 kg glass.\nThat's about €118 to the treatment fund — and enough flake for 3 face shields heading to the workshop. You make that happen.", fa:"تیم‌های امروز ۲۱۴ کیلو جمع کردند: ۹۶ کیلو پت · ۴۱ فلز · ۵۲ کاغذ · ۲۵ شیشه.\nیعنی حدود €118 به صندوق درمان — و خردِ کافی برای ۳ شیلد صورت به سمت کارگاه. این تو اتفاق انداختی." } }, { id:"about", kw:["who are you","what are you","raha","رها کیست","تو کی هستی","چی هستی"], r:{ en:"I'm Raha — \"رهاء\" means freedom. I'm the program's AI companion: craving SOS, mood check-ins, token wallet and career-rewind coach. I'm a tool with human oversight — your counselor and doctors make the clinical calls. My data policy is simple: your story belongs to you.", fa:"من رها هستم؛ «رهاء» یعنی آزادی. همیار هوش مصنوعی برنامه‌ام: SOS هوس، چک-این خلق، کیف توکن و مربی بازگشت شغلی. من یک ابزار با نظارت انسانی‌ام — تصمیم‌های بالینی با مشاور و پزشکت. سیاست داده‌ام ساده‌ست: داستان زندگی‌ات مال خودته." } }, { id:"thanks", kw:["thank","thanks","merci","مرسی","ممنون","متشکر","سپاس","teşekkür","sağol"], r:{ en:"Anytime. That's what I'm here for — see you at check-in tomorrow? 🌱", fa:"همیشه در خدمتم. برای همین اینجام — فردا سر چک-این می‌بینمت؟ 🌱" } } ]; var CHAT_FALLBACK = { en:"I hear you. I'm the demo version — I know cravings, mood, tokens, the weekly plan and career rewind. Try a chip below, or type \"craving\", \"job\", \"balance\"…", fa:"شنیدمت. من نسخهٔ دمو هستم — از هوس، خلق، توکن، برنامهٔ هفتگی و بازگشت شغلی سر درمیارم. یکی از دکمه‌ها رو بزن، یا بنویس «هوس»، «شغل»، «موجودی»…" }; var CHAT_GREETING = { en:"Hi, I'm Raha 🌱 GreenRoot's recovery companion. How are you feeling today? Tap a chip below or just type — English or فارسی, both work.", fa:"سلام، من رها هستم 🌱 همیار بهبودی گرین‌روت. امروز حالت چطوره؟ از دکمه‌های پایین استفاده کن یا آزادانه بنویس — فارسی یا English، هر دو جواب می‌ده." }; var CHAT_CHIPS = [ { id:"craving", en:"I have a craving", fa:"هوس دارم" }, { id:"mood", en:"I feel low", fa:"حالم پایینه" }, { id:"career", en:"Career rewind", fa:"بازگشت شغلی" }, { id:"balance", en:"Token balance", fa:"موجودی توکن" }, { id:"schedule",en:"This week's plan",fa:"برنامهٔ این هفته" } ]; var chatBody, chatInput; function el(id){ return document.getElementById(id); } function chatMsg(text, who){ var m = document.createElement("div"); m.className = "msg " + who; m.textContent = text; chatBody.appendChild(m); chatBody.scrollTop = chatBody.scrollHeight; return m; } function botReply(intentId, userText){ var typing = document.createElement("div"); typing.className = "msg bot typing"; typing.innerHTML = ""; chatBody.appendChild(typing); chatBody.scrollTop = chatBody.scrollHeight; var resp, d = I18N[lang]||I18N.en; if (intentId){ resp = CHAT_INTENTS.find(function(i){return i.id===intentId;}).r[lang] || CHAT_INTENTS.find(function(i){return i.id===intentId;}).r.en; } else { var lower = (userText||"").toLowerCase(); var hit = CHAT_INTENTS.find(function(i){ return i.kw.some(function(k){ return lower.indexOf(k.toLowerCase())>-1; }); }); resp = hit ? (hit.r[lang]||hit.r.en) : (CHAT_FALLBACK[lang]||CHAT_FALLBACK.en); } setTimeout(function(){ typing.remove(); chatMsg(resp,"bot"); }, 800 + Math.random()*500); } function routeIntent(intentId){ var chip = CHAT_CHIPS.find(function(c){return c.id===intentId;}); var label = chip ? (chip[lang]||chip.en) : intentId; chatMsg(label,"user"); botReply(intentId,null); } function renderChips(){ var wrap = el("chatChips"); if (!wrap) return; wrap.innerHTML = ""; CHAT_CHIPS.forEach(function(c){ var b = document.createElement("button"); b.type = "button"; b.textContent = c[lang]||c.en; b.addEventListener("click", function(){ routeIntent(c.id); }); wrap.appendChild(b); }); } function sendChat(){ var v = (chatInput.value||"").trim(); if (!v) return; chatMsg(v,"user"); chatInput.value = ""; botReply(null,v); } function initAI(){ chatBody = el("chatBody"); chatInput = el("chatInput"); var shell = document.querySelector(".chat-shell"); if (shell){ shell.removeAttribute("dir"); } applyChatDir(); chatMsg(CHAT_GREETING[lang]||CHAT_GREETING.en,"bot"); renderChips(); var send = el("chatSend"); if (send) send.addEventListener("click", sendChat); if (chatInput) chatInput.addEventListener("keydown", function(e){ if (e.key==="Enter") sendChat(); }); /* career rewind */ var plans = CAREER_PLANS; var picker = el("careerPicker"), planBox = el("careerPlan"); if (picker && planBox){ picker.querySelectorAll("button").forEach(function(b){ b.addEventListener("click", function(){ picker.querySelectorAll("button").forEach(function(x){ x.classList.remove("on"); }); b.classList.add("on"); var job = b.getAttribute("data-job"); renderPlan(job); }); }); } function renderPlan(job){ var p = plans[job]; planBox.style.display = "block"; planBox.innerHTML = "

"+ (p.title[lang]||p.title.en) +"

" + "
  1. "+ (p.s1[lang]||p.s1.en) +"
  2. "+ (p.s2[lang]||p.s2.en) +"
  3. "+ (p.s3[lang]||p.s3.en) +"
" + "

💡 "+ (p.story[lang]||p.story.en) +"

"; } /* mood tracker */ var moodLog = []; var moodRow = el("moodRow"), moodMsg = el("moodMsg"); if (moodRow && moodMsg){ moodRow.querySelectorAll("button").forEach(function(b){ b.addEventListener("click", function(){ moodLog.push(parseInt(b.getAttribute("data-mood"),10)); if (moodLog.length>12) moodLog.shift(); renderMood(); }); }); } function renderMood(){ if (!moodLog.length) return; var MOOD_TXT = { 1:{en:"Very low — you're not alone. Tap \"I have a craving\" / SOS or call your counselor. I've flagged a check-in.",fa:"خیلی پایین — تنها نیستی. «هوس دارم»/SOS رو بزن یا به مشاورت زنگ بزن. یک چک-این علامت خوردم."}, 2:{en:"Low — thanks for logging. Consider an SOS session or an early night.",fa:"پایین — ممنون که ثبت کردی. یک جلسهٔ SOS یا زودخوابیدن رو در نظر بگیر."}, 3:{en:"Okay days count too. Logged.",fa:"روزهای معمولی هم می‌شمارند. ثبت شد."}, 4:{en:"Good — noted. Keep the rhythm.",fa:"خوب — ثبت شد. ریتم رو نگه دار."}, 5:{en:"Great day — logged. Streaks are how recovery is built. 🌱",fa:"روزِ خوبی بود — ثبت شد. رشته‌ها، بهبودی را می‌سازند. 🌱"} }; var last = moodLog[moodLog.length-1]; var txt = (lang==="tr" && window.GR_EXTRA_TR && window.GR_EXTRA_TR.mood[last]) || MOOD_TXT[last][lang] || MOOD_TXT[last].en; var trend = moodLog.length>1 ? (moodLog[moodLog.length-1]>=moodLog[moodLog.length-2] ? " ↗" : " ↘") : ""; /* sparkline */ var w=220,h=44,pts=""; moodLog.forEach(function(v,i){ var x = moodLog.length===1 ? w/2 : (i/(moodLog.length-1))*(w-8)+4; var y = h-6-((v-1)/4)*(h-12); pts += x.toFixed(1)+","+y.toFixed(1)+" "; }); var svg = ""; moodMsg.innerHTML = txt + trend + "
" + svg + "
" + moodLog.length + " × " + (lang==="fa"?"چک-این":"check-ins") + ""; } } var CAREER_PLANS = { driver:{ title:{en:"🚚 Driver — rewind plan",fa:"🚚 راننده — طرح بازگشت"}, s1:{en:"Licence & record check: we verify your licence status and the skills fund covers any refresher course.",fa:"بررسی گواهینامه و سوابق: وضعیت گواهینامه‌ات را بررسی می‌کنیم و صندوق مهارت هزینهٔ دورهٔ تجدید را می‌پوشاند."}, s2:{en:"6 paid weeks as relief driver for the cleanup crews' logistics — with a clean-shift certificate.",fa:"۶ هفتهٔ حقوق‌دار به‌عنوان رانندهٔ جانشین در حمل‌ونقل تیم‌های پاک‌سازی — با گواهی شیفت‌های تمیز."}, s3:{en:"Raha rebuilds your CV around 12+ months of documented reliability, then places you with partner logistics firms.",fa:"رها رزومه‌ات را حول ۱۲+ ماه اتکاپذیریِ مستند بازمی‌سازد و بعد با شرکت‌های حمل‌ونقل شریک قرارت می‌دهد."}, story:{en:"Your time on the crew isn't a gap — it's proof of reliability.",fa:"بودنت در تیم، یک «وقفه» نیست — مدرک اتکاپذیری است."}}, nurse:{ title:{en:"🧑‍⚕️ Nurse / health worker — rewind plan",fa:"🧑‍⚕️ پرستار / کارمند سلامت — طرح بازگشت"}, s1:{en:"Re-enter clinical life through lower-intensity roles: hygiene and health-promotion rounds within the crews.",fa:"بازگشت به فضای بالینی از نقش‌های کم‌فشار: گشتی‌های بهداشت و ارتقای سلامت درون تیم‌ها."}, s2:{en:"Skills revalidation: BLS refresher, licence paperwork — supported by the skills fund.",fa:"بازاعتبارسنجی مهارت: دورهٔ BLS، امور پروانه — با پشتیبانی صندوق مهارت."}, s3:{en:"Supported shifts with partner clinics while Raha builds your gradual full-return plan.",fa:"شیفت‌های حمایتی در کلینیک‌های شریک، در حالی که رها طرح بازگشت کامل تدریجی‌ات را می‌سازد."}, story:{en:"The care you learned to give yourself is now your credential.",fa:"مراقبتی که یاد گرفتی به خودت بدهی، حالا اعتبارت است."}}, accountant:{ title:{en:"🧾 Accountant — rewind plan",fa:"🧾 حسابدار — طرح بازگشت"}, s1:{en:"Skills audit with free assessments (Excel, bookkeeping) — a gap map within one week.",fa:"ارزیابی مهارت با تست‌های رایگان (اکسل، اصول حسابداری) — نقشهٔ شکاف‌ها در یک هفته."}, s2:{en:"Six weeks of software refresh + a real role: counting and reporting the crews' material revenue.",fa:"شش هفته به‌روزرسانی نرم‌افزار + یک نقش واقعی: شمارش و گزارش درآمد مواد تیم‌ها."}, s3:{en:"Raha frames your CV around \"12 months of clean data\", then runs interview practice with partner firms.",fa:"رها رزومه را حول «۱۲ ماه دادهٔ تمیز» قاب می‌گیرد و بعد با شرکت‌های شریک مصاحبه تمرینی می‌گذارد."}, story:{en:"The discipline you built in recovery is exactly what accounting wants.",fa:"انضباطی که در بهبودی ساختی، دقیقاً همان چیزی است که حسابداری می‌خواهد."}}, mechanic:{ title:{en:"🔧 Mechanic — rewind plan",fa:"🔧 مکانیک — طرح بازگشت"}, s1:{en:"Workshop assessment: tools, safety, current skills — with a technical mentor.",fa:"ارزیابی کارگاهی: ابزار، ایمنی، مهارت‌های فعلی — با یک مربی فنی."}, s2:{en:"Documented experience maintaining the recycling line's machines and vehicles, on site.",fa:"تجربهٔ مستند نگهداشت ماشین‌آلات و خودروهای خط بازیافت — در همان سایت."}, s3:{en:"Specialist certificate (e.g. electromechanics) from the skills fund + placement at partner workshops.",fa:"گواهی تخصصی (مثلاً الکترومکانیک) از صندوق مهارت + قرارگیری در کارگاه‌های شریک."}, story:{en:"The machines you brought back to life are your best résumé.",fa:"ماشین‌هایی که به آن‌ها زندگی دوباره دادی، بهترین رزومهٔ تو هستند."}}, teacher:{ title:{en:"🧑‍🏫 Teacher — rewind plan",fa:"🧑‍🏫 معلم — طرح بازگشت"}, s1:{en:"The honest-narrative plan: how to tell the gap in interviews, practised with Raha until it's strength.",fa:"طرحِ روایت صادقانه: چطور وقفه را در مصاحبه بگویی — با رها تمرین می‌کنی تا به نقطه‌قوت تبدیل شود."}, s2:{en:"Real classroom: environmental-literacy lessons for school groups in the parks your crew cleaned.",fa:"کلاس واقعی: درس‌های سواد محیط‌زیست برای گروه‌های مدرسه‌ای در پارک‌هایی که تیمت تمیز کرده."}, s3:{en:"Teaching-certificate refresh + assistant placement at partner schools, stepping up to full-time.",fa:"روزآمدسازی گواهی تدریس + جایگاه دستیار در مدارس شریک، تا رسیدن به تمام‌وقت."}, story:{en:"Your recovery is the deepest lesson your future classroom will ever get.",fa:"بهبودی‌ات، عمیق‌ترین درسی است که کلاس آینده‌ات می‌گیرد."}}, cook:{ title:{en:"🍳 Cook — rewind plan",fa:"🍳 آشپز — طرح بازگشت"}, s1:{en:"Food safety & hygiene certificate — official, funded by the skills fund.",fa:"گواهی ایمنی و بهداشت غذا — رسمی، هزینه‌اش با صندوق مهارت."}, s2:{en:"Real volume experience: cooking crew lunches for 50+ people every day.",fa:"تجربهٔ حجم واقعی: پخت ناهار تیم‌ها برای ۵۰+ نفر هر روز."}, s3:{en:"Supported internship in a partner kitchen with a mentor, then part-time or full-time placement.",fa:"کارآموزی حمایتی در آشپزخانهٔ شریک با مربی، بعد جایگاه پاره‌وقت یا تمام‌وقت."}, story:{en:"The meals you cook for the crew are the first order of your comeback.",fa:"غذاهایی که برای تیم می‌پزی، اولین سفارشِ بازگشت تو هستند."}} }; function applyChatDir(){ var shell = document.querySelector(".chat-shell"); if (shell) shell.setAttribute("dir", lang==="fa" ? "rtl" : "ltr"); if (chatBody) chatBody.setAttribute("dir", lang==="fa" ? "rtl" : "ltr"); } /* ============================================================ Dashboard charts ============================================================ */ var MONTHLY_KG = [1000,1100,1200,1300,1400,1500,1600,1700,1800,1900,2000,2400]; var WASTE_MIX = [ {label:"PET", v:42, color:"#16A34A"}, {label:"Paper", v:22, color:"#0D9488"}, {label:"Metal", v:18, color:"#F59E0B"}, {label:"Glass", v:11, color:"#3B82F6"}, {label:"Other", v:7, color:"#94A3B8"} ]; var FUND = [ {v:1900, color:"#16A34A"}, {v:1250, color:"#F59E0B"}, {v:600, color:"#0D9488"} ]; var REPORT = [ {m:7, a:98, kg:1600, eur:3200}, {m:8, a:104, kg:1700, eur:3400}, {m:9, a:109, kg:1800, eur:3600}, {m:10,a:113, kg:1900, eur:3800}, {m:11,a:117, kg:2000, eur:4100}, {m:12,a:120, kg:2400, eur:4600} ]; function renderReportTable(){ var body = el("reportBody"); if (!body) return; body.innerHTML = REPORT.map(function(r){ return ""+r.m+""+r.a+""+fmt(r.kg)+"€"+fmt(r.eur)+""; }).join(""); } function initDashboard(){ drawBars(el("chartMonthly"), MONTHLY_KG); drawDonut(el("chartMix"), WASTE_MIX); drawHBars(el("chartFund"), FUND); renderReportTable(); } function drawBars(container, values){ if (!container) return; var W=460,H=230,pad=34,bw=(W-pad-10)/values.length; var max = Math.max.apply(null,values)*1.12; var s = ""; s += ""; values.forEach(function(v,i){ var h = Math.round((v/max)*(H-58)); var x = pad + i*bw + 3; var y = H-26-h; s += ""+fmt(v)+" kg"; if (i%2===0) s += ""+(i+1)+""; if (i===values.length-1) s += ""+fmt(v)+""; }); s += ""; s += ""; container.innerHTML = s; } function drawDonut(container, segs){ if (!container) return; var total = segs.reduce(function(a,b){return a+b.v;},0); var R=76,C=2*Math.PI*R, off=0; var s = ""; s += ""; segs.forEach(function(seg){ var len = seg.v/total*C; s += ""+seg.label+" "+seg.v+"%"; off += len; }); s += ""+t("dash.ch2.t1")+""; s += ""+t("dash.ch2.t2")+""; container.innerHTML = s; var lg = el("mixLegend"); if (lg){ lg.innerHTML = segs.map(function(seg){ return ""+seg.label+" "+seg.v+"%"; }).join(""); } } function drawHBars(container, items){ if (!container) return; var labels = [ t("dash.ch3.l1"), t("dash.ch3.l2"), t("dash.ch3.l3") ]; var max = Math.max.apply(null, items.map(function(i){return i.v;}))*1.1; var s = ""; items.forEach(function(it,i){ var pct = Math.round(it.v/max*100); s += "
" + "
"+labels[i]+"€"+fmt(it.v)+"/"+(lang==="fa"?"ماه":"mo")+"
" + "
"; }); container.innerHTML = s; } /* ============================================================ Join form ============================================================ */ function initJoin(){ var f = el("joinForm"); if (!f) return; f.addEventListener("submit", function(e){ e.preventDefault(); el("formOk").style.display = "block"; f.querySelector("button[type=submit]").disabled = true; }); } })();