/* ============ MAIN: auth state, group hub, group view, routing ============ */
(function(){
  const { useState, useEffect, useRef, useCallback } = React;
  const { Onboarding, AuthScreen, ProfileSetup, Calculator, Chat, Leaderboard, AvatarImg, AvatarPicker, GroupIcon, GroupIconPicker, InfoScreen, IntroSplash, InstallPrompt, MemberActionSheet, OwnerAdminPanel, ConfirmDialog, ConsentScreen, KidsParentGate, LegalModal, LegalLinks, PromoVideo } = window;
  const LEGAL = window.LEGAL || {POLICY_VERSION:'2026-06'};
  const OWNER_EMAILS = window.OWNER_EMAILS || ['netanelm87@gmail.com','moyalnh@gmail.com'];
  const isOwnerEmail = (email)=> !!email && OWNER_EMAILS.includes((email||'').trim().toLowerCase());
  const LS_INTRO='bottlex-intro';

  const LS_ONB='bottlex-onboarded';
  const gidKey=(uid)=>'bottlex-gid-'+uid;
  const mutedKey='bottlex-muted';
  const genCode=()=>{ const c='ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; let s=''; for(let i=0;i<5;i++) s+=c[Math.floor(Math.random()*c.length)]; return s; };
  const db=()=>window.fbDb;
  const KOFI_URL='https://ko-fi.com/warooms';
  const VERIFY_VALID_DAYS=30;
  function KofiButton({style}){
    return (
      <a className="btn kofi" href={KOFI_URL} target="_blank" rel="noopener noreferrer" style={style}>
        <span className="kofi-cup">☕</span> נהנים מבנקבוק? קנו לי קפה
      </a>
    );
  }

  /* ---------- toast ---------- */
  function useToast(){
    const [msg,setMsg]=useState('');
    const t=useRef(null);
    const show=useCallback((m)=>{ setMsg(m); clearTimeout(t.current); t.current=setTimeout(()=>setMsg(''),2400); },[]);
    const node = msg ? <div className="toast">{msg}</div> : null;
    return [show, node];
  }

  /* ---------- flexible multiplier control ---------- */
  function MultControl({value, onChange}){
    const presets=[{v:1,l:'ללא'},{v:1.5,l:'×1.5'},{v:2,l:'×2'},{v:3,l:'×3'}];
    const isPreset=presets.some(p=>p.v===value);
    return (
      <div>
        <div className="seg">
          {presets.map(p=>(<button type="button" key={p.v} className={value===p.v?'on':''} onClick={()=>onChange(p.v)}>{p.l}</button>))}
          <button type="button" className={!isPreset?'on':''} onClick={()=>onChange(value&&!isPreset?value:2.5)}>אחר</button>
        </div>
        {!isPreset && (
          <label className="fld"><span className="lab">מכפיל מותאם (לדוגמה 0.5, 2.5, 5)</span>
            <input className="input" type="number" step="0.5" min="0.5" max="20" dir="ltr" value={value} onChange={e=>onChange(parseFloat(e.target.value)||1)}/>
          </label>
        )}
      </div>
    );
  }

  /* ---------- create group sheet ---------- */
  function CreateGroupSheet({uid, profile, onClose, onCreated, toast}){
    const [name,setName]=useState('');
    const [goalName,setGoalName]=useState('');
    const [goalAmount,setGoalAmount]=useState('');
    const [boostName,setBoostName]=useState('');
    const [boostMult,setBoostMult]=useState(1);
    const [icon,setIcon]=useState('♻️');
    const [busy,setBusy]=useState(false);
    const create=async(e)=>{
      e.preventDefault(); if(!name.trim())return; setBusy(true);
      const gid=genCode(); const now=Date.now();
      try{
        await db().ref('groups/'+gid).set({
          name:name.trim(), icon:icon, goalName:goalName.trim(), goalAmount:goalAmount||'',
          boostName:boostName.trim(), boostMult:boostMult,
          createdBy:uid, createdAt:now,
          members:{[uid]:{name:profile.name, avatar:profile.avatar, joinedAt:now, role:'admin'}},
        });
        await db().ref('users/'+uid+'/groups/'+gid).set(name.trim());
        onCreated(gid);
      }catch(ex){ toast('שגיאה ביצירת הקבוצה'); setBusy(false); }
    };
    return (
      <div className="sheet-bg" onClick={onClose}>
        <form className="sheet" onClick={e=>e.stopPropagation()} onSubmit={create}>
          <div className="sheet-handle"></div>
          <h3>קבוצה חדשה 🎉</h3>
          <label className="fld"><span className="lab">שם הקבוצה</span>
            <input className="input" required value={name} onChange={e=>setName(e.target.value)} placeholder="משפחת כהן · כיתה ג'2 · שבט נחשון" maxLength={30}/>
          </label>
          <span className="lab" style={{display:'block',marginBottom:2}}>תמונת הקבוצה</span>
          <GroupIconPicker value={icon} onChange={setIcon}/>
          <div className="goal-inputs" style={{marginBottom:4}}>
            <input className="gname input" style={{flex:1}} value={goalName} onChange={e=>setGoalName(e.target.value)} placeholder="חוסכים ל… (לא חובה)" maxLength={30}/>
            <input className="gamt input" style={{width:110,textAlign:'center'}} type="number" inputMode="decimal" value={goalAmount} onChange={e=>setGoalAmount(e.target.value)} placeholder="₪ יעד"/>
          </div>
          <div style={{margin:'14px 0 4px'}}>
            <span className="lab" style={{display:'block',marginBottom:6}}>תומך שמכפיל (לא חובה)</span>
            <p className="muted" style={{margin:'0 0 8px'}}>סבא, סבתא, אמא, אבא, דוד, ספונסר, מורה או מדריך — מישהו שמכפיל את הסכום שאספתם.</p>
            <input className="input" value={boostName} onChange={e=>setBoostName(e.target.value)} placeholder="שם התומך (למשל: סבתא חיה)" maxLength={20} style={{marginBottom:10}}/>
            <span className="lab" style={{display:'block',marginBottom:4}}>כמה הוא מכפיל?</span>
            <MultControl value={boostMult} onChange={setBoostMult}/>
          </div>
          <button className="btn" type="submit" disabled={busy} style={{marginTop:8}}>{busy?'יוצר…':'יצירת הקבוצה 🚀'}</button>
        </form>
      </div>
    );
  }

  /* ---------- settings sheet (edit group) ---------- */
  function SettingsSheet({gid, group, isAdmin, selfUid, onClose, onDeleted, toast}){
    const [name,setName]=useState(group.name||'');
    const [goalName,setGoalName]=useState(group.goalName||'');
    const [goalAmount,setGoalAmount]=useState(group.goalAmount||'');
    const [boostName,setBoostName]=useState(group.boostName||'');
    const [boostMult,setBoostMult]=useState(group.boostMult||1);
    const [icon,setIcon]=useState(group.icon||'♻️');
    const [busy,setBusy]=useState(false);
    const [confirmDel,setConfirmDel]=useState(false);
    const [busyDel,setBusyDel]=useState(false);
    const isFamily=!!group.family;
    const deleteGroup=async()=>{
      setBusyDel(true);
      try{
        await db().ref('public/groups/'+gid).remove().catch(()=>{});
        await db().ref('users/'+selfUid+'/groups/'+gid).remove().catch(()=>{});
        await db().ref('groups/'+gid).remove();
        toast('הקבוצה נמחקה'); setConfirmDel(false); onDeleted&&onDeleted();
      }catch(ex){ console.warn('[del-group]',ex&&ex.code); toast('שגיאה במחיקה'+(ex&&ex.code?' ('+ex.code+')':'')); setBusyDel(false); }
    };
    const save=async(e)=>{
      e.preventDefault(); setBusy(true);
      try{
        await db().ref('groups/'+gid).update({name:name.trim(), icon:icon, goalName:goalName.trim(), goalAmount:goalAmount||'', boostName:boostName.trim(), boostMult:boostMult});
        await db().ref('users/'+group.createdBy+'/groups/'+gid).set(name.trim());
        toast('נשמר ✓'); onClose();
      }catch(ex){ toast('שגיאה בשמירה'); setBusy(false); }
    };
    return (
      <div className="sheet-bg" onClick={onClose}>
        <form className="sheet" onClick={e=>e.stopPropagation()} onSubmit={save}>
          <div className="sheet-handle"></div>
          <h3>הגדרות הקבוצה ⚙️</h3>
          {!isAdmin && <div className="err">רק מנהל הקבוצה יכול לערוך הגדרות</div>}
          <fieldset disabled={!isAdmin} style={{border:'none',padding:0,margin:0}}>
            <label className="fld"><span className="lab">שם הקבוצה</span>
              <input className="input" value={name} onChange={e=>setName(e.target.value)} maxLength={30}/>
            </label>
            <span className="lab" style={{display:'block',marginBottom:2}}>תמונת הקבוצה</span>
            <GroupIconPicker value={icon} onChange={setIcon}/>
            <div className="goal-inputs" style={{marginBottom:14}}>
              <input className="gname input" style={{flex:1}} value={goalName} onChange={e=>setGoalName(e.target.value)} placeholder="חוסכים ל…" maxLength={30}/>
              <input className="gamt input" style={{width:110,textAlign:'center'}} type="number" value={goalAmount} onChange={e=>setGoalAmount(e.target.value)} placeholder="₪ יעד"/>
            </div>
            <span className="lab" style={{display:'block',marginBottom:4}}>שם התומך המכפיל</span>
            <input className="input" value={boostName} onChange={e=>setBoostName(e.target.value)} placeholder="למשל: סבתא חיה" maxLength={20} style={{marginBottom:10}}/>
            <span className="lab" style={{display:'block',marginBottom:4}}>כמה הוא מכפיל?</span>
            <MultControl value={boostMult} onChange={setBoostMult}/>
            {isAdmin && <button className="btn" type="submit" disabled={busy} style={{marginTop:12}}>{busy?'שומר…':'שמירה'}</button>}
          </fieldset>
          <div className="divider">תומכים בפיתוח 💚</div>
          <KofiButton/>
          {isAdmin && !isFamily && (
            <>
              <div className="divider">אזור מסוכן</div>
              <button type="button" className="btn ghost danger-line" onClick={()=>setConfirmDel(true)}>🗑️ מחיקת הקבוצה לצמיתות</button>
            </>
          )}
          {confirmDel && ConfirmDialog && (
            <ConfirmDialog
              title={'למחוק את "'+(group.name||'הקבוצה')+'"?'}
              body="כל החברים, הספירות, הקבלות והצ'אט יימחקו לצמיתות. אי-אפשר לבטל."
              confirmLabel="מחיקה לצמיתות" danger={true} busy={busyDel}
              onCancel={()=>{ if(!busyDel) setConfirmDel(false); }}
              onConfirm={deleteGroup}/>
          )}
        </form>
      </div>
    );
  }

  /* ---------- personal profile editor ---------- */
  function ProfileEditSheet({uid, profile, onClose, toast}){
    const [name,setName]=useState(profile.name||'');
    const [avatar,setAvatar]=useState(profile.avatar);
    const [busy,setBusy]=useState(false);
    const save=async(e)=>{
      e.preventDefault(); if(!name.trim())return; setBusy(true);
      const nm=name.trim();
      try{
        await db().ref('users/'+uid).update({name:nm, avatar});
        const snap=await db().ref('users/'+uid+'/groups').get();
        const gids=Object.keys(snap.val()||{});
        await Promise.all(gids.map(gid=> db().ref('groups/'+gid+'/members/'+uid).update({name:nm, avatar}).catch(()=>{}) ));
        db().ref('public/users/'+uid).update({name:nm, avatar}).catch(()=>{});
        toast('הפרופיל עודכן ✓'); onClose();
      }catch(ex){ toast('שגיאה בשמירה'); setBusy(false); }
    };
    return (
      <div className="sheet-bg" onClick={onClose}>
        <form className="sheet" onClick={e=>e.stopPropagation()} onSubmit={save}>
          <div className="sheet-handle"></div>
          <div className="md-head">
            <AvatarImg value={avatar} size={64}/>
            <div><h3 style={{margin:0}}>הפרופיל שלי</h3><div className="muted" style={{fontWeight:600}}>השם והדמות יתעדכנו בכל הקבוצות שלכם</div></div>
          </div>
          <label className="fld"><span className="lab">השם שלכם</span>
            <input className="input" required value={name} onChange={e=>setName(e.target.value)} maxLength={20} placeholder="איך לקרוא לכם?"/>
          </label>
          <span className="lab" style={{display:'block',marginBottom:2}}>הדמות שלכם</span>
          <AvatarPicker value={avatar} onChange={setAvatar}/>
          <button className="btn" type="submit" disabled={busy} style={{marginTop:12}}>{busy?'שומר…':'שמירת הפרופיל ✨'}</button>
        </form>
      </div>
    );
  }

  /* ---------- group hub ---------- */
  function GroupHub({uid, profile, pendingInvite, onEnter, toast, onSignOut, isOwner, onOpenOwner}){
    const [groups,setGroups]=useState(null);
    const [icons,setIcons]=useState({});
    const [showCreate,setShowCreate]=useState(false);
    const [code,setCode]=useState(pendingInvite||'');
    const [busy,setBusy]=useState(false);
    const [pending,setPending]=useState(null); // {gid,name}
    const [showEditProfile,setShowEditProfile]=useState(false);
    const [legal,setLegal]=useState(null);

    useEffect(()=>{
      const ref=db().ref('users/'+uid+'/groups');
      const h=(s)=>setGroups(s.val()||{});
      ref.on('value',h); return ()=>ref.off('value',h);
    },[uid]);

    // live group icons for the pills
    useEffect(()=>{
      if(!groups) return;
      const offs=[];
      Object.keys(groups).forEach(gid=>{ const r=db().ref('groups/'+gid+'/icon'); const h=s=>setIcons(p=>({...p,[gid]:s.val()})); r.on('value',h); offs.push(()=>r.off('value',h)); });
      return ()=>offs.forEach(f=>f());
    },[groups]);

    // after sending a join request — wait for the admin to approve, then enter automatically
    useEffect(()=>{
      if(!pending) return;
      const memRef=db().ref('groups/'+pending.gid+'/members/'+uid);
      const reqRef=db().ref('groups/'+pending.gid+'/joinRequests/'+uid);
      const mh=(s)=>{ if(s.exists()){ db().ref('users/'+uid+'/groups/'+pending.gid).set(pending.name); setPending(null); onEnter(pending.gid); } };
      const rh=(s)=>{ if(!s.exists()){ memRef.get().then(ms=>{ if(!ms.exists()){ toast('הבקשה לא אושרה הפעם'); setPending(null); } }); } };
      memRef.on('value',mh); reqRef.on('value',rh);
      return ()=>{ memRef.off('value',mh); reqRef.off('value',rh); };
    },[pending,uid]);

    const cancelRequest=async()=>{ if(pending){ try{ await db().ref('groups/'+pending.gid+'/joinRequests/'+uid).remove(); }catch(e){} setPending(null); } };

    const join=async(e)=>{
      e&&e.preventDefault(); const c=(code||'').trim().toUpperCase(); if(!c)return; setBusy(true);
      try{
        const meSnap=await db().ref('groups/'+c+'/members/'+uid).get();
        if(meSnap.exists()){ const nm=(await db().ref('groups/'+c+'/name').get()).val()||'קבוצה'; await db().ref('users/'+uid+'/groups/'+c).set(nm); onEnter(c); return; }
        const nameSnap=await db().ref('groups/'+c+'/name').get();
        if(!nameSnap.exists()){ toast('קוד לא נמצא 🤔'); setBusy(false); return; }
        await db().ref('groups/'+c+'/joinRequests/'+uid).set({name:profile.name, avatar:profile.avatar, ts:Date.now()});
        setBusy(false); setPending({gid:c, name:nameSnap.val()});
      }catch(ex){ toast('שגיאה בהצטרפות'); setBusy(false); }
    };

    const list=groups?Object.keys(groups):[];
    if(pending){
      return (
        <div className="center-screen">
          <div className="brandmark">
            <div className="logo"><img src="icons/icon-192.png" alt="בנקבוק"/></div>
            <h1>הבקשה נשלחה!</h1>
            <p>לקבוצה: {pending.name}</p>
          </div>
          <div className="card pending-wait">
            <div className="pw-emoji">⏳</div>
            <h2 style={{fontFamily:"'Varela Round'",margin:'0 0 8px',fontSize:'1.4rem',color:'var(--ink)'}}>ממתינים לאישור המנהל</h2>
            <p className="muted" style={{lineHeight:1.6,marginBottom:16}}>ברגע שמנהל הקבוצה יאשר אתכם — תיכנסו אוטומטית. אפשר להשאיר את המסך פתוח.</p>
            <div className="spin" style={{margin:'0 auto 6px'}}></div>
            <button className="linkbtn" style={{color:'#9bb0a4'}} onClick={cancelRequest}>ביטול הבקשה</button>
          </div>
        </div>
      );
    }
    return (
      <div className="center-screen">
        <div className="brandmark">
          <button onClick={()=>setShowEditProfile(true)} style={{background:'none',border:'none',padding:0,cursor:'pointer'}} aria-label="עריכת פרופיל"><AvatarImg value={profile.avatar} size={64}/></button>
          <h1 style={{marginTop:4}}>היי {profile.name}! 👋</h1>
          <button className="linkbtn" onClick={()=>setShowEditProfile(true)}>✏️ עריכת הפרופיל שלי</button>
        </div>
        <div className="card">
          {pendingInvite && (
            <div className="invite-box">
              הוזמנתם לקבוצה!<div className="code">{pendingInvite}</div>
              <button className="btn cyan sm" style={{width:'100%'}} onClick={join} disabled={busy}>{busy?'מצטרף…':'הצטרפו עכשיו'}</button>
            </div>
          )}
          {list.length>0 && (
            <>
              <span className="lab" style={{display:'block',marginBottom:8}}>הקבוצות שלי</span>
              <div className="hub-groups">
                {list.map(gid=>(
                  <button className="group-pill" key={gid} onClick={()=>onEnter(gid)}>
                    <GroupIcon value={icons[gid]} size={40} radius={12}/>
                    <div className="gp-info"><div className="gp-name">{groups[gid]}</div><div className="gp-sub">קוד: {gid}</div></div>
                    <div className="gp-arrow">‹</div>
                  </button>
                ))}
              </div>
              <div className="divider">או</div>
            </>
          )}
          <button className="btn" onClick={()=>setShowCreate(true)}>➕ קבוצה חדשה</button>
          <div className="divider">או הצטרפו עם קוד</div>
          <form className="goal-inputs" onSubmit={join} style={{marginBottom:0}}>
            <input className="input" style={{flex:1,textAlign:'center',letterSpacing:'.18em',textTransform:'uppercase',direction:'ltr',fontWeight:800}} value={code} onChange={e=>setCode(e.target.value)} placeholder="קוד קבוצה" maxLength={5}/>
            <button className="btn cyan sm" type="submit" disabled={busy||!code.trim()}>הצטרפות</button>
          </form>
        </div>
        {isOwner && <button className="btn ghost owner-btn" style={{maxWidth:420,width:'100%',marginTop:16}} onClick={onOpenOwner}>🛡️ אזור ניהול-על</button>}
        <KofiButton style={{maxWidth:420,width:'100%',marginTop:16}}/>
        <button className="linkbtn" style={{marginTop:14,color:'#9bb0a4'}} onClick={onSignOut}>התנתקות</button>
        <LegalLinks onOpen={setLegal} style={{marginTop:6}}/>
        {legal && LegalModal && <LegalModal initial={legal} onClose={()=>setLegal(null)}/>}
        {showCreate && <CreateGroupSheet uid={uid} profile={profile} toast={toast} onClose={()=>setShowCreate(false)} onCreated={(gid)=>{setShowCreate(false);onEnter(gid);}}/>}
        {showEditProfile && <ProfileEditSheet uid={uid} profile={profile} toast={toast} onClose={()=>setShowEditProfile(false)}/>}
      </div>
    );
  }

  /* ---------- add a child profile (no login) — any group admin ---------- */
  function AddChildSheet({gid, selfUid, onClose, onAdded, toast}){
    const [name,setName]=useState('');
    const [avatar,setAvatar]=useState(()=> (window.CHARACTERS?window.CHARACTERS[Math.floor(Math.random()*window.CHARACTERS.length)].id:'fox'));
    const [busy,setBusy]=useState(false);
    const [ok,setOk]=useState(false);
    const save=async(e)=>{
      e.preventDefault(); if(!name.trim()||!ok)return; setBusy(true);
      try{
        const id=await window.KidsApi.addChildToGroup(gid, name, avatar);
        try{ await db().ref('groups/'+gid+'/members/'+id+'/parentConsent').set({by:selfUid||'', ts:Date.now()}); }catch(e){}
        toast('נוסף/ה ✓'); onAdded&&onAdded(id); onClose();
      }
      catch(ex){ console.warn('[add-participant]',ex&&ex.code); toast('לא הצלחנו להוסיף — נסו שוב'); setBusy(false); }
    };
    return (
      <div className="sheet-bg" onClick={onClose}>
        <form className="sheet" onClick={e=>e.stopPropagation()} onSubmit={save}>
          <div className="sheet-handle"></div>
          <h3 style={{margin:'0 0 4px',fontFamily:"'Varela Round'"}}>הוספת משתתף/ת</h3>
          <p className="muted" style={{margin:'0 0 14px',lineHeight:1.5}}>למי שאין לו מייל או מכשיר משלו — ילד/ה, סבא/תא או כל משתתף/ת. הזנה בלחיצה על הפרצוף, מהמכשיר שלכם.</p>
          <label className="fld"><span className="lab">השם</span>
            <input className="input" autoFocus value={name} onChange={e=>setName(e.target.value)} placeholder="איך לקרוא לו/לה?" maxLength={16}/>
          </label>
          <span className="lab" style={{display:'block',marginBottom:2}}>בחרו דמות</span>
          <window.AvatarPicker value={avatar} onChange={setAvatar}/>
          <label className="consent-check" style={{marginTop:12}}>
            <input type="checkbox" checked={ok} onChange={e=>setOk(e.target.checked)}/>
            <span>אני ההורה/אפוטרופוס של המשתתף/ת, או מורשה/ת לצרף אותו/ה, ומאשר/ת את ההשתתפות.</span>
          </label>
          <button className="btn" type="submit" disabled={busy||!ok} style={{marginTop:12}}>{busy?'רגע…':'הוספה ✨'}</button>
        </form>
      </div>
    );
  }

  /* ---------- "who's counting?" picker overlay (parent's family device) ---------- */
  function KidsPickOverlay({group, members, selfUid, selfProfile, onPick, onAddChild, onClose}){
    const list=members.map(id=>({id, m:group.members[id]}));
    return (
      <div className="kids-overlay">
        <div className="ko-head">
          <h2>מי מזין/ה עכשיו?</h2>
          <button className="ko-x" onClick={onClose} aria-label="סגירה">×</button>
        </div>
        <div className="kids-grid">
          {list.map(({id,m})=>(
            <button type="button" className="kid-tile" key={id} onClick={()=>onPick(id)}>
              <div className="kid-face"><window.AvatarImg value={m.avatar} size={84}/></div>
              <div className="kid-name">{id===selfUid?'אני':m.name}</div>
            </button>
          ))}
          <button type="button" className="kid-tile add" onClick={onAddChild}>
            <div className="kid-face plus">＋</div>
            <div className="kid-name">משתתף/ת</div>
          </button>
        </div>
      </div>
    );
  }

  /* ---------- group view ---------- */
  function GroupView({gid, group, uid, profile, muted, setMuted, onLeaveToHub, onLeaveGroup, toast, kidsMode, onSwitchKid}){
    const [tab,setTab]=useState('calc');
    const [showSettings,setShowSettings]=useState(false);
    const [actMember,setActMember]=useState(null);   // member uid whose admin action-sheet is open
    const [viewReceipt,setViewReceipt]=useState(null);
    const [actAs,setActAs]=useState(null);          // when a parent counts "as" a child profile
    const [showKidsPick,setShowKidsPick]=useState(false);
    const [showAddChild,setShowAddChild]=useState(false);
    const goalTimer=useRef(null);
    const isAdmin=(group.members&&group.members[uid]&&group.members[uid].role==='admin');
    // effective identity used for counting/receipts/chat (self, or the child being entered)
    const actMeta = actAs && group.members ? group.members[actAs] : null;
    const actId = (actAs && actMeta) ? actAs : uid;
    const actProfile = (actAs && actMeta) ? {name:actMeta.name, avatar:actMeta.avatar} : profile;

    const onCount=useCallback((cid,delta,asGroup)=>{
      const tid = asGroup ? '_shared' : actId;
      const cur=(group.counts&&group.counts[tid]&&group.counts[tid][cid])||0;
      const next=Math.max(0,cur+delta);
      db().ref('groups/'+gid+'/counts/'+tid+'/'+cid).set(next);
      // sync public aggregates for the global leaderboard (best-effort)
      try{
        const C=window.CONTAINERS||[];
        const all=Object.assign({}, group.counts||{});
        all[tid]=Object.assign({}, all[tid]||{}); all[tid][cid]=next;
        let gMoney=0,gCans=0,myMoney=0,myCans=0;
        Object.keys(all).forEach(u=>{ C.forEach(d=>{ const n=(all[u]&&all[u][d.id])||0; gMoney+=n*d.rate; gCans+=n; if(u===actId){ myMoney+=n*d.rate; myCans+=n; } }); });
        const mult=Math.max(1, group.boostMult||1);
        db().ref('public/groups/'+gid).update({ name:group.name||'קבוצה', icon:group.icon||'♻️', cans:gCans, money:gMoney, total:gMoney*mult, members:Object.keys(group.members||{}).length, ts:Date.now() });
        if(!asGroup){
          db().ref('public/users/'+actId).update({ name:actProfile.name, avatar:actProfile.avatar, ts:Date.now() });
          db().ref('public/users/'+actId+'/groups/'+gid).set({cans:myCans, money:myMoney});
        }
      }catch(e){}
    },[gid,group,actId,actProfile]);

    const onGoal=useCallback((patch)=>{
      clearTimeout(goalTimer.current);
      goalTimer.current=setTimeout(()=>{ db().ref('groups/'+gid).update(patch); },600);
    },[gid]);

    const onSend=useCallback((text)=>{
      db().ref('groups/'+gid+'/chat').push({uid:actId, name:actProfile.name, avatar:actProfile.avatar, text, ts:Date.now()});
    },[gid,actId,actProfile]);

    const onDeleteMsg=useCallback((m)=> db().ref('groups/'+gid+'/chat/'+m.id).remove(),[gid]);
    const onReportMsg=useCallback((m)=> db().ref('groups/'+gid+'/reports').push({
      type:'message', msgId:m.id||'', targetUid:m.uid||'', targetName:m.name||'',
      text:(m.text||'').slice(0,400), byUid:actId, byName:actProfile.name||'', ts:Date.now(), status:'open'
    }),[gid,actId,actProfile]);

    const onReceipt=useCallback((img,amount)=>{
      db().ref('groups/'+gid+'/receipts').push({uid:actId, name:actProfile.name, avatar:actProfile.avatar, img, amount:amount||'', ts:Date.now(), status:'pending'});
      toast('הקבלה נשלחה לאימות 📸');
    },[gid,actId,actProfile,toast]);

    // backfill public aggregates for ALL members of an open/family group, so
    // everyone shows in the global leaderboard even if they haven't tapped since
    // their counts were seeded (e.g. the migrated family). best-effort.
    useEffect(()=>{
      if(!group || !group.openJoin) return;
      const C=window.CONTAINERS||[]; const counts=group.counts||{}; const mem=group.members||{};
      const mult=Math.max(1, group.boostMult||1);
      let gMoney=0,gCans=0;
      Object.keys(counts).forEach(u=>{ C.forEach(d=>{ const n=(counts[u]&&counts[u][d.id])||0; gMoney+=n*d.rate; gCans+=n; }); });
      try{
        db().ref('public/groups/'+gid).update({ name:group.name||'קבוצה', icon:group.icon||'♻️', cans:gCans, money:gMoney, total:gMoney*mult, members:Object.keys(mem).length, ts:Date.now() });
        Object.keys(mem).forEach(u=>{
          const mc=counts[u]||{}; let money=0,cans=0; C.forEach(d=>{ const n=mc[d.id]||0; money+=n*d.rate; cans+=n; });
          if(cans>0||money>0){
            db().ref('public/users/'+u).update({ name:mem[u].name, avatar:mem[u].avatar, ts:Date.now() });
            db().ref('public/users/'+u+'/groups/'+gid).set({cans, money});
          }
        });
      }catch(e){}
    },[gid, group&&group.openJoin, group&&JSON.stringify(group.counts||{})]);

    const members=group.members?Object.keys(group.members):[];
    const childMembers=members.filter(u=>group.members[u]&&group.members[u].child);
    const inviteLink=location.origin+location.pathname+'?g='+gid;
    const copyInvite=async()=>{ try{ await navigator.clipboard.writeText(inviteLink); toast('הקישור הועתק! שתפו אותו 🔗'); }catch(e){ toast('קוד הקבוצה: '+gid); } };

    // join requests + receipt verification (30-day validity + trust score)
    const joinReqsObj=group.joinRequests||{};
    const joinReqs=Object.keys(joinReqsObj).map(k=>({uid:k,...joinReqsObj[k]}));
    const receiptsObj=group.receipts||{};
    const receipts=Object.keys(receiptsObj).map(k=>({id:k,...receiptsObj[k]})).sort((a,b)=>(b.ts||0)-(a.ts||0));
    const pendingReceipts=receipts.filter(r=>r.status==='pending');
    const VALID_MS=VERIFY_VALID_DAYS*86400000;
    const verifyInfo={};
    receipts.forEach(r=>{ if(r.status==='verified'){ const t=r.decidedAt||r.ts||0; const inf=verifyInfo[r.uid]||(verifyInfo[r.uid]={count:0,lastTs:0}); inf.count++; if(t>inf.lastTs) inf.lastTs=t; } });
    Object.keys(verifyInfo).forEach(u=>{ const i=verifyInfo[u]; i.active=(Date.now()-i.lastTs)<=VALID_MS; i.expiresAt=i.lastTs+VALID_MS; });
    const verifiedSet={}; Object.keys(verifyInfo).forEach(u=>{ if(verifyInfo[u].active) verifiedSet[u]=true; });
    const myPendingReceipt=receipts.some(r=>r.uid===actId && r.status==='pending');
    const reportsObj=group.reports||{};
    const reports=Object.keys(reportsObj).map(k=>({id:k,...reportsObj[k]})).filter(r=>r.status!=='closed').sort((a,b)=>(b.ts||0)-(a.ts||0));
    const pendingCount=isAdmin?(joinReqs.length+pendingReceipts.length+reports.length):0;

    const closeReport=async(r)=>{ try{ await db().ref('groups/'+gid+'/reports/'+r.id).remove(); }catch(e){} };
    const deleteReportedMsg=async(r)=>{ try{ if(r.msgId) await db().ref('groups/'+gid+'/chat/'+r.msgId).remove(); await db().ref('groups/'+gid+'/reports/'+r.id).remove(); toast('טופל ✓'); }catch(e){ toast('שגיאה'); } };

    const approveJoin=async(rid,req)=>{ try{ await db().ref('groups/'+gid+'/members/'+rid).set({name:req.name,avatar:req.avatar,joinedAt:Date.now(),role:'member'}); await db().ref('groups/'+gid+'/joinRequests/'+rid).remove(); toast('אושר ✓'); }catch(e){ toast('שגיאה'); } };
    const rejectJoin=async(rid)=>{ try{ await db().ref('groups/'+gid+'/joinRequests/'+rid).remove(); }catch(e){} };
    const verifyReceipt=async(r)=>{ try{ await db().ref('groups/'+gid+'/receipts/'+r.id).update({status:'verified', by:uid, decidedAt:Date.now()}); toast('אומת ✓'); setViewReceipt(null); }catch(e){ toast('שגיאה'); } };
    const rejectReceipt=async(r)=>{ try{ await db().ref('groups/'+gid+'/receipts/'+r.id).update({status:'rejected', by:uid, decidedAt:Date.now()}); setViewReceipt(null); }catch(e){} };

    return (
      <div className="app">
        <div className="gv-top">
          <button className="gv-back" onClick={onLeaveToHub} aria-label={kidsMode?'החלפת בת':'הקבוצות שלי'}>{kidsMode ? <window.AvatarImg value={profile.avatar} size={40}/> : <img src="icons/icon-192.png" alt="בנקבוק"/>}</button>
          <GroupIcon value={group.icon} size={40} radius={12}/>
          <div className="gv-title">
            <h2>{group.name}</h2>
            {group.goalName ? <div style={{color:'#bdf0d2',fontSize:'.74rem',fontWeight:700,marginTop:2}}>🎯 {group.goalName}</div> : null}
          </div>
          <button className={"gv-icon"+(muted?'':' on')} onClick={()=>setMuted(m=>!m)} aria-label="צליל">{muted?'🔇':'🔊'}</button>
          <button className="gv-icon" onClick={()=>setShowSettings(true)} aria-label="הגדרות">⚙️</button>
        </div>

        {tab==='calc' && (<>
          {actAs && actMeta && (
            <div className="acting-banner">
              <window.AvatarImg value={actMeta.avatar} size={34}/>
              <span>מזינים בתור <b>{actMeta.name}</b></span>
              <button onClick={()=>setShowKidsPick(true)}>🔁 החלפה</button>
              <button onClick={()=>setActAs(null)}>✓ סיום</button>
            </div>
          )}
          <Calculator group={group} uid={actId} muted={muted} onCount={onCount} onGoal={onGoal} verifiedSet={verifiedSet} verifyInfo={verifyInfo} myPendingReceipt={myPendingReceipt} onReceipt={onReceipt}/>
        </>)}
        {tab==='board' && <Leaderboard group={group} uid={uid} gid={gid}/>}
        {tab==='chat' && <Chat group={group} uid={actId} profile={actProfile} onSend={onSend} isAdmin={isAdmin} onDelete={onDeleteMsg} onReport={onReportMsg}/>}
        {tab==='info' && <InfoScreen/>}
        {tab==='members' && (
          <div>
            <div className="sec-title"><h2>👥 חברי הקבוצה</h2><div className="ln"></div></div>
            {kidsMode ? (
              <div className="invite-box" style={{textAlign:'center'}}>
                👧 זו הקבוצה שלכן!
                <button className="btn sm" style={{width:'100%',marginTop:4}} onClick={onSwitchKid}>🔁 החלפת בת</button>
              </div>
            ) : (
            <div className="invite-box">
              הזמינו חברים עם הקוד<div className="code">{gid}</div>
              <button className="btn sm" style={{width:'100%'}} onClick={copyInvite}>📤 העתקת קישור הזמנה</button>
            </div>
            )}

            {!kidsMode && isAdmin && (
              <div className="addpart">
                <div className="addpart-txt">אפשר לצרף גם מי שאין לו חשבון משלו — ילד/ה, סבא/תא או כל משתתף/ת. הם מזינים מהמכשיר שלכם.</div>
                <div style={{display:'flex',gap:8,marginTop:10}}>
                  <button className="btn soft sm" style={{flex:1,width:'auto'}} onClick={()=>setShowAddChild(true)}>➕ הוספת משתתף/ת</button>
                  {childMembers.length>0 && <button className="btn soft sm" style={{flex:1,width:'auto'}} onClick={()=>setShowKidsPick(true)}>👥 הזנה משותפת</button>}
                </div>
              </div>
            )}

            {isAdmin && joinReqs.length>0 && (
              <div className="pending-box">
                <div className="ph">🟢 מבקשים להצטרף ({joinReqs.length})</div>
                {joinReqs.map(r=>(
                  <div className="pending-row" key={r.uid}>
                    <AvatarImg value={r.avatar} size={40}/>
                    <div className="pr-name">{r.name}</div>
                    <div className="pr-act">
                      <button className="pr-btn ok" aria-label="אישור" onClick={()=>approveJoin(r.uid,r)}>✓</button>
                      <button className="pr-btn no" aria-label="דחייה" onClick={()=>rejectJoin(r.uid)}>✕</button>
                    </div>
                  </div>
                ))}
              </div>
            )}

            {isAdmin && pendingReceipts.length>0 && (
              <div className="pending-box">
                <div className="ph">📸 קבלות לאימות ({pendingReceipts.length})</div>
                <p className="muted" style={{margin:'-4px 0 10px',lineHeight:1.5}}>אשרו רק אם הפרטים בקבלה תואמים את הדיווח. התג בתוקף ל-{VERIFY_VALID_DAYS} יום ומתחדש עם כל אימות.</p>
                {pendingReceipts.map(r=>(
                  <div className="pending-row" key={r.id}>
                    <img className="rcpt-thumb" src={r.img} alt="" onClick={()=>setViewReceipt(r)}/>
                    <div className="pr-name">{r.name}{r.amount?<div className="muted" style={{fontWeight:700}} dir="ltr">₪{r.amount}</div>:null}</div>
                    <button className="btn cyan sm" onClick={()=>setViewReceipt(r)}>צפייה</button>
                  </div>
                ))}
              </div>
            )}

            {isAdmin && reports.length>0 && (
              <div className="pending-box">
                <div className="ph">🚩 דיווחים שממתינים לטיפול ({reports.length})</div>
                {reports.map(r=>(
                  <div className="report-row" key={r.id}>
                    <div className="rr-body">
                      <div className="rr-meta">{r.byName||'מישהו'} דיווח/ה {r.targetName?('על '+r.targetName):''}</div>
                      {r.text ? <div className="rr-text">“{r.text}”</div> : null}
                    </div>
                    <div className="rr-acts">
                      {r.type==='message' && r.msgId && <button className="btn pink sm" onClick={()=>deleteReportedMsg(r)}>🗑️ מחיקת ההודעה</button>}
                      {r.targetUid && group.members&&group.members[r.targetUid] && <button className="btn soft sm" onClick={()=>{ setActMember(r.targetUid); }}>⚙️ טיפול בחבר/ה</button>}
                      <button className="linkbtn" onClick={()=>closeReport(r)}>התעלמות</button>
                    </div>
                  </div>
                ))}
              </div>
            )}

            <div className="rows">
              {members.map(u=>{
                const m=group.members[u];
                const canManage = isAdmin && !kidsMode;
                return (
                  <div className={"member-row"+(canManage?' tappable':'')} key={u} onClick={canManage?()=>setActMember(u):undefined} role={canManage?'button':undefined}>
                    <AvatarImg value={m.avatar} size={44}/>
                    <div className="mr-name">{m.name}{m.child && <span className="mr-child">משתתף/ת</span>}{verifiedSet[u] && <span className="vbadge" title="מאומת">✓</span>}{m.role==='admin' && <span style={{color:'var(--sun-dk)',fontSize:'.7rem',fontWeight:800}}> · מנהל</span>}</div>
                    {u===uid && <span className="mr-you">אתם</span>}
                    {canManage && <span className="mr-gear">⚙️</span>}
                  </div>
                );
              })}
            </div>
            <button className="btn ghost" style={{marginTop:18}} onClick={()=>{ if(kidsMode){ onSwitchKid(); return; } if(confirm('לצאת מהקבוצה? תוכלו לחזור עם הקוד.')) onLeaveGroup(); }}>{kidsMode?'🔁 החלפת בת':'🚪 יציאה מהקבוצה'}</button>
          </div>
        )}

        <div className="tabbar"><div className="inner">
          <button className={"tab"+(tab==='calc'?' active':'')} onClick={()=>setTab('calc')}><span className="ti">🥤</span>מחשבון</button>
          <button className={"tab"+(tab==='board'?' active':'')} onClick={()=>setTab('board')}><span className="ti">🏆</span>דירוג</button>
          <button className={"tab"+(tab==='chat'?' active':'')} onClick={()=>setTab('chat')}><span className="ti">💬</span>צ'אט</button>
          <button className={"tab"+(tab==='info'?' active':'')} onClick={()=>setTab('info')}><span className="ti">♻️</span>מידע</button>
          <button className={"tab"+(tab==='members'?' active':'')} onClick={()=>setTab('members')}><span className="ti">👥</span>חברים{pendingCount>0 && <span className="badge">{pendingCount}</span>}</button>
        </div></div>

        {showSettings && <SettingsSheet gid={gid} group={group} isAdmin={isAdmin} selfUid={uid} toast={toast} onClose={()=>setShowSettings(false)} onDeleted={()=>{ setShowSettings(false); onLeaveToHub(); }}/>}
        {actMember && MemberActionSheet && (
          <MemberActionSheet gid={gid} group={group} mid={actMember} selfUid={uid} toast={toast}
            onClose={()=>setActMember(null)} onAfterRemove={()=>setActMember(null)}/>
        )}
        {showAddChild && <AddChildSheet gid={gid} selfUid={uid} toast={toast} onClose={()=>setShowAddChild(false)} onAdded={(id)=>{ setActAs(id); setTab('calc'); }}/>}
        {showKidsPick && (
          <KidsPickOverlay group={group} members={members} selfUid={uid} selfProfile={profile}
            onPick={(id)=>{ setActAs(id===uid?null:id); setShowKidsPick(false); setTab('calc'); }}
            onAddChild={()=>{ setShowKidsPick(false); setShowAddChild(true); }}
            onClose={()=>setShowKidsPick(false)}/>
        )}
        {viewReceipt && (
          <div className="sheet-bg" onClick={()=>setViewReceipt(null)}>
            <div className="sheet" onClick={e=>e.stopPropagation()}>
              <div className="sheet-handle"></div>
              <div className="md-head">
                <AvatarImg value={viewReceipt.avatar} size={48}/>
                <div><h3 style={{margin:0}}>{viewReceipt.name}</h3>{viewReceipt.amount?<div className="md-totals" dir="ltr">סכום שדווח: ₪{viewReceipt.amount}</div>:null}</div>
              </div>
              <img className="rcpt-full" src={viewReceipt.img} alt="קבלה"/>
              {(()=>{ const C=window.CONTAINERS||[]; const mc=(group.counts&&group.counts[viewReceipt.uid])||{}; let mn=0,cn=0; C.forEach(d=>{const n=mc[d.id]||0; mn+=n*d.rate; cn+=n;}); return (
                <div className="rcpt-report">דיווח נוכחי בקבוצה: <b dir="ltr">₪{mn.toFixed(2)}</b> · {cn} מכלים<div className="muted" style={{marginTop:4,fontWeight:600}}>השווו לסכום שעל הקבלה לפני אישור.</div></div>
              ); })()}
              {viewReceipt.status==='pending' ? (
                <div style={{display:'flex',gap:10,marginTop:14}}>
                  <button className="btn" style={{flex:1}} onClick={()=>verifyReceipt(viewReceipt)}>✓ אימות</button>
                  <button className="btn pink" style={{flex:1}} onClick={()=>rejectReceipt(viewReceipt)}>✕ דחייה</button>
                </div>
              ) : (
                <div className="err" style={{marginTop:14,background:viewReceipt.status==='verified'?'#e3f9ec':'#ffe3ee',color:viewReceipt.status==='verified'?'var(--leaf-dk)':'var(--pink-dk)'}}>{viewReceipt.status==='verified'?'✓ אומת':'נדחה'}</div>
              )}
            </div>
          </div>
        )}
      </div>
    );
  }

  /* ---- kids error screen ---- */
  function KidsErrorScreen({msg, onRetry, onExit}){
    return (
      <div className="center-screen">
        <div className="brandmark"><div className="logo"><img src="icons/icon-192.png" alt=""/></div><h1>רגע…</h1></div>
        <div className="card" style={{textAlign:'center'}}>
          <div style={{fontSize:'3rem',margin:'4px 0 10px'}}>🔌</div>
          <p style={{color:'#5e7468',fontWeight:600,lineHeight:1.6,margin:'0 0 16px'}}>{msg}</p>
          <button className="btn" onClick={onRetry}>נסו שוב</button>
          {onExit && <button className="linkbtn" style={{marginTop:10,color:'#9bb0a4'}} onClick={onExit}>כניסה עם חשבון אחר ←</button>}
        </div>
      </div>
    );
  }

  /* ---------- root app ---------- */
  function App(){
    const [authReady,setAuthReady]=useState(false);
    const [user,setUser]=useState(null);
    const [profile,setProfile]=useState(undefined); // undefined=loading, null=none
    const [gid,setGidState]=useState(null);
    const [group,setGroup]=useState(undefined);
    const [onboarded,setOnboarded]=useState(()=>!!localStorage.getItem(LS_ONB));
    const [muted,setMutedState]=useState(()=>localStorage.getItem(mutedKey)==='1');
    const [pendingInvite,setPendingInvite]=useState(null);
    const [introDone,setIntroDone]=useState(()=> sessionStorage.getItem(LS_INTRO)==='1' || !window.IntroSplash);
    const [promoDone,setPromoDone]=useState(()=>{ try{ return !window.PromoVideo || localStorage.getItem('bottlex-promo-v1')==='1'; }catch(e){ return true; } });
    const [toast,toastNode]=useToast();

    // ---- kids mode (no-email family entry) ----
    const [kidsMode,setKidsMode]=useState(()=>{ const sp=location.search||''; if(/[?&](login|exitkids)\b/.test(sp)){ try{localStorage.removeItem('bottlex-kids');localStorage.removeItem('bottlex-kids-slot');}catch(e){} return false; } const m=/[?&]kids\b/.test(sp); if(m){ try{localStorage.setItem('bottlex-kids','1');}catch(e){} } return m || (()=>{try{return localStorage.getItem('bottlex-kids')==='1';}catch(e){return false;}})(); });
    const [kidsSlot,setKidsSlotState]=useState(()=>{ try{return localStorage.getItem('bottlex-kids-slot')||null;}catch(e){return null;} });
    const [kidsReady,setKidsReady]=useState(false);
    const [kidsErr,setKidsErr]=useState(null);
    const [kidsConsent,setKidsConsent]=useState(()=>{ try{ return localStorage.getItem('bottlex-kids-consent')===(window.LEGAL&&window.LEGAL.POLICY_VERSION); }catch(e){ return false; } });
    const [showOwner,setShowOwner]=useState(false);
    const setKidsSlot=useCallback((s)=>{ setKidsSlotState(s); try{ if(s) localStorage.setItem('bottlex-kids-slot',s); else localStorage.removeItem('bottlex-kids-slot'); }catch(e){} },[]);
    const enterKids=useCallback(()=>{ try{localStorage.setItem('bottlex-kids','1');}catch(e){} setKidsMode(true); },[]);
    const exitKids=useCallback(()=>{ try{localStorage.removeItem('bottlex-kids');localStorage.removeItem('bottlex-kids-slot');}catch(e){} setKidsSlot(null); setKidsMode(false); if(window.fbAuth&&window.fbAuth.currentUser&&window.fbAuth.currentUser.isAnonymous){ window.fbAuth.signOut(); } },[setKidsSlot]);

    const setMuted=useCallback((fn)=>{ setMutedState(prev=>{ const v=typeof fn==='function'?fn(prev):fn; localStorage.setItem(mutedKey,v?'1':'0'); return v; }); },[]);
    const setGid=useCallback((g)=>{ setGidState(g); if(user){ if(g) localStorage.setItem(gidKey(user.uid),g); else localStorage.removeItem(gidKey(user.uid)); } },[user]);

    useEffect(()=>{ window.initConfetti&&window.initConfetti(); const m=location.search.match(/[?&]g=([A-Za-z0-9]+)/); if(m) setPendingInvite(m[1].toUpperCase()); },[]);

    useEffect(()=>{
      if(!window.fbAuth){ setAuthReady(true); return; }
      const un=window.fbAuth.onAuthStateChanged(u=>{
        setUser(u); setAuthReady(true);
        if(u){ const g=localStorage.getItem(gidKey(u.uid)); setGidState(g||null); }
        else { setProfile(undefined); setGidState(null); setGroup(undefined); }
      });
      return un;
    },[]);

    useEffect(()=>{
      if(!user){ return; }
      const ref=db().ref('users/'+user.uid);
      const h=(s)=>{ const v=s.val(); setProfile(v&&v.name?v:null); };
      ref.on('value',h); return ()=>ref.off('value',h);
    },[user]);

    // kids: sign in anonymously (only to satisfy security rules)
    useEffect(()=>{
      if(!kidsMode || !authReady) return;
      if(!user && window.fbAuth){ window.KidsApi.ensureAnon().catch(e=>{ console.warn('[kids-auth] anonymous sign-in unavailable (enable Anonymous in Firebase Console)',e&&e.code); setKidsErr(window.KidsApi.heAuthErr(e)); }); }
    },[kidsMode,authReady,user]);

    // kids: create the family group once, then point gid at it
    useEffect(()=>{
      if(!kidsMode || !user) return;
      let alive=true;
      window.KidsApi.ensureFamilyGroup()
        .then(()=>{ if(alive){ setKidsReady(true); setGidState(window.KidsApi.FAMILY_GID); } })
        .catch(e=>{ console.warn('[kids-group]',e&&e.code); if(alive) setKidsErr(window.KidsApi.heAuthErr(e)); });
      return ()=>{ alive=false; };
    },[kidsMode,user]);

    useEffect(()=>{
      if(!gid){ setGroup(undefined); return; }
      const ref=db().ref('groups/'+gid);
      const h=(s)=>{ if(!s.exists()){ setGroup(null); } else setGroup(s.val()); };
      ref.on('value',h); return ()=>ref.off('value',h);
    },[gid]);

    const signOut=()=>{ window.fbAuth.signOut(); };
    const isOwner = !!(user && isOwnerEmail(user.email));
    const leaveGroup=async()=>{
      try{ await db().ref('groups/'+gid+'/members/'+user.uid).remove(); await db().ref('users/'+user.uid+'/groups/'+gid).remove(); }catch(e){}
      setGid(null);
    };

    // ---- routing ----
    const route=()=>{
      if(kidsMode){
        if(kidsErr) return <KidsErrorScreen msg={kidsErr} onRetry={()=>{ setKidsErr(null); location.reload(); }} onExit={exitKids}/>;
        if(!kidsConsent && KidsParentGate) return <><KidsParentGate onAgree={()=>setKidsConsent(true)} onExit={exitKids}/>{toastNode}</>;
        if(!authReady || !user || !kidsReady) return <div className="center-load"><div className="spin"></div></div>;
        if(!kidsSlot) return <><window.KidsPicker members={group&&group.members} onPick={setKidsSlot} toast={toast} onExit={exitKids}/>{toastNode}</>;
        if(group===undefined) return <div className="center-load"><div className="spin"></div></div>;
        const meta=(group&&group.members)?group.members[kidsSlot]:null;
        if(!meta) return <><window.KidsPicker members={group&&group.members} onPick={setKidsSlot} toast={toast} onExit={exitKids}/>{toastNode}</>;
        return (<><GroupView gid={window.KidsApi.FAMILY_GID} group={group} uid={kidsSlot} profile={{name:meta.name, avatar:meta.avatar}} muted={muted} setMuted={setMuted} toast={toast} kidsMode={true} onSwitchKid={()=>setKidsSlot(null)} onLeaveToHub={()=>setKidsSlot(null)} onLeaveGroup={()=>setKidsSlot(null)}/>{toastNode}</>);
      }
      if(!authReady) return <div className="center-load"><div className="spin"></div></div>;
      if(!user){ return onboarded ? <AuthScreen onKidsLogin={enterKids}/> : <Onboarding onDone={()=>{ localStorage.setItem(LS_ONB,'1'); setOnboarded(true); }}/>; }
      if(profile===undefined) return <div className="center-load"><div className="spin"></div></div>;
      if(profile===null) return <ProfileSetup uid={user.uid} defaultName={user.displayName} defaultPhoto={user.photoURL} onSaved={()=>{}}/>;
      if(ConsentScreen && !(profile.consent && profile.consent.v===LEGAL.POLICY_VERSION)) return <><ConsentScreen uid={user.uid} name={profile.name} toast={toast} onAgreed={()=>{}}/>{toastNode}</>;
      if(showOwner && isOwner && OwnerAdminPanel) return <><OwnerAdminPanel selfUid={user.uid} selfEmail={user.email} toast={toast} onClose={()=>setShowOwner(false)} onEnterGroup={(g)=>{ setShowOwner(false); setGid(g); }}/>{toastNode}</>;
      if(!gid || group===null) return <GroupHub uid={user.uid} profile={profile} pendingInvite={pendingInvite} toast={toast} onSignOut={signOut} isOwner={isOwner} onOpenOwner={()=>setShowOwner(true)} onEnter={(g)=>{ setGid(g); setPendingInvite(null); }}/>;
      if(group===undefined) return <div className="center-load"><div className="spin"></div></div>;
      return (<><GroupView gid={gid} group={group} uid={user.uid} profile={profile} muted={muted} setMuted={setMuted} toast={toast} onLeaveToHub={()=>setGid(null)} onLeaveGroup={leaveGroup}/>{toastNode}</>);
    };

    return (<>
      {route()}
      {InstallPrompt && <InstallPrompt lifted={!!(user && profile && gid && group)}/>}
      {!introDone && <IntroSplash onDone={()=>{ try{sessionStorage.setItem(LS_INTRO,'1');}catch(e){} setIntroDone(true); }}/>}
      {introDone && !promoDone && PromoVideo && <PromoVideo onDone={()=>{ try{localStorage.setItem('bottlex-promo-v1','1');}catch(e){} setPromoDone(true); }}/>}
    </>);
  }

  ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
})();
