# main.py — مخيم إيواء الحرية – نتساريم ١٨
# PyScript 2026.x  |  from pyscript import web, when, js

from pyscript import web, when
import js, json, io, csv as csv_mod
from datetime import datetime, date

# ═══════════════════════════════════════════════════════════════
#  STORAGE KEYS
# ═══════════════════════════════════════════════════════════════
KEY_RECORDS  = "freedom_camp_records_v1"
KEY_DISEASES = "freedom_camp_diseases_v1"
KEY_ZONES    = "freedom_camp_zones_v1"
KEY_SETTINGS = "freedom_camp_settings_v1"
KEY_OLD_V2   = "netsareem_registry_v2"   # migration source

PAGE_TABLE  = 50
PAGE_FAMILY = 20

RELATIONS = ["رب الأسرة","الزوجة","إبن","إبنة","أخ","أخت",
             "حفيدة","حفيد","أم","أب","أخرى"]

REL_NORM = {
    "رب الاسرة":"رب الأسرة","الزوج":"الزوجة",
    "الزوجة 1":"الزوجة","الزوجة 2":"الزوجة","الزوجة 3":"الزوجة",
    "بنت الإبن":"حفيدة","ابن":"إبن","ابنة":"إبنة",
    "اخ":"أخ","اخت":"أخت","الأخت":"أخت",
}
MARITAL_NORM = {
    "متزوجة":"متزوج","منزوج":"متزوج","متعدد":"متزوج",
    "مطلقة":"مطلق","أرملة":"أرمل","ارملة":"أرمل",
    "آنسة":"أعزب","انسة":"أعزب","الناجي الوحيد":"أعزب",
}

DEFAULT_DISEASES = [
    {"id":1,"name":"السكري","category":"أمراض مزمنة","is_active":True},
    {"id":2,"name":"ارتفاع ضغط الدم","category":"أمراض مزمنة","is_active":True},
    {"id":3,"name":"أمراض القلب","category":"أمراض مزمنة","is_active":True},
    {"id":4,"name":"أمراض الكلى","category":"أمراض مزمنة","is_active":True},
    {"id":5,"name":"الفشل الكلوي","category":"أمراض مزمنة","is_active":True},
    {"id":6,"name":"السرطان","category":"أمراض مزمنة","is_active":True},
    {"id":7,"name":"أمراض الجهاز التنفسي","category":"أمراض مزمنة","is_active":True},
    {"id":8,"name":"أمراض العظام والمفاصل","category":"أمراض مزمنة","is_active":True},
    {"id":9,"name":"الإعاقة الجسدية","category":"إعاقة جسدية","is_active":True},
    {"id":10,"name":"الإعاقة الذهنية","category":"إعاقة ذهنية","is_active":True},
    {"id":11,"name":"الأمراض النفسية","category":"أمراض نفسية","is_active":True},
    {"id":12,"name":"الأمراض العصبية","category":"أمراض عضوية","is_active":True},
]

DEFAULT_ZONES = [
    {"id":1,"code":"A","name":"القطاع A","is_active":True},
    {"id":2,"code":"A1","name":"القطاع A1","is_active":True},
    {"id":3,"code":"A2","name":"القطاع A2","is_active":True},
    {"id":4,"code":"B1","name":"القطاع B1","is_active":True},
    {"id":5,"code":"B2","name":"القطاع B2","is_active":True},
    {"id":6,"code":"C","name":"القطاع C","is_active":True},
    {"id":7,"code":"C1","name":"القطاع C1","is_active":True},
    {"id":8,"code":"D1","name":"القطاع D1","is_active":True},
]

DEFAULT_SETTINGS = {
    "camp_name":  "مخيم إيواء الحرية – نتساريم ١٨",
    "issuer_name":"إدارة المخيم",
    "camp_logo":  "⛺",
}

# ═══════════════════════════════════════════════════════════════
#  GLOBAL STATE
# ═══════════════════════════════════════════════════════════════
_all_recs:  list = []
_filtered:  list = []
_page:      int  = 0
_view:      str  = "table"
_section:   str  = "dashboard"
_edit_id         = None
_del_id          = None
_del_callback    = None
_edit_disease_id = None
_edit_zone_id    = None

# Filter state
_q        = ""
_blocks: set = {"all"}
_gender   = ""
_origin   = ""
_rel      = ""
_marital  = ""
_presence = ""
_age_min  = None
_age_max  = None
_fs_min   = None
_fs_max   = None
_fl_sn    = False
_fl_preg  = False
_fl_cd    = False

# ═══════════════════════════════════════════════════════════════
#  DB LAYER — RECORDS
# ═══════════════════════════════════════════════════════════════
def _load() -> list:
    raw = js.window.localStorage.getItem(KEY_RECORDS)
    if raw is None or str(raw) in ("null","undefined","None",""):
        return []
    try:    return json.loads(str(raw))
    except: return []

def _save(records: list):
    js.window.localStorage.setItem(KEY_RECORDS, json.dumps(records, ensure_ascii=False))

def _next_id(records: list) -> int:
    return max((r.get("row_id",0) for r in records), default=0) + 1

def db_create(data: dict):
    recs = _load()
    data["row_id"]       = _next_id(recs)
    data["registered_at"]= datetime.now().strftime("%Y-%m-%d %H:%M")
    data["updated_at"]   = data["registered_at"]
    recs.append(data)
    _save(recs)

def db_update(row_id: int, data: dict):
    recs = _load()
    for r in recs:
        if r.get("row_id") == row_id:
            for k, v in data.items():
                if k not in ("row_id","registered_at"):
                    r[k] = v
            r["updated_at"] = datetime.now().strftime("%Y-%m-%d %H:%M")
            break
    _save(recs)

def db_delete(row_id: int):
    _save([r for r in _load() if r.get("row_id") != row_id])

def db_bulk_insert(new_recs: list, mode: str = "replace"):
    existing = _load() if mode == "merge" else []
    nid = _next_id(existing) if existing else 1
    for r in new_recs:
        r["row_id"] = nid; nid += 1
    _save(existing + new_recs)

# ═══════════════════════════════════════════════════════════════
#  DB LAYER — DISEASES
# ═══════════════════════════════════════════════════════════════
def _load_diseases() -> list:
    raw = js.window.localStorage.getItem(KEY_DISEASES)
    if raw is None or str(raw) in ("null","undefined","None",""):
        return []
    try:    return json.loads(str(raw))
    except: return []

def _save_diseases(items: list):
    js.window.localStorage.setItem(KEY_DISEASES, json.dumps(items, ensure_ascii=False))

def _next_disease_id(items: list) -> int:
    return max((d.get("id",0) for d in items), default=0) + 1

def _ensure_diseases():
    if not _load_diseases():
        _save_diseases(DEFAULT_DISEASES)

def disease_create(name: str, category: str):
    items = _load_diseases()
    items.append({"id":_next_disease_id(items),"name":name,"category":category,"is_active":True})
    _save_diseases(items)

def disease_update(did: int, name: str, category: str):
    items = _load_diseases()
    for d in items:
        if d.get("id") == did:
            d["name"] = name; d["category"] = category; break
    _save_diseases(items)

def disease_toggle(did: int):
    items = _load_diseases()
    recs  = _load()
    linked_names = {r.get("chronic","") for r in recs}
    for d in items:
        if d.get("id") == did:
            name = d.get("name","")
            if d.get("is_active") and any(name in str(s) for s in linked_names if s):
                return False   # cannot deactivate — in use
            d["is_active"] = not d.get("is_active", True)
            break
    _save_diseases(items)
    return True

# ═══════════════════════════════════════════════════════════════
#  DB LAYER — ZONES
# ═══════════════════════════════════════════════════════════════
def _load_zones() -> list:
    raw = js.window.localStorage.getItem(KEY_ZONES)
    if raw is None or str(raw) in ("null","undefined","None",""):
        return []
    try:    return json.loads(str(raw))
    except: return []

def _save_zones(items: list):
    js.window.localStorage.setItem(KEY_ZONES, json.dumps(items, ensure_ascii=False))

def _next_zone_id(items: list) -> int:
    return max((z.get("id",0) for z in items), default=0) + 1

def _ensure_zones():
    if not _load_zones():
        _save_zones(DEFAULT_ZONES)

def zone_create(code: str, name: str):
    items = _load_zones()
    items.append({"id":_next_zone_id(items),"code":code.upper(),"name":name,"is_active":True})
    _save_zones(items)
    _rebuild_block_chips()

def zone_update(zid: int, code: str, name: str):
    items = _load_zones()
    for z in items:
        if z.get("id") == zid:
            z["code"] = code.upper(); z["name"] = name; break
    _save_zones(items)
    _rebuild_block_chips()

def zone_delete(zid: int):
    items = _load_zones()
    _save_zones([z for z in items if z.get("id") != zid])
    _rebuild_block_chips()

def _active_zone_codes() -> list:
    return [z["code"] for z in _load_zones() if z.get("is_active")]

# ═══════════════════════════════════════════════════════════════
#  DB LAYER — SETTINGS
# ═══════════════════════════════════════════════════════════════
def _load_settings() -> dict:
    raw = js.window.localStorage.getItem(KEY_SETTINGS)
    if raw is None or str(raw) in ("null","undefined","None",""):
        return dict(DEFAULT_SETTINGS)
    try:    return json.loads(str(raw))
    except: return dict(DEFAULT_SETTINGS)

def _save_settings(s: dict):
    js.window.localStorage.setItem(KEY_SETTINGS, json.dumps(s, ensure_ascii=False))

# ═══════════════════════════════════════════════════════════════
#  DATA MIGRATION  (v2 → v1)
# ═══════════════════════════════════════════════════════════════
def _migrate_if_needed():
    if _load():
        return   # new key already has data
    raw = js.window.localStorage.getItem(KEY_OLD_V2)
    if raw is None or str(raw) in ("null","undefined","None",""):
        return
    try:
        old_recs = json.loads(str(raw))
    except:
        return
    new_recs = []
    for r in old_recs:
        new_recs.append({
            "row_id":           r.get("row_id",0),
            "family_num":       r.get("family_num"),
            "block":            r.get("block",""),
            "relation":         r.get("relation",""),
            "member_num":       r.get("member_num",1),
            "name":             r.get("name",""),
            "father_name":      "",
            "grandfather_name": "",
            "mother_name":      "",
            "tribe_name":       "",
            "gender":           r.get("gender",""),
            "dob":              r.get("dob",""),
            "age":              r.get("age"),
            "id_number":        r.get("id_number",""),
            "phone":            r.get("phone",""),
            "marital_status":   r.get("marital_status",""),
            "family_size":      r.get("family_size"),
            "education":        "",
            "origin":           r.get("origin",""),
            "presence_status":  "داخل المخيم",
            "departure_date":   "",
            "return_date":      "",
            "departure_reason": "",
            "special_needs":    r.get("special_needs",""),
            "chronic":          r.get("chronic",""),
            "pregnant":         r.get("pregnant",""),
            "expected_delivery_date": "",
            "delivery_completed":     False,
            "delivery_date":          "",
            "vulnerability_level":    5,
            "notes":            r.get("notes",""),
            "registered_at":    r.get("registered_at",""),
            "updated_at":       r.get("registered_at",""),
        })
    if new_recs:
        _save(new_recs)

# ═══════════════════════════════════════════════════════════════
#  PART 2 — HELPERS / FILTERS / INTELLIGENCE (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  HELPERS
# ═══════════════════════════════════════════════════════════════
def _calc_age(dob: str):
    if not dob: return None
    try:
        d = date.fromisoformat(dob); today = date.today()
        age = today.year - d.year - ((today.month, today.day) < (d.month, d.day))
        return age if 0 <= age <= 120 else None
    except: return None

def _age(r: dict):
    a = r.get("age")
    return a if a is not None else _calc_age(r.get("dob",""))

def _fv(fid: str) -> str:
    return str(web.page[fid].value).strip()

def _sv(fid: str, val):
    web.page[fid].value = str(val) if val is not None else ""

def _toast(msg: str, kind: str = "success"):
    t = web.page["toast"]
    t.textContent = msg
    t.className   = f"show {kind}"
    def _hide(*a): t.className = ""
    js.window.setTimeout(_hide, 3400)

def _modal_open(mid: str):
    web.page[mid].classList.add("open")

def _modal_close(mid: str):
    web.page[mid].classList.remove("open")

def _show(fid: str, visible: bool):
    web.page[fid].style.display = "" if visible else "none"

def _today() -> str:
    return date.today().isoformat()

def _now() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M")

_REL_CLS = {
    "رب الأسرة":"b-head","الزوجة":"b-wife","إبن":"b-son",
    "إبنة":"b-dau","أخ":"b-bro","أخت":"b-sis","حفيدة":"b-dau","حفيد":"b-son",
}

def _rel_badge(rel: str) -> str:
    cls = _REL_CLS.get(rel, "b-other")
    return f'<span class="badge {cls}">{rel or "—"}</span>'

def _presence_badge(p: str) -> str:
    cls = {"داخل المخيم":"b-inside","خارج المخيم":"b-outside","مفقود":"b-missing"}.get(p,"b-other")
    return f'<span class="badge {cls}">{p or "—"}</span>'

def _med_flags(r: dict) -> str:
    parts = []
    if r.get("special_needs",""):  parts.append('<span class="flag flag-sn"  title="احتياجات خاصة">♿</span>')
    if r.get("pregnant",""):        parts.append(f'<span class="flag flag-preg" title="{r["pregnant"]}">🤰</span>')
    if r.get("chronic",""):         parts.append('<span class="flag flag-cd"  title="مرض مزمن">💊</span>')
    if r.get("presence_status","") == "خارج المخيم": parts.append('<span class="flag flag-absent">🚪</span>')
    return f'<div class="flags">{"".join(parts)}</div>' if parts else '<span class="t3">—</span>'

def _vuln_badge(v: int) -> str:
    labels = {1:"حرج",2:"عالي",3:"متوسط",4:"منخفض",5:"طبيعي"}
    cls    = {1:"b-v1",2:"b-v2",3:"b-v3",4:"b-v4",5:"b-v5"}
    return f'<span class="badge {cls.get(v,"b-v5")}">{labels.get(v,"—")}</span>'

def _pagination(total: int, ps: int, unit: str = "سجل") -> str:
    if total <= ps: return ""
    tp = (total + ps - 1) // ps
    s  = _page * ps; e = min(s + ps, total)
    prev = f'<button class="page-btn" data-page="{_page-1}" {"disabled" if _page==0 else ""}>→ السابق</button>'
    nxt  = f'<button class="page-btn" data-page="{_page+1}" {"disabled" if e>=total else ""}>التالي ←</button>'
    nums = ""
    for i in range(tp):
        if i==0 or i==tp-1 or abs(i-_page)<=2:
            ac = 'class="page-btn active"' if i==_page else 'class="page-btn"'
            nums += f'<button {ac} data-page="{i}">{i+1}</button>'
        elif abs(i-_page)==3:
            nums += '<span class="page-btn" style="pointer-events:none;opacity:.5">…</span>'
    return (f'<div class="pagination"><span class="page-info">عرض {s+1}–{e} من {total:,} {unit}</span>'
            f'<div class="page-btns">{prev}{nums}{nxt}</div></div>')

# ═══════════════════════════════════════════════════════════════
#  FILTER LOGIC
# ═══════════════════════════════════════════════════════════════
def _apply_filters():
    global _filtered, _page
    q = _q.lower(); result = []
    for r in _all_recs:
        if q:
            hay = " ".join([r.get("name",""),r.get("father_name",""),r.get("tribe_name",""),
                            r.get("id_number",""),r.get("phone",""),r.get("origin",""),
                            r.get("notes","")]).lower()
            if q not in hay: continue
        if "all" not in _blocks and r.get("block","") not in _blocks: continue
        if _gender   and r.get("gender","")          != _gender:   continue
        if _origin   and r.get("origin","")          != _origin:   continue
        if _rel      and r.get("relation","")        != _rel:      continue
        if _marital  and r.get("marital_status","")  != _marital:  continue
        if _presence and r.get("presence_status","") != _presence: continue
        age = _age(r)
        if _age_min is not None and (age is None or age < _age_min): continue
        if _age_max is not None and (age is None or age > _age_max): continue
        fs = r.get("family_size")
        if _fs_min is not None and (fs is None or fs < _fs_min): continue
        if _fs_max is not None and (fs is None or fs > _fs_max): continue
        if _fl_sn   and not r.get("special_needs",""): continue
        if _fl_preg and not r.get("pregnant",""):       continue
        if _fl_cd   and not r.get("chronic",""):        continue
        result.append(r)
    _filtered = result; _page = 0

def _count_active() -> int:
    n = 0
    if _q: n+=1
    if "all" not in _blocks: n+=1
    for v in (_gender,_origin,_rel,_marital,_presence):
        if v: n+=1
    if _age_min is not None or _age_max is not None: n+=1
    if _fs_min  is not None or _fs_max  is not None: n+=1
    if _fl_sn:   n+=1
    if _fl_preg: n+=1
    if _fl_cd:   n+=1
    return n

def _sync_filter_badge():
    n = _count_active()
    badge = web.page["flt-badge-tb"]
    btn   = web.page["filter-toggle-btn"]
    if n > 0:
        badge.textContent   = str(n)
        badge.style.display = "inline"
        btn.classList.add("active")
    else:
        badge.style.display = "none"
        btn.classList.remove("active")

def _sync_block_chips():
    for chip in web.page.find(".chip-block"):
        val = chip.getAttribute("data-val")
        on  = ("all" in _blocks and val == "all") or val in _blocks
        chip.classList.toggle("active", on)

def _sync_gender_chips():
    for chip in web.page.find(".chip-gender"):
        chip.classList.toggle("active", chip.getAttribute("data-val") == _gender)

# ═══════════════════════════════════════════════════════════════
#  INTELLIGENCE ENGINE
# ═══════════════════════════════════════════════════════════════

def _calc_vulnerability(r: dict) -> int:
    has_sn   = bool(r.get("special_needs","").strip())
    has_cd   = bool(r.get("chronic","").strip())
    has_preg = bool(r.get("pregnant","").strip())
    age      = _age(r)
    elderly  = age is not None and age >= 65
    child    = age is not None and age <= 5
    if (has_sn and has_cd) or (has_sn and has_preg): return 1
    if has_sn or (has_cd and has_preg):               return 2
    if has_cd and (elderly or child):                 return 3
    if has_cd or (has_preg and elderly):              return 3
    if has_preg or elderly or child:                  return 4
    return 5

def _enrich_vulnerability(records: list) -> list:
    for r in records:
        r["vulnerability_level"] = _calc_vulnerability(r)
    return records

def _detect_siblings(records: list) -> dict:
    groups: dict = {}
    for r in records:
        fn = (r.get("father_name","") or "").strip()
        gn = (r.get("grandfather_name","") or "").strip()
        tn = (r.get("tribe_name","") or "").strip()
        if fn and (gn or tn):
            key = f"{fn}|{gn}|{tn}"
            groups.setdefault(key, []).append(r.get("row_id"))
    return {k:v for k,v in groups.items() if len(v)>1}

def _check_pregnancy_alerts(records: list) -> list:
    today = date.today(); alerts = []
    for r in records:
        if r.get("pregnant","") and not r.get("delivery_completed", False):
            edd = r.get("expected_delivery_date","")
            if edd:
                try:
                    if date.fromisoformat(edd) < today: alerts.append(r)
                except: pass
    return alerts

def _validate_record(data: dict) -> str:
    if data.get("gender") == "ذكر" and data.get("pregnant",""):
        return "⚠️ لا يمكن تسجيل حالة حمل لفرد ذكر."
    age = _calc_age(data.get("dob",""))
    if age is not None and age < 10 and data.get("marital_status") == "متزوج":
        return "⚠️ الحالة الاجتماعية 'متزوج' غير منطقية لعمر أقل من 10 سنوات."
    if age is not None and age > 65 and data.get("pregnant",""):
        return "⚠️ تنبيه: تسجيل حمل لفرد عمره أكثر من 65 سنة — يرجى المراجعة."
    return ""

# ═══════════════════════════════════════════════════════════════
#  POPULATE DYNAMIC UI
# ═══════════════════════════════════════════════════════════════
def _populate_origin_dropdown():
    origins = sorted({r.get("origin","") for r in _all_recs if r.get("origin","")})
    sel = web.page["fl-origin"]; sel.innerHTML = '<option value="">الكل</option>'
    for o in origins:
        opt = js.document.createElement("option")
        opt.value = o; opt.textContent = o; sel.appendChild(opt)
    dl = web.page["origin-dl"]; dl.innerHTML = ""
    for o in origins:
        opt = js.document.createElement("option"); opt.value = o; dl.appendChild(opt)

def _rebuild_block_chips():
    codes  = _active_zone_codes()
    chips  = web.page["block-chips"]
    chips.innerHTML = '<span class="chip chip-block active" data-val="all">الكل</span>'
    for c in codes:
        span = js.document.createElement("span")
        span.className = "chip chip-block"
        span.setAttribute("data-val", c)
        span.textContent = c
        chips.appendChild(span)
    # also rebuild block select in form
    sel = web.page["f-block"]
    sel.innerHTML = '<option value="">اختر…</option>'
    for c in codes:
        opt = js.document.createElement("option"); opt.value = c; opt.textContent = c
        sel.appendChild(opt)

# ═══════════════════════════════════════════════════════════════
#  PART 3 — DASHBOARD RENDERER (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  RENDER: DASHBOARD
# ═══════════════════════════════════════════════════════════════
def _render_dashboard():
    data    = _all_recs
    total   = len(data)
    fams    = len({r.get("family_num") for r in data if r.get("family_num")})
    males   = sum(1 for r in data if r.get("gender") == "ذكر")
    females = sum(1 for r in data if r.get("gender") == "أنثى")
    absent  = sum(1 for r in data if r.get("presence_status","") == "خارج المخيم")
    missing = sum(1 for r in data if r.get("presence_status","") == "مفقود")
    sn      = sum(1 for r in data if r.get("special_needs",""))
    preg    = sum(1 for r in data if r.get("pregnant",""))
    cd      = sum(1 for r in data if r.get("chronic",""))
    med_total = sum(1 for r in data if r.get("special_needs","") or r.get("pregnant","") or r.get("chronic",""))

    # Age groups
    ages = [_age(r) for r in data if _age(r) is not None]
    ch   = sum(1 for a in ages if a <= 11)
    yo   = sum(1 for a in ages if 12 <= a <= 17)
    ya   = sum(1 for a in ages if 18 <= a <= 35)
    ad   = sum(1 for a in ages if 36 <= a <= 60)
    el   = sum(1 for a in ages if a > 60)
    age_max = max(ch,yo,ya,ad,el,1)

    def pct(n): return round(n/age_max*100) if age_max else 0
    def bar_color(label):
        return {"أطفال":"#0d9488","شباب":"#3b82f6","بالغون":"#8b5cf6","كهول":"#f59e0b","كبار":"#ef4444"}.get(label,"#94a3b8")

    age_bars = ""
    for lbl, cnt in [("أطفال",ch),("شباب",yo),("بالغون",ya),("كهول",ad),("كبار",el)]:
        h = pct(cnt)
        age_bars += f"""
<div class="age-bar-wrap">
  <div class="age-bar-val">{cnt}</div>
  <div class="age-bar-outer" style="min-height:8px">
    <div class="age-bar-inner" style="height:{h}%;background:{bar_color(lbl)};min-height:4px"></div>
  </div>
  <div class="age-bar-lbl">{lbl}</div>
</div>"""

    # Vulnerability breakdown
    vuln_counts = {1:0,2:0,3:0,4:0,5:0}
    for r in data: vuln_counts[_calc_vulnerability(r)] = vuln_counts.get(_calc_vulnerability(r),0) + 1
    vuln_labels = {1:"حرج 🔴",2:"عالي 🟠",3:"متوسط 🟡",4:"منخفض 🟢",5:"طبيعي ⚪"}
    vuln_colors = {1:"#ef4444",2:"#f97316",3:"#f59e0b",4:"#10b981",5:"#94a3b8"}
    vuln_rows = ""
    for lv in range(1,6):
        cnt = vuln_counts[lv]; pct_v = round(cnt/total*100) if total else 0
        vuln_rows += f"""
<div class="vuln-row">
  <div class="vuln-label" style="color:{vuln_colors[lv]}">{vuln_labels[lv]}</div>
  <div class="vuln-bar-wrap"><div class="vuln-bar-fill" style="width:{pct_v}%;background:{vuln_colors[lv]}"></div></div>
  <div class="vuln-count">{cnt}</div>
</div>"""

    # Block distribution
    block_counts: dict = {}
    for r in data:
        b = r.get("block","—") or "—"
        block_counts[b] = block_counts.get(b,0)+1
    block_rows = "".join(
        f'<div class="rpt-row"><span>بلوك {b}</span><strong>{c:,}</strong></div>'
        for b,c in sorted(block_counts.items())
    ) or '<div class="rpt-row"><span>لا توجد بيانات</span></div>'

    # Pregnancy alerts
    alerts = _check_pregnancy_alerts(data)
    alert_html = ""
    if alerts:
        items = "".join(f'<div class="alert-item">⚠️ {r.get("name","—")} — موعد ولادة: {r.get("expected_delivery_date","")}</div>' for r in alerts[:5])
        alert_html = f'<div class="alert-card danger"><div class="alert-title danger">🚨 تنبيهات الولادة ({len(alerts)} حالة)</div>{items}</div>'

    settings = _load_settings()
    camp_name = settings.get("camp_name","مخيم إيواء الحرية")

    web.page["dash-content"].innerHTML = f"""
<div class="dash-hero">
  <div class="dash-hero-title">⛺ {camp_name}</div>
  <div class="dash-hero-sub">آخر تحديث: {_now()} &nbsp;·&nbsp; {total:,} مسجّل</div>
</div>

{alert_html}

<div class="dash-grid">
  <div class="kpi-card">
    <div class="kpi-top"><div class="kpi-icon teal">👥</div></div>
    <div class="kpi-val">{total:,}</div>
    <div class="kpi-lbl">إجمالي المقيمين</div>
    <div class="kpi-sub">في {fams:,} أسرة مسجّلة</div>
    <div class="kpi-bar"><div class="kpi-bar-fill" style="width:100%;background:var(--p)"></div></div>
  </div>
  <div class="kpi-card">
    <div class="kpi-top"><div class="kpi-icon blue">⚧️</div></div>
    <div class="kpi-val" style="font-size:1.4rem">{males:,} / {females:,}</div>
    <div class="kpi-lbl">ذكور / إناث</div>
    <div class="kpi-sub">{round(males/total*100) if total else 0}% ذكور</div>
    <div class="kpi-bar"><div class="kpi-bar-fill" style="width:{round(males/total*100) if total else 0}%;background:var(--info)"></div></div>
  </div>
  <div class="kpi-card">
    <div class="kpi-top"><div class="kpi-icon red">🏥</div></div>
    <div class="kpi-val" style="color:var(--danger)">{med_total:,}</div>
    <div class="kpi-lbl">الحالات الطبية</div>
    <div class="kpi-sub">♿{sn} &nbsp;🤰{preg} &nbsp;💊{cd}</div>
    <div class="kpi-bar"><div class="kpi-bar-fill" style="width:{round(med_total/total*100) if total else 0}%;background:var(--danger)"></div></div>
  </div>
  <div class="kpi-card">
    <div class="kpi-top"><div class="kpi-icon amber">🚪</div></div>
    <div class="kpi-val" style="color:var(--amber)">{absent:,}</div>
    <div class="kpi-lbl">خارج المخيم</div>
    <div class="kpi-sub">{'مفقود: '+str(missing) if missing else 'لا مفقودون'}</div>
    <div class="kpi-bar"><div class="kpi-bar-fill" style="width:{round(absent/total*100) if total else 0}%;background:var(--amber)"></div></div>
  </div>
</div>

<div style="display:grid;grid-template-columns:1fr 1fr;gap:.55rem;margin-bottom:.85rem">
  <div class="card">
    <div class="card-header"><span class="card-title">📊 التوزيع العمري</span></div>
    <div class="card-body">
      <div class="age-dist">{age_bars}</div>
      <div style="font-size:.7rem;color:var(--t4);text-align:center;margin-top:.3rem">
        0-11 · 12-17 · 18-35 · 36-60 · 60+
      </div>
    </div>
  </div>
  <div class="card">
    <div class="card-header"><span class="card-title">⚠️ مستوى الهشاشة</span></div>
    <div class="card-body">
      <div class="vuln-list">{vuln_rows}</div>
    </div>
  </div>
</div>

<div style="display:grid;grid-template-columns:1fr 1fr;gap:.55rem;margin-bottom:1rem">
  <div class="card">
    <div class="card-header"><span class="card-title">🏘️ توزيع البلوكات</span></div>
    <div class="card-body" style="display:flex;flex-direction:column;gap:.2rem">{block_rows}</div>
  </div>
  <div class="card">
    <div class="card-header"><span class="card-title">📈 ملخص سريع</span></div>
    <div class="card-body" style="display:flex;flex-direction:column;gap:.25rem">
      <div class="rpt-row"><span>🏠 أسر</span><strong>{fams:,}</strong></div>
      <div class="rpt-row"><span>🤰 حوامل/مرضعات</span><strong>{preg}</strong></div>
      <div class="rpt-row"><span>♿ احتياجات خاصة</span><strong>{sn}</strong></div>
      <div class="rpt-row"><span>💊 أمراض مزمنة</span><strong>{cd}</strong></div>
      <div class="rpt-row"><span>🚪 غائبون</span><strong>{absent}</strong></div>
      <div class="rpt-row"><span>❓ مفقودون</span><strong>{missing}</strong></div>
    </div>
  </div>
</div>

<div style="display:flex;gap:.5rem;flex-wrap:wrap">
  <button class="btn btn-p btn-sm" id="dash-add-btn">＋ إضافة فرد</button>
  <button class="btn btn-outline btn-sm" id="dash-report-btn">📊 تقارير</button>
  <button class="btn btn-outline btn-sm" id="dash-import-btn">📥 استيراد Excel</button>
</div>"""

    # Wire dashboard quick buttons after render
    try:
        web.page["dash-add-btn"].onclick = lambda e: _open_person_modal(None)
        web.page["dash-report-btn"].onclick = lambda e: (_update_report_stats(), _modal_open("modal-report-bd"))
        web.page["dash-import-btn"].onclick = lambda e: _modal_open("modal-import-bd")
    except: pass

# ═══════════════════════════════════════════════════════════════
#  PART 4 — INDIVIDUALS RENDERER (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  RENDER: STATS BAR  (individuals section)
# ═══════════════════════════════════════════════════════════════
def _render_stats():
    data    = _filtered; total = len(data)
    fams    = len({r.get("family_num") for r in data if r.get("family_num")})
    males   = sum(1 for r in data if r.get("gender") == "ذكر")
    females = sum(1 for r in data if r.get("gender") == "أنثى")
    med     = sum(1 for r in data if r.get("special_needs","") or r.get("pregnant","") or r.get("chronic",""))
    pct     = round(males/total*100) if total else 0
    web.page["ind-stats"].innerHTML = f"""
<div class="stat-card">
  <div class="stat-ico">👥</div><div class="stat-lbl">الأفراد</div>
  <div class="stat-val">{total:,}</div>
  <div class="stat-sub">من {len(_all_recs):,} إجمالاً</div>
</div>
<div class="stat-card">
  <div class="stat-ico">🏠</div><div class="stat-lbl">الأسر</div>
  <div class="stat-val">{fams:,}</div><div class="stat-sub">أسرة مسجّلة</div>
</div>
<div class="stat-card">
  <div class="stat-ico">⚧️</div><div class="stat-lbl">ذكور / إناث</div>
  <div class="stat-val" style="font-size:1.3rem">{males:,}/{females:,}</div>
  <div class="stat-sub">{pct}% ذكور</div>
</div>
<div class="stat-card danger">
  <div class="stat-ico">🏥</div><div class="stat-lbl">حالات طبية</div>
  <div class="stat-val danger">{med:,}</div>
  <div class="stat-sub">تستدعي اهتماماً</div>
</div>"""

# ═══════════════════════════════════════════════════════════════
#  RENDER: TABLE VIEW
# ═══════════════════════════════════════════════════════════════
def _render_table():
    total = len(_filtered); s = _page * PAGE_TABLE; e = min(s+PAGE_TABLE, total)
    rows  = ""
    for r in _filtered[s:e]:
        age  = _age(r)
        pres = r.get("presence_status","داخل المخيم")
        rows += f"""
<tr data-id="{r.get('row_id','')}">
  <td class="td-num">{r.get('family_num') or '—'}</td>
  <td class="td-name">{r.get('name') or '—'}</td>
  <td><span class="badge b-block">{r.get('block') or '—'}</span></td>
  <td>{_rel_badge(r.get('relation',''))}</td>
  <td>{r.get('gender') or '—'}</td>
  <td>{age if age is not None else '—'}</td>
  <td class="td-mono">{r.get('id_number') or '—'}</td>
  <td class="td-mono">{r.get('phone') or '—'}</td>
  <td>{r.get('marital_status') or '—'}</td>
  <td>{r.get('origin') or '—'}</td>
  <td style="text-align:center">{r.get('family_size') if r.get('family_size') is not None else '—'}</td>
  <td>{_presence_badge(pres)}</td>
  <td>{_vuln_badge(_calc_vulnerability(r))}</td>
  <td>{_med_flags(r)}</td>
  <td class="td-actions">
    <div class="row-acts">
      <button class="btn-icon bti-e" data-action="edit" data-id="{r.get('row_id','')}">✏️</button>
      <button class="btn-icon bti-d" data-action="del"  data-id="{r.get('row_id','')}">🗑️</button>
    </div>
  </td>
</tr>"""
    if not _filtered[s:e]:
        rows = '<tr><td colspan="15"><div class="empty-state"><div class="em-ico">🔍</div><p class="em-title">لا توجد نتائج</p><p class="em-sub">جرّب تغيير الفلاتر أو البحث</p></div></td></tr>'

    web.page["content-area"].innerHTML = f"""
<div class="table-card">
  <div class="table-scroll">
    <table>
      <thead><tr>
        <th>رقم الأسرة</th><th>الاسم</th><th>البلوك</th><th>الصلة</th>
        <th>الجنس</th><th>العمر</th><th>رقم الهوية</th><th>الجوال</th>
        <th>الحالة الاجتماعية</th><th>السكن الأصلي</th><th>حجم الأسرة</th>
        <th>الحضور</th><th>الهشاشة</th><th>طبي</th><th>إجراءات</th>
      </tr></thead>
      <tbody>{rows}</tbody>
    </table>
  </div>
  {_pagination(total, PAGE_TABLE)}
</div>"""

# ═══════════════════════════════════════════════════════════════
#  RENDER: FAMILY VIEW
# ═══════════════════════════════════════════════════════════════
def _render_families():
    families: dict = {}
    for r in _filtered:
        k = r.get("family_num") or 0
        families.setdefault(k,[]).append(r)
    sorted_fams = sorted(families.items(), key=lambda x:(x[0]==0, x[0]))
    total_fams  = len(sorted_fams)
    s = _page * PAGE_FAMILY; e = min(s+PAGE_FAMILY, total_fams)
    html = ""
    for fnum, members in sorted_fams[s:e]:
        head     = next((m for m in members if m.get("relation")=="رب الأسرة"), members[0])
        med_cnt  = sum(1 for m in members if m.get("special_needs","") or m.get("pregnant","") or m.get("chronic",""))
        absent   = sum(1 for m in members if m.get("presence_status","")=="خارج المخيم")
        med_badge = f'<span class="badge b-v2">🏥 {med_cnt}</span>' if med_cnt else ""
        abs_badge = f'<span class="badge b-outside">🚪 {absent}</span>' if absent else ""

        member_rows = ""
        for m in sorted(members, key=lambda x: x.get("member_num",99)):
            age     = _age(m)
            age_str = f" · {age} سنة" if age is not None else ""
            member_rows += f"""
<div class="member-row" data-id="{m.get('row_id','')}">
  <div class="mbr-rel">{_rel_badge(m.get('relation',''))}</div>
  <div class="mbr-name">{m.get('name','—')}<span class="mbr-meta">{m.get('gender','')}{age_str}</span></div>
  <div class="mbr-flags">{_med_flags(m)}</div>
  <div class="mbr-id">{m.get('id_number','') or ''}</div>
  <div class="mact">
    <button class="btn-icon bti-e" data-action="edit" data-id="{m.get('row_id','')}">✏️</button>
    <button class="btn-icon bti-d" data-action="del"  data-id="{m.get('row_id','')}">🗑️</button>
  </div>
</div>"""

        phone_str = f"📞 {head.get('phone','')}" if head.get("phone","") else ""
        html += f"""
<div class="family-card">
  <div class="family-head">
    <div class="fam-num">{fnum if fnum else '?'}</div>
    <div class="fam-info">
      <div class="fam-nm">{head.get('name','—')}</div>
      <div class="fam-meta">
        <span class="badge b-block">{head.get('block','—')}</span>
        {head.get('origin','—')} · {len(members)} أفراد
        {f'· {phone_str}' if phone_str else ''}
        {med_badge}{abs_badge}
      </div>
    </div>
    <div class="fam-meta-acts">
      <button class="btn btn-sm btn-outline" data-action="add-member" data-fnum="{fnum}">+ فرد</button>
    </div>
  </div>
  <div class="family-members">{member_rows}</div>
</div>"""
    if not sorted_fams[s:e]:
        html = '<div class="empty-state"><div class="em-ico">🏠</div><p class="em-title">لا توجد أسر مطابقة</p></div>'
    web.page["content-area"].innerHTML = html + _pagination(total_fams, PAGE_FAMILY, "أسرة")

# ═══════════════════════════════════════════════════════════════
#  FULL RENDER CYCLE
# ═══════════════════════════════════════════════════════════════
def _render():
    _render_stats()
    web.page["results-count"].textContent = f"{len(_filtered):,} نتيجة"
    _sync_filter_badge()
    if _view == "family": _render_families()
    else:                  _render_table()

def _filter_and_render():
    _apply_filters(); _render()

# ═══════════════════════════════════════════════════════════════
#  PART 5 — REPORTS ENGINE (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  REPORT ENGINE
# ═══════════════════════════════════════════════════════════════
def _report_data() -> list:
    use_filtered = web.page["rpt-filtered"].checked
    return _filtered if use_filtered else _all_recs

def _update_report_stats():
    data  = _report_data(); total = len(data)
    fams  = len({r.get("family_num") for r in data if r.get("family_num")})
    males = sum(1 for r in data if r.get("gender")=="ذكر")
    females=sum(1 for r in data if r.get("gender")=="أنثى")
    sn    = sum(1 for r in data if r.get("special_needs",""))
    preg  = sum(1 for r in data if r.get("pregnant",""))
    cd    = sum(1 for r in data if r.get("chronic",""))
    web.page["rpt-count"].textContent = f"{total:,}"
    web.page["rpt-stats"].innerHTML = f"""
<div class="rpt-row"><span>👥 الأفراد</span><strong>{total:,}</strong></div>
<div class="rpt-row"><span>🏠 الأسر</span><strong>{fams:,}</strong></div>
<div class="rpt-row"><span>♂ ذكور</span><strong>{males:,}</strong></div>
<div class="rpt-row"><span>♀ إناث</span><strong>{females:,}</strong></div>
<div class="rpt-row"><span>♿ احتياجات خاصة</span><strong>{sn}</strong></div>
<div class="rpt-row"><span>🤰 حوامل/مرضعات</span><strong>{preg}</strong></div>
<div class="rpt-row"><span>💊 أمراض مزمنة</span><strong>{cd}</strong></div>"""

def _report_header_html(title: str, subtitle: str, issuer: str, data: list) -> str:
    settings = _load_settings()
    camp     = settings.get("camp_name","مخيم إيواء الحرية – نتساريم ١٨")
    today    = _today()
    total    = len(data)
    fams     = len({r.get("family_num") for r in data if r.get("family_num")})
    males    = sum(1 for r in data if r.get("gender")=="ذكر")
    females  = sum(1 for r in data if r.get("gender")=="أنثى")
    return f"""
<div class="hdr">
  <div class="camp">{camp}</div>
  <h1>{title}</h1>
  <p>{subtitle}</p>
</div>
<div class="meta">
  <div class="mi"><div class="mv">{today}</div><div class="ml">تاريخ الإصدار</div></div>
  <div class="mi"><div class="mv">{issuer or 'إدارة المخيم'}</div><div class="ml">جهة الإصدار</div></div>
  <div class="mi"><div class="mv">{total:,}</div><div class="ml">إجمالي السجلات</div></div>
  <div class="mi"><div class="mv">{fams:,}</div><div class="ml">عدد الأسر</div></div>
  <div class="mi"><div class="mv">{males:,}</div><div class="ml">ذكور</div></div>
  <div class="mi"><div class="mv">{females:,}</div><div class="ml">إناث</div></div>
</div>"""

_REPORT_BASE_CSS = """
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:'Tajawal',Arial,sans-serif;direction:rtl;color:#0f172a;font-size:8pt}
.hdr{background:linear-gradient(135deg,#0d9488,#115e59);color:white;padding:.7cm 1cm}
.hdr .camp{font-size:9pt;opacity:.8;margin-bottom:2pt}
.hdr h1{font-size:15pt;margin-bottom:2pt}.hdr p{font-size:8pt;opacity:.85}
.meta{display:flex;gap:.5cm;padding:.4cm 1cm;background:#f0fdfa;border-bottom:1.5pt solid #0d9488;flex-wrap:wrap}
.mi{text-align:center;min-width:55px}
.mv{font-size:12pt;font-weight:900;color:#0d9488}.ml{font-size:6pt;color:#64748b;text-transform:uppercase}
.tbl{padding:.3cm .7cm}
table{width:100%;border-collapse:collapse;font-size:7pt}
th{background:#f8fafc;padding:3.5pt 3pt;border-bottom:1.5pt solid #0d9488;font-weight:700;text-align:right;white-space:nowrap}
td{padding:3pt 3pt;border-bottom:.4pt solid #e2e8f0}
tr:nth-child(even) td{background:#f8fafc}
.ft{padding:.4cm 1cm;text-align:center;font-size:6pt;color:#94a3b8;border-top:1pt solid #e2e8f0}
@media print{@page{margin:.5cm;size:A4 landscape}}
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700&display=swap');"""

def _open_print_window(html_body: str):
    w = js.window.open("","_blank","width=1150,height=780")
    w.document.write(html_body); w.document.close()

def _generate_full_list(data, title, issuer):
    rows = ""
    for r in data:
        age = _age(r)
        med = " ".join(filter(None,[
            "♿" if r.get("special_needs","") else "",
            "🤰" if r.get("pregnant","") else "",
            "💊" if r.get("chronic","") else "",
        ]))
        rows += f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td>{r.get('relation','—')}</td><td>{r.get('gender','—')}</td>
<td>{age if age is not None else '—'}</td>
<td dir="ltr">{r.get('id_number','—')}</td>
<td dir="ltr">{r.get('phone','—')}</td>
<td>{r.get('marital_status','—')}</td><td>{r.get('origin','—')}</td>
<td style="text-align:center">{r.get('family_size','—')}</td>
<td>{r.get('presence_status','—')}</td><td>{med or '—'}</td>
</tr>"""
    hdr = _report_header_html(title or "القائمة الكاملة للمقيمين","قائمة شاملة بجميع بيانات المقيمين",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>{title}</title><style>{_REPORT_BASE_CSS}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم</th><th>الصلة</th><th>الجنس</th>
<th>العمر</th><th>الهوية</th><th>الجوال</th><th>الحالة</th><th>السكن</th>
<th>حجم الأسرة</th><th>الحضور</th><th>طبي</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_phone_dir(data, title, issuer):
    heads = [r for r in data if r.get("relation")=="رب الأسرة"]
    if not heads: heads = data
    rows = "".join(f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td dir="ltr" style="font-size:9pt;font-weight:700">{r.get('phone','—')}</td>
<td>{r.get('origin','—')}</td><td>{r.get('family_size','—')}</td>
</tr>""" for r in sorted(heads, key=lambda x:(x.get('block',''),x.get('family_num') or 0)))
    hdr = _report_header_html(title or "دليل الهواتف","أرقام هواتف أرباب الأسر",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>دليل الهواتف</title><style>{_REPORT_BASE_CSS}
@media print{{@page{{size:A4 portrait}}}}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>رب الأسرة</th><th>رقم الجوال</th>
<th>السكن الأصلي</th><th>حجم الأسرة</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_critical(data, title, issuer):
    crit = [r for r in data if r.get("special_needs","") or r.get("chronic","") or r.get("pregnant","")]
    crit.sort(key=lambda r: _calc_vulnerability(r))
    rows = "".join(f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td>{r.get('gender','—')}</td><td>{_age(r) if _age(r) is not None else '—'}</td>
<td dir="ltr">{r.get('phone','—')}</td>
<td>{r.get('special_needs','') or '—'}</td>
<td>{r.get('chronic','') or '—'}</td>
<td>{r.get('pregnant','') or '—'}</td>
<td style="font-weight:700">{'⚠️ حرج' if _calc_vulnerability(r)==1 else '🔶 عالي' if _calc_vulnerability(r)==2 else '🟡 متوسط'}</td>
</tr>""" for r in crit)
    hdr = _report_header_html(title or "تقرير الحالات الحرجة","الأفراد ذوو الاحتياجات الخاصة والأمراض المزمنة",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>الحالات الحرجة</title><style>{_REPORT_BASE_CSS}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم</th><th>الجنس</th><th>العمر</th>
<th>الجوال</th><th>احتياجات خاصة</th><th>أمراض مزمنة</th><th>حمل/رضاعة</th><th>الأولوية</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()} &nbsp;·&nbsp; إجمالي الحالات: {len(crit)}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_age_class(data, title, issuer):
    groups = [("أطفال (0–11)",lambda a:a<=11),("شباب (12–17)",lambda a:12<=a<=17),
              ("بالغون (18–35)",lambda a:18<=a<=35),("كهول (36–60)",lambda a:36<=a<=60),
              ("كبار السن (60+)",lambda a:a>60)]
    sections = ""
    for gname, cond in groups:
        grp = [r for r in data if _age(r) is not None and cond(_age(r))]
        m   = sum(1 for r in grp if r.get("gender")=="ذكر")
        f   = sum(1 for r in grp if r.get("gender")=="أنثى")
        sections += f'<tr style="background:#f0fdfa;font-weight:800"><td colspan="6">📌 {gname} — {len(grp)} فرد ({m} ذكر / {f} أنثى)</td></tr>'
        sections += "".join(f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td>{r.get('name','—')}</td><td>{r.get('gender','—')}</td>
<td>{_age(r)}</td><td>{r.get('marital_status','—')}</td>
</tr>""" for r in grp)
    hdr = _report_header_html(title or "التصنيف العمري","توزيع السكان حسب الفئة العمرية",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>التصنيف العمري</title><style>{_REPORT_BASE_CSS}@media print{{@page{{size:A4 portrait}}}}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم</th><th>الجنس</th><th>العمر</th><th>الحالة الاجتماعية</th>
</tr></thead><tbody>{sections}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_absent(data, title, issuer):
    absent = [r for r in data if r.get("presence_status","") in ("خارج المخيم","مفقود")]
    rows = "".join(f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td>{r.get('gender','—')}</td><td>{_age(r) if _age(r) is not None else '—'}</td>
<td dir="ltr">{r.get('phone','—')}</td>
<td style="color:{'#991b1b' if r.get('presence_status')=='مفقود' else '#9a3412'};font-weight:700">{r.get('presence_status','—')}</td>
<td>{r.get('departure_date','—') or '—'}</td>
<td>{r.get('departure_reason','—') or '—'}</td>
</tr>""" for r in absent)
    hdr = _report_header_html(title or "تقرير الغائبين","قائمة الأفراد خارج المخيم أو المفقودين",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>الغائبون</title><style>{_REPORT_BASE_CSS}@media print{{@page{{size:A4 portrait}}}}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم</th><th>الجنس</th><th>العمر</th>
<th>الجوال</th><th>الحالة</th><th>تاريخ الخروج</th><th>السبب</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()} &nbsp;·&nbsp; إجمالي الغائبين: {len(absent)}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_pregnant(data, title, issuer):
    preg = [r for r in data if r.get("pregnant","")]
    today_d = date.today()
    rows = ""
    for r in preg:
        edd = r.get("expected_delivery_date","")
        urgent = ""
        if edd:
            try:
                diff = (date.fromisoformat(edd) - today_d).days
                urgent = f"🔴 تأخر {-diff} يوم" if diff < 0 else f"⏳ {diff} يوم"
            except: pass
        rows += f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td>{_age(r) if _age(r) is not None else '—'}</td>
<td dir="ltr">{r.get('phone','—')}</td>
<td>{r.get('pregnant','—')}</td>
<td>{edd or '—'}</td>
<td style="font-weight:700">{urgent or '—'}</td>
</tr>"""
    hdr = _report_header_html(title or "تقرير الحوامل والمرضعات","قائمة الحالات",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>الحوامل والمرضعات</title><style>{_REPORT_BASE_CSS}@media print{{@page{{size:A4 portrait}}}}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم</th><th>العمر</th><th>الجوال</th>
<th>الحالة</th><th>موعد الولادة</th><th>المدة</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()} &nbsp;·&nbsp; إجمالي: {len(preg)}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_vuln(data, title, issuer):
    sorted_d = sorted(data, key=lambda r: _calc_vulnerability(r))
    rows = "".join(f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td>{r.get('gender','—')}</td><td>{_age(r) if _age(r) is not None else '—'}</td>
<td dir="ltr">{r.get('phone','—')}</td>
<td>{r.get('special_needs','') or '—'}</td>
<td>{r.get('chronic','') or '—'}</td>
<td>{r.get('pregnant','') or '—'}</td>
<td style="font-weight:800;color:{'#991b1b' if _calc_vulnerability(r)==1 else '#9a3412' if _calc_vulnerability(r)==2 else '#92400e'}">{['—','حرج','عالي','متوسط','منخفض','طبيعي'][_calc_vulnerability(r)]}</td>
</tr>""" for r in sorted_d if _calc_vulnerability(r) <= 4)
    hdr = _report_header_html(title or "تقرير الهشاشة والأولويات","الأفراد الأكثر احتياجاً للدعم",issuer,data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>تقرير الهشاشة</title><style>{_REPORT_BASE_CSS}</style></head><body>
{hdr}<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم</th><th>الجنس</th><th>العمر</th>
<th>الجوال</th><th>احتياجات خاصة</th><th>أمراض</th><th>حمل</th><th>مستوى الهشاشة</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{_load_settings().get('camp_name','')} &nbsp;·&nbsp; {_today()}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _generate_wfp(data, title, issuer):
    settings = _load_settings()
    camp = settings.get("camp_name","مخيم إيواء الحرية – نتساريم ١٨")
    total = len(data); fams = len({r.get("family_num") for r in data if r.get("family_num")})
    males=sum(1 for r in data if r.get("gender")=="ذكر")
    females=sum(1 for r in data if r.get("gender")=="أنثى")
    ch=sum(1 for r in data if _age(r) is not None and _age(r)<=11)
    el=sum(1 for r in data if _age(r) is not None and _age(r)>60)
    sn=sum(1 for r in data if r.get("special_needs",""))
    preg_c=sum(1 for r in data if r.get("pregnant",""))
    cd=sum(1 for r in data if r.get("chronic",""))
    rows = "".join(f"""<tr>
<td>{r.get('family_num','—')}</td><td>{r.get('block','—')}</td>
<td style="font-weight:700">{r.get('name','—')}</td>
<td dir="ltr">{r.get('id_number','—')}</td>
<td>{r.get('gender','—')}</td><td>{_age(r) if _age(r) is not None else '—'}</td>
<td style="text-align:center">{r.get('family_size','—')}</td>
<td>{'نعم' if r.get('special_needs','') else ''}</td>
</tr>""" for r in data)
    return f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>تقرير WFP</title><style>{_REPORT_BASE_CSS}
.wfp-summary{{display:grid;grid-template-columns:repeat(4,1fr);gap:.3cm;padding:.4cm 1cm;background:#fff;border-bottom:1pt solid #e2e8f0}}
.ws{{background:#f0fdfa;border-radius:8px;padding:.3cm;text-align:center}}
.wsv{{font-size:14pt;font-weight:900;color:#0d9488}}.wsl{{font-size:6pt;color:#64748b}}
</style></head><body>
<div class="hdr">
  <div class="camp">{camp}</div>
  <h1>{title or 'تقرير برنامج الأغذية العالمي'}</h1>
  <p>تاريخ الإصدار: {_today()} &nbsp;|&nbsp; جهة الإصدار: {issuer or 'إدارة المخيم'}</p>
</div>
<div class="wfp-summary">
  <div class="ws"><div class="wsv">{total:,}</div><div class="wsl">إجمالي الأفراد</div></div>
  <div class="ws"><div class="wsv">{fams:,}</div><div class="wsl">عدد الأسر</div></div>
  <div class="ws"><div class="wsv">{males:,}/{females:,}</div><div class="wsl">ذكور/إناث</div></div>
  <div class="ws"><div class="wsv">{ch:,}</div><div class="wsl">أطفال (0-11)</div></div>
  <div class="ws"><div class="wsv">{el:,}</div><div class="wsl">كبار السن (+60)</div></div>
  <div class="ws"><div class="wsv">{sn}</div><div class="wsl">احتياجات خاصة</div></div>
  <div class="ws"><div class="wsv">{preg_c}</div><div class="wsl">حوامل/مرضعات</div></div>
  <div class="ws"><div class="wsv">{cd}</div><div class="wsl">أمراض مزمنة</div></div>
</div>
<div class="tbl"><table><thead><tr>
<th>رقم الأسرة</th><th>البلوك</th><th>الاسم الكامل</th><th>رقم الهوية</th>
<th>الجنس</th><th>العمر</th><th>حجم الأسرة</th><th>إعاقة</th>
</tr></thead><tbody>{rows}</tbody></table></div>
<div class="ft">{camp} &nbsp;·&nbsp; {_today()} &nbsp;·&nbsp; للاستخدام الرسمي فقط</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""

def _do_print_report():
    data   = _report_data()
    rtype  = str(web.page["rpt-type-sel"].value)
    title  = _fv("rpt-title")
    issuer = _fv("rpt-issuer")
    if not data:
        _toast("لا توجد بيانات للتصدير","error"); return
    html_map = {
        "full":     _generate_full_list,
        "phone":    _generate_phone_dir,
        "critical": _generate_critical,
        "age":      _generate_age_class,
        "absent":   _generate_absent,
        "pregnant": _generate_pregnant,
        "vuln":     _generate_vuln,
        "wfp":      _generate_wfp,
    }
    fn = html_map.get(rtype, _generate_full_list)
    _open_print_window(fn(data, title, issuer))
    _modal_close("modal-report-bd")
    _toast(f"🖨️ جاري فتح التقرير ({len(data):,} سجل)")

def _do_export_excel():
    data  = _report_data()
    if not data:
        _toast("لا توجد بيانات","error"); return
    FIELDS  = ["family_num","block","name","father_name","grandfather_name","tribe_name",
               "relation","member_num","gender","dob","age","id_number","phone",
               "marital_status","family_size","origin","presence_status",
               "special_needs","pregnant","expected_delivery_date","chronic","notes","registered_at"]
    HEADERS = ["رقم الأسرة","البلوك","الاسم","اسم الأب","اسم الجد","العائلة/القبيلة",
               "صلة القرابة","رقم الفرد","الجنس","تاريخ الميلاد","العمر","رقم الهوية",
               "الجوال","الحالة الاجتماعية","حجم الأسرة","السكن الأصلي","حالة الحضور",
               "ذوو احتياجات خاصة","حوامل/مرضعات","موعد الولادة","أمراض مزمنة","ملاحظات","تاريخ التسجيل"]
    rows_out = [HEADERS]
    for r in data:
        rows_out.append([str(r.get(f,"") or "") for f in FIELDS])
    fname = f"مخيم_نتساريم_{datetime.now():%Y%m%d_%H%M}.xlsx"
    js.window.exportToExcel(json.dumps(rows_out, ensure_ascii=False), fname)
    _toast(f"📊 تم تصدير {len(data):,} سجل Excel"); _modal_close("modal-report-bd")

def _do_export_csv():
    data = _report_data()
    if not data:
        _toast("لا توجد بيانات","error"); return
    FIELDS  = ["family_num","block","name","relation","gender","dob","age",
               "id_number","phone","marital_status","family_size","origin",
               "presence_status","special_needs","pregnant","chronic","notes","registered_at"]
    HEADERS = ["رقم الأسرة","البلوك","الاسم","الصلة","الجنس","تاريخ الميلاد","العمر",
               "رقم الهوية","الجوال","الحالة الاجتماعية","حجم الأسرة","السكن",
               "حالة الحضور","ذوو احتياجات","حوامل","أمراض مزمنة","ملاحظات","تاريخ التسجيل"]
    buf = io.StringIO(); w = csv_mod.writer(buf); w.writerow(HEADERS)
    for r in data: w.writerow([r.get(f,"") for f in FIELDS])
    content = "\N{ZERO WIDTH NO-BREAK SPACE}" + buf.getvalue()
    blob = js.Blob.new([content],{"type":"text/csv;charset=utf-8"})
    url  = js.URL.createObjectURL(blob)
    a    = js.document.createElement("a")
    a.href = url; a.download = f"netsareem_{datetime.now():%Y%m%d_%H%M}.csv"; a.click()
    js.URL.revokeObjectURL(url)
    _toast(f"📄 تم تصدير {len(data):,} سجل CSV"); _modal_close("modal-report-bd")

# ═══════════════════════════════════════════════════════════════
#  PART 6 — ID CARDS + SETTINGS RENDERER (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  ID CARD GENERATOR
# ═══════════════════════════════════════════════════════════════
def _print_id_cards():
    scope    = str(web.page["idc-scope"].value)
    level    = str(web.page["idc-level"].value)
    per_page = int(str(web.page["idc-perpage"].value))
    settings = _load_settings()
    camp     = settings.get("camp_name","مخيم إيواء الحرية – نتساريم ١٨")

    if scope == "all":       residents = _all_recs
    elif scope == "heads":   residents = [r for r in _all_recs if r.get("relation")=="رب الأسرة"]
    else:                    residents = _filtered

    if not residents:
        _toast("لا توجد سجلات للطباعة","error"); return

    card_w = "48%" if per_page in (4,6) else "23%"
    cols   = 2 if per_page in (4,6) else 4

    def _build_card(r):
        age = _age(r)
        basic = f"""
<div style="font-size:6.5pt;line-height:1.7">
  <div style="display:flex;justify-content:space-between;border-bottom:.5pt solid #e2e8f0;padding-bottom:2pt;margin-bottom:3pt">
    <span style="color:#64748b">رقم الأسرة</span><span style="font-weight:800">{r.get('family_num','—')}</span>
  </div>
  <div style="display:flex;justify-content:space-between;border-bottom:.5pt solid #e2e8f0;padding-bottom:2pt;margin-bottom:3pt">
    <span style="color:#64748b">البلوك</span><span style="font-weight:800">{r.get('block','—')}</span>
  </div>
  <div style="display:flex;justify-content:space-between;border-bottom:.5pt solid #e2e8f0;padding-bottom:2pt;margin-bottom:3pt">
    <span style="color:#64748b">الصلة</span><span style="font-weight:800">{r.get('relation','—')}</span>
  </div>
  <div style="display:flex;justify-content:space-between">
    <span style="color:#64748b">الجنس / العمر</span><span style="font-weight:800">{r.get('gender','—')} / {age if age is not None else '—'}</span>
  </div>
</div>"""
        detailed = f"""
  <div style="display:flex;justify-content:space-between;border-bottom:.5pt solid #e2e8f0;padding-bottom:2pt;margin-bottom:3pt">
    <span style="color:#64748b">رقم الهوية</span><span style="font-weight:800;direction:ltr">{r.get('id_number','—')}</span>
  </div>
  <div style="display:flex;justify-content:space-between;border-bottom:.5pt solid #e2e8f0;padding-bottom:2pt;margin-bottom:3pt">
    <span style="color:#64748b">الجوال</span><span style="font-weight:800;direction:ltr">{r.get('phone','—')}</span>
  </div>
  <div style="display:flex;justify-content:space-between">
    <span style="color:#64748b">السكن</span><span style="font-weight:800">{r.get('origin','—')}</span>
  </div>""" if level in ("detailed","medical") else ""
        medical = f"""
  <div style="margin-top:4pt;padding-top:3pt;border-top:.5pt solid #fecaca;font-size:6pt;color:#991b1b">
    {'♿ ' + r.get('special_needs','') if r.get('special_needs','') else ''}
    {'🤰 ' + r.get('pregnant','') if r.get('pregnant','') else ''}
    {'💊 ' + r.get('chronic','') if r.get('chronic','') else ''}
  </div>""" if level == "medical" and (r.get("special_needs","") or r.get("pregnant","") or r.get("chronic","")) else ""
        return f"""
<div style="border:1.5pt solid #e2e8f0;border-radius:8pt;padding:6pt 7pt;width:{card_w};
            box-shadow:0 1pt 4pt rgba(0,0,0,.08);page-break-inside:avoid;margin-bottom:8pt">
  <div style="background:linear-gradient(135deg,#0d9488,#115e59);color:white;border-radius:5pt;
              padding:4pt 6pt;margin-bottom:5pt">
    <div style="font-size:5.5pt;opacity:.8">{camp}</div>
    <div style="font-size:9pt;font-weight:900">{r.get('name','—')}</div>
  </div>
  {basic}{detailed}{medical}
  <div style="margin-top:4pt;font-size:5pt;color:#94a3b8;text-align:center;border-top:.5pt solid #f1f5f9;padding-top:3pt">
    بطاقة رقم {r.get('row_id','')} &nbsp;|&nbsp; {_today()}
  </div>
</div>"""

    cards_html = ""
    for i, r in enumerate(residents):
        cards_html += _build_card(r)
        if (i+1) % per_page == 0:
            cards_html += '<div style="page-break-after:always"></div>'

    html = f"""<!DOCTYPE html><html dir="rtl" lang="ar"><head><meta charset="utf-8">
<title>بطاقات الهوية — {camp}</title>
<style>
*{{box-sizing:border-box;margin:0;padding:0}}
body{{font-family:'Tajawal',Arial,sans-serif;direction:rtl;padding:.5cm;background:#f8fafc}}
.cards-wrap{{display:flex;flex-wrap:wrap;gap:8pt;justify-content:flex-start}}
@media print{{body{{background:white;padding:.3cm}}@page{{margin:.4cm;size:A4 portrait}}}}
@import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700;900&display=swap');
</style></head><body>
<div style="text-align:center;padding:.3cm;margin-bottom:.3cm;border-bottom:1.5pt solid #0d9488">
  <div style="font-size:13pt;font-weight:900;color:#0d9488">{camp}</div>
  <div style="font-size:8pt;color:#64748b">بطاقات الهوية — {len(residents)} بطاقة — {_today()}</div>
</div>
<div class="cards-wrap">{cards_html}</div>
<script>window.onload=()=>setTimeout(()=>window.print(),600);</script>
</body></html>"""
    _open_print_window(html)
    _modal_close("modal-idcard-bd")
    _toast(f"🪪 جاري طباعة {len(residents)} بطاقة")

# ═══════════════════════════════════════════════════════════════
#  SETTINGS RENDERER
# ═══════════════════════════════════════════════════════════════
def _render_settings():
    settings = _load_settings()
    diseases = _load_diseases()
    zones    = _load_zones()

    # General tab
    general_html = f"""
<div class="setting-row">
  <div><div class="setting-label">اسم المخيم</div><div class="setting-hint">يظهر في التقارير والبطاقات</div></div>
  <input type="text" id="set-campname" class="fi" style="max-width:280px" value="{settings.get('camp_name','')}"/>
</div>
<div class="setting-row">
  <div><div class="setting-label">اسم جهة الإصدار</div><div class="setting-hint">يظهر في رأس التقارير الرسمية</div></div>
  <input type="text" id="set-issuer" class="fi" style="max-width:280px" value="{settings.get('issuer_name','')}"/>
</div>
<div style="display:flex;justify-content:flex-end;margin-top:.9rem">
  <button class="btn btn-p btn-sm" id="save-settings-btn">💾 حفظ الإعدادات</button>
</div>"""

    # Diseases tab
    dis_items = ""
    for d in diseases:
        status = "" if d.get("is_active") else " inactive"
        dis_items += f"""
<div class="disease-item{status}" data-did="{d['id']}">
  <div style="flex:1">
    <div class="disease-name">{d['name']}</div>
    <div class="disease-cat">{d.get('category','')}</div>
  </div>
  <button class="btn btn-xs btn-outline" data-action="edit-disease" data-did="{d['id']}">✏️</button>
  <button class="btn btn-xs {'btn-outline' if d.get('is_active') else 'btn-p'}"
          data-action="toggle-disease" data-did="{d['id']}">{'🚫 تعطيل' if d.get('is_active') else '✅ تفعيل'}</button>
</div>"""

    diseases_html = f"""
<div style="display:flex;justify-content:flex-end;margin-bottom:.7rem">
  <button class="btn btn-p btn-sm" id="add-disease-btn">+ إضافة مرض</button>
</div>
<div id="diseases-list">{dis_items}</div>"""

    # Zones tab
    zone_items = ""
    for z in zones:
        zone_items += f"""
<div class="zone-item" data-zid="{z['id']}">
  <div class="zone-code">{z['code']}</div>
  <div class="zone-info">
    <div class="zone-name">{z.get('name','')}</div>
    <div class="zone-sub">رمز: {z['code']}</div>
  </div>
  <button class="btn btn-xs btn-outline" data-action="edit-zone" data-zid="{z['id']}">✏️</button>
  <button class="btn btn-xs btn-danger"   data-action="del-zone"  data-zid="{z['id']}">🗑️</button>
</div>"""

    zones_html = f"""
<div style="display:flex;justify-content:flex-end;margin-bottom:.7rem">
  <button class="btn btn-p btn-sm" id="add-zone-btn">+ إضافة بلوك</button>
</div>
<div id="zones-list">{zone_items}</div>"""

    # Data management tab
    data_html = f"""
<div class="setting-row">
  <div><div class="setting-label">استيراد بيانات Excel</div><div class="setting-hint">استيراد أو دمج بيانات من ملف Excel</div></div>
  <button class="btn btn-import btn-sm" id="set-import-btn">📥 استيراد</button>
</div>
<div class="setting-row">
  <div><div class="setting-label">تصدير النسخة الاحتياطية</div><div class="setting-hint">تصدير جميع البيانات بصيغة Excel</div></div>
  <button class="btn btn-export btn-sm" id="set-export-btn">📤 تصدير كامل</button>
</div>
<div class="setting-row">
  <div><div class="setting-label" style="color:var(--danger)">مسح جميع البيانات</div>
  <div class="setting-hint">حذف كامل لا يمكن التراجع عنه</div></div>
  <button class="btn btn-danger btn-sm" id="set-clear-btn">🗑️ مسح الكل</button>
</div>"""

    web.page["settings-content"].innerHTML = f"""
<div class="card" style="margin-bottom:.85rem">
  <div class="card-body">
    <div class="settings-tabs">
      <button class="stab active" data-stab="general">⚙️ عام</button>
      <button class="stab" data-stab="diseases">🏥 أنواع الأمراض</button>
      <button class="stab" data-stab="zones">🏘️ البلوكات والقطاعات</button>
      <button class="stab" data-stab="data">💾 البيانات</button>
    </div>
    <div class="stab-content active" id="stab-general">{general_html}</div>
    <div class="stab-content" id="stab-diseases">{diseases_html}</div>
    <div class="stab-content" id="stab-zones">{zones_html}</div>
    <div class="stab-content" id="stab-data">{data_html}</div>
  </div>
</div>"""

    _wire_settings_events()

def _wire_settings_events():
    try:
        web.page["save-settings-btn"].onclick = lambda e: _save_settings_form()
    except: pass
    try:
        web.page["add-disease-btn"].onclick = lambda e: _open_disease_modal(None)
    except: pass
    try:
        web.page["add-zone-btn"].onclick = lambda e: _open_zone_modal(None)
    except: pass
    try:
        web.page["set-import-btn"].onclick = lambda e: _modal_open("modal-import-bd")
    except: pass
    try:
        web.page["set-export-btn"].onclick = lambda e: _do_export_excel()
    except: pass
    try:
        web.page["set-clear-btn"].onclick = lambda e: _confirm_clear_all()
    except: pass
    # Settings tabs
    for btn in web.page.find(".stab"):
        tab_id = btn.getAttribute("data-stab")
        if tab_id:
            btn.onclick = lambda e, tid=tab_id: _switch_settings_tab(tid)
    # Diseases list delegation
    try:
        web.page["diseases-list"].onclick = lambda e: _on_diseases_click(e)
    except: pass
    # Zones list delegation
    try:
        web.page["zones-list"].onclick = lambda e: _on_zones_click(e)
    except: pass

def _switch_settings_tab(tab_id: str):
    for btn in web.page.find(".stab"):
        btn.classList.toggle("active", btn.getAttribute("data-stab")==tab_id)
    for content in web.page.find(".stab-content"):
        content.classList.toggle("active", content.id == f"stab-{tab_id}")

def _save_settings_form():
    try:
        s = _load_settings()
        s["camp_name"]   = str(web.page["set-campname"].value).strip()
        s["issuer_name"] = str(web.page["set-issuer"].value).strip()
        _save_settings(s)
        # update sidebar camp name
        web.page["sb-camp-name"].textContent = s.get("camp_name","مخيم إيواء الحرية")
        _toast("✅ تم حفظ الإعدادات")
    except Exception as ex:
        _toast(f"خطأ: {ex}", "error")

def _on_diseases_click(event):
    btn = event.target.closest("[data-action]")
    if not btn: return
    action = btn.getAttribute("data-action")
    did    = btn.getAttribute("data-did")
    if not did: return
    did = int(did)
    if action == "edit-disease":
        _open_disease_modal(did)
    elif action == "toggle-disease":
        ok = disease_toggle(did)
        if ok: _toast("✅ تم تحديث الحالة"); _render_settings()
        else:  _toast("⚠️ لا يمكن تعطيل مرض مرتبط بسجلات موجودة","warn")

def _on_zones_click(event):
    btn = event.target.closest("[data-action]")
    if not btn: return
    action = btn.getAttribute("data-action")
    zid    = btn.getAttribute("data-zid")
    if not zid: return
    zid = int(zid)
    if action == "edit-zone":
        _open_zone_modal(zid)
    elif action == "del-zone":
        _confirm_action("هل تريد حذف هذا البلوك؟", lambda: (zone_delete(zid), _render_settings()))

# ═══════════════════════════════════════════════════════════════
#  PART 7 — MODAL LOGIC + CRUD EVENT HANDLERS (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  PERSON MODAL (ADD / EDIT)
# ═══════════════════════════════════════════════════════════════
def _open_person_modal(row_id, preset_family=None):
    global _edit_id; _edit_id = row_id
    web.page["modal-err"].style.display  = "none"
    web.page["modal-warn"].style.display = "none"

    if row_id is None:
        web.page["modal-person-title"].textContent = "إضافة فرد جديد"
        web.page["person-submit-btn"].textContent  = "➕ إضافة"
        for fid in ("f-name","f-fname","f-gname","f-mname","f-tribe",
                    "f-id","f-phone","f-origin","f-sn","f-cd","f-notes",
                    "f-depart","f-return","f-depart-reason","f-edd","f-deldate"):
            _sv(fid,"")
        _sv("f-block",""); _sv("f-fnum", preset_family or "")
        _sv("f-rel","رب الأسرة"); _sv("f-gender","ذكر"); _sv("f-dob","")
        _sv("f-marital",""); _sv("f-fsize",""); _sv("f-mnum","1")
        _sv("f-edu",""); _sv("f-presence","داخل المخيم"); _sv("f-preg","")
        web.page["f-delivered"].checked = False
        web.page["fg-edd"].style.display      = "none"
        web.page["fg-delivery"].style.display = "none"
        web.page["fg-delivery-check"].style.display = "none"
    else:
        rec = next((r for r in _all_recs if r.get("row_id")==row_id), None)
        if not rec: return
        web.page["modal-person-title"].textContent = "تعديل بيانات فرد"
        web.page["person-submit-btn"].textContent  = "💾 حفظ التعديلات"
        for fid, key in [("f-name","name"),("f-fname","father_name"),("f-gname","grandfather_name"),
                          ("f-mname","mother_name"),("f-tribe","tribe_name"),("f-id","id_number"),
                          ("f-phone","phone"),("f-origin","origin"),("f-sn","special_needs"),
                          ("f-cd","chronic"),("f-notes","notes"),("f-depart","departure_date"),
                          ("f-return","return_date"),("f-depart-reason","departure_reason"),
                          ("f-edd","expected_delivery_date"),("f-deldate","delivery_date")]:
            _sv(fid, rec.get(key,""))
        _sv("f-block",   rec.get("block",""))
        _sv("f-fnum",    rec.get("family_num",""))
        _sv("f-rel",     rec.get("relation","رب الأسرة"))
        _sv("f-gender",  rec.get("gender","ذكر"))
        _sv("f-dob",     rec.get("dob",""))
        _sv("f-marital", rec.get("marital_status",""))
        _sv("f-fsize",   rec.get("family_size",""))
        _sv("f-mnum",    rec.get("member_num",1))
        _sv("f-edu",     rec.get("education",""))
        _sv("f-presence",rec.get("presence_status","داخل المخيم"))
        _sv("f-preg",    rec.get("pregnant",""))
        web.page["f-delivered"].checked = bool(rec.get("delivery_completed"))
        preg_val = rec.get("pregnant","")
        show_preg = bool(preg_val)
        web.page["fg-edd"].style.display      = "" if show_preg else "none"
        web.page["fg-delivery"].style.display = "" if show_preg else "none"
        web.page["fg-delivery-check"].style.display = "" if show_preg else "none"

    _modal_open("modal-person-bd")
    web.page["f-name"].focus()

@when("click","#modal-person-cancel")
def on_person_cancel(e): _modal_close("modal-person-bd")

@when("click","#modal-person-bd")
def on_person_backdrop(e):
    if e.target.id == "modal-person-bd": _modal_close("modal-person-bd")

@when("submit","#person-form")
def on_person_submit(e):
    global _edit_id, _all_recs
    e.preventDefault()
    name = _fv("f-name")
    if not name:
        err = web.page["modal-err"]
        err.textContent = "⚠️ الاسم الكامل مطلوب."
        err.style.display = "block"
        web.page["f-name"].focus(); return

    fnum_raw = _fv("f-fnum"); fs_raw = _fv("f-fsize")
    mnum_raw = _fv("f-mnum"); dob_str = _fv("f-dob")
    preg_val = str(web.page["f-preg"].value)

    data = {
        "family_num":       int(fnum_raw) if fnum_raw.isdigit() else None,
        "block":            str(web.page["f-block"].value),
        "relation":         str(web.page["f-rel"].value),
        "member_num":       int(mnum_raw) if mnum_raw.isdigit() else 1,
        "name":             name,
        "father_name":      _fv("f-fname"),
        "grandfather_name": _fv("f-gname"),
        "mother_name":      _fv("f-mname"),
        "tribe_name":       _fv("f-tribe"),
        "gender":           str(web.page["f-gender"].value),
        "dob":              dob_str,
        "age":              _calc_age(dob_str),
        "id_number":        _fv("f-id"),
        "phone":            _fv("f-phone"),
        "marital_status":   str(web.page["f-marital"].value),
        "family_size":      int(fs_raw) if fs_raw.isdigit() else None,
        "education":        str(web.page["f-edu"].value),
        "origin":           _fv("f-origin"),
        "presence_status":  str(web.page["f-presence"].value),
        "departure_date":   _fv("f-depart"),
        "return_date":      _fv("f-return"),
        "departure_reason": _fv("f-depart-reason"),
        "special_needs":    _fv("f-sn"),
        "chronic":          _fv("f-cd"),
        "pregnant":         preg_val if preg_val != "لا يوجد" else "",
        "expected_delivery_date": _fv("f-edd"),
        "delivery_completed":     bool(web.page["f-delivered"].checked),
        "delivery_date":          _fv("f-deldate"),
        "notes":            _fv("f-notes"),
    }
    # Auto-clear pregnancy if delivery completed
    if data["delivery_completed"]:
        data["pregnant"] = ""

    data["vulnerability_level"] = _calc_vulnerability(data)

    # Validation
    warn_msg = _validate_record(data)
    if warn_msg:
        w = web.page["modal-warn"]
        w.textContent = warn_msg; w.style.display = "block"

    if _edit_id is None:
        db_create(data); _toast("✅ تم إضافة الفرد بنجاح")
    else:
        db_update(_edit_id, data); _toast("✅ تم حفظ التعديلات")

    _all_recs = _load()
    _populate_origin_dropdown()
    _modal_close("modal-person-bd")
    _filter_and_render()

# ═══════════════════════════════════════════════════════════════
#  CONFIRM MODAL (generic)
# ═══════════════════════════════════════════════════════════════
def _confirm_action(msg: str, callback, title: str = "تأكيد"):
    global _del_callback
    _del_callback = callback
    web.page["confirm-title"].textContent = title
    web.page["confirm-msg"].textContent   = msg
    _modal_open("confirm-bd")

def _confirm_clear_all():
    _confirm_action("هل أنت متأكد من حذف جميع البيانات نهائياً؟ لا يمكن التراجع.", _do_clear_all, "⚠️ تحذير")

def _do_clear_all():
    global _all_recs
    js.window.localStorage.removeItem(KEY_RECORDS)
    _all_recs = []; _populate_origin_dropdown()
    _filter_and_render(); _render_dashboard()
    _toast("🗑️ تم مسح جميع البيانات")

@when("click","#confirm-cancel-btn")
def on_confirm_cancel(e):
    global _del_callback; _del_callback = None; _modal_close("confirm-bd")

@when("click","#confirm-ok-btn")
def on_confirm_ok(e):
    global _del_callback
    _modal_close("confirm-bd")
    if _del_callback:
        cb = _del_callback; _del_callback = None; cb()

@when("click","#confirm-bd")
def on_confirm_backdrop(e):
    if e.target.id == "confirm-bd": _modal_close("confirm-bd")

# Delete a record
def _delete_record(row_id: int):
    global _all_recs
    rec  = next((r for r in _all_recs if r.get("row_id")==row_id), None)
    name = rec.get("name","هذا الفرد") if rec else "هذا الفرد"
    def _do():
        global _all_recs
        db_delete(row_id); _all_recs = _load()
        _filter_and_render(); _toast("🗑️ تم الحذف")
    _confirm_action(f'هل تريد حذف "{name}"؟ لا يمكن التراجع.', _do, "تأكيد الحذف")

# ═══════════════════════════════════════════════════════════════
#  CONTENT AREA — DELEGATED CLICKS
# ═══════════════════════════════════════════════════════════════
@when("click","#content-area")
def on_content_click(e):
    global _page
    action_el = e.target.closest("[data-action]")
    if action_el:
        action = action_el.getAttribute("data-action")
        rid    = action_el.getAttribute("data-id")
        fnum   = action_el.getAttribute("data-fnum")
        if action == "edit" and rid:      _open_person_modal(int(rid))
        elif action == "del" and rid:     _delete_record(int(rid))
        elif action == "add-member":
            preset = int(fnum) if fnum and fnum.isdigit() else None
            _open_person_modal(None, preset_family=preset)
        return
    page_el = e.target.closest("[data-page]")
    if page_el:
        ps = PAGE_TABLE if _view=="table" else PAGE_FAMILY
        tp = (len(_filtered)+ps-1)//ps
        try:
            np = int(page_el.getAttribute("data-page"))
            if 0 <= np < tp:
                _page = np; _render()
                web.page["main-content"].scrollTo(0,0)
        except: pass

# ═══════════════════════════════════════════════════════════════
#  DISEASE MODAL
# ═══════════════════════════════════════════════════════════════
def _open_disease_modal(did):
    global _edit_disease_id; _edit_disease_id = did
    web.page["disease-err"].style.display = "none"
    if did is None:
        web.page["disease-modal-title"].textContent = "إضافة نوع مرض"
        _sv("dis-name",""); _sv("dis-cat","أمراض مزمنة")
    else:
        d = next((x for x in _load_diseases() if x.get("id")==did), None)
        if not d: return
        web.page["disease-modal-title"].textContent = "تعديل نوع المرض"
        _sv("dis-name", d.get("name","")); _sv("dis-cat", d.get("category",""))
    _modal_open("modal-disease-bd")

@when("click","#close-disease-btn")
def on_close_disease(e): _modal_close("modal-disease-bd")

@when("click","#disease-save-btn")
def on_disease_save(e):
    name = _fv("dis-name"); cat = str(web.page["dis-cat"].value)
    if not name:
        web.page["disease-err"].textContent="⚠️ الاسم مطلوب."
        web.page["disease-err"].style.display="block"; return
    if _edit_disease_id is None: disease_create(name,cat)
    else:                         disease_update(_edit_disease_id,name,cat)
    _modal_close("modal-disease-bd"); _render_settings()
    _toast("✅ تم حفظ نوع المرض")

# ═══════════════════════════════════════════════════════════════
#  ZONE MODAL
# ═══════════════════════════════════════════════════════════════
def _open_zone_modal(zid):
    global _edit_zone_id; _edit_zone_id = zid
    web.page["zone-err"].style.display = "none"
    if zid is None:
        web.page["zone-modal-title"].textContent = "إضافة بلوك / قطاع"
        _sv("zone-code",""); _sv("zone-name","")
    else:
        z = next((x for x in _load_zones() if x.get("id")==zid), None)
        if not z: return
        web.page["zone-modal-title"].textContent = "تعديل البلوك"
        _sv("zone-code", z.get("code","")); _sv("zone-name", z.get("name",""))
    _modal_open("modal-zone-bd")

@when("click","#close-zone-btn")
def on_close_zone(e): _modal_close("modal-zone-bd")

@when("click","#zone-save-btn")
def on_zone_save(e):
    code = _fv("zone-code"); name = _fv("zone-name")
    if not code:
        web.page["zone-err"].textContent="⚠️ الرمز مطلوب."
        web.page["zone-err"].style.display="block"; return
    if _edit_zone_id is None: zone_create(code,name)
    else:                      zone_update(_edit_zone_id,code,name)
    _modal_close("modal-zone-bd"); _render_settings()
    _toast("✅ تم حفظ البلوك")

# ═══════════════════════════════════════════════════════════════
#  FILTER EVENT HANDLERS
# ═══════════════════════════════════════════════════════════════
@when("input","#tb-search")
def on_tb_search(e):
    global _q; _q = e.target.value.strip(); _filter_and_render()

@when("change","#fl-origin")
def on_fl_origin(e): global _origin; _origin=e.target.value; _filter_and_render()

@when("change","#fl-rel")
def on_fl_rel(e): global _rel; _rel=e.target.value; _filter_and_render()

@when("change","#fl-marital")
def on_fl_marital(e): global _marital; _marital=e.target.value; _filter_and_render()

@when("change","#fl-presence")
def on_fl_presence(e): global _presence; _presence=e.target.value; _filter_and_render()

@when("input","#fl-age-min")
def on_age_min(e): global _age_min; v=e.target.value; _age_min=int(v) if v.isdigit() else None; _filter_and_render()

@when("input","#fl-age-max")
def on_age_max(e): global _age_max; v=e.target.value; _age_max=int(v) if v.isdigit() else None; _filter_and_render()

@when("input","#fl-fs-min")
def on_fs_min(e): global _fs_min; v=e.target.value; _fs_min=int(v) if v.isdigit() else None; _filter_and_render()

@when("input","#fl-fs-max")
def on_fs_max(e): global _fs_max; v=e.target.value; _fs_max=int(v) if v.isdigit() else None; _filter_and_render()

@when("change","#fl-sn")
def on_fl_sn(e): global _fl_sn; _fl_sn=e.target.checked; _filter_and_render()

@when("change","#fl-preg")
def on_fl_preg(e): global _fl_preg; _fl_preg=e.target.checked; _filter_and_render()

@when("change","#fl-cd")
def on_fl_cd(e): global _fl_cd; _fl_cd=e.target.checked; _filter_and_render()

@when("click","#block-chips")
def on_block_chip(e):
    global _blocks
    chip = e.target.closest(".chip-block")
    if not chip: return
    val = chip.getAttribute("data-val")
    if val == "all": _blocks = {"all"}
    else:
        _blocks.discard("all")
        if val in _blocks: _blocks.discard(val)
        else:              _blocks.add(val)
        if not _blocks:    _blocks = {"all"}
    _sync_block_chips(); _filter_and_render()

@when("click","#gender-chips")
def on_gender_chip(e):
    global _gender
    chip = e.target.closest(".chip-gender")
    if not chip: return
    _gender = chip.getAttribute("data-val"); _sync_gender_chips(); _filter_and_render()

@when("click","#reset-filters-btn")
def on_reset_filters(e):
    global _q,_blocks,_gender,_origin,_rel,_marital,_presence
    global _age_min,_age_max,_fs_min,_fs_max,_fl_sn,_fl_preg,_fl_cd
    _q=""; _blocks={"all"}; _gender=""; _origin=""; _rel=""; _marital=""; _presence=""
    _age_min=_age_max=_fs_min=_fs_max=None; _fl_sn=_fl_preg=_fl_cd=False
    for fid in ("tb-search","fl-origin","fl-rel","fl-marital","fl-presence",
                "fl-age-min","fl-age-max","fl-fs-min","fl-fs-max"):
        web.page[fid].value = ""
    for fid in ("fl-sn","fl-preg","fl-cd"):
        web.page[fid].checked = False
    _sync_block_chips(); _sync_gender_chips(); _filter_and_render()

# ═══════════════════════════════════════════════════════════════
#  VIEW TOGGLE
# ═══════════════════════════════════════════════════════════════
@when("click","#view-table-btn")
def on_view_table(e):
    global _view,_page; _view="table"; _page=0
    web.page["view-table-btn"].classList.add("active")
    web.page["view-family-btn"].classList.remove("active"); _render()

@when("click","#view-family-btn")
def on_view_family(e):
    global _view,_page; _view="family"; _page=0
    web.page["view-family-btn"].classList.add("active")
    web.page["view-table-btn"].classList.remove("active"); _render()

# ═══════════════════════════════════════════════════════════════
#  HEADER / SIDEBAR BUTTONS
# ═══════════════════════════════════════════════════════════════
@when("click","#hdr-add-btn")
def on_hdr_add(e): _open_person_modal(None); _nav_to_section("individuals")

@when("click","#hdr-report-btn")
def on_hdr_report(e): _update_report_stats(); _modal_open("modal-report-bd")

@when("click","#hdr-import-btn")
def on_hdr_import(e): _modal_open("modal-import-bd")

@when("click","#fab-add")
def on_fab_add(e): _open_person_modal(None)

@when("click","#sb-import-btn")
def on_sb_import(e): _modal_open("modal-import-bd")

@when("click","#sb-export-quick-btn")
def on_sb_export(e): _update_report_stats(); _modal_open("modal-report-bd")

@when("click","#sb-clear-btn")
def on_sb_clear(e): _confirm_clear_all()

# ═══════════════════════════════════════════════════════════════
#  REPORT MODAL HANDLERS
# ═══════════════════════════════════════════════════════════════
@when("click","#close-report-btn")
def on_close_report(e): _modal_close("modal-report-bd")

@when("click","#modal-report-bd")
def on_report_backdrop(e):
    if e.target.id=="modal-report-bd": _modal_close("modal-report-bd")

@when("click","#rpt-print-btn")
def on_rpt_print(e): _do_print_report()

@when("click","#rpt-excel-btn")
def on_rpt_excel(e): _do_export_excel()

@when("click","#rpt-csv-btn")
def on_rpt_csv(e): _do_export_csv()

@when("change","#rpt-type-sel")
def on_rpt_type_change(e): _update_report_stats()

@when("change","#rpt-filtered")
def on_rpt_filtered(e): _update_report_stats()

# ═══════════════════════════════════════════════════════════════
#  ID CARD MODAL HANDLERS
# ═══════════════════════════════════════════════════════════════
@when("click","#close-idcard-btn")
def on_close_idcard(e): _modal_close("modal-idcard-bd")

@when("click","#idc-print-btn")
def on_idc_print(e): _print_id_cards()

# ═══════════════════════════════════════════════════════════════
#  IMPORT MODAL HANDLERS
# ═══════════════════════════════════════════════════════════════
@when("click","#close-import-btn")
def on_close_import(e): _modal_close("modal-import-bd")

@when("click","#modal-import-bd")
def on_import_backdrop(e):
    if e.target.id=="modal-import-bd": _modal_close("modal-import-bd")

# ═══════════════════════════════════════════════════════════════
#  SECTION NAVIGATION (called from HTML JS navTo())
# ═══════════════════════════════════════════════════════════════
def _nav_to_section(sec: str):
    global _section; _section = sec
    if sec == "reports":
        _render_reports_section()
    elif sec == "idcards":
        _render_idcards_section()
    elif sec == "settings":
        _render_settings()
    elif sec == "dashboard":
        _render_dashboard()

def _render_reports_section():
    web.page["reports-content"].innerHTML = f"""
<div class="card" style="margin-bottom:.85rem">
  <div class="card-header"><span class="card-title">📊 مولّد التقارير</span></div>
  <div class="card-body">
    <p style="font-size:.84rem;color:var(--t3);margin-bottom:1rem">
      اختر نوع التقرير واضغط <strong>توليد</strong> للمعاينة والطباعة أو التصدير.
    </p>
    <div style="display:flex;gap:.55rem;flex-wrap:wrap">
      <button class="btn btn-p" id="sec-rpt-open-btn">📋 فتح مولّد التقارير</button>
      <button class="btn btn-export" id="sec-rpt-excel-btn">📊 تصدير Excel سريع</button>
      <button class="btn btn-outline" id="sec-rpt-csv-btn">📄 تصدير CSV</button>
    </div>
  </div>
</div>
<div class="card">
  <div class="card-header"><span class="card-title">🗂️ أنواع التقارير المتاحة</span></div>
  <div class="card-body">
    <div class="report-types">
      {''.join(f'<div class="rpt-type-card" data-rtype="{rt}" onclick="_open_report_type(\'{rt}\')">'
               f'<div class="rpt-type-ico">{ico}</div><div class="rpt-type-name">{nm}</div>'
               f'<div class="rpt-type-desc">{desc}</div></div>'
               for rt,ico,nm,desc in [
                   ("full","📋","القائمة الكاملة","جميع البيانات لكل الأفراد"),
                   ("phone","📞","دليل الهواتف","أرقام هواتف أرباب الأسر"),
                   ("family","🏠","توزيع الأسر","الأسر وتفاصيلها"),
                   ("critical","🚨","الحالات الحرجة","ذوو الاحتياجات والأمراض"),
                   ("health","🏥","التقرير الصحي","تحليل الحالات الطبية"),
                   ("age","📅","التصنيف العمري","الفئات العمرية المختلفة"),
                   ("absent","🚪","الغائبون","خارج المخيم والمفقودون"),
                   ("pregnant","🤰","الحوامل/المرضعات","مواعيد الولادة والأولوية"),
                   ("vuln","⚠️","تقرير الهشاشة","الأفراد الأولى بالدعم"),
                   ("wfp","🌍","تقرير WFP","مخصص للمنظمات الدولية"),
               ])}
    </div>
  </div>
</div>"""
    try:
        web.page["sec-rpt-open-btn"].onclick  = lambda e: (_update_report_stats(), _modal_open("modal-report-bd"))
        web.page["sec-rpt-excel-btn"].onclick = lambda e: _do_export_excel()
        web.page["sec-rpt-csv-btn"].onclick   = lambda e: _do_export_csv()
    except: pass

def _open_report_type(rtype: str):
    _sv("rpt-type-sel", rtype)
    _update_report_stats()
    _modal_open("modal-report-bd")

def _render_idcards_section():
    web.page["idcards-content"].innerHTML = f"""
<div class="card" style="margin-bottom:.85rem">
  <div class="card-header"><span class="card-title">🪪 مولّد بطاقات الهوية</span></div>
  <div class="card-body">
    <p style="font-size:.84rem;color:var(--t3);margin-bottom:1rem">
      أنشئ بطاقات هوية قابلة للطباعة بمستويات تفاصيل مختلفة للمقيمين في المخيم.
    </p>
    <button class="btn btn-p" id="sec-idc-open-btn">🖨️ فتح مولّد البطاقات</button>
  </div>
</div>
<div class="card">
  <div class="card-header"><span class="card-title">ℹ️ معلومات</span></div>
  <div class="card-body" style="font-size:.84rem;color:var(--t3);line-height:1.7">
    <p>• <strong>أساسي:</strong> الاسم، رقم الأسرة، البلوك، صلة القرابة، الجنس والعمر.</p>
    <p>• <strong>تفصيلي:</strong> + رقم الهوية، الجوال، السكن الأصلي.</p>
    <p>• <strong>طبي:</strong> + الاحتياجات الخاصة والأمراض المزمنة وحالة الحمل.</p>
    <p style="margin-top:.5rem">الإجمالي الحالي: <strong>{len(_filtered):,} فرد</strong> مطابق للفلاتر الحالية.</p>
  </div>
</div>"""
    try:
        web.page["sec-idc-open-btn"].onclick = lambda e: _modal_open("modal-idcard-bd")
    except: pass

# ═══════════════════════════════════════════════════════════════
#  PART 8 — EXCEL IMPORT + INITIALIZATION (continues below)
# ═══════════════════════════════════════════════════════════════
# ═══════════════════════════════════════════════════════════════
#  EXCEL IMPORT
# ═══════════════════════════════════════════════════════════════
@when("click","#confirm-import-btn")
def on_confirm_import(e):
    global _all_recs
    raw = js.window.importedExcelData
    if raw is None or str(raw) in ("null","undefined","None",""):
        js.window.alert("لم يتم تحميل أي ملف. الرجاء اختيار ملف Excel أولاً."); return
    try:
        rows = json.loads(str(raw))
    except:
        js.window.alert("خطأ في قراءة بيانات الملف."); return
    if len(rows) < 2:
        js.window.alert("الملف لا يحتوي على بيانات كافية."); return

    mode = str(web.page["import-mode"].value)

    # Column layout (matching original Excel structure):
    # [0]الرقم [1]البلوك [2]صلة القرابة [3]عدد [4]الإسم [5]الجنس
    # [6]تاريخ الميلاد [7]العمر [8]الهوية [9]الجوال [10]الحالة الاجتماعية
    # [11]عدد الأفراد [12]عنوان السكن [13]ذوي احتياجات [14]حوامل
    # [15]أمراض مزمنة [16]مأهول/غير [17]ملاحظات

    cur_fnum=None; cur_block=""; cur_origin=""; cur_fsize=None
    new_recs=[]

    def _clean_phone(v) -> str:
        if not v or str(v) in ("None","null",""): return ""
        digits="".join(c for c in str(v) if c.isdigit())
        return digits if len(digits)>=7 else str(v).strip()

    def _clean_id(v) -> str:
        if not v or str(v) in ("None","null",""): return ""
        s=str(v).strip()
        try: return str(int(float(s))) if "." in s else s
        except: return s

    def _parse_dob(raw_val) -> str:
        s=str(raw_val).strip()
        if not s or s in ("None","null",""): return ""
        try:
            if len(s)>=10 and s[4]=="-": return s[:10]
            if "/" in s:
                p=s.split("/")
                if len(p)==3 and len(p[2])==4: return f"{p[2]}-{p[0].zfill(2)}-{p[1].zfill(2)}"
            if "." in s:
                p=s.split(".")
                if len(p)==3: return f"{p[2]}-{p[1].zfill(2)}-{p[0].zfill(2)}"
        except: pass
        return ""

    for row in rows[1:]:
        if not row or len(row)<5: continue
        cell0=row[0]
        if cell0 is not None and str(cell0).strip() not in ("","None","null"):
            try: cur_fnum=int(float(str(cell0)))
            except: pass
            cur_block  = str(row[1]).strip() if len(row)>1 and row[1] else cur_block
            cur_origin = str(row[12]).strip() if len(row)>12 and row[12] and str(row[12]) not in ("None","") else ""
            try: cur_fsize=int(row[11]) if len(row)>11 and row[11] else None
            except: cur_fsize=None

        name=str(row[4]).strip() if len(row)>4 and row[4] else ""
        if not name or name.lower() in ("none","null",""): continue

        dob_str = _parse_dob(row[6]) if len(row)>6 and row[6] else ""
        rel_raw = str(row[2]).strip() if len(row)>2 and row[2] else ""
        rel     = REL_NORM.get(rel_raw, rel_raw)
        mar_raw = str(row[10]).strip() if len(row)>10 and row[10] else ""
        mar     = MARITAL_NORM.get(mar_raw, mar_raw)
        if any(c.isdigit() for c in mar) or len(mar)>15: mar=""

        rec = {
            "family_num":       cur_fnum,
            "block":            cur_block,
            "relation":         rel,
            "member_num":       int(row[3]) if len(row)>3 and row[3] and str(row[3]).isdigit() else 1,
            "name":             name,
            "father_name":      "",
            "grandfather_name": "",
            "mother_name":      "",
            "tribe_name":       "",
            "gender":           str(row[5]).strip() if len(row)>5 and row[5] else "",
            "dob":              dob_str,
            "age":              _calc_age(dob_str),
            "id_number":        _clean_id(row[8] if len(row)>8 else ""),
            "phone":            _clean_phone(row[9] if len(row)>9 else ""),
            "marital_status":   mar,
            "family_size":      cur_fsize,
            "education":        "",
            "origin":           cur_origin,
            "presence_status":  "داخل المخيم",
            "departure_date":   "",
            "return_date":      "",
            "departure_reason": "",
            "special_needs":    str(row[13]).strip() if len(row)>13 and row[13] and str(row[13]) not in ("None","") else "",
            "pregnant":         str(row[14]).strip() if len(row)>14 and row[14] and str(row[14]) not in ("None","") else "",
            "expected_delivery_date":"",
            "delivery_completed":False,
            "delivery_date":    "",
            "chronic":          str(row[15]).strip() if len(row)>15 and row[15] and str(row[15]) not in ("None","") else "",
            "notes":            str(row[17]).strip() if len(row)>17 and row[17] and str(row[17]) not in ("None","") else "",
            "registered_at":    _now(),
            "updated_at":       _now(),
        }
        rec["vulnerability_level"] = _calc_vulnerability(rec)
        new_recs.append(rec)

    if not new_recs:
        js.window.alert("لم يتم العثور على سجلات صالحة في الملف."); return

    db_bulk_insert(new_recs, mode=mode)
    _all_recs = _load()
    _populate_origin_dropdown()
    js.window.importedExcelData = None
    web.page["import-file"].value = ""
    web.page["import-preview"].style.display = "none"
    web.page["import-file-name"].style.display = "none"
    web.page["import-zone"].classList.remove("active")
    _modal_close("modal-import-bd")
    _filter_and_render()
    _render_dashboard()
    _toast(f"✅ تم استيراد {len(new_recs):,} سجل بنجاح")

# ═══════════════════════════════════════════════════════════════
#  NAVIGATION HANDLER (called from HTML JS)
# ═══════════════════════════════════════════════════════════════
def _nav_to_section(sec: str):
    global _section; _section = sec
    # Update section count badge
    try:
        n = len(_all_recs)
        badge = web.page["nav-count"]
        if n > 0:
            badge.textContent = f"{n:,}"
            badge.style.display = "inline"
        else:
            badge.style.display = "none"
    except: pass
    # Trigger renders for sections that need it
    if sec == "reports":   _render_reports_section()
    elif sec == "idcards": _render_idcards_section()
    elif sec == "settings":_render_settings()
    elif sec == "dashboard":_render_dashboard()
    # individuals section renders automatically via _render()

# Expose to JS global scope so navTo() in HTML can call Python
js.window._py_nav = _nav_to_section

# ═══════════════════════════════════════════════════════════════
#  FATAL ERROR DISPLAY
# ═══════════════════════════════════════════════════════════════
def _show_fatal(msg: str):
    js.document.getElementById("loading").innerHTML = f"""
<div style="background:white;border-radius:16px;padding:2rem 2.5rem;max-width:520px;
            box-shadow:0 8px 40px rgba(0,0,0,.15);text-align:center;direction:rtl">
  <div style="font-size:2.5rem;margin-bottom:.6rem">⚠️</div>
  <h2 style="color:#dc2626;font-family:Tajawal,sans-serif;margin-bottom:.8rem">خطأ في التحميل</h2>
  <pre style="background:#fef2f2;color:#991b1b;padding:1rem;border-radius:8px;
              font-size:.72rem;text-align:right;white-space:pre-wrap;
              max-height:260px;overflow-y:auto">{msg}</pre>
  <p style="margin-top:1rem;font-size:.82rem;color:#64748b;font-family:Tajawal,sans-serif">
    انسخ الخطأ وأرسله لمعالجة المشكلة.
  </p>
</div>"""

# ═══════════════════════════════════════════════════════════════
#  PATCH navTo IN JS TO ALSO CALL PYTHON
# ═══════════════════════════════════════════════════════════════
_NAV_PATCH = """
(function(){
  const _origNavTo = window.navTo;
  window.navTo = function(sec){
    _origNavTo(sec);
    try{ window._py_nav(sec); }catch(e){}
  };
})();
"""

# ═══════════════════════════════════════════════════════════════
#  INITIALIZATION
# ═══════════════════════════════════════════════════════════════
def _init():
    global _all_recs
    try:
        js.document.getElementById("loading-msg").textContent = "جاري تهيئة قاعدة البيانات…"
        _ensure_diseases()
        _ensure_zones()
        js.document.getElementById("loading-msg").textContent = "جاري تحويل البيانات القديمة…"
        _migrate_if_needed()
        js.document.getElementById("loading-msg").textContent = "جاري تحميل البيانات…"
        _all_recs = _load()
        js.document.getElementById("loading-msg").textContent = "جاري بناء الواجهة…"
        _apply_filters()
        _rebuild_block_chips()
        _populate_origin_dropdown()
        _render_dashboard()
        _render()
        # Update nav badge
        try:
            n = len(_all_recs)
            badge = web.page["nav-count"]
            if n:
                badge.textContent = f"{n:,}"; badge.style.display = "inline"
        except: pass
        # Update sidebar camp name from settings
        try:
            s = _load_settings()
            web.page["sb-camp-name"].textContent = s.get("camp_name","مخيم إيواء الحرية")
        except: pass
        # Patch JS navTo to call Python side too
        js.eval(_NAV_PATCH)
        # Hide loading, show app
        js.document.getElementById("loading").style.display  = "none"
        js.document.getElementById("app-root").style.display = "flex"
    except Exception:
        import traceback
        _show_fatal(traceback.format_exc())

_init()
