/* YeYe Portal — Modals + App root */
const PURCHASE_KEY = 'yeye_expat_purchased_v1';
const GHL_TASK_SYNC_BASE = 'https://ghl-read-service-ib6dfdthbq-ew.a.run.app';
function readPurchaseStore() {
  try { return JSON.parse(localStorage.getItem(PURCHASE_KEY) || '{}') || {}; } catch (_) { return {}; }
}
function servicePrice(s) { return s.p + (s.u || ''); }
function serviceDesc(s, t) {
  const map = {
    immig: 'svc.detail.immig', docs: 'svc.detail.docs', legal: 'svc.detail.legal',
    biz: 'svc.detail.biz', fin: 'svc.detail.fin',
  };
  return t(map[s.cat] || 'svc.detail.default');
}
function browserTimeZone() {
  try { return Intl.DateTimeFormat().resolvedOptions().timeZone || 'Europe/Prague'; } catch (_) { return 'Europe/Prague'; }
}
function taskDateLabel(value) {
  if (!value) return '—';
  const d = new Date(value);
  if (Number.isNaN(d.getTime())) return String(value).slice(0, 12);
  return d.toLocaleDateString(undefined, { day: 'numeric', month: 'short' });
}
function taskCategoryFromText(task) {
  const raw = String([task.category, task.title, task.body, task.notes].filter(Boolean).join(' ')).toLowerCase();
  if (/invoice|payment|pay|fee|fatura|ödeme|odeme|ücret|ucret/.test(raw)) return 'finance';
  if (/appointment|calendar|randevu|biometric|embassy|police|oamp/.test(raw)) return 'appointment';
  if (/passport|document|upload|file|insurance|contract|belge|evrak|pasaport|sigorta/.test(raw)) return 'document';
  if (/immigration|visa|card|permit|residence|blue|employee|göç|goc|ikamet/.test(raw)) return 'immigration';
  if (/admin|office|form|signature|imza/.test(raw)) return 'admin';
  return 'other';
}
function parseTaskTitlePrefix(title) {
  const raw = String(title || '');
  const match = raw.match(/^\s*\[(Belge|Bilgi)\]\s*/i);
  if (!match) return { title: raw, taskType: '', taskTypeLabelKey: '', taskTypeTone: 'neut' };
  const kind = match[1].toLowerCase() === 'belge' ? 'belge' : 'bilgi';
  return {
    title: raw.slice(match[0].length).trim() || raw,
    taskType: kind,
    taskTypeLabelKey: kind === 'belge' ? 'task.type.documentRequest' : 'task.type.info',
    taskTypeTone: kind === 'belge' ? 'warn' : 'info',
  };
}
function normalizePortalTask(task) {
  const done = !!(task.done || task.completed || String(task.status || '').toLowerCase() === 'completed');
  const rawTitle = task.title || task.subject || task.body || 'GHL task';
  const parsedTitle = parseTaskTitlePrefix(rawTitle);
  const category = taskCategoryFromText({ ...task, title: rawTitle });
  return {
    id: task.id || task.ghlTaskId || ('task-' + Math.random().toString(36).slice(2)),
    ghlTaskId: task.ghlTaskId || task.id || task.taskId,
    contactId: task.contactId,
    title: parsedTitle.title,
    rawTitle,
    taskType: parsedTitle.taskType,
    taskTypeLabelKey: parsedTitle.taskTypeLabelKey,
    taskTypeTone: parsedTitle.taskTypeTone,
    body: task.body || task.notes || '',
    due: taskDateLabel(task.due || task.dueDate || task.date),
    dueRaw: task.due || task.dueDate || task.date,
    done,
    category,
    tone: done ? 'ok' : (category === 'finance' ? 'warn' : category === 'document' ? 'bad' : 'info'),
    source: task.source || 'ghl',
  };
}
function eventDateParts(isoDate) {
  const d = new Date((isoDate || '').slice(0, 10) + 'T12:00:00');
  if (Number.isNaN(d.getTime())) return { day: 16, dateLabel: '16 Jun' };
  const day = d.getDate();
  const dateLabel = d.toLocaleDateString(undefined, { day: 'numeric', month: 'short' });
  return { day, dateLabel };
}

/* ---------- Service purchase modal ---------- */
function ServiceDisclaimer({ data, t }) {
  const liStyle = { marginBottom: 4 };
  const ulStyle = { margin: '6px 0 14px 18px', padding: 0 };
  const h = { fontSize: 14, fontWeight: 700, marginTop: 0, marginBottom: 6 };
  const sub = { fontSize: 13.5, fontWeight: 600, marginTop: 10, marginBottom: 4 };
  const p = { fontSize: 13, lineHeight: 1.55, margin: '4px 0' };
  return (
    <div style={{ maxHeight: 360, overflowY: 'auto', padding: '12px 14px', border: '1px solid var(--line-2)', borderRadius: 10, background: 'var(--surface-2)' }}>
      <div style={h}>{data.title}</div>
      <div style={p}>{data.intro}</div>
      <div style={sub}>{t('mod.included')}</div>
      <ul style={ulStyle}>
        {data.included.map((x, i) => <li key={i} style={liStyle}>{x}</li>)}
      </ul>
      <div style={{ marginTop: 12, padding: '12px 14px', border: '1px solid var(--bad)', borderRadius: 10, background: 'var(--bad-bg)' }}>
        <div style={{ ...h, color: 'var(--bad)' }}>{t('mod.excluded')}</div>
        <div style={p}>{t('mod.excludedNote')}</div>
        <ul style={ulStyle}>
          {data.excluded.map((x, i) => <li key={i} style={liStyle}>{x}</li>)}
        </ul>
      </div>
    </div>
  );
}
function ServiceModal({ service, contact, liveContact, onClose, onConfirm }) {
  const { t, lang } = useT();
  const s = service || window.YEYE.services[0];
  const icon = window.YEYE.catIcon[s.cat];
  const price = servicePrice(s);
  const entry = (window.YEYE_DISCLAIMERS || {})[s.k];
  const disclaimer = entry ? (entry[lang] || entry.en || entry.tr) : null;
  const [agreed, setAgreed] = useState(false);
  const [step, setStep] = useState('review');
  const contactEmail = ((liveContact && liveContact.email) || (contact && contact.email) || '').trim();
  const deliverables = disclaimer && disclaimer.included ? disclaimer.included.slice(0, 4) : [t('mod.b1'), t('mod.b2'), t('mod.b3')];
  const buildPayUrl = () => {
    if (!s.payUrl) return null;
    const src = liveContact || contact || {};
    const first = src.firstName || src.first_name || (src.name ? String(src.name).split(' ')[0] : '') || '';
    const last = src.lastName || src.last_name || (src.name ? String(src.name).split(' ').slice(1).join(' ') : '') || '';
    const email = src.email || '';
    const phone = src.phone || '';
    const params = new URLSearchParams();
    if (first) params.set('first_name', first);
    if (last) params.set('last_name', last);
    if (email) params.set('email', email);
    if (phone) params.set('phone', phone);
    const qs = params.toString();
    return qs ? s.payUrl + (s.payUrl.includes('?') ? '&' : '?') + qs : s.payUrl;
  };
  const goToPayment = () => {
    const url = buildPayUrl();
    if (url) window.open(url, '_blank', 'noopener');
    onConfirm(s);
  };
  const handleConfirm = () => {
    if (s.payUrl) setStep('emailNotice');
    else { onConfirm(s); }
  };
  if (step === 'emailNotice') {
    return (
      <Modal icon="mail-check" title="Confirm your email" sub="Use this email at checkout" onClose={onClose}
        footer={<>
          <Btn variant="ghost" onClick={() => setStep('review')}>Back</Btn>
          <Btn variant="primary" icon="arrow-right" onClick={goToPayment}>Continue to Payment</Btn>
        </>}>
        <div className="flex col gap-16">
          <div className="alert warn">
            <div className="a-ic"><Icon name="alert-triangle" size={16} /></div>
            <div className="grow">
              <div className="a-t">Please use the email address below on the payment page</div>
              <div className="a-s">If you enter a different email, your purchase will not be linked to your account and services will not appear here automatically.</div>
            </div>
          </div>
          <div style={{ background: 'var(--surface-2)', border: '1px solid var(--line)', borderRadius: 'var(--r-lg)', padding: '18px 20px' }}>
            <div className="eyebrow mb-8">Your registered email</div>
            <div className="strong" style={{ fontSize: 18, wordBreak: 'break-all' }}>{contactEmail || '—'}</div>
          </div>
          <div className="muted" style={{ fontSize: 13, lineHeight: 1.5 }}>
            You will now be redirected to the secure payment page. On the checkout form, make sure the email you enter matches the one above.
          </div>
        </div>
      </Modal>
    );
  }
  const confirmBtn = disclaimer ? (
    <Btn variant="primary" icon="check" onClick={agreed ? handleConfirm : undefined}
      style={!agreed ? { opacity: 0.5, cursor: 'not-allowed', pointerEvents: 'none' } : undefined}>
      {t('mod.confirmBuy')}
    </Btn>
  ) : <Btn variant="primary" icon="check" onClick={handleConfirm}>{t('mod.confirmBuy')}</Btn>;
  return (
    <Modal icon={icon} title={t('svc.' + s.k)} sub={t('scat.' + s.cat) + ' · ' + price} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.cancel')}</Btn>{confirmBtn}</>}>
      <div className="flex col gap-14 mb-16">
        <div>
          <div className="eyebrow mb-8">{t('svc.description')}</div>
          <div className="muted" style={{ fontSize: 13.5, lineHeight: 1.55 }}>{disclaimer ? disclaimer.intro : serviceDesc(s, t)}</div>
        </div>
        <div>
          <div className="eyebrow mb-8">{t('svc.price')}</div>
          <div className="strong tnum" style={{ fontSize: 18 }}>{price}</div>
        </div>
        <div>
          <div className="eyebrow mb-8">{t('svc.deliverables')}</div>
          <div className="flex col gap-8">
            {deliverables.map((x, i) => (
              <div key={i} className="flex ac gap-10"><div className="hd-ic" style={{ width: 28, height: 28, borderRadius: 8 }}><Icon name="check" size={15} /></div><span style={{ fontSize: 13.5 }}>{x}</span></div>
            ))}
          </div>
        </div>
      </div>
      {disclaimer ? (
        <>
          <ServiceDisclaimer data={disclaimer} t={t} />
          <label className="flex ac gap-10 mt-16" style={{ cursor: 'pointer', userSelect: 'none' }}>
            <input type="checkbox" checked={agreed} onChange={(e) => setAgreed(e.target.checked)} style={{ width: 18, height: 18, cursor: 'pointer' }} />
            <span style={{ fontSize: 13.5, fontWeight: 600 }}>{t('mod.iAgree')}</span>
          </label>
        </>
      ) : (
        <div className="alert info mt-20"><div className="a-ic"><Icon name="info" size={16} /></div><div className="grow"><div className="a-t">{t('mod.noCharge')}</div><div className="a-s">{t('mod.noChargeDesc')}</div></div></div>
      )}
    </Modal>
  );
}

/* ---------- Upload modal ---------- */
function UploadModal({ onClose }) {
  const { t } = useT();
  const [drag, setDrag] = useState(false);
  return (
    <Modal icon="upload" title={t('mod.upTitle')} sub={t('mod.upSub')} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.cancel')}</Btn><Btn variant="primary" icon="upload" onClick={onClose}>{t('mod.uploadFile')}</Btn></>}>
      <Field label={t('mod.docType')}>
        <select className="select"><option>{t('doc.criminal')}</option><option>{t('doc.insurance')}</option><option>{t('doc.accommodation')}</option><option>{t('mod.normal')}</option></select>
      </Field>
      <div className="mt-16" onDragOver={(e) => { e.preventDefault(); setDrag(true); }} onDragLeave={() => setDrag(false)} onDrop={(e) => { e.preventDefault(); setDrag(false); }}
        style={{ border: '2px dashed ' + (drag ? 'var(--brand-400)' : 'var(--line)'), background: drag ? 'var(--brand-50)' : 'var(--surface-2)', borderRadius: 'var(--r-lg)', padding: '34px 20px', textAlign: 'center', transition: '.15s' }}>
        <div className="hd-ic" style={{ width: 48, height: 48, margin: '0 auto 12px', borderRadius: 13 }}><Icon name="cloud-upload" size={24} /></div>
        <div className="strong">{t('mod.dragTitle')}</div>
        <div className="muted" style={{ fontSize: 13, marginTop: 4 }}>{t('mod.or')} <span style={{ color: 'var(--brand-600)', fontWeight: 600 }}>{t('c.browse')}</span></div>
      </div>
    </Modal>
  );
}

function TaskAttachmentModal({ task, contact, onClose }) {
  const { t } = useT();
  const [files, setFiles] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [uploading, setUploading] = React.useState(false);
  const [progress, setProgress] = React.useState(0);
  const [error, setError] = React.useState(null);
  const inputRef = React.useRef(null);
  const contactId = contact && contact.id;
  const taskId = task && (task.id || task.ghlId || task.k);
  const taskTitle = task && (task.title || task.tk || "");
  async function refresh() {
    setLoading(true); setError(null);
    try { const r = await window.YEYE_BACKEND.listTaskFiles({ contactId, taskId, taskTitle }); setFiles((r && r.files) || []); }
    catch (e) { setError(e.message || "list-failed"); }
    finally { setLoading(false); }
  }
  React.useEffect(() => { if (contactId && taskId) refresh(); else setLoading(false); }, [contactId, taskId]);
  async function handleFiles(fileList) {
    if (!fileList || !fileList.length) return;
    if (!contactId || !taskId) { setError("missing-ids"); return; }
    setUploading(true); setError(null); setProgress(0);
    for (const f of Array.from(fileList)) {
      if (f.size > 25 * 1024 * 1024) { setError("too-large"); setUploading(false); return; }
      try { await window.YEYE_BACKEND.uploadTaskFile({ contactId, taskId, taskTitle, file: f, onProgress: setProgress }); }
      catch (e) { setError(e.message || "upload-failed"); setUploading(false); return; }
    }
    setUploading(false); setProgress(0);
    await refresh();
  }
  const fmtSize = (b) => { if (!b) return ""; const n = Number(b); if (n < 1024) return n + " B"; if (n < 1048576) return (n/1024).toFixed(1) + " KB"; return (n/1048576).toFixed(1) + " MB"; };
  return (
    <Modal icon="paperclip" title={taskTitle || t("task.attach.title")} sub={t("task.attach.sub")} onClose={onClose}
      footer={<Btn variant="ghost" onClick={onClose}>{t("c.close")}</Btn>} wide>
      <div className="flex col gap-14">
        <div style={{border: "2px dashed var(--line)", borderRadius: 12, padding: "20px", textAlign: "center", background: "var(--surface-2)"}}
          onDragOver={(e) => e.preventDefault()}
          onDrop={(e) => { e.preventDefault(); handleFiles(e.dataTransfer.files); }}>
          <div className="hd-ic" style={{width: 40, height: 40, margin: "0 auto 10px", borderRadius: 12}}><Icon name="cloud-upload" size={20} /></div>
          <div className="strong">{t("task.attach.drop")}</div>
          <div className="muted" style={{fontSize: 13, marginTop: 4}}>{t("mod.or")} <span style={{color: "var(--brand-600)", fontWeight: 600, cursor: "pointer"}} onClick={() => inputRef.current && inputRef.current.click()}>{t("c.browse")}</span></div>
          <input ref={inputRef} type="file" multiple style={{display: "none"}} onChange={(e) => handleFiles(e.target.files)} />
          {uploading && <div style={{marginTop: 12}}><div style={{height: 4, background: "var(--line)", borderRadius: 2, overflow: "hidden"}}><div style={{height: "100%", width: progress + "%", background: "var(--brand-500)", transition: ".2s"}} /></div><div className="muted" style={{fontSize: 12, marginTop: 6}}>{t("task.attach.uploading")} {progress}%</div></div>}
        </div>
        {error && <div className="alert bad"><div className="a-ic"><Icon name="alert-triangle" size={16} /></div><div className="grow"><div className="a-t">{t("task.attach.err." + error) || error}</div></div></div>}
        <div>
          <div className="strong" style={{marginBottom: 8}}>{t("task.attach.filesList")} ({files.length})</div>
          {loading ? <div className="muted" style={{fontSize: 13}}>{t("c.loading")}</div> :
            files.length === 0 ? <div className="muted" style={{fontSize: 13}}>{t("task.attach.empty")}</div> :
            <div className="rowlist">{files.map((f) => (
              <div className="lrow" key={f.id}>
                <Icon name="file-text" size={16} />
                <div className="l-bd"><div className="l-t">{f.name}</div><div className="l-s">{fmtSize(f.size)} • {(new Date(f.createdTime)).toLocaleDateString()}</div></div>
                <Btn variant="ghost" size="sm" icon="external-link" onClick={() => window.open(f.webViewLink, "_blank")}>{t("c.open")}</Btn>
              </div>
            ))}</div>
          }
        </div>
      </div>
    </Modal>
  );
}

/* ---------- New ticket modal ---------- */
function TicketModal({ onClose, preset, onSubmit }) {
  const { t } = useT();
  const cats = window.YEYE.ticketCats || ['immigration', 'billing', 'documents', 'it'];
  const [catK, setCatK] = useState((preset && preset.catK) || 'immigration');
  const [subject, setSubject] = useState((preset && preset.subject) || '');
  const [details, setDetails] = useState((preset && preset.details) || '');
  const [priority, setPriority] = useState('normal');
  const submit = () => {
    onSubmit({ catK, subject: subject.trim() || t('mod.subjectPh'), details, priority });
  };
  return (
    <Modal icon="life-buoy" title={t('mod.ticketTitle')} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.cancel')}</Btn><Btn variant="primary" icon="send" onClick={submit}>{t('mod.submit')}</Btn></>}>
      <div className="flex col gap-14">
        <Field label={t('col.category')}><select className="select" value={catK} onChange={(e) => setCatK(e.target.value)}>{cats.map((c) => <option key={c} value={c}>{t('cat.' + c)}</option>)}</select></Field>
        <Field label={t('mod.subject')}><input className="input" value={subject} onChange={(e) => setSubject(e.target.value)} placeholder={t('mod.subjectPh')} /></Field>
        <Field label={t('mod.detailsL')}><textarea className="ta" value={details} onChange={(e) => setDetails(e.target.value)} placeholder={t('mod.detailsPh')} /></Field>
        <Field label={t('mod.priority')}><div className="flex gap-8">{['normal', 'high', 'urgent'].map((p) => <button key={p} type="button" className={'chip ' + (priority === p ? 'on' : '')} onClick={() => setPriority(p)}>{t('mod.' + p)}</button>)}</div></Field>
      </div>
    </Modal>
  );
}

function CalendarEventModal({ onClose, onSubmit }) {
  const { t } = useT();
  const today = new Date().toISOString().slice(0, 10);
  const [title, setTitle] = useState('');
  const [date, setDate] = useState(today);
  const [time, setTime] = useState('09:00');
  const [loc, setLoc] = useState('');
  const submit = () => {
    const parts = eventDateParts(date);
    onSubmit({
      d: parts.day,
      date,
      dateLabel: parts.dateLabel,
      key: 'custom',
      title: title.trim() || t('mod.eventTitlePh'),
      loc: loc.trim() || t('mod.eventLocPh'),
      time,
      tone: 'brand',
      ic: 'calendar-plus',
    });
  };
  return (
    <Modal icon="calendar-plus" title={t('mod.eventTitle')} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.cancel')}</Btn><Btn variant="primary" icon="plus" onClick={submit}>{t('mod.addEvent')}</Btn></>}>
      <div className="flex col gap-14">
        <Field label={t('col.subject')}><input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder={t('mod.eventTitlePh')} /></Field>
        <Field label={t('col.date')}><input className="input" type="date" value={date} onChange={(e) => setDate(e.target.value)} /></Field>
        <Field label={t('mod.time')}><input className="input" type="time" value={time} onChange={(e) => setTime(e.target.value)} /></Field>
        <Field label={t('mod.location')}><input className="input" value={loc} onChange={(e) => setLoc(e.target.value)} placeholder={t('mod.eventLocPh')} /></Field>
      </div>
    </Modal>
  );
}

function TaskModal({ onClose, onSubmit }) {
  const { t } = useT();
  const [title, setTitle] = useState('');
  const [due, setDue] = useState('16 Jun');
  const submit = () => {
    onSubmit({
      title: title.trim() || t('mod.taskTitlePh'),
      due: due.trim() || '16 Jun',
      done: false,
      tone: 'warn',
    });
  };
  return (
    <Modal icon="circle-plus" title={t('mod.taskTitle')} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.cancel')}</Btn><Btn variant="primary" icon="plus" onClick={submit}>{t('mod.addTask')}</Btn></>}>
      <div className="flex col gap-14">
        <Field label={t('col.subject')}><input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder={t('mod.taskTitlePh')} /></Field>
        <Field label={t('c.due')}><input className="input" value={due} onChange={(e) => setDue(e.target.value)} placeholder="16 Jun" /></Field>
      </div>
    </Modal>
  );
}

function ServiceManageModal({ item, onClose, onStatus, openTicket, showToast }) {
  const { t } = useT();
  const inputRef = useRef(null);
  const service = item && item.service;
  const purchase = (item && item.purchase) || {};
  const status = purchase.status || 'active';
  if (!service) return null;
  const upload = () => {
    if (inputRef.current) inputRef.current.click();
  };
  const cancel = () => {
    if (confirm(t('svc.cancelConfirm'))) onStatus(service.k, 'cancelled');
  };
  return (
    <Modal icon="settings" title={t('svc.manageTitle')} sub={t('svc.' + service.k)} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.close')}</Btn><Btn variant="primary" icon="life-buoy" onClick={() => openTicket(service)}>{t('svc.supportRequest')}</Btn></>}>
      <div className="flex col gap-16">
        <Field label={t('svc.updateStatus')}>
          <select className="select" value={status} onChange={(e) => onStatus(service.k, e.target.value)}>
            {['active', 'paused', 'cancelled'].map((s) => <option key={s} value={s}>{t('st.' + s)}</option>)}
          </select>
        </Field>
        <div className="flex gap-10 wrap">
          <Btn variant="ghost" icon="upload" onClick={upload}>{t('svc.uploadDoc')}</Btn>
          <Btn variant="ghost" icon="life-buoy" onClick={() => openTicket(service)}>{t('svc.supportRequest')}</Btn>
          <Btn variant="ghost" icon="x-circle" onClick={cancel}>{t('svc.cancelService')}</Btn>
        </div>
        <input ref={inputRef} type="file" style={{ display: 'none' }} onChange={() => showToast(t('toast.uploadQueued'))} />
      </div>
    </Modal>
  );
}

function Toast({ text }) {
  if (!text) return null;
  return (
    <div style={{ position: 'fixed', right: 22, bottom: 22, zIndex: 120, background: 'var(--ink-900)', color: '#fff', borderRadius: 10, padding: '11px 14px', boxShadow: 'var(--sh-lg)', fontSize: 13.5, fontWeight: 600 }}>
      {text}
    </div>
  );
}

/* ---------- Notifications panel ---------- */
function NotifPanel({ onClose, go }) {
  const { t } = useT();
  const items = [
    { ic: 'file-warning', ty: 'bad', tk: 'n_criminal', s: '2h' },
    { ic: 'calendar-clock', ty: 'warn', tk: 'n_biometrics', s: '5h' },
    { ic: 'check', ty: 'ok', tk: 'n_verified', s: '1d' },
    { ic: 'megaphone', ty: 'info', tk: 'n_rules', s: '2d' },
    { ic: 'receipt', ty: 'warn', tk: 'n_invoice', s: '3d' },
  ];
  const col = { bad: 'var(--bad)', warn: 'var(--warn)', ok: 'var(--ok)', info: 'var(--info)' };
  const bg = { bad: 'var(--bad-bg)', warn: 'var(--warn-bg)', ok: 'var(--ok-bg)', info: 'var(--info-bg)' };
  return (
    <Panel title={t('sec.notifications')} onClose={onClose} footer={<Btn variant="ghost" className="btn-block" onClick={onClose}>{t('c.markRead')}</Btn>}>
      <div className="rowlist" style={{ margin: '-6px 0' }}>
        {items.map((n, i) => (
          <div key={i} className="lrow pointer" onClick={() => { onClose(); go('dashboard'); }}>
            <div className="l-ic" style={{ background: bg[n.ty], color: col[n.ty] }}><Icon name={n.ic} size={18} /></div>
            <div className="l-bd"><div className="l-t" style={{ fontSize: 13, fontWeight: 500 }}>{t(n.tk)}</div><div className="l-s">{n.s} {t('col.ago')}</div></div>
          </div>
        ))}
      </div>
    </Panel>
  );
}

/* ============================================================
   APP ROOT
   ============================================================ */
const TITLES = {
  dashboard: ['Dashboard', null], services: ['Services', 'Purchase & manage services'],
  cases: ['Cases', null], documents: ['My Docs', null], appointments: ['Appointments', null],
  messages: ['Messages', null], tasks: ['My Tasks', null], invoices: ['Payments', null],
  reports: ['Reports', null], support: ['Support Center', null], profile: ['Profile', null], settings: ['Settings', null],
};

async function bridgeExpatTicketToFirestore(localTicket, ticket, currentExpatUser) {
  const fb = window.YEYE_EXPAT_FB;
  if (!fb || !fb.db || !window.firebase || !window.firebase.firestore) return;

  try {
    await fb.ready;
  } catch (err) {
    console.warn('Skipping Firestore ticket bridge because Firebase auth is not ready.', err);
    return;
  }

  const db = fb.db;
  const category = ticket.catK || localTicket.catK || null;
  const subject = (ticket.subject || localTicket.subject || '').trim();
  const body = (ticket.details || ticket.description || subject || '').trim();
  const ownerEmail = (currentExpatUser && currentExpatUser.email) || 'expat-portal';
  const serverTimestamp = window.firebase.firestore.FieldValue.serverTimestamp;

  try {
    await db.collection('notifications').add({
      userEmail: 'support@yeyeagency.com',
      userUid: null,
      title: 'Yeni Expat Ticket: ' + (subject || category || 'IT'),
      body: body,
      type: 'expat-ticket',
      link: '/support',
      status: 'unread',
      createdAt: serverTimestamp(),
      createdBy: ownerEmail,
      source: 'expat-portal',
      expatTicketId: localTicket.id,
      expatCategory: category,
    });
  } catch (err) {
    console.warn('Failed to create dashboard notification for Expat ticket.', err);
  }

  try {
    await db.collection('expatTickets').add({
      id: localTicket.id,
      tk: localTicket.tk,
      subject: subject,
      catK: category,
      category: category,
      status: localTicket.st,
      statusColor: localTicket.stc,
      updated: localTicket.upd,
      details: body,
      priority: ticket.priority || 'normal',
      createdAt: serverTimestamp(),
      ownerEmail: ownerEmail,
      source: 'expat-portal',
    });
  } catch (err) {
    console.warn('Failed to persist Expat ticket to Firestore.', err);
  }
}

function normalizeTicketDoc(doc) {
  const data = doc.data ? doc.data() : doc;
  if (!data) return null;
  const status = data.st || data.status || data.approvalStatus || data.requestStatus || 'open';
  return {
    id: data.id || data.expatTicketId || doc.id,
    tk: data.tk || 'custom',
    subject: data.subject || '',
    catK: data.catK || data.category || 'it',
    st: status,
    stc: data.stc || data.statusColor || (status === 'resolved' || status === 'approved' ? 'ok' : status === 'progress' || status === 'pending' ? 'warn' : 'info'),
    upd: data.upd || data.updated || 'now',
    details: data.details || '',
    priority: data.priority || 'normal',
  };
}

function readContactValue(contact, matcher) {
  const fields = (contact && contact.customFields) || [];
  for (const f of fields) {
    const hay = String((f.key || '') + ' ' + (f.name || '') + ' ' + (f.id || '')).toLowerCase();
    if (matcher(hay)) return String(f.value || '').toLowerCase();
  }
  return '';
}

function hasManagerApproval(contact) {
  const tags = ((contact && contact.tags) || []).map((x) => String(x).toLowerCase());
  if (tags.some((x) => /manager.*(approved|confirmed)|approved.*manager|request_approved|hr_approved/.test(x))) return true;
  const val = readContactValue(contact, (k) => k.includes('manager') && (k.includes('approval') || k.includes('status')));
  return /approved|confirmed|onay|schval/.test(val);
}

function App() {
  const [authState, setAuthState] = useState(() => window.YEYE_AUTH.getState());
  useEffect(() => window.YEYE_AUTH.subscribe(setAuthState), []);
  const initialBlankProfile = (() => {
    const snap = window.YEYE_AUTH.getState();
    const email = ((snap.user && snap.user.email) || (snap.contact && snap.contact.email) || '').toLowerCase();
    return email === 'testblue.demo+20260619@yeye-internal.example.com';
  })();
  const [clientType, setClientType] = useState('employee_card');
  const [branding, setBranding] = useState('individual');
  const [page, setPage] = useState('dashboard');
  const [mini, setMini] = useState(false);
  const [drawer, setDrawer] = useState(false);
  const [modal, setModal] = useState(null);
  const [modalData, setModalData] = useState(null);
  const [tickets, setTickets] = useState(() => initialBlankProfile ? [] : window.YEYE.tickets.slice());
  const [calendarEvents, setCalendarEvents] = useState(() => initialBlankProfile ? [] : (typeof CAL_EVENTS !== 'undefined' ? CAL_EVENTS.slice() : []));
  const [tasks, setTasks] = useState(() => []);
  const [taskSync, setTaskSync] = useState({ syncing: false, error: '', lastSync: null });
  const [purchasedServices, setPurchasedServices] = useState([]);
  const [calendarSync, setCalendarSync] = useState({
    connected: !!(authState.calendarToken && authState.calendarExpiresAt > Date.now()),
    syncing: false,
    error: '',
  });
  const [fieldMappings, setFieldMappings] = useState([]);
  const [contactSync, setContactSync] = useState({ syncing: false, lastSync: null, error: '' });
  const [toast, setToast] = useState('');
  const toastTimer = useRef(null);
  const [notif, setNotif] = useState(false);
  const [lang, setLang] = useState(() => localStorage.getItem('yeye-lang') || 'en');
  const authed = window.YEYE_AUTH.isAuthed();
  const checking = !!authState.gateChecking;

  const t = React.useMemo(() => ((k) => (window.I18N[lang] && window.I18N[lang][k]) || window.I18N.en[k] || k), [lang]);
  const dict = window.I18N[lang] || window.I18N.en;
  const setLangP = (l) => { setLang(l); localStorage.setItem('yeye-lang', l); };
  const userPurchaseKey = ((authState.user && authState.user.email) || (authState.contact && authState.contact.email) || 'guest').toLowerCase();
  const blankProfile = userPurchaseKey === 'testblue.demo+20260619@yeye-internal.example.com';
  const showToast = (msg) => {
    setToast(msg);
    window.clearTimeout(toastTimer.current);
    toastTimer.current = window.setTimeout(() => setToast(''), 2400);
  };

  // Derive case type from GHL tags (falls back to employee_card)
  const deriveCaseType = (tags) => {
    const ts = (tags || []).map((x) => String(x).toLowerCase());
    if (ts.some((x) => x.startsWith('blue_card') || x.includes('bluecard'))) return 'blue_card';
    if (ts.some((x) => x.startsWith('family'))) return 'family_reunion';
    if (ts.some((x) => x.startsWith('business'))) return 'business_visa';
    if (ts.some((x) => x.startsWith('osvc'))) return 'osvc';
    if (ts.some((x) => x.startsWith('relocation'))) return 'relocation';
    if (ts.some((x) => x.startsWith('employee_card') || x.includes('employee_onboarding'))) return 'employee_card';
    return 'employee_card';
  };

  // Build live case-type data from GHL contact + mock template
  const buildLiveCt = (mockCt, contact) => {
    if (!contact) return mockCt;
    const cap = (w) => w ? w.charAt(0).toUpperCase() + w.slice(1) : '';
    const full = [contact.firstName, contact.lastName].filter(Boolean).join(' ').split(' ').map(cap).join(' ').trim();
    const addrField = (contact.customFields || []).find((f) => /correspondence|address|adres/i.test(f.key || ''));
    let region = mockCt.region;
    if (addrField && typeof addrField.value === 'string') {
      const m = addrField.value.match(/([A-Za-zÀ-ž\s]+)\/([A-Za-zÀ-ž\s]+)\s*$/);
      if (m) region = cap(m[1].trim()) + ', ' + cap(m[2].trim());
    }
    const caseId = 'YE-' + String(contact.contactId || '').slice(0, 8).toUpperCase();
    return { ...mockCt, who: full || mockCt.who, region, caseId };
  };

  // Live client-type derived from contact tags; user can still switch via the demo ClientTypeMenu
  const derivedKey = authState.contact ? deriveCaseType(authState.contact.tags) : clientType;
  const effectiveKey = clientType === 'employee_card' && authState.contact ? derivedKey : clientType;
  const mockCt = window.YEYE.clientTypes[effectiveKey] || window.YEYE.clientTypes.employee_card;
  const ctData = buildLiveCt(mockCt, authState.contact);
  const managerApproved = hasManagerApproval(authState.contact);
  const liveCtData = React.useMemo(() => {
    if (!managerApproved || effectiveKey !== 'employee_card') return ctData;
    return { ...ctData, curr: 'Approved', currTone: 'ok', pct: Math.max(ctData.pct || 0, 70), managerApproved: true };
  }, [ctData, managerApproved, effectiveKey]);

  const go = (k) => { if (k === 'logout') { window.YEYE_AUTH.signOut(); return; } setPage(k); window.scrollTo && window.scrollTo(0, 0); const c = document.querySelector('.content'); if (c) c.scrollTop = 0; };
  const openModal = (kind, data) => { setModalData(data || null); setModal(kind); };

  useEffect(() => {
    const store = readPurchaseStore();
    if (blankProfile && store[userPurchaseKey]) {
      delete store[userPurchaseKey];
      localStorage.setItem(PURCHASE_KEY, JSON.stringify(store));
    }
    setPurchasedServices(store[userPurchaseKey] || []);
  }, [userPurchaseKey, blankProfile]);

  // Sync purchased services from GHL contact tags (e.g. blue_card_payment_received → blue_card).
  useEffect(() => {
    const contact = authState.contact;
    if (!contact) return;
    const rawTags = [
      ...((contact.tags || [])),
      ...((contact.raw && contact.raw.tags) || []),
    ].map((t) => String(t || '').toLowerCase().trim()).filter(Boolean);
    if (!rawTags.length) return;
    const map = (window.YEYE && window.YEYE.tagToServiceKey) || {};
    const derived = [];
    const seen = new Set();
    rawTags.forEach((tag) => {
      const key = map[tag];
      if (key && !seen.has(key)) {
        seen.add(key);
        derived.push({ id: 'PS-tag-' + key, k: key, status: 'active', source: 'ghl_tag', purchasedAt: new Date().toISOString() });
      }
    });
    if (!derived.length) return;
    setPurchasedServices((prev) => {
      const byKey = new Map();
      prev.forEach((p) => byKey.set(p.k, p));
      derived.forEach((d) => { if (!byKey.has(d.k)) byKey.set(d.k, d); });
      return Array.from(byKey.values());
    });
  }, [authState.contact]);

  useEffect(() => {
    if (!blankProfile) return;
    setTickets([]);
    setCalendarEvents([]);
  }, [blankProfile]);

  useEffect(() => {
    if (!authed || checking) return;
    const contact = authState.contact;
    if (!contact || !(contact.contactId || contact.id)) return;
    syncGhlTasks();
  }, [authed, checking, blankProfile, authState.contact?.contactId, authState.contact?.id, authState.user?.email]);

  useEffect(() => {
    const connected = !!(authState.calendarToken && authState.calendarExpiresAt > Date.now());
    setCalendarSync((prev) => ({ ...prev, connected }));
  }, [authState.calendarToken, authState.calendarExpiresAt]);

  useEffect(() => {
    if (!window.YEYE_FIELD_MAPPING || !window.YEYE_FIELD_MAPPING.load) return undefined;
    let cancelled = false;
    window.YEYE_FIELD_MAPPING.load()
      .then((rows) => { if (!cancelled) setFieldMappings(rows || []); })
      .catch((err) => console.warn('Failed to load Blue/Employee field mapping.', err));
    return () => { cancelled = true; };
  }, []);

  const persistPurchases = (next) => {
    const store = readPurchaseStore();
    store[userPurchaseKey] = next;
    localStorage.setItem(PURCHASE_KEY, JSON.stringify(store));
    setPurchasedServices(next);
  };
  const addPurchasedService = (service) => {
    const exists = purchasedServices.some((x) => x.k === service.k);
    const next = exists ? purchasedServices : [{ id: 'PS-' + Date.now(), k: service.k, status: 'active', purchasedAt: new Date().toISOString() }, ...purchasedServices];
    persistPurchases(next);
    setModal(null);
    showToast(t('toast.servicePurchased'));
    setPage('dashboard');
  };
  const updatePurchasedStatus = (serviceKey, status) => {
    const existing = purchasedServices.find((x) => x.k === serviceKey) || { id: 'PS-' + Date.now(), k: serviceKey, purchasedAt: new Date().toISOString() };
    const rest = purchasedServices.filter((x) => x.k !== serviceKey);
    persistPurchases([{ ...existing, status }, ...rest]);
    setModalData((d) => d ? { ...d, purchase: { ...existing, status } } : d);
    showToast(t('toast.statusUpdated'));
  };
  const addTicket = (ticket) => {
    const nextId = 'SUP-' + String(3200 + tickets.length + 1);
    const localTicket = {
      id: nextId,
      tk: 'custom',
      subject: ticket.subject,
      catK: ticket.catK,
      st: 'open',
      stc: 'info',
      upd: 'now',
      details: ticket.details,
      priority: ticket.priority,
    };
    setTickets((prev) => [localTicket, ...prev]);
    setModal(null);
    showToast(t('toast.ticketCreated'));
    bridgeExpatTicketToFirestore(localTicket, ticket, authState.user || authState.contact);
  };
  const upsertCalendarEvents = (incoming) => {
    setCalendarEvents((prev) => {
      const byId = new Map();
      incoming.concat(prev).forEach((ev) => {
        const id = ev.id || [ev.key, ev.title, ev.date, ev.time].filter(Boolean).join(':') || String(Math.random());
        if (!byId.has(id)) byId.set(id, ev);
      });
      return Array.from(byId.values());
    });
  };
  const fetchGoogleCalendarEvents = async (token) => {
    const accessToken = token || (window.YEYE_AUTH.getCalendarToken && window.YEYE_AUTH.getCalendarToken());
    if (!accessToken) throw new Error(t('cal.needConnect'));
    const now = new Date();
    const later = new Date(now.getTime() + 90 * 24 * 60 * 60 * 1000);
    const url = 'https://www.googleapis.com/calendar/v3/calendars/primary/events'
      + '?singleEvents=true&orderBy=startTime&maxResults=20'
      + '&timeMin=' + encodeURIComponent(now.toISOString())
      + '&timeMax=' + encodeURIComponent(later.toISOString());
    const res = await fetch(url, { headers: { Authorization: 'Bearer ' + accessToken } });
    if (!res.ok) throw new Error('Google Calendar ' + res.status);
    const data = await res.json();
    const rows = (data.items || []).filter((item) => item.status !== 'cancelled').map((item) => {
      const startRaw = (item.start && (item.start.dateTime || item.start.date)) || '';
      const start = new Date(item.start && item.start.dateTime ? item.start.dateTime : startRaw + 'T09:00:00');
      const safe = Number.isNaN(start.getTime()) ? new Date() : start;
      return {
        id: 'google:' + item.id,
        key: 'google',
        title: item.summary || t('cal.googleEvent'),
        loc: item.location || 'Google Calendar',
        d: safe.getDate(),
        date: safe.toISOString().slice(0, 10),
        dateLabel: safe.toLocaleDateString(undefined, { day: 'numeric', month: 'short' }),
        time: item.start && item.start.date ? t('cal.allDay') : safe.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
        tag: 'confirmed',
        tone: 'ok',
        tagc: 'ok',
        ic: 'calendar-check',
      };
    });
    upsertCalendarEvents(rows);
    return rows;
  };
  const connectGoogleCalendar = async () => {
    setCalendarSync({ connected: calendarSync.connected, syncing: true, error: '' });
    try {
      const token = await window.YEYE_AUTH.connectGoogleCalendar();
      await fetchGoogleCalendarEvents(token);
      setCalendarSync({ connected: true, syncing: false, error: '' });
      showToast(t('toast.calendarConnected'));
    } catch (err) {
      const msg = err && err.message ? err.message : String(err || '');
      setCalendarSync({ connected: false, syncing: false, error: msg });
      showToast(msg);
    }
  };
  const syncGoogleCalendar = async () => {
    setCalendarSync((prev) => ({ ...prev, syncing: true, error: '' }));
    try {
      await fetchGoogleCalendarEvents();
      setCalendarSync({ connected: true, syncing: false, error: '' });
      showToast(t('toast.calendarSynced'));
    } catch (err) {
      const msg = err && err.message ? err.message : String(err || '');
      setCalendarSync((prev) => ({ ...prev, syncing: false, error: msg }));
      showToast(msg);
    }
  };
  const addCalendarEvent = async (event) => {
    setCalendarEvents((prev) => [event, ...prev]);
    const token = window.YEYE_AUTH.getCalendarToken && window.YEYE_AUTH.getCalendarToken();
    if (token && event.date) {
      try {
        const start = new Date(event.date + 'T' + (event.time || '09:00') + ':00');
        const end = new Date(start.getTime() + 60 * 60 * 1000);
        const body = {
          summary: event.title,
          location: event.loc,
          start: { dateTime: start.toISOString(), timeZone: browserTimeZone() },
          end: { dateTime: end.toISOString(), timeZone: browserTimeZone() },
        };
        await fetch('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
          method: 'POST',
          headers: { Authorization: 'Bearer ' + token, 'Content-Type': 'application/json' },
          body: JSON.stringify(body),
        });
      } catch (err) {
        console.warn('Google Calendar event create failed', err);
        showToast(t('toast.eventLocalOnly'));
      }
    }
    setModal(null);
    showToast(t('toast.eventCreated'));
  };
  const addTask = (task) => {
    setTasks((prev) => [normalizePortalTask(task), ...prev]);
    setModal(null);
    showToast(t('toast.taskCreated'));
  };
  const syncGhlTasks = async () => {
    const contact = window.YEYE_AUTH.getState().contact || authState.contact;
    const email = (authState.user && authState.user.email) || (contact && contact.email) || '';
    const contactId = contact && (contact.contactId || contact.id);
    if (!contactId || !email) {
      setTasks([]);
      return [];
    }
    setTaskSync((prev) => ({ ...prev, syncing: true, error: '' }));
    try {
      const url = GHL_TASK_SYNC_BASE + '/contacts/' + encodeURIComponent(contactId) + '/tasks?email=' + encodeURIComponent(email);
      const res = await fetch(url);
      if (!res.ok) throw new Error('GHL task sync failed (' + res.status + ')');
      const data = await res.json();
      const rows = (data.items || []).map(normalizePortalTask);
      setTasks(rows);
      setTaskSync({ syncing: false, error: '', lastSync: new Date().toISOString() });
      return rows;
    } catch (err) {
      const msg = err && err.message ? err.message : String(err || '');
      setTaskSync({ syncing: false, error: msg, lastSync: new Date().toISOString() });
      return [];
    }
  };
  const toggleGhlTask = async (task) => {
    const nextDone = !task.done;
    setTasks((prev) => prev.map((row) => row.id === task.id ? { ...row, done: nextDone, tone: nextDone ? 'ok' : row.tone } : row));
    if (!task.ghlTaskId || !task.contactId) return;
    try {
      const email = (authState.user && authState.user.email) || '';
      const url = GHL_TASK_SYNC_BASE + '/contacts/' + encodeURIComponent(task.contactId) + '/tasks/' + encodeURIComponent(task.ghlTaskId) + '/completed';
      const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ completed: nextDone, email }),
      });
      if (!res.ok) throw new Error('GHL task update failed (' + res.status + ')');
    } catch (err) {
      setTasks((prev) => prev.map((row) => row.id === task.id ? { ...row, done: task.done } : row));
      showToast(err && err.message ? err.message : String(err || 'GHL task update failed'));
    }
  };
  const openServiceTicket = (service) => {
    openModal('ticket', { catK: 'it', subject: t('ticket.serviceSubject') + ': ' + t('svc.' + service.k) });
  };
  const refreshContact = async () => {
    if (!window.YEYE_AUTH.refreshContactFromGhl) return null;
    setContactSync((prev) => ({ ...prev, syncing: true, error: '' }));
    try {
      const contact = await window.YEYE_AUTH.refreshContactFromGhl();
      setContactSync({ syncing: false, lastSync: new Date().toISOString(), error: '' });
      return contact;
    } catch (err) {
      setContactSync({ syncing: false, lastSync: new Date().toISOString(), error: err && err.message ? err.message : String(err || '') });
      return null;
    }
  };

  useEffect(() => {
    if (!authed || checking || !authState.user?.email) return;
    const contact = authState.contact;
    const customFields = contact?.customFields;
    const hasLiveFields = Array.isArray(customFields) && customFields.length > 0;
    const isDemoContact = String(contact?.id || '').startsWith('testblue-demo');
    if (!contact || !hasLiveFields || isDemoContact) {
      refreshContact();
    }
  }, [authed, checking, authState.user?.email, authState.contact?.id]);

  // when client type changes, jump to dashboard; employer-sponsored branding only valid for sponsored types
  useEffect(() => { setPage('dashboard'); if (!liveCtData.org && branding === 'corporate') setBranding('individual'); }, [clientType]);

  // when contact loads, sync clientType to derived
  useEffect(() => {
    if (authState.contact) {
      const k = deriveCaseType(authState.contact.tags);
      if (k !== clientType) setClientType(k);
    }
  }, [authState.contact]);

  useEffect(() => {
    const fb = window.YEYE_EXPAT_FB;
    if (!fb || !fb.db || !authState.user || !authState.user.email) return undefined;
    let unsub = null;
    let cancelled = false;
    fb.ready.then(() => {
      if (cancelled) return;
      unsub = fb.db.collection('expatTickets')
        .where('ownerEmail', '==', authState.user.email)
        .onSnapshot((snap) => {
          const remote = snap.docs.map(normalizeTicketDoc).filter(Boolean);
          setTickets((prev) => {
            const byId = new Map();
            remote.concat(prev).forEach((tk) => { if (tk && tk.id && !byId.has(tk.id)) byId.set(tk.id, tk); });
            return Array.from(byId.values());
          });
        }, (err) => console.warn('Failed to load Expat tickets from Firestore.', err));
    }).catch(() => {});
    return () => { cancelled = true; if (unsub) unsub(); };
  }, [authState.user && authState.user.email]);

  const renderPage = () => {
    if (page === 'dashboard') return <ExpatDashboard ct={liveCtData} go={go} openModal={openModal} calendarEvents={calendarEvents} tasks={tasks} purchasedServices={purchasedServices} blankProfile={blankProfile} calendarSync={calendarSync} onConnectGoogleCalendar={connectGoogleCalendar} onSyncGoogleCalendar={syncGoogleCalendar} onToggleTask={toggleGhlTask} />;
    switch (page) {
      case 'services': return <ServicesPage openModal={openModal} purchasedServices={purchasedServices} blankProfile={blankProfile} />;
      case 'formSubmission': return <FormSubmissionPage ct={liveCtData} contact={authState.contact} fieldMappings={fieldMappings} onRefresh={refreshContact} syncState={contactSync} />;
      case 'purchasedServices': return <PurchasedServicesPage openModal={openModal} purchasedServices={purchasedServices} go={go} blankProfile={blankProfile} />;
      case 'documents': return <DocumentsPage openModal={openModal} blankProfile={blankProfile} contact={authState.contact} onRefresh={refreshContact} />;
      case 'invoices': return <InvoicesPage openModal={openModal} blankProfile={blankProfile} />;
      case 'support': return <SupportPage openModal={openModal} tickets={tickets} />;
      case 'cases': return <CasesPage ct={liveCtData} contact={authState.contact} fieldMappings={fieldMappings} />;
      case 'appointments': return <AppointmentsPage events={calendarEvents} openModal={openModal} />;
      case 'tasks': return <TasksPage tasks={tasks} openModal={openModal} onSync={syncGhlTasks} syncState={taskSync} onToggleTask={toggleGhlTask} contact={authState.contact} />;
      case 'reports': return <ReportsPage />;
      case 'profile': return <SimplePage icon="user" title={t('nav.profile')} sub={t('pg.profileSub')} />;
      case 'settings': return <SettingsPage />;
      default: return <SimplePage icon="circle-dashed" title={t('pg.soon')} sub={t('pg.soonSub')} />;
    }
  };

  if (!authed) {
    return (
      <LangCtx.Provider value={{ lang, t, dict }}>
        <LoginScreen error={authState.error} checking={checking} />
      </LangCtx.Provider>
    );
  }

  if (authState.mustChangePassword) {
    return (
      <LangCtx.Provider value={{ lang, t, dict }}>
        <ForceChangePasswordScreen email={authState.user && authState.user.email} />
      </LangCtx.Provider>
    );
  }

  return (
    <LangCtx.Provider value={{ lang, t, dict }}>
    <div className="app">
      <div className={'scrim ' + (drawer ? 'show' : '')} onClick={() => setDrawer(false)} />
      <Sidebar nav={window.YEYE.nav.map((it) => {
        if (it.key !== 'tasks') return it;
        const openCount = tasks.filter((t) => !t.done).length;
        return openCount > 0 ? { ...it, badge: openCount } : it;
      })} active={page} onNav={go} mini={mini} open={drawer} onClose={() => setDrawer(false)} ct={liveCtData} />
      <div className="main">
        <Topbar
          title={page === 'dashboard' ? t('nav.dashboard') : t('nav.' + page)} sub={page === 'dashboard' ? t('ct.' + clientType) : null}
          ct={liveCtData} branding={branding} onBranding={setBranding}
          ctKey={clientType} onCt={setClientType} lang={lang} onLang={setLangP}
          onToggleSidebar={() => setMini((m) => !m)} onHamburger={() => setDrawer(true)}
          onNotif={() => setNotif(true)} onSearch={() => {}} />
        <div className="content">
          <div className="page">{renderPage()}</div>
          <MobileClientType ctKey={clientType} onCt={setClientType} />
        </div>
      </div>

      {modal === 'service' && <ServiceModal service={modalData} contact={authState.contact} liveContact={liveCtData} onClose={() => setModal(null)} onConfirm={addPurchasedService} />}
      {modal === 'upload' && <UploadModal onClose={() => setModal(null)} />}
      {modal === 'taskAttachment' && <TaskAttachmentModal task={modalData && modalData.task} contact={modalData && modalData.contact} onClose={() => setModal(null)} />}
      {modal === 'ticket' && <TicketModal preset={modalData} onClose={() => setModal(null)} onSubmit={addTicket} />}
      {modal === 'calendarEvent' && <CalendarEventModal onClose={() => setModal(null)} onSubmit={addCalendarEvent} />}
      {modal === 'task' && <TaskModal onClose={() => setModal(null)} onSubmit={addTask} />}
      {modal === 'manageService' && <ServiceManageModal item={modalData} onClose={() => setModal(null)} onStatus={updatePurchasedStatus} openTicket={openServiceTicket} showToast={showToast} />}
      {notif && <NotifPanel onClose={() => setNotif(false)} go={go} />}
      <Toast text={toast} />
    </div>
    </LangCtx.Provider>
  );
}

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