* { box-sizing: border-box; }
#impact-app-wp {
–bg: #f7faf9; –card: #ffffff; –ink: #102a26; –muted: #5d6b68;
–brand: #219f8d; –brand-ink: #0e5e55; –accent: #41a777; –shadow: 0 10px 25px rgba(0,0,0,.06);
font-family: “Tajawal”, system-ui, -apple-system, “Segoe UI”, Roboto, “Noto Kufi Arabic”, “Noto Sans”, Arial;
color: var(–ink); background: var(–bg); padding: 16px;
}
.container { max-width: 1180px; margin: 0 auto; }
.hero { position: relative; background: linear-gradient(180deg, #e9f6f3, #f7faf9); border-radius: 20px;
padding: clamp(18px, 4vw, 28px); overflow: hidden; box-shadow: var(–shadow); }
.hero-inner { display: grid; grid-template-columns: 1.2fr .8fr; gap: clamp(16px, 3vw, 28px); align-items: center; }
.hero-title { font-size: clamp(20px, 2.6vw, 32px); line-height: 1.25; margin: 0 0 8px; font-weight: 800; }
.hero-sub { color: var(–muted); margin: 0 0 14px; font-size: clamp(14px, 1.8vw, 16px); }
.cta { display: inline-flex; align-items: center; gap: 10px; background: var(–brand); color: #fff; padding: 12px 18px;
border-radius: 12px; text-decoration: none; font-weight: 700; box-shadow: 0 8px 18px rgba(33,159,141,.25);
transition: transform .15s ease, box-shadow .15s ease, background .15s ease; }
.cta:hover { transform: translateY(-2px); background: var(–brand-ink); box-shadow: 0 10px 22px rgba(33,159,141,.3); }
.flag-wrap { position: relative; width: 100%; aspect-ratio: 4/3; display: grid; place-items: center; isolation: isolate; }
.flag { width: 86%; max-width: 360px; aspect-ratio: 4/3; background: #006c35; border-radius: 10px;
box-shadow: 0 20px 40px rgba(0,0,0,.12), inset 0 0 40px rgba(255,255,255,.12);
position: relative; overflow: hidden; transform-style: preserve-3d; animation: wave 3.4s ease-in-out infinite; }
@keyframes wave { 0%{transform:perspective(800px) rotateY(-6deg) skewY(0)} 50%{transform:perspective(800px) rotateY(6deg) skewY(1deg)} 100%{transform:perspective(800px) rotateY(-6deg) skewY(0)} }
.flag:after { content:””; position:absolute; inset:0; background:linear-gradient(115deg,transparent 40%,rgba(255,255,255,.08) 50%,transparent 60%);
mix-blend-mode:screen; animation: shine 4.8s linear infinite; }
@keyframes shine { to{ transform: translateX(-30%) translateY(-10%);} }
.metric-badge { margin-top: 10px; display: inline-flex; align-items: center; gap: 10px; padding: 10px 14px; background: #fff; border-radius: 12px; box-shadow: var(–shadow); }
.metric-badge .num { font-size: clamp(22px, 3.8vw, 36px); line-height: 1; font-weight: 900; color: var(–brand-ink); min-width: 1ch; }
.metric-badge .label { color: var(–muted); font-weight: 700; }
/* إجمالي المستفيدين */
.beneficiaries { margin-top: 14px; display: grid; grid-template-columns: 1fr; background: #ffffff; border-radius: 16px; box-shadow: var(–shadow); padding: 16px; gap: 8px; }
.beneficiaries .title { color: var(–muted); font-weight: 800; font-size: 14px; }
.beneficiaries .counter { font-weight: 900; font-size: clamp(28px, 6vw, 56px); color: var(–brand-ink); letter-spacing: 1px; position: relative; }
.spark { position: absolute; inset-inline-end: -10px; top: -10px; width: 10px; height: 10px;
background: radial-gradient(circle, #ffd27a, #ffa400); border-radius: 50%; animation: pop 1.2s ease infinite; filter: blur(.3px); }
@keyframes pop { 0%{transform:scale(.6); opacity:.6} 70%{transform:scale(1.4); opacity:.1} 100%{transform:scale(.6); opacity:.6} }
/* البطاقات */
.grid { margin-top: 18px; display: grid; gap: 14px; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) { .grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 760px) { .hero-inner { grid-template-columns: 1fr; } .grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .grid { grid-template-columns: 1fr; } }
.card { background: var(–card); border-radius: 16px; padding: 16px; box-shadow: var(–shadow);
transition: transform .15s ease, box-shadow .15s ease; display: grid; gap: 10px; min-height: 132px; }
.card:hover { transform: translateY(-2px); box-shadow: 0 14px 26px rgba(0,0,0,.08); }
.card .head { display: flex; align-items: center; gap: 10px; font-weight: 800; }
.icon { width: 28px; height: 28px; border-radius: 8px; background: #e9f6f3; display: grid; place-items: center; font-size: 18px; color: var(–brand-ink); flex: 0 0 28px; }
.kpis { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.kpis .today { font-size: 22px; font-weight: 900; color: var(–brand-ink); }
.kpis .sep { color: #c6d4d1; }
.kpis .total { color: var(–muted); font-weight: 700; }
.progress { height: 8px; width: 100%; background: #edf3f2; border-radius: 999px; overflow: hidden; }
.bar { height: 100%; width: 0%; background: linear-gradient(90deg, var(–brand), var(–accent)); transition: width .8s ease; }
/* شريط المحاضرات */
.ticker-wrap { margin-top: 18px; background: #ffffff; border-radius: 14px; box-shadow: var(–shadow); overflow: hidden; position: relative; }
.ticker-title { position: absolute; inset-inline-start: 0; top: 0; bottom: 0; width: 180px; display: grid; place-items: center; background: #0e5e55; color: #fff; font-weight: 800; }
.ticker { white-space: nowrap; display: flex; align-items: center; gap: 26px; padding-inline: 200px 20px; padding-block: 12px; animation: slide 28s linear infinite; }
@keyframes slide { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.tick { display: inline-flex; align-items: center; gap: 10px; color: var(–ink); background: #f2f8f6; padding: 8px 12px; border-radius: 999px; font-weight: 700; }
.tick:before { content: “📚”; }
/* أعلام الدول */
.countries { margin-top: 18px; background: #ffffff; border-radius: 14px; box-shadow: var(–shadow); padding: 12px 14px; }
.countries .title { font-weight: 800; margin-bottom: 10px; }
.flags { display: grid; grid-template-columns: repeat(8, minmax(92px,1fr)); gap: 10px; }
@media (max-width: 900px) { .flags { grid-template-columns: repeat(5, minmax(92px,1fr)); } }
@media (max-width: 600px) { .flags { grid-template-columns: repeat(3, minmax(92px,1fr)); } }
.flag-card { display: grid; grid-template-rows: auto auto; justify-items: center; gap: 6px; background: #f6fbfa; border: 1px solid #e5f0ee; border-radius: 12px; padding: 8px; }
.flag-img { width: 44px; height: 32px; border-radius: 6px; box-shadow: 0 4px 10px rgba(0,0,0,.06); object-fit: cover; }
.flag-name { font-size: 12px; color: var(–muted); }
.flag-count { font-weight: 800; color: var(–brand-ink); font-size: 14px; }
/* فوتر */
.foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 16px; color: var(–muted); font-size: 13px; }
/* ===== بدّل هذه الروابط بروابط CSV (Google Sheets → Publish to web → CSV) ===== */
const CSV_URLS = {
KPIS: “”, // مثال: https://docs.google.com/spreadsheets/d/xxx/pub?output=csv
PROJECTS: “”,
LECTURES: “”,
COUNTRIES:”” // جدول أعلام الدول
};
/* ===== بيانات تجريبية تعمل بدون روابط ===== */
const TZ = “Asia/Riyadh”;
const DEMO_TODAY = new Date().toLocaleDateString(“en-CA”, { timeZone: TZ });
const DEMO = {
KPIS: [
{date: DEMO_TODAY, metric_key: “new_muslims”, value_today: “9”, value_total: “435”, monthly_target: “300”},
{date: DEMO_TODAY, metric_key: “beneficiaries_total”, value_today: “140”, value_total: “283551”, monthly_target: “300000”},
{date: DEMO_TODAY, metric_key: “lectures”, value_today: “12”, value_total: “310”, monthly_target: “250”},
{date: DEMO_TODAY, metric_key: “quran_distributed”, value_today: “85”, value_total: “5920”, monthly_target: “4000”}
],
PROJECTS: [
{order: “1”, title_ar: “المسلمون الجدد”, metric_key: “new_muslims”, icon: “”, show: “TRUE”},
{order: “2”, title_ar: “الدروس والمحاضرات”, metric_key: “lectures”, icon: “”, show: “TRUE”},
{order: “3”, title_ar: “توزيع المصاحف”, metric_key: “quran_distributed”, icon: “”, show: “TRUE”}
],
LECTURES: [
{date: DEMO_TODAY, title_ar: “وصايا مهمة للشباب”},
{date: DEMO_TODAY, title_ar: “دروس في السيرة”},
{date: DEMO_TODAY, title_ar: “شرح رياض الصالحين”}
],
COUNTRIES: [
{date: DEMO_TODAY, country_code: “PH”, country_name_ar: “الفلبين”, count_today: “3”, count_total: “120”},
{date: DEMO_TODAY, country_code: “IN”, country_name_ar: “الهند”, count_today: “2”, count_total: “95”},
{date: DEMO_TODAY, country_code: “BD”, country_name_ar: “بنغلاديش”, count_today: “1”, count_total: “86”},
{date: DEMO_TODAY, country_code: “ET”, country_name_ar: “إثيوبيا”, count_today: “1”, count_total: “44”},
{date: DEMO_TODAY, country_code: “NG”, country_name_ar: “نيجيريا”, count_today: “1”, count_total: “27”},
{date: DEMO_TODAY, country_code: “NP”, country_name_ar: “نيبال”, count_today: “1”, count_total: “13”}
]
};
/* ===== أدوات مساعدة ===== */
const todayStr = new Date().toLocaleDateString(“en-CA”, { timeZone: TZ });
function parseCSV(text) {
const rows = []; let i = 0, field = “”, row = [], inQuotes = false;
while (i r.length && r.some(v => v)).map(r => {
const obj = {}; header.forEach((h, idx) => obj[h.trim()] = (r[idx] ?? “”).toString().trim()); return obj;
});
}
async function fetchCSV(url) {
const res = await fetch(url, { cache: “no-store” });
if (!res.ok) throw new Error(“CSV fetch failed: ” + url);
const text = await res.text();
return parseCSV(text);
}
function countUp(el, to, duration = 1200) {
const from = Number(el.textContent.replace(/\D/g, “”)) || 0;
const start = performance.now();
const diff = to – from;
function tick(now) {
const t = Math.min(1, (now – start) / duration);
const ease = 1 – Math.pow(1 – t, 3);
const val = Math.round(from + diff * ease);
el.textContent = val.toLocaleString(“ar-SA”);
if (t < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}
function pct(a, b) { if (!b || b (r.date || “”) === todayStr);
const latestByKey = {};
kpis.forEach(r => { const key = r.metric_key; if (!key) return;
if (!latestByKey[key] || (r.date > latestByKey[key].date)) latestByKey[key] = r; });
const metrics = {}; const keysSeen = new Set();
todays.forEach(r => { if (!r.metric_key) return;
keysSeen.add(r.metric_key);
metrics[r.metric_key] = { today: Number(r.value_today||0), total: Number(r.value_total||0), target: Number(r.monthly_target||0) };
});
Object.keys(latestByKey).forEach(key => { if (!keysSeen.has(key)) {
const r = latestByKey[key];
metrics[key] = { today: Number(r.value_today||0), total: Number(r.value_total||0), target: Number(r.monthly_target||0) };
} });
// Hero counters
countUp(document.getElementById(“heroNewMuslims”), (metrics[“new_muslims”]?.today) ?? 0);
// إجمالي المستفيدين (يعتمد على KPI بالمفتاح beneficiaries_total)
const beneficiariesTotal = (metrics[“beneficiaries_total”]?.total) ?? 0;
countUp(document.getElementById(“beneficiariesCounter”), beneficiariesTotal, 1600);
// Projects cards
const grid = document.getElementById(“projectsGrid”);
const sorted = […projects].filter(p => (p.show || “”).toString().toLowerCase() !== “false”)
.sort((a,b) => Number(a.order||0) – Number(b.order||0));
grid.innerHTML = “”;
sorted.forEach(p => {
const m = metrics[p.metric_key] || { today: 0, total: 0, target: 0 };
const progress = pct(m.total, m.target);
const card = document.createElement(“article”);
card.className = “card”;
card.innerHTML = `
`;
}).join(“”);
// Lectures ticker
const ticker = document.getElementById(“lecturesTicker”);
const todaysLectures = lectures.filter(r => (r.date || “”) === todayStr);
const l = (todaysLectures.length ? todaysLectures : lectures.slice(-6)).map(r => r.title_ar).filter(Boolean);
if (!l.length) l.push(“لا توجد محاضرات اليوم”);
ticker.innerHTML = […l, …l].map(t => `${escapeHTML(t)}`).join(“”);
// تحديث الوقت
const dt = new Date().toLocaleString(“ar-SA”, { timeZone: TZ, hour12: false });
document.getElementById(“lastUpdated”).textContent =
(isFresh ? “آخر تحديث مباشرة” : “آخر نسخة محفوظة”) + (note ? ” • ” + note : “”) + ” — ” + dt;
// تحريك أرقام البطاقات
requestAnimationFrame(() => {
document.querySelectorAll(“[data-today]”).forEach(el => { const val = Number(el.textContent.replace(/[^\d]/g, “”)) || 0; el.textContent = “0”; countUp(el, val, 900); });
document.querySelectorAll(“[data-total]”).forEach(el => { const val = Number(el.textContent.replace(/[^\d]/g, “”)) || 0; el.textContent = “0”; countUp(el, val, 900); });
});
}
function escapeHTML(str) {
return (str ?? “”).toString().replaceAll(“&”,”&”).replaceAll(“”,”>”)
.replaceAll(‘”‘,’"’).replaceAll(“‘”,”'”);
}
// ابدأ
(function init(){ loadAll(); })();
إنجازات اليوم في جمعية الدعوة بالطائف
تحديث يومي مباشر من لوحة المتابعة. شاهد أثر تبرعك لحظة بلحظة.
0
مسلم جديد اليوم
إجمالي المستفيدين حتى الآن
0
المسلمون الجدد اليوم حسب الدول
محاضرات اليوم
آخر تحديث — …
واجهة حيّة • أرقام اليوم + الإجمالي
${p.title_ar || p.metric_key || “مشروع”}
${(m.today||0).toLocaleString(“ar-SA”)}
اليوم
الإجمالي: ${(m.total||0).toLocaleString(“ar-SA”)}
`;
grid.appendChild(card);
});
// Countries flags (today)
const flagsGrid = document.getElementById(“flagsGrid”);
const todaysCountries = countries.filter(r => (r.date || “”) === todayStr).filter(r => Number(r.count_today||0) > 0);
const list = todaysCountries.length ? todaysCountries : countries.slice(0, 12);
flagsGrid.innerHTML = list.map(c => {
const code = (c.country_code || “”).toUpperCase();
const src = `https://flagcdn.com/w40/${code.toLowerCase()}.png`;
const name = c.country_name_ar || code;
const cnt = Number(c.count_today || 0);
return `
${name}
+${cnt.toLocaleString(“ar-SA”)}