/* =====================================================================
   Mereka v2 — Talent Intelligence module (Neol-inspired)
   Powers: Application Review (Agent E AI evaluation), Trainer sourcing
   (NL search + AI match + invite + CSV import), Learning Path Journey (living
   profiles), "Add to SEEK Pass" credential, AI Brief generation.
   Comms handled by Respond.io (WhatsApp) modals.
   Feature-flag switcher (bottom-right) shows/hides each capability.
   ===================================================================== */

/* ---------- Feature flags store ---------- */
const FEATURE_KEYS = ['applications', 'trainers', 'seekpass', 'journey', 'aibrief'];
let _feat = (() => {
  try { const v = JSON.parse(localStorage.getItem('mereka_features') || '{}'); return v; } catch (e) { return {}; }
})();
const _featSubs = new Set();
function getFeature(k) { return _feat[k] === undefined ? true : !!_feat[k]; }
function setFeature(k, v) { _feat = { ..._feat, [k]: !!v }; try { localStorage.setItem('mereka_features', JSON.stringify(_feat)); } catch (e) {} _featSubs.forEach(fn => fn(_feat)); }
function useFeature(k) {
  const [v, setV] = React.useState(getFeature(k));
  React.useEffect(() => { const fn = () => setV(getFeature(k)); _featSubs.add(fn); setV(getFeature(k)); return () => _featSubs.delete(fn); }, [k]);
  return v;
}

/* ---------- Dev dock visibility (right-edge Features + Pages) ---------- */
let _dockOpen = (() => {
  try { const v = localStorage.getItem('mereka_dock'); if (v !== null) return v === '1'; } catch (e) {}
  return (typeof window !== 'undefined' && window.innerWidth >= 768); // hidden by default on mobile
})();
const _dockSubs = new Set();
function setDockOpen(v) { _dockOpen = !!v; try { localStorage.setItem('mereka_dock', _dockOpen ? '1' : '0'); } catch (e) {} _dockSubs.forEach(fn => fn(_dockOpen)); }
function useDockOpen() {
  const [v, setV] = React.useState(_dockOpen);
  React.useEffect(() => { const fn = (x) => setV(x); _dockSubs.add(fn); setV(_dockOpen); return () => _dockSubs.delete(fn); }, []);
  return v;
}
function DevDockToggle() {
  const open = useDockOpen();
  return ReactDOM.createPortal(
    <button onClick={() => setDockOpen(!open)} aria-label={open ? 'Hide tools' : 'Show tools'} title={open ? 'Hide tools' : 'Show tools'}
      className="fixed right-0 bottom-4 z-[60] w-6 h-14 rounded-l-lg bg-ink text-white flex items-center justify-center shadow-lg hover:bg-black transition-colors">
      <Icon name={open ? 'chevronRight' : 'chevronLeft'} size={15} />
    </button>, document.body);
}

/* ---------- Data ---------- */
const AGENT_E = { name: 'Agent E', version: 'v0.2.1' };
const NEOL_ELIGIBILITY = ['B40 household income', 'Aged 18–35', 'Currently unemployed / underemployed', 'Resident in target state', 'Interest in digital / tech'];

const NEOL_APPLICANTS = [
  { id: 'a1', name: 'Nurul Aisyah binti Rahman', age: 24, loc: 'Klang Valley', gender: 'F', b40: true, employed: false, prior: false, programme: 'AI4U', stage: 'Pending', score: 82, matches: 4, submitted: '2 Sep 2026', phone: '+60 12-345 6789',
    strengths: ['B40 household verified (eKasih)', 'Currently unemployed — priority segment', 'Resident in Selangor (target state)', 'Stated interest in a tech career'], gaps: ['No record of a prior digital-skills learning path'],
    receipt: 'AE-9F2C-0417', evidence: ['eKasih income band: B40', 'EPF contribution: none in 6 months', 'Intake Q3: "I want to work in tech / data"'] },
  { id: 'a2', name: 'Muhammad Danial bin Zainal', age: 27, loc: 'Johor Bahru', gender: 'M', b40: true, employed: true, prior: true, programme: 'AI4U', stage: 'Under Review', score: 61, matches: 3, submitted: '2 Sep 2026', phone: '+60 13-222 8890',
    strengths: ['B40 household verified', 'Resident in Johor (target state)', 'Completed a prior digital-skills learning path'], gaps: ['Currently employed full-time — lower priority', 'Age 27 within range but upper band'],
    receipt: 'AE-7A11-0418', evidence: ['eKasih income band: B40', 'SOCSO active employment record', 'Prior: Digital Marketing Essentials (2025)'] },
  { id: 'a3', name: 'Kavitha a/p Suresh', age: 22, loc: 'George Town', gender: 'F', b40: true, employed: false, prior: false, programme: 'AI4U', stage: 'Shortlisted', score: 88, matches: 5, submitted: '1 Sep 2026', phone: '+60 16-778 1234',
    strengths: ['B40 household verified', 'Unemployed — priority segment', 'Resident in Penang (target state)', 'Strong stated interest + portfolio link', 'Aged 22 — core target band'], gaps: [],
    receipt: 'AE-3D40-0402', evidence: ['eKasih income band: B40', 'No EPF/SOCSO activity', 'Intake Q3 + attached self-taught portfolio'] },
  { id: 'a4', name: 'Lim Wei Sheng', age: 31, loc: 'Kuala Lumpur', gender: 'M', b40: false, employed: true, prior: false, programme: 'AI4U', stage: 'Pending', score: 34, matches: 1, submitted: '2 Sep 2026', phone: '+60 12-999 4432',
    strengths: ['Resident in target state'], gaps: ['Not B40 (M40 household)', 'Currently employed', 'Aged 31 — outside 18–30 preference', 'No demonstrated need'],
    receipt: 'AE-88B2-0421', evidence: ['eKasih: not listed (M40 est.)', 'SOCSO active employment', 'Intake Q3: general interest'] },
  { id: 'a5', name: 'Siti Zubaidah binti Omar', age: 19, loc: 'Kota Bharu', gender: 'F', b40: true, employed: false, prior: false, programme: 'AI4U', stage: 'Pending', score: 79, matches: 4, submitted: '2 Sep 2026', phone: '+60 19-334 5567',
    strengths: ['B40 household verified', 'Unemployed — priority', 'Aged 19 — core target band', 'Interest in tech'], gaps: ['Resident in Kelantan — outside current cohort target states'],
    receipt: 'AE-5C21-0430', evidence: ['eKasih income band: B40', 'No employment record', 'Intake Q3'] },
  { id: 'a6', name: 'Arjun Nair', age: 25, loc: 'Shah Alam', gender: 'M', b40: true, employed: false, prior: true, programme: 'AI4U', stage: 'Accepted', score: 90, matches: 5, submitted: '30 Aug 2026', phone: '+60 11-2233 4455',
    strengths: ['B40 verified', 'Unemployed', 'Target state (Selangor)', 'Interest confirmed', 'Prior learning path shows commitment'], gaps: [],
    receipt: 'AE-1188-0388', evidence: ['eKasih band B40', 'No EPF activity', 'Prior: Freelancing 101'] },
  { id: 'a7', name: 'Farah Nabila binti Yusof', age: 23, loc: 'Ipoh', gender: 'F', b40: true, employed: false, prior: false, programme: 'AI4U', stage: 'Rejected', score: 41, matches: 2, submitted: '29 Aug 2026', phone: '+60 17-556 7788',
    strengths: ['B40 verified', 'Interest in tech'], gaps: ['Incomplete intake form (2 required fields blank)', 'Could not verify residency'],
    receipt: 'AE-2F90-0361', evidence: ['eKasih band B40', 'Address field blank', 'Intake incomplete'] },
  { id: 'a8', name: 'Tan Mei Ling', age: 26, loc: 'Seremban', gender: 'F', b40: true, employed: false, prior: false, programme: 'AI4U', stage: 'Pending', score: 74, matches: 4, submitted: '2 Sep 2026', phone: '+60 12-661 0099',
    strengths: ['B40 verified', 'Unemployed', 'Interest in data', 'Aged 26 — in band'], gaps: ['Negeri Sembilan — adjacent to target, needs confirmation'],
    receipt: 'AE-6E70-0444', evidence: ['eKasih band B40', 'No EPF activity', 'Intake Q3: "interested in data analytics"'] },
];

const NEOL_TRAINERS = [
  { id: 't1', name: 'Dr. Farah Lim', tags: ['AI Literacy L1-3', 'Data Analytics', 'Prompt Engineering'], hrdcorp: true, langs: ['EN', 'BM', 'Mandarin'], loc: 'Kuala Lumpur', delivered: 42, satisfaction: 4.8, available: 'Oct 2026', rate: 'RM 2,500 / day', match: 94, sectors: ['Manufacturing', 'Public sector'],
    summary: 'Strong fit. HRD Corp accredited, delivers AI Literacy L2 in Bahasa Malaysia, and is available in October in the Klang Valley. 42 learning paths delivered at a 4.8 average satisfaction — top-decile in the network.' },
  { id: 't2', name: 'Amir Hakim', tags: ['AI Literacy L1-2', 'Design Thinking Facilitation'], hrdcorp: true, langs: ['EN', 'BM'], loc: 'Johor Bahru', delivered: 28, satisfaction: 4.6, available: 'Oct 2026', rate: 'RM 1,800 / day', match: 88, sectors: ['SME', 'Youth'],
    summary: 'Good fit for southern-region cohorts. HRD Corp accredited, native BM delivery, available October. Slightly lighter on advanced (L3) content than the brief ideally wants.' },
  { id: 't3', name: 'Priya Chandran', tags: ['Data Analytics', 'Power BI', 'AI Literacy L1-3'], hrdcorp: true, langs: ['EN', 'BM', 'Tamil'], loc: 'Penang', delivered: 35, satisfaction: 4.7, available: 'Nov 2026', rate: 'RM 2,200 / day', match: 79, sectors: ['Electronics', 'Manufacturing'],
    summary: 'Excellent content match and manufacturing-sector experience (a nice-to-have), but earliest availability is November — one month after the requested window.' },
  { id: 't4', name: 'Zulkifli Rahman', tags: ['AI Literacy L1-2', 'Cybersecurity Basics'], hrdcorp: false, langs: ['EN', 'BM'], loc: 'Kuching', delivered: 19, satisfaction: 4.4, available: 'Oct 2026', rate: 'RM 1,500 / day', match: 66, sectors: ['Public sector'],
    summary: 'Available and BM-capable, but not HRD Corp accredited — a stated must-have — so excluded from claimable cohorts unless accreditation is fast-tracked.' },
  { id: 't5', name: 'Grace Wong', tags: ['AI Literacy L1-3', 'Machine Learning', 'Python'], hrdcorp: true, langs: ['EN', 'Mandarin'], loc: 'Kuala Lumpur', delivered: 51, satisfaction: 4.9, available: 'Dec 2026', rate: 'RM 3,000 / day', match: 72, sectors: ['Fintech', 'Startups'],
    summary: 'Highest-rated trainer in the network, but delivers primarily in English/Mandarin (limited BM) and is booked until December — misses the BM + October requirements.' },
  { id: 't6', name: 'Hafiz Iskandar', tags: ['AI Literacy L1-2', 'Digital Marketing'], hrdcorp: true, langs: ['EN', 'BM'], loc: 'Shah Alam', delivered: 24, satisfaction: 4.5, available: 'Oct 2026', rate: 'RM 1,700 / day', match: 84, sectors: ['SME', 'Retail'],
    summary: 'Solid, affordable, HRD Corp accredited, BM delivery, available October in Selangor. A strong value option for a large cohort even if not the deepest on advanced AI content.' },
];

const NEOL_JOURNEY = [
  { date: 'Jan 2025', title: 'Enrolled — Freelancing 101', kind: 'programme', detail: 'Biji-biji Initiative · 5 modules', done: true },
  { date: 'Mar 2025', title: 'Completed Freelancing 101', kind: 'certificate', detail: 'Certificate issued · MRK-FRL-2025-1180', done: true },
  { date: 'Jun 2025', title: 'Enrolled — AI Fluency for Beginners', kind: 'course', detail: '6 modules · 100% attendance', done: true },
  { date: 'Aug 2025', title: 'Assessment passed — AI Fluency', kind: 'assessment', detail: 'Score 88% · Trainer: Dr. Farah Lim', done: true },
  { date: 'Sep 2025', title: 'Certificate — AI Fluency', kind: 'certificate', detail: 'Added to SEEK Pass ✓', done: true },
  { date: 'Jan 2026', title: 'Employment milestone', kind: 'employment', detail: 'Hired: Junior Data Analyst, KL (self-reported + SOCSO match)', done: true },
  { date: 'Now', title: 'Enrolled — AI4U Learning Path', kind: 'programme', detail: 'In progress · Module 3 of 8', done: false },
];

/* ---------- Small helpers ---------- */
function AgentEBadge({ size = 'sm' }) {
  return (
    <span className={`inline-flex items-center gap-1.5 rounded-full bg-[#EEF2FF] text-[#4338CA] font-bold ${size === 'sm' ? 'h-6 px-2.5 text-[11px]' : 'h-7 px-3 text-[12px]'}`}>
      <span className="w-4 h-4 rounded-full bg-[#4338CA] text-white flex items-center justify-center text-[9px]">AE</span> Agent E
    </span>
  );
}
function ScoreRing({ value = 0, size = 44 }) {
  const r = (size - 6) / 2, c = 2 * Math.PI * r, off = c - (value / 100) * c;
  const col = value >= 75 ? '#1FA85B' : value >= 50 ? '#E8901A' : '#E4572E';
  return (
    <span className="relative inline-flex items-center justify-center flex-shrink-0" style={{ width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="#EEF0F2" strokeWidth="4" />
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={col} strokeWidth="4" strokeDasharray={c} strokeDashoffset={off} strokeLinecap="round" />
      </svg>
      <span className="absolute text-[12px] font-bold num-tabular" style={{ color: col }}>{value}</span>
    </span>
  );
}
const NEOL_STAGES = ['Pending', 'Under Review', 'Shortlisted', 'Accepted', 'Rejected'];
function StagePill({ stage }) {
  const map = { Pending: 'bg-neutral-100 text-neutral-600', 'Under Review': 'bg-[#EAF0F8] text-support', Shortlisted: 'bg-[#FFF4D6] text-[#B8860B]', Accepted: 'bg-green-50 text-green-600', Rejected: 'bg-red-50 text-red-500' };
  return <span className={`px-2.5 h-6 inline-flex items-center rounded-full text-[12px] font-semibold ${map[stage] || map.Pending}`}>{stage}</span>;
}

/* ---------- Respond.io comms modal ---------- */
function RespondModal({ open, onClose, kind, count, name, svc, ctx }) {
  const [sent, setSent] = React.useState(false);
  React.useEffect(() => { setSent(false); }, [open]);
  if (!open) return null;
  const isGig = svc === 'gig';
  const ctxName = ctx || (isGig ? 'this gig' : 'the AI4U programme');
  const templates = {
    Accepted: isGig
      ? `Hi ${name || '{name}'} 🎉 Good news — we'd like to move forward with your proposal for ${ctxName}. Reply YES and we'll set up milestones and escrow to get started.`
      : `Hi ${name || '{name}'} 🎉 Great news — you've been accepted into ${ctxName}! Your first session details are on the way. Reply YES to confirm your seat.`,
    Rejected: isGig
      ? `Hi ${name || '{name}'}, thank you for your proposal for ${ctxName}. We've gone with another freelancer this time, but we'd love to consider you for future gigs. We'll keep you posted.`
      : `Hi ${name || '{name}'}, thank you for applying to ${ctxName}. You weren't selected for this intake, but we'd love to see you apply for the next cohort. We'll keep you posted.`,
    Invite: `Hi ${name || '{name}'}, Mereka would like to invite you to deliver the AI4U programme (AI Literacy L2, Bahasa Malaysia, Klang Valley, October). Are you available? Reply to view the brief.`,
  };
  return (
    <div className="fixed inset-0 z-[130] flex items-center justify-center px-4 bg-black/50 backdrop-blur-sm" onClick={onClose}>
      <div className="w-full max-w-md bg-white rounded-2xl shadow-2xl p-6" onClick={e => e.stopPropagation()}>
        {!sent ? (<>
          <div className="flex items-start justify-between">
            <div className="flex items-center gap-2"><span className="w-9 h-9 rounded-xl bg-[#25D366] text-white flex items-center justify-center"><Icon name="chat" size={18} /></span><div><h3 className="text-lg font-bold text-ink" style={{ fontFamily: _pp }}>Send via Respond.io</h3><p className="text-[12px] text-neutral-500">WhatsApp · {count ? `${count} recipient${count > 1 ? 's' : ''}` : name}</p></div></div>
            <button onClick={onClose} className="text-neutral-400 hover:text-neutral-700"><Icon name="close" size={20} /></button>
          </div>
          <p className="mt-4 text-[12px] font-bold uppercase tracking-wide text-neutral-400">Message template ({kind})</p>
          <div className="mt-2 rounded-xl bg-[#E6F4EA] p-3 text-[14px] text-neutral-700 leading-relaxed">{templates[kind] || templates.Accepted}</div>
          <p className="mt-3 text-[12px] text-neutral-400">Sent through the approved WhatsApp Business template. Recipients must have opted in.</p>
          <div className="mt-5 flex justify-end gap-2">
            <button onClick={onClose} className="h-10 px-4 rounded-full border border-neutral-200 text-sm font-semibold hover:bg-neutral-50">Cancel</button>
            <button onClick={() => setSent(true)} className="h-10 px-5 rounded-full bg-[#25D366] text-white text-sm font-semibold inline-flex items-center gap-2 hover:brightness-95"><Icon name="send" size={15} /> Send WhatsApp</button>
          </div>
        </>) : (
          <div className="text-center py-4">
            <div className="w-16 h-16 rounded-2xl bg-[#E6F4EA] text-[#25D366] mx-auto flex items-center justify-center mb-4"><Icon name="check" size={34} /></div>
            <h3 className="text-xl font-bold text-ink" style={{ fontFamily: _pp }}>Sent via Respond.io</h3>
            <p className="mt-2 text-sm text-neutral-600">{count ? `${count} WhatsApp message${count > 1 ? 's' : ''} queued.` : `Message to ${name} queued.`} You can track delivery in Respond.io.</p>
            <button onClick={onClose} className="mt-5 h-10 px-5 rounded-full bg-ink text-white text-sm font-semibold hover:bg-black">Done</button>
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------- Agent E evaluation card ---------- */
function AgentEval({ a, expanded }) {
  const [open, setOpen] = React.useState(!!expanded);
  const crit = a._criteria || NEOL_ELIGIBILITY;
  return (
    <div className="rounded-2xl border border-[#DDE3F0] bg-[#F8FAFF] p-5">
      <div className="flex items-start justify-between gap-3">
        <div className="flex items-center gap-3"><ScoreRing value={a.score} /><div><div className="flex items-center gap-2"><span className="font-bold text-ink">Fit evaluation</span></div><p className="text-[13px] text-neutral-500">Matches <span className="font-bold text-ink">{a.matches} of {crit.length}</span> criteria</p></div></div>
        <span className="text-[11px] font-mono text-neutral-400">receipt {a.receipt}</span>
      </div>
      <div className="mt-4 grid sm:grid-cols-2 gap-4">
        <div><p className="text-[12px] font-bold uppercase tracking-wide text-green-600 mb-1.5">Strengths</p><ul className="space-y-1">{a.strengths.map(s => <li key={s} className="flex items-start gap-1.5 text-[13px] text-neutral-700"><Icon name="check" size={14} className="text-green-600 mt-0.5 flex-shrink-0" /> {s}</li>)}</ul></div>
        <div><p className="text-[12px] font-bold uppercase tracking-wide text-[#B8860B] mb-1.5">Gaps</p>{a.gaps.length ? <ul className="space-y-1">{a.gaps.map(s => <li key={s} className="flex items-start gap-1.5 text-[13px] text-neutral-700"><Icon name="warning" size={14} className="text-[#E8901A] mt-0.5 flex-shrink-0" /> {s}</li>)}</ul> : <p className="text-[13px] text-neutral-400">None — meets all criteria.</p>}</div>
      </div>
      <button onClick={() => setOpen(o => !o)} className="mt-4 text-[13px] font-semibold text-[#4338CA] inline-flex items-center gap-1">{open ? 'Hide' : 'Show'} evidence <Icon name={open ? 'chevronUp' : 'chevronDown'} size={13} /></button>
      {open && <ul className="mt-2 space-y-1 border-t border-[#DDE3F0] pt-3">{a.evidence.map(e => <li key={e} className="flex items-start gap-1.5 text-[13px] text-neutral-600"><Icon name="document" size={13} className="text-neutral-400 mt-0.5 flex-shrink-0" /> {e}</li>)}</ul>}
    </div>
  );
}

/* ---------- Multi-service applications registry (Agent E across services) ---------- */
const NEOL_PATH_LISTINGS = [
  { id: 'pl-ai4u', svc: 'path', title: 'AI4U Learning Path', org: 'Biji-biji Initiative', img: '/home/dash/prog-1.jpg', to: '/web/learning-paths/ai4u', criteria: NEOL_ELIGIBILITY },
  { id: 'pl-aifm', svc: 'path', title: 'AI Fluency by Microsoft', org: 'Mereka Academy', img: '/home/dash/course-3.jpg', to: '/web/courses/ai-fluency', criteria: ['Working professional or student', 'Basic digital literacy', 'Can commit to the 6-week schedule', 'English proficiency (B2+)', 'Access to a laptop'] },
];
const NEOL_AIFM_APPLICANTS = [
  { id: 'fm1', name: 'Wong Jia Hui', age: 29, loc: 'Kuala Lumpur', gender: 'F', b40: false, employed: true, prior: true, programme: 'AI Fluency by Microsoft', stage: 'Shortlisted', score: 86, matches: 5, submitted: '2 Sep 2026', phone: '+60 12-500 2201',
    strengths: ['Working professional (product marketer)', 'Strong baseline digital literacy', 'Confirmed availability for the full 6 weeks', 'English proficiency C1', 'Company-sponsored seat'], gaps: [],
    receipt: 'AE-AF01-0510', evidence: ['Employer confirmation letter attached', 'Self-assessment: advanced spreadsheet + SaaS tools', 'Intake: "want to lead AI adoption on my team"'] },
  { id: 'fm2', name: 'Ravindran Pillai', age: 34, loc: 'Petaling Jaya', gender: 'M', b40: false, employed: true, prior: false, programme: 'AI Fluency by Microsoft', stage: 'Under Review', score: 68, matches: 3, submitted: '2 Sep 2026', phone: '+60 13-702 8841',
    strengths: ['Working professional (operations lead)', 'Basic digital literacy confirmed', 'English proficiency B2'], gaps: ['Flagged a scheduling clash in weeks 3-4', 'No laptop confirmed — may need a loaner'],
    receipt: 'AE-AF02-0511', evidence: ['Intake form complete', 'Availability: partial (weeks 3-4 uncertain)', 'Device: pending confirmation'] },
  { id: 'fm3', name: 'Chong Mei Yee', age: 22, loc: 'Cyberjaya', gender: 'F', b40: false, employed: false, prior: false, programme: 'AI Fluency by Microsoft', stage: 'Pending', score: 74, matches: 4, submitted: '1 Sep 2026', phone: '+60 16-220 7789',
    strengths: ['Final-year student — eligible track', 'Good digital literacy', 'Full availability for the schedule', 'Own laptop confirmed'], gaps: ['English proficiency self-rated B1 — just under B2 bar'],
    receipt: 'AE-AF03-0512', evidence: ['Student ID verified', 'Availability: full', 'Language self-assessment: B1'] },
];

const NEOL_GIG_CRITERIA = ['Relevant portfolio / track record', 'Rate within the posted budget', 'Available in the requested window', 'Rating 4.5+ with reviews', 'Directly relevant domain experience'];
const NEOL_FREELANCERS = [
  { name: 'Aiman Zulkifli', role: 'Brand & Identity Designer', loc: 'Kuala Lumpur', rate: 'RM 7,500', avail: 'Within 1 week', rating: 4.9, reviews: 38, port: true, domain: true, budget: true },
  { name: 'Studio Kuala', role: 'Design Studio', loc: 'Kuala Lumpur', rate: 'RM 8,200', avail: 'Within 2 weeks', rating: 4.8, reviews: 64, port: true, domain: true, budget: true },
  { name: 'Nadia Rahman', role: 'Freelance Designer', loc: 'Penang', rate: 'RM 6,000', avail: 'Immediately', rating: 4.7, reviews: 21, port: true, domain: false, budget: true },
  { name: 'Rueben Anand', role: 'Product & UI Designer', loc: 'Petaling Jaya', rate: 'RM 11,000', avail: 'Within 3 weeks', rating: 4.6, reviews: 29, port: true, domain: true, budget: false },
  { name: 'Chloe Tan', role: 'Junior Designer', loc: 'Remote', rate: 'RM 4,500', avail: 'Immediately', rating: 4.3, reviews: 8, port: false, domain: false, budget: true },
  { name: 'Haziq Idris', role: 'Brand Strategist', loc: 'Johor Bahru', rate: 'RM 9,000', avail: 'Next month', rating: 4.8, reviews: 44, port: true, domain: true, budget: false },
];
function neolGigApps(gig) {
  if (!gig) return [];
  const seed = String(gig.id).split('').reduce((a, c) => a + c.charCodeAt(0), 0);
  const stages = ['Shortlisted', 'Under Review', 'Pending', 'Pending', 'Accepted'];
  const n = 3 + (seed % 2);
  const apps = [];
  for (let i = 0; i < n; i++) {
    const f = NEOL_FREELANCERS[(seed + i) % NEOL_FREELANCERS.length];
    const availOk = f.avail !== 'Next month';
    const flags = [f.port, f.budget, availOk, f.rating >= 4.5, f.domain];
    const matches = flags.filter(Boolean).length;
    let score = Math.round((matches / 5) * 100) - (f.rating < 4.5 ? 8 : 0) + (f.port ? 3 : 0);
    score = Math.max(28, Math.min(96, score));
    const strengths = [], gaps = [];
    f.port ? strengths.push('Portfolio shows directly relevant work') : gaps.push('Portfolio is thin for this scope');
    f.budget ? strengths.push('Proposed rate ' + f.rate + ' is within budget') : gaps.push('Proposed rate ' + f.rate + ' is above the posted budget');
    availOk ? strengths.push('Available ' + f.avail.toLowerCase()) : gaps.push('Earliest availability is next month');
    (f.rating >= 4.5) ? strengths.push('Strong rating ' + f.rating + ' across ' + f.reviews + ' reviews') : gaps.push('Rating ' + f.rating + ' is below the 4.5 bar');
    f.domain ? strengths.push('Direct domain experience for this brief') : gaps.push('Limited experience in this specific domain');
    apps.push({
      id: gig.id + '-p' + (i + 1), listingId: gig.id, svc: 'gig', name: f.name, role: f.role, loc: f.loc,
      rate: f.rate, avail: f.avail, rating: f.rating, reviews: f.reviews, stage: stages[(seed + i) % stages.length],
      score, matches, submitted: '2 Sep 2026', phone: '+60 1' + ((seed + i) % 8 + 1) + '-' + (200 + i * 3) + ' ' + (1000 + (seed * (i + 1)) % 8999),
      receipt: 'AE-' + String(gig.id).toUpperCase().replace(/[^A-Z0-9]/g, '').slice(0, 3) + i + '-0' + (500 + i),
      strengths, gaps,
      evidence: ['Portfolio link reviewed by Agent E', 'Proposed rate: ' + f.rate, 'Stated availability: ' + f.avail, 'Marketplace rating: ' + f.rating + ' (' + f.reviews + ' reviews)'],
    });
  }
  return apps.sort((a, b) => b.score - a.score);
}
function neolGigRows() { return (typeof GIG_ROWS_BY_HUB !== 'undefined') ? GIG_ROWS_BY_HUB.flat() : []; }
function neolGigListing(id) {
  const g = neolGigRows().find(x => x.id === id);
  if (!g) return null;
  return { id: g.id, svc: 'gig', title: g.name, org: g.by, criteria: NEOL_GIG_CRITERIA, gig: g };
}
function neolListing(id) { return NEOL_PATH_LISTINGS.find(l => l.id === id) || neolGigListing(id); }
function neolAllListings() {
  const gigs = neolGigRows().map(g => ({ id: g.id, svc: 'gig', title: g.name, org: g.by }));
  return [...NEOL_PATH_LISTINGS.map(l => ({ id: l.id, svc: 'path', title: l.title, org: l.org })), ...gigs];
}
function neolAppsForListing(id) {
  const l = neolListing(id); if (!l) return [];
  if (l.svc === 'path') {
    const src = id === 'pl-ai4u' ? NEOL_APPLICANTS : id === 'pl-aifm' ? NEOL_AIFM_APPLICANTS : [];
    return src.map(a => ({ ...a, listingId: id, svc: 'path' }));
  }
  return neolGigApps(l.gig);
}
function neolAllApps() {
  const paths = [...NEOL_APPLICANTS.map(a => ({ ...a, listingId: 'pl-ai4u', svc: 'path' })), ...NEOL_AIFM_APPLICANTS.map(a => ({ ...a, listingId: 'pl-aifm', svc: 'path' }))];
  const gigs = neolGigRows().flatMap(g => neolGigApps(g));
  return [...paths, ...gigs];
}
function neolResolveApp(id) {
  const app = neolAllApps().find(a => a.id === id);
  if (!app) return null;
  const listing = neolListing(app.listingId);
  return { app: { ...app, _criteria: listing ? listing.criteria : NEOL_ELIGIBILITY, _listing: listing }, listing };
}
function neolAppSub(a) {
  if (a.svc === 'gig') return a.role + ' · ' + a.rate + ' · ' + a.avail + ' · ★ ' + a.rating + ' (' + a.reviews + ')';
  return a.age + 'y · ' + a.loc + ' · ' + (a.b40 ? 'B40' : 'M40') + ' · ' + (a.employed ? 'employed' : 'unemployed');
}
function ListingPill({ l }) {
  if (!l) return null;
  return <span className="inline-flex items-center gap-1 px-2 h-5 rounded-full bg-neutral-100 text-neutral-600 text-[11px] font-semibold"><Icon name={l.svc === 'gig' ? 'briefcase' : 'programme'} size={11} className="text-neutral-400" /> {l.title}</span>;
}

/* ---------- Agent-E integration: verdicts, CSV export, results webhook (per MEREKA-V2-INTEGRATION spec) ---------- */
const NEOL_RESULTS_URL = 'https://agent-e.mereka.dev/projects/ai4u/runs/latest/results';
// Agent-E returns a verdict per applicant via signed webhook: final_score, eligibility_status,
// confidence_score, requires_manual_review. Derived here from the prototype's scored data.
function neolVerdict(a) {
  const crit = (a._listing && a._listing.criteria) || a._criteria || NEOL_ELIGIBILITY;
  const score = a.score;
  const eligible = score >= 60 && a.matches >= Math.ceil(crit.length * 0.6);
  const incomplete = (a.gaps || []).some(g => /incomplete|could not verify|pending|blank|confirm/i.test(g));
  const manual = incomplete || (!eligible && score >= 50) || (eligible && (a.gaps || []).length >= 2);
  let conf = 0.6 + (a.matches / crit.length) * 0.32 + ((a.gaps || []).length === 0 ? 0.06 : 0);
  if (incomplete) conf -= 0.24;
  conf = Math.max(0.42, Math.min(0.98, conf));
  return { final_score: score, eligibility_status: eligible ? 'eligible' : 'ineligible', confidence_score: Math.round(conf * 100) / 100, requires_manual_review: manual };
}
// mereka_application_id — V2's stable id, the single key the whole integration rides on.
function neolExportId(a) { return 'MRK-' + String(a.listingId || 'APP').toUpperCase().replace(/[^A-Z0-9]/g, '') + '-' + String(a.id).toUpperCase(); }
function neolEmail(name) { return String(name || 'applicant').toLowerCase().replace(/[^a-z ]/g, '').trim().split(/\s+/).slice(0, 2).join('.') + '@example.com'; }
function neolCsvCell(v) { v = v == null ? '' : String(v); return '"' + v.replace(/"/g, '""') + '"'; }
// One row per response. mereka_application_id first, then stable question headers (renaming a header
// creates a new field in Agent-E, so they must stay stable). CSV, never XLSX.
function neolBuildCSV(apps) {
  const headers = ['mereka_application_id', 'Full name', 'Email', 'Age', 'Location / State', 'Household income band', 'Employment status', 'Applying for', 'submitted_at'];
  const rows = apps.map(a => [
    neolExportId(a), a.name, neolEmail(a.name),
    a.age == null ? '' : a.age, a.loc || '',
    a.b40 == null ? '' : (a.b40 ? 'B40' : 'M40'),
    a.employed == null ? '' : (a.employed ? 'Employed' : 'Unemployed'),
    (a._listing && a._listing.title) || a.programme || a.role || '',
    a.submitted || ''
  ].map(neolCsvCell).join(','));
  return [headers.map(neolCsvCell).join(','), ...rows].join('\r\n');
}
function neolDownloadCSV(apps, filename) {
  try {
    const blob = new Blob([neolBuildCSV(apps)], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url; link.download = filename || 'mereka-applications.csv';
    document.body.appendChild(link); link.click(); document.body.removeChild(link);
    setTimeout(() => URL.revokeObjectURL(url), 1000);
  } catch (e) { /* prototype: download best-effort */ }
}
function VerdictStat({ label, value }) {
  return <div className="rounded-xl border border-neutral-100 bg-neutral-50 p-3"><div className="text-[11px] font-bold uppercase tracking-wide text-neutral-400">{label}</div><div className="mt-1 text-lg font-bold text-ink num-tabular" style={{ fontFamily: _pp }}>{value}</div></div>;
}
// Evaluation status strip: shows the export → upload → approve → results flow, the counts check
// (counts.without_correlation_id — verdicts that couldn't be matched back to an application), and
// a deep link into Agent-E for the full reasoning (single sign-on).
function NeolAgentEStrip({ apps }) {
  const total = apps.length;
  const unmatched = 0; // counts.without_correlation_id from the webhook — 0 when headers stayed stable
  const steps = ['Export CSV', 'Operator uploads', 'Rubric approved', 'Results received'];
  return (
    <div className="mb-5 rounded-2xl border border-[#DDE3F0] bg-[#F8FAFF] p-4">
      <div className="flex items-start justify-between gap-3 flex-wrap">
        <div className="flex items-center gap-2.5">
          <span className="w-9 h-9 rounded-xl bg-[#4338CA] text-white flex items-center justify-center flex-shrink-0"><Icon name="spark" size={18} /></span>
          <div>
            <div className="font-bold text-ink">Evaluated by Agent E</div>
            <p className="text-[12px] text-neutral-500">Against the approved rubric · last run 2 Sep 2026</p>
          </div>
        </div>
        <div className="flex items-center gap-2 flex-wrap">
          <span className={`text-[12px] font-semibold inline-flex items-center gap-1 px-2.5 h-7 rounded-full ${unmatched ? 'bg-[#FFF4D6] text-[#B8860B]' : 'bg-green-50 text-green-600'}`}><Icon name={unmatched ? 'warning' : 'check'} size={13} /> {total} evaluated · {unmatched} unmatched</span>
          <a href={NEOL_RESULTS_URL} target="_blank" rel="noopener noreferrer" className="h-8 px-3 rounded-full bg-white border border-[#C7CEF7] text-[#4338CA] text-[12px] font-semibold inline-flex items-center gap-1 hover:bg-[#EEF2FF]">View results in Agent E <Icon name="arrowUpRight" size={12} /></a>
        </div>
      </div>
      <div className="mt-3 flex items-center gap-1.5 flex-wrap">
        {steps.map((s, i) => (<React.Fragment key={s}><span className="inline-flex items-center gap-1.5 text-[11px] font-semibold text-neutral-500"><span className="w-4 h-4 rounded-full bg-[#4338CA] text-white flex items-center justify-center text-[9px] num-tabular">{i + 1}</span>{s}</span>{i < steps.length - 1 && <Icon name="chevronRight" size={12} className="text-neutral-300" />}</React.Fragment>))}
      </div>
      <p className="mt-2 text-[11px] text-neutral-400">Applications are exported as CSV and evaluated in Agent E once an operator approves the rubric. Verdicts return automatically; answers and evidence stay in Mereka — open Agent E for the full reasoning.</p>
    </div>
  );
}
// Export modal: builds and downloads the CSV Agent-E ingests. mereka_application_id is the key.
function NeolExportModal({ open, onClose, apps, listing }) {
  if (!open) return null;
  const cols = ['mereka_application_id', 'Full name', 'Email', 'Age', 'Location / State', 'Household income band', 'Employment status', 'Applying for', 'submitted_at'];
  const fname = (listing ? String(listing.title).toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') : 'mereka') + '-applications.csv';
  return (
    <div className="fixed inset-0 z-[130] flex items-center justify-center px-4 bg-black/50 backdrop-blur-sm" onClick={onClose}>
      <div className="w-full max-w-lg bg-white rounded-2xl shadow-2xl p-6" onClick={e => e.stopPropagation()}>
        <div className="flex items-start justify-between"><div><h3 className="text-lg font-bold text-ink" style={{ fontFamily: _pp }}>Export for Agent E</h3><p className="text-[12px] text-neutral-500 mt-0.5">{apps.length} {apps.length === 1 ? 'application' : 'applications'}{listing ? ' · ' + listing.title : ''}</p></div><button onClick={onClose} className="text-neutral-400 hover:text-neutral-700"><Icon name="close" size={20} /></button></div>
        <div className="mt-4 rounded-xl border border-neutral-200 overflow-hidden">
          <div className="px-3 py-2 bg-neutral-50 border-b border-neutral-100 text-[11px] font-bold uppercase tracking-wide text-neutral-400">CSV columns</div>
          <div className="p-3 flex flex-wrap gap-1.5">{cols.map(c => <span key={c} className={`px-2 h-6 inline-flex items-center rounded-md text-[11px] font-semibold ${c === 'mereka_application_id' ? 'bg-[#EEF2FF] text-[#4338CA]' : 'bg-neutral-100 text-neutral-600'}`}>{c}</span>)}</div>
        </div>
        <ul className="mt-4 space-y-2 text-[13px] text-neutral-600">
          <li className="flex items-start gap-2"><Icon name="check" size={14} className="text-green-600 mt-0.5 flex-shrink-0" /><span><span className="font-semibold text-ink">mereka_application_id</span> is the correlation key — it survives ingest and comes back on every verdict.</span></li>
          <li className="flex items-start gap-2"><Icon name="warning" size={14} className="text-[#E8901A] mt-0.5 flex-shrink-0" /><span>Keep question headers stable. Renaming one mid-programme creates a new field in Agent E instead of updating the old one.</span></li>
          <li className="flex items-start gap-2"><Icon name="warning" size={14} className="text-[#E8901A] mt-0.5 flex-shrink-0" /><span>Matching is on the id, never name, email or row order.</span></li>
        </ul>
        <div className="mt-5 flex items-center justify-between gap-2 flex-wrap">
          <p className="text-[12px] text-neutral-400">CSV (not XLSX — XLSX needs a human to confirm the sheet first).</p>
          <button onClick={() => { neolDownloadCSV(apps, fname); onClose(); }} className="h-10 px-5 rounded-full bg-ink text-white text-sm font-semibold inline-flex items-center gap-2 hover:bg-black"><Icon name="document" size={15} /> Download {fname}</button>
        </div>
      </div>
    </div>
  );
}

/* ---------- Applications workspace (multi-service) ---------- */
function NeolApplicationsPage() {
  const params = new URLSearchParams(typeof location !== 'undefined' ? location.search : '');
  const scopedId = params.get('listing');
  const scoped = scopedId ? neolListing(scopedId) : null;
  const [svc, setSvc] = React.useState(scoped ? scoped.svc : 'all');
  const [listingId, setListingId] = React.useState(scoped ? scopedId : 'all');
  const [stage, setStage] = React.useState('All');
  const [q, setQ] = React.useState('');
  const [sel, setSel] = React.useState({});
  const [comms, setComms] = React.useState(null);
  const [ddOpen, setDdOpen] = React.useState(false);
  const [exportOpen, setExportOpen] = React.useState(false);
  const chips = ['All', ...NEOL_STAGES];
  const listings = neolAllListings();
  const svcListings = listings.filter(l => svc === 'all' || l.svc === svc);

  let base = listingId !== 'all' ? neolAppsForListing(listingId) : neolAllApps().filter(a => svc === 'all' || a.svc === svc);
  base = base.map(a => ({ ...a, _listing: neolListing(a.listingId) }));
  const view = base.filter(a => { const qq = q.trim().toLowerCase(); return (stage === 'All' || a.stage === stage) && (qq === '' || a.name.toLowerCase().includes(qq) || (a._listing && a._listing.title && a._listing.title.toLowerCase().includes(qq)) || (a.role && a.role.toLowerCase().includes(qq))); });
  const selIds = Object.keys(sel).filter(k => sel[k]);
  const cnt = (st) => base.filter(a => a.stage === st).length;
  const toggle = (id) => setSel(s => ({ ...s, [id]: !s[id] }));
  const activeListing = listingId !== 'all' ? neolListing(listingId) : null;
  const commsSvc = activeListing ? activeListing.svc : (svc === 'gig' ? 'gig' : 'path');
  const commsCtx = activeListing ? activeListing.title : null;

  const setSvcAnd = (v) => { setSvc(v); setListingId('all'); setSel({}); };

  return (
    <UserShell route="/app/hub/applications">
      <div className="max-w-[1200px]">
        <div className="flex items-start justify-between gap-4 flex-wrap mb-5">
          <div>
            <h1 className="text-3xl font-bold text-ink" style={{ fontFamily: _pp }}>Applications</h1>
            <p className="text-neutral-500 mt-1">{activeListing
              ? <>Reviewing {activeListing.svc === 'gig' ? 'proposals' : 'applicants'} for <span className="font-semibold text-ink">{activeListing.title}</span>.</>
              : <>Applicants and proposals across all your services, auto-scored for fit.</>}</p>
          </div>
          <button onClick={() => setExportOpen(true)} className="h-10 px-4 rounded-full border border-neutral-200 text-sm font-semibold inline-flex items-center gap-2 hover:bg-neutral-50 flex-shrink-0"><Icon name="document" size={15} /> Export CSV</button>
        </div>

        {/* service + listing selectors */}
        <div className="flex items-center gap-3 flex-wrap mb-4">
          <div className="inline-flex items-center p-1 rounded-full bg-neutral-100">
            {[['all', 'All services'], ['path', 'Learning Paths'], ['gig', 'Gigs']].map(([v, l]) => (
              <button key={v} onClick={() => setSvcAnd(v)} className={`h-8 px-3.5 rounded-full text-[13px] font-semibold ${svc === v ? 'bg-white text-ink shadow-sm' : 'text-neutral-500 hover:text-neutral-800'}`}>{l}</button>
            ))}
          </div>
          {(() => {
            const pick = (id) => { setListingId(id); setSel({}); setDdOpen(false); const l = id === 'all' ? null : neolListing(id); if (l) setSvc(l.svc); };
            const pathItems = svcListings.filter(l => l.svc === 'path');
            const gigItems = svcListings.filter(l => l.svc === 'gig');
            const Row = ({ id, label, sub }) => {
              const on = listingId === id;
              return <button onClick={() => pick(id)} className={`w-full flex items-center justify-between gap-3 px-3 h-10 rounded-xl text-left text-[13px] ${on ? 'bg-[#EEF2FF] text-[#4338CA] font-semibold' : 'text-neutral-700 hover:bg-neutral-50 font-medium'}`}><span className="truncate">{label}</span><span className="flex items-center gap-2 flex-shrink-0">{sub != null && <span className="text-[11px] font-semibold text-neutral-400 num-tabular">{sub}</span>}{on && <Icon name="check" size={15} />}</span></button>;
            };
            const Group = ({ title, items }) => items.length ? <div className="px-1"><div className="px-2 pt-2 pb-1 text-[11px] font-bold uppercase tracking-wide text-neutral-400">{title}</div>{items.map(l => <Row key={l.id} id={l.id} label={l.title} sub={neolAppsForListing(l.id).length} />)}</div> : null;
            return (
              <div className="relative">
                <button onClick={() => setDdOpen(o => !o)} className={`h-9 pl-3.5 pr-3 rounded-full border text-[13px] font-semibold inline-flex items-center gap-2 ${activeListing ? 'border-[#C7CEF7] bg-[#EEF2FF] text-[#4338CA]' : 'border-neutral-200 bg-white text-neutral-700 hover:border-neutral-300'}`}>
                  <Icon name="filter" size={14} className={activeListing ? 'text-[#4338CA]' : 'text-neutral-400'} />
                  <span className="max-w-[220px] truncate">{activeListing ? activeListing.title : `All ${svc === 'gig' ? 'gigs' : svc === 'path' ? 'learning paths' : 'listings'}`}</span>
                  <Icon name="chevronDown" size={14} className={activeListing ? 'text-[#4338CA]' : 'text-neutral-400'} />
                </button>
                {ddOpen && (<>
                  <div className="fixed inset-0 z-[70]" onClick={() => setDdOpen(false)} />
                  <div className="absolute left-0 top-full mt-2 z-[71] w-72 max-h-[400px] overflow-auto bg-white border border-neutral-200 rounded-2xl shadow-xl py-1.5">
                    <div className="px-1"><Row id="all" label={`All ${svc === 'gig' ? 'gigs' : svc === 'path' ? 'learning paths' : 'listings'}`} sub={null} /></div>
                    <Group title="Learning Paths" items={pathItems} />
                    <Group title="Gigs" items={gigItems} />
                  </div>
                </>)}
              </div>
            );
          })()}
          {activeListing && <button onClick={() => { setListingId('all'); setSel({}); }} className="text-[13px] font-semibold text-primary hover:underline inline-flex items-center gap-1"><Icon name="close" size={13} /> Clear</button>}
        </div>

        <NeolAgentEStrip apps={base} />

        <div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-5">
          {[['Pending', cnt('Pending'), 'clock'], ['Shortlisted', cnt('Shortlisted'), 'star'], ['Accepted', cnt('Accepted'), 'check'], ['Total', base.length, 'user']].map(([l, n, ic]) => (
            <div key={l} className="bg-white border border-neutral-200 rounded-2xl p-4"><div className="flex items-center justify-between text-[12px] font-bold uppercase tracking-wide text-neutral-400">{l} <Icon name={ic} size={15} className="text-neutral-300" /></div><div className="text-2xl font-bold text-ink num-tabular mt-1" style={{ fontFamily: _pp }}>{n}</div></div>
          ))}
        </div>
        <div className="flex items-center justify-between gap-3 flex-wrap mb-4">
          <div className="flex items-center gap-2 flex-wrap">{chips.map(c => <button key={c} onClick={() => setStage(c)} className={`px-3.5 h-8 inline-flex items-center rounded-full text-[13px] font-semibold ${stage === c ? 'bg-ink text-white' : 'border border-neutral-200 text-neutral-600 hover:border-neutral-300'}`}>{c}</button>)}</div>
          <div className="relative w-full sm:w-64"><Icon name="search" size={16} className="absolute left-3.5 top-1/2 -translate-y-1/2 text-neutral-400" /><input value={q} onChange={e => setQ(e.target.value)} placeholder="Search applicants or services..." className="w-full h-10 pl-10 pr-4 rounded-full border border-neutral-200 text-sm focus:outline-none focus:border-primary" /></div>
        </div>
        {selIds.length > 0 && (
          <div className="mb-4 flex items-center justify-between gap-3 flex-wrap bg-ink text-white rounded-xl px-4 py-2.5">
            <span className="text-sm font-semibold">{selIds.length} selected</span>
            <div className="flex items-center gap-2"><button onClick={() => setComms({ kind: 'Accepted', count: selIds.length })} className="h-9 px-4 rounded-full bg-green-500 text-white text-[13px] font-semibold inline-flex items-center gap-1 hover:brightness-95"><Icon name="check" size={14} /> Accept &amp; notify</button><button onClick={() => setComms({ kind: 'Rejected', count: selIds.length })} className="h-9 px-4 rounded-full bg-white/15 text-white text-[13px] font-semibold inline-flex items-center gap-1 hover:bg-white/25">Reject &amp; notify</button></div>
          </div>
        )}
        {view.length === 0 ? (
          <div className="bg-white border border-neutral-200 rounded-2xl p-10 text-center text-sm text-neutral-500">No submissions in this stage.</div>
        ) : (() => {
          const groups = []; const byId = {};
          view.forEach(a => { const k = a.listingId || 'none'; if (!byId[k]) { byId[k] = { listing: a._listing, apps: [] }; groups.push(byId[k]); } byId[k].apps.push(a); });
          return (
            <div className="space-y-5">
              {groups.map((g, gi) => {
                const l = g.listing;
                return (
                  <div key={l ? l.id : gi} className="bg-white border border-neutral-200 rounded-2xl overflow-hidden">
                    {l && (
                      <div className="flex items-center gap-3 p-3 sm:p-4 bg-neutral-50 border-b border-neutral-100">
                        {l.img ? <img src={l.img} alt="" className="w-14 h-14 rounded-xl object-cover flex-shrink-0" /> : <span className="w-14 h-14 rounded-xl bg-[#EEF2FF] text-[#4338CA] flex items-center justify-center flex-shrink-0"><Icon name={l.svc === 'gig' ? 'briefcase' : 'programme'} size={22} /></span>}
                        <div className="min-w-0 flex-1">
                          <div className="text-[11px] font-bold uppercase tracking-wide text-neutral-400">{l.svc === 'gig' ? 'Gig' : 'Learning Path'}</div>
                          <div className="font-bold text-ink truncate" style={{ fontFamily: _pp }}>{l.title}</div>
                          <div className="text-[12px] text-neutral-500 truncate">{l.org} · {g.apps.length} {g.apps.length === 1 ? 'applicant' : 'applicants'}</div>
                        </div>
                        <div className="flex items-center gap-2 flex-shrink-0">
                          {listingId === 'all' && <button onClick={() => { setListingId(l.id); setSvc(l.svc); setSel({}); }} className="h-8 px-3 rounded-full border border-neutral-200 bg-white text-[12px] font-semibold text-neutral-700 hover:border-neutral-300 inline-flex items-center gap-1">All applications <Icon name="chevronRight" size={12} /></button>}
                          {l.to && <Link to={l.to} className="h-8 px-3 rounded-full bg-ink text-white text-[12px] font-semibold hover:bg-black inline-flex items-center gap-1">View service <Icon name="arrowUpRight" size={12} /></Link>}
                        </div>
                      </div>
                    )}
                    {g.apps.map((a, i) => (
                      <div key={a.id} className={`flex items-center gap-3 px-4 py-3 ${i ? 'border-t border-neutral-100' : ''} hover:bg-neutral-50`}>
                        <input type="checkbox" checked={!!sel[a.id]} onChange={() => toggle(a.id)} className="w-4 h-4 accent-[#1FA3A6]" />
                        <ScoreRing value={a.score} size={38} />
                        <div className="min-w-0 flex-1">
                          <div className="flex items-center gap-2 flex-wrap"><span className="font-bold text-ink">{a.name}</span><StagePill stage={a.stage} /></div>
                          <p className="text-[12px] text-neutral-500 truncate">{neolAppSub(a)} · matches {a.matches}/{a._listing ? a._listing.criteria.length : 5}</p>
                        </div>
                        <Link to={`/app/hub/applications/${a.id}`} className="h-9 px-4 rounded-full border border-neutral-200 text-[13px] font-semibold inline-flex items-center gap-1 hover:bg-neutral-50 flex-shrink-0">Review <Icon name="chevronRight" size={13} /></Link>
                      </div>
                    ))}
                  </div>
                );
              })}
            </div>
          );
        })()}
      </div>
      <NeolExportModal open={exportOpen} onClose={() => setExportOpen(false)} apps={view.map(a => ({ ...a, _listing: neolListing(a.listingId) }))} listing={activeListing} />
      <RespondModal open={!!comms} onClose={() => { setComms(null); setSel({}); }} kind={comms && comms.kind} count={comms && comms.count} svc={commsSvc} ctx={commsCtx} />
    </UserShell>
  );
}

/* ---------- Application detail (multi-service) ---------- */
function NeolApplicationDetailPage({ id }) {
  const res = neolResolveApp(id) || neolResolveApp('a1');
  const a = res.app; const listing = res.listing;
  const crit = a._criteria || NEOL_ELIGIBILITY;
  const critLabel = a.svc === 'gig' ? 'Fit criteria' : 'Eligibility criteria';
  const backTo = a.listingId ? `/app/hub/applications?listing=${a.listingId}` : '/app/hub/applications';
  const [stage, setStage] = React.useState(a.stage);
  const [noteTab, setNoteTab] = React.useState('private');
  const [comms, setComms] = React.useState(null);
  const [log, setLog] = React.useState([{ who: 'AI review', act: `Evaluated against the approved rubric · scored ${a.score}, ${a.matches}/${crit.length} criteria`, when: a.submitted }, { who: 'Operator', act: 'Approved the evaluation rubric in Agent E', when: a.submitted }]);
  const move = (s) => { setStage(s); setLog(l => [{ who: 'Faiz Fadhillah', act: `Moved to ${s}`, when: 'just now' }, ...l]); if (s === 'Accepted' || s === 'Rejected') setComms({ kind: s, name: a.name.split(' ')[0] }); };
  return (
    <UserShell route="/app/hub/applications">
      <div className="max-w-[1100px]">
        <Link to={backTo} className="inline-flex items-center gap-1 text-sm text-neutral-500 hover:text-neutral-900 mb-4"><Icon name="chevronLeft" size={14} /> Back to applications</Link>
        <div className="grid lg:grid-cols-[1fr_320px] gap-6">
          <div className="space-y-5">
            <div className="flex items-center gap-3"><Avatar name={a.name} size={56} /><div><div className="flex items-center gap-2 flex-wrap"><h1 className="text-2xl font-bold text-ink" style={{ fontFamily: _pp }}>{a.name}</h1><StagePill stage={stage} /></div><p className="text-sm text-neutral-500">{neolAppSub(a)} · applied {a.submitted}</p></div></div>
{listing && (
              <div className="bg-white border border-neutral-200 rounded-2xl p-4 flex items-center gap-3">
                {listing.img ? <img src={listing.img} alt="" className="w-14 h-14 rounded-xl object-cover flex-shrink-0" /> : <span className="w-14 h-14 rounded-xl bg-[#EEF2FF] text-[#4338CA] flex items-center justify-center flex-shrink-0"><Icon name={listing.svc === 'gig' ? 'briefcase' : 'programme'} size={22} /></span>}
                <div className="min-w-0 flex-1">
                  <div className="text-[11px] font-bold uppercase tracking-wide text-neutral-400">Applying for · {listing.svc === 'gig' ? 'Gig' : 'Learning Path'}</div>
                  <div className="font-bold text-ink truncate" style={{ fontFamily: _pp }}>{listing.title}</div>
                  <div className="text-[12px] text-neutral-500 truncate">{listing.org}</div>
                </div>
                <div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 flex-shrink-0">
                  <Link to={backTo} className="h-8 px-3 rounded-full border border-neutral-200 text-[12px] font-semibold text-neutral-700 hover:bg-neutral-50 inline-flex items-center justify-center gap-1">All applications</Link>
                  {listing.to && <Link to={listing.to} className="h-8 px-3 rounded-full bg-ink text-white text-[12px] font-semibold hover:bg-black inline-flex items-center justify-center gap-1">View service <Icon name="arrowUpRight" size={12} /></Link>}
                </div>
              </div>
            )}
            {(() => { const v = neolVerdict(a); return (
              <div className="bg-white border border-neutral-200 rounded-2xl p-5">
                <div className="flex items-center justify-between gap-3 flex-wrap">
                  <div className="flex items-center gap-2"><span className="w-7 h-7 rounded-lg bg-[#EEF2FF] text-[#4338CA] flex items-center justify-center flex-shrink-0"><Icon name="spark" size={14} /></span><h3 className="font-bold text-ink">Agent E verdict</h3></div>
                  <a href={NEOL_RESULTS_URL} target="_blank" rel="noopener noreferrer" className="text-[13px] font-semibold text-[#4338CA] inline-flex items-center gap-1 hover:underline">View reasoning in Agent E <Icon name="arrowUpRight" size={13} /></a>
                </div>
                <div className="mt-4 grid grid-cols-2 sm:grid-cols-4 gap-3">
                  <VerdictStat label="Final score" value={v.final_score} />
                  <div className="rounded-xl border border-neutral-100 bg-neutral-50 p-3"><div className="text-[11px] font-bold uppercase tracking-wide text-neutral-400">Eligibility</div><div className="mt-1"><span className={`px-2.5 h-6 inline-flex items-center rounded-full text-[12px] font-semibold ${v.eligibility_status === 'eligible' ? 'bg-green-50 text-green-600' : 'bg-red-50 text-red-500'}`}>{v.eligibility_status}</span></div></div>
                  <VerdictStat label="Confidence" value={Math.round(v.confidence_score * 100) + '%'} />
                  <div className="rounded-xl border border-neutral-100 bg-neutral-50 p-3"><div className="text-[11px] font-bold uppercase tracking-wide text-neutral-400">Manual review</div><div className="mt-1 text-[13px] font-semibold inline-flex items-center gap-1">{v.requires_manual_review ? <><Icon name="warning" size={14} className="text-[#E8901A]" /> Required</> : <><Icon name="check" size={14} className="text-green-600" /> Not needed</>}</div></div>
                </div>
                <p className="mt-3 text-[11px] text-neutral-400">Verdict returned by Agent E via signed webhook (id <span className="font-mono">{neolExportId(a)}</span>). Answers and evidence stay in Mereka — open Agent E for the full breakdown; it opens with single sign-on.</p>
              </div>
            ); })()}
            <AgentEval a={a} expanded />
            <div className="bg-white border border-neutral-200 rounded-2xl p-5">
              <h3 className="font-bold text-ink mb-3">{critLabel}</h3>
              <ul className="space-y-2">{crit.map((c, i) => { const ok = i < a.matches; return <li key={c} className="flex items-center gap-2 text-sm"><span className={`w-5 h-5 rounded-full flex items-center justify-center ${ok ? 'bg-green-50 text-green-600' : 'bg-red-50 text-red-500'}`}><Icon name={ok ? 'check' : 'close'} size={12} /></span><span className={ok ? 'text-neutral-700' : 'text-neutral-400'}>{c}</span></li>; })}</ul>
            </div>
            <div className="bg-white border border-neutral-200 rounded-2xl p-5">
              <div className="flex items-center gap-2 mb-3"><button onClick={() => setNoteTab('private')} className={`h-8 px-3 rounded-full text-[13px] font-semibold ${noteTab === 'private' ? 'bg-ink text-white' : 'border border-neutral-200 text-neutral-600'}`}>Private notes (Staff)</button><button onClick={() => setNoteTab('shared')} className={`h-8 px-3 rounded-full text-[13px] font-semibold ${noteTab === 'shared' ? 'bg-ink text-white' : 'border border-neutral-200 text-neutral-600'}`}>Shared (Hub-visible)</button></div>
              <textarea rows={3} placeholder={noteTab === 'private' ? 'Internal note — visible to Mereka Staff only…' : 'Note visible to the Hub…'} className="w-full px-4 py-3 rounded-xl border border-neutral-200 text-sm focus:outline-none focus:border-primary resize-none" />
              <div className="mt-2 flex justify-end"><button className="h-9 px-4 rounded-full bg-ink text-white text-[13px] font-semibold hover:bg-black">Save note</button></div>
            </div>
          </div>
          <aside className="space-y-4">
            <div className="bg-white border border-neutral-200 rounded-2xl p-5">
              <p className="text-[12px] font-bold uppercase tracking-wide text-neutral-400 mb-3">Move to stage</p>
              <div className="space-y-2">{NEOL_STAGES.map(s => <button key={s} onClick={() => move(s)} className={`w-full h-10 px-4 rounded-xl text-sm font-semibold text-left flex items-center justify-between ${stage === s ? 'bg-ink text-white' : 'border border-neutral-200 text-neutral-700 hover:bg-neutral-50'}`}>{s} {stage === s && <Icon name="check" size={15} />}</button>)}</div>
              <p className="mt-3 text-[12px] text-neutral-400">{a.svc === 'gig' ? 'Accept moves the proposal toward hire; Reject sends a WhatsApp via Respond.io.' : 'Accept / Reject sends a WhatsApp via Respond.io.'}</p>
              {a.svc === 'gig' && a.listingId && <Link to={`/app/hub/gigs/${a.listingId}/proposals`} className="mt-3 w-full h-10 rounded-xl border border-neutral-200 text-sm font-semibold text-neutral-700 hover:bg-neutral-50 inline-flex items-center justify-center gap-1.5"><Icon name="briefcase" size={14} /> Open in hire &amp; escrow</Link>}
            </div>
            <div className="bg-white border border-neutral-200 rounded-2xl p-5">
              <p className="text-[12px] font-bold uppercase tracking-wide text-neutral-400 mb-3">Activity log</p>
              <ul className="space-y-3">{log.map((e, i) => <li key={i} className="flex gap-2.5 text-[13px]"><span className="w-7 h-7 rounded-full bg-neutral-100 flex items-center justify-center flex-shrink-0"><Icon name={e.who === 'AI review' ? 'spark' : 'user'} size={13} className="text-neutral-500" /></span><div><p className="text-neutral-700"><span className="font-semibold text-ink">{e.who}</span> {e.act}</p><p className="text-[11px] text-neutral-400">{e.when}</p></div></li>)}</ul>
            </div>
          </aside>
        </div>
      </div>
      <RespondModal open={!!comms} onClose={() => setComms(null)} kind={comms && comms.kind} name={comms && comms.name} svc={a.svc} ctx={listing && listing.title} />
    </UserShell>
  );
}

/* ---------- Trainer sourcing ---------- */
function TrainerCard({ t, onInvite }) {
  return (
    <div className="bg-white border border-neutral-200 rounded-2xl p-5">
      <div className="flex items-start gap-3">
        <Avatar name={t.name} size={46} />
        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-2 flex-wrap"><Link to={`/app/hub/trainers/${t.id}`} className="font-bold text-ink hover:text-primary-700">{t.name}</Link>{t.hrdcorp && <span className="px-2 h-5 inline-flex items-center rounded-full bg-green-50 text-green-600 text-[10px] font-bold">HRD Corp</span>}</div>
          <p className="text-[12px] text-neutral-500">{t.loc} · {t.langs.join('/')} · {t.available}</p>
        </div>
        <div className="text-right flex-shrink-0"><div className="text-lg font-bold num-tabular" style={{ color: t.match >= 85 ? '#1FA85B' : t.match >= 70 ? '#E8901A' : '#E4572E' }}>{t.match}%</div><div className="text-[10px] font-bold uppercase text-neutral-400">match</div></div>
      </div>
      <div className="mt-3 flex flex-wrap gap-1.5">{t.tags.map(tag => <span key={tag} className="px-2 h-6 inline-flex items-center rounded-md bg-neutral-100 text-[11px] font-semibold text-neutral-600">{tag}</span>)}</div>
      <div className="mt-3 rounded-xl bg-[#F8FAFF] border border-[#DDE3F0] p-3"><p className="text-[13px] text-neutral-600 leading-snug">{t.summary}</p></div>
      <div className="mt-3 flex items-center justify-between gap-2 flex-wrap">
        <span className="text-[12px] text-neutral-500 inline-flex items-center gap-1"><Icon name="star" size={13} fill="#E8B23A" strokeWidth={0} /> {t.satisfaction} · {t.delivered} delivered · {t.rate}</span>
        <div className="flex items-center gap-2"><Link to={`/app/hub/trainers/${t.id}`} className="h-9 px-3 rounded-full border border-neutral-200 text-[13px] font-semibold hover:bg-neutral-50">View</Link><button onClick={() => onInvite(t)} className="h-9 px-4 rounded-full bg-ink text-white text-[13px] font-semibold inline-flex items-center gap-1 hover:bg-black"><Icon name="send" size={13} /> Invite</button></div>
      </div>
    </div>
  );
}
function NeolTrainersPage() {
  const [nl, setNl] = React.useState('AI Literacy Level 2 in Bahasa Malaysia, Klang Valley, available October');
  const [must, setMust] = React.useState('HRD Corp accredited');
  const [nice, setNice] = React.useState('Manufacturing sector experience');
  const [excl, setExcl] = React.useState('');
  const [ran, setRan] = React.useState(true);
  const [invite, setInvite] = React.useState(null);
  const [csv, setCsv] = React.useState(false);
  const view = [...NEOL_TRAINERS].sort((x, y) => y.match - x.match);
  return (
    <UserShell route="/app/hub/trainers">
      <div className="max-w-[1200px]">
        <div className="flex items-start justify-between gap-4 flex-wrap mb-5">
          <div><h1 className="text-3xl font-bold text-ink" style={{ fontFamily: _pp }}>Trainer Network</h1><p className="text-neutral-500 mt-1">Describe who you need — AI matches trainers to your learning path brief.</p></div>
          <button onClick={() => setCsv(true)} className="h-10 px-4 rounded-full border border-neutral-200 text-sm font-semibold inline-flex items-center gap-2 hover:bg-neutral-50"><Icon name="upload" size={15} /> Import CSV</button>
        </div>
        <div className="bg-white border border-neutral-200 rounded-2xl p-5">
          <div className="relative"><Icon name="spark" size={18} className="absolute left-4 top-4 text-[#4338CA]" /><textarea value={nl} onChange={e => setNl(e.target.value)} rows={2} placeholder="e.g. Find a trainer who can deliver AI Literacy L2 in Bahasa Malaysia in Sabah, available in October" className="w-full pl-11 pr-4 py-3 rounded-xl border border-neutral-200 text-[15px] focus:outline-none focus:border-primary resize-none" /></div>
          <div className="mt-3 grid sm:grid-cols-3 gap-3">
            {[['Must-have', must, setMust, 'text-green-600'], ['Nice-to-have', nice, setNice, 'text-[#B8860B]'], ['Exclude', excl, setExcl, 'text-red-500']].map(([l, v, set, col]) => (
              <div key={l}><p className={`text-[11px] font-bold uppercase tracking-wide mb-1 ${col}`}>{l}</p><input value={v} onChange={e => set(e.target.value)} className="w-full h-9 px-3 rounded-lg border border-neutral-200 text-[13px] focus:outline-none focus:border-primary" /></div>
            ))}
          </div>
          <div className="mt-4 flex justify-end"><button onClick={() => setRan(true)} className="h-10 px-5 rounded-full bg-[#4338CA] text-white text-sm font-semibold inline-flex items-center gap-2 hover:brightness-110"><Icon name="spark" size={15} /> Search with Agent E</button></div>
        </div>
        {ran && (<>
          <div className="mt-5 flex items-center gap-2"><Icon name="spark" size={15} className="text-[#4338CA]" /> <span className="text-[13px] text-neutral-500">ranked {view.length} trainers by fit to your brief</span></div>
          <div className="mt-3 grid grid-cols-1 lg:grid-cols-2 gap-4">{view.map(t => <TrainerCard key={t.id} t={t} onInvite={setInvite} />)}</div>
        </>)}
      </div>
      <RespondModal open={!!invite} onClose={() => setInvite(null)} kind="Invite" name={invite && invite.name.split(' ')[0]} />
      <NeolCsvModal open={csv} onClose={() => setCsv(false)} />
    </UserShell>
  );
}
function NeolTrainerDetailPage({ id }) {
  const t = NEOL_TRAINERS.find(x => x.id === id) || NEOL_TRAINERS[0];
  const [invite, setInvite] = React.useState(false);
  const similar = NEOL_TRAINERS.filter(x => x.id !== t.id).slice(0, 3);
  return (
    <UserShell route="/app/hub/trainers">
      <div className="max-w-[1000px]">
        <Link to="/app/hub/trainers" className="inline-flex items-center gap-1 text-sm text-neutral-500 hover:text-neutral-900 mb-4"><Icon name="chevronLeft" size={14} /> Back to network</Link>
        <div className="grid lg:grid-cols-[1fr_300px] gap-6">
          <div className="space-y-5">
            <div className="flex items-center gap-4"><Avatar name={t.name} size={64} /><div><div className="flex items-center gap-2 flex-wrap"><h1 className="text-2xl font-bold text-ink" style={{ fontFamily: _pp }}>{t.name}</h1>{t.hrdcorp && <span className="px-2 h-6 inline-flex items-center rounded-full bg-green-50 text-green-600 text-[11px] font-bold">HRD Corp accredited</span>}</div><p className="text-sm text-neutral-500">{t.loc} · {t.langs.join(' / ')} · {t.rate}</p></div></div>
            <div className="flex flex-wrap gap-1.5">{t.tags.map(tag => <span key={tag} className="px-2.5 h-7 inline-flex items-center rounded-md bg-neutral-100 text-[12px] font-semibold text-neutral-600">{tag}</span>)}</div>
            <div className="rounded-2xl bg-[#F8FAFF] border border-[#DDE3F0] p-4"><p className="text-[14px] text-neutral-600 leading-relaxed">{t.summary}</p></div>
            <div className="bg-white border border-neutral-200 rounded-2xl p-5">
              <h3 className="font-bold text-ink mb-3">Engagement history</h3>
              <div className="grid grid-cols-3 gap-3 text-center">
                <div><div className="text-2xl font-bold text-ink num-tabular" style={{ fontFamily: _pp }}>{t.delivered}</div><div className="text-[11px] text-neutral-400 uppercase">Learning Paths</div></div>
                <div><div className="text-2xl font-bold text-ink num-tabular" style={{ fontFamily: _pp }}>{t.satisfaction}</div><div className="text-[11px] text-neutral-400 uppercase">Avg satisfaction</div></div>
                <div><div className="text-2xl font-bold text-green-600 num-tabular" style={{ fontFamily: _pp }}>{t.available}</div><div className="text-[11px] text-neutral-400 uppercase">Next available</div></div>
              </div>
              <p className="mt-3 text-[13px] text-neutral-500">Sectors: {t.sectors.join(', ')}</p>
            </div>
            <div>
              <h3 className="font-bold text-ink mb-3">Find similar trainers</h3>
              <div className="grid sm:grid-cols-3 gap-3">{similar.map(s => <Link key={s.id} to={`/app/hub/trainers/${s.id}`} className="bg-white border border-neutral-200 rounded-2xl p-4 hover:border-primary hover:shadow-sm transition-all text-center"><Avatar name={s.name} size={40} /><div className="font-bold text-ink text-sm mt-2">{s.name}</div><div className="text-[11px] text-neutral-400 mt-0.5">{s.match}% match · {s.loc}</div></Link>)}</div>
            </div>
          </div>
          <aside>
            <div className="bg-white border border-neutral-200 rounded-2xl p-5 lg:sticky lg:top-24">
              <div className="text-center mb-3"><div className="text-3xl font-bold num-tabular" style={{ color: '#1FA85B', fontFamily: _pp }}>{t.match}%</div><div className="text-[11px] font-bold uppercase text-neutral-400">fit to your brief</div></div>
              <button onClick={() => setInvite(true)} className="w-full h-11 rounded-full bg-ink text-white text-sm font-semibold inline-flex items-center justify-center gap-2 hover:bg-black"><Icon name="send" size={15} /> Invite to learning path</button>
              <p className="mt-2 text-[12px] text-neutral-400 text-center">Sends the brief via Respond.io (WhatsApp).</p>
            </div>
          </aside>
        </div>
      </div>
      <RespondModal open={invite} onClose={() => setInvite(false)} kind="Invite" name={t.name.split(' ')[0]} />
    </UserShell>
  );
}

/* ---------- CSV import modal ---------- */
function NeolCsvModal({ open, onClose }) {
  const [done, setDone] = React.useState(false);
  React.useEffect(() => { setDone(false); }, [open]);
  if (!open) return null;
  return (
    <div className="fixed inset-0 z-[130] flex items-center justify-center px-4 bg-black/50 backdrop-blur-sm" onClick={onClose}>
      <div className="w-full max-w-md bg-white rounded-2xl shadow-2xl p-6" onClick={e => e.stopPropagation()}>
        <div className="flex items-start justify-between"><h3 className="text-lg font-bold text-ink" style={{ fontFamily: _pp }}>Import trainers (CSV)</h3><button onClick={onClose} className="text-neutral-400 hover:text-neutral-700"><Icon name="close" size={20} /></button></div>
        {!done ? (<>
          <p className="mt-2 text-[13px] text-neutral-500">Columns: name, email, skills, HRD Corp status, location, languages.</p>
          <div className="mt-4 border-2 border-dashed border-neutral-300 rounded-xl p-8 text-center"><Icon name="upload" size={28} className="text-neutral-400 mx-auto mb-2" /><p className="text-sm text-neutral-500">Drop a CSV or <span className="text-primary-700 font-semibold">browse</span></p><p className="text-[12px] text-neutral-400 mt-1">trainers_sample.csv · 34 rows detected</p></div>
          <div className="mt-4 flex justify-end"><button onClick={() => setDone(true)} className="h-10 px-5 rounded-full bg-ink text-white text-sm font-semibold hover:bg-black">Import 34 trainers</button></div>
        </>) : (
          <div className="text-center py-4"><div className="w-14 h-14 rounded-2xl bg-primary-light text-primary-700 mx-auto flex items-center justify-center mb-3"><Icon name="check" size={30} /></div><h4 className="font-bold text-ink text-lg" style={{ fontFamily: _pp }}>34 trainers imported</h4><p className="text-sm text-neutral-600 mt-1">Profiles created. Agent E will enrich them from learning path data over time.</p><button onClick={onClose} className="mt-4 h-10 px-5 rounded-full bg-ink text-white text-sm font-semibold hover:bg-black">Done</button></div>
        )}
      </div>
    </div>
  );
}

/* ---------- AI Brief modal (AI description generator — NOT Agent E) ---------- */
function NeolAiBriefModal({ open, onClose }) {
  const [gen, setGen] = React.useState(false);
  React.useEffect(() => { if (!open) setGen(false); }, [open]);
  if (!open) return null;
  const brief = `AI4U is a hands-on AI-literacy programme for young Malaysians (18–30) from B40 households who are unemployed or underemployed. Over 8 weeks, participants move from everyday AI tools to practical data and automation skills, ending with a portfolio project and an industry-recognised certificate. Delivered bilingually (BM/EN) in the Klang Valley, the programme prioritises real employment outcomes through employer connections and SEEK Pass verified credentials.`;
  return (
    <div className="fixed inset-0 z-[130] flex items-center justify-center px-4 bg-black/50 backdrop-blur-sm" onClick={onClose}>
      <div className="w-full max-w-lg bg-white rounded-2xl shadow-2xl p-6" onClick={e => e.stopPropagation()}>
        <div className="flex items-start justify-between"><div className="flex items-center gap-2"><h3 className="text-lg font-bold text-ink" style={{ fontFamily: _pp }}>Draft brief</h3><span className="px-2 h-6 inline-flex items-center rounded-full bg-[#EEF2FF] text-[#4338CA] text-[11px] font-bold">AI</span></div><button onClick={onClose} className="text-neutral-400 hover:text-neutral-700"><Icon name="close" size={20} /></button></div>
        {!gen ? (<>
          <div className="mt-4 grid grid-cols-2 gap-3">
            {[['Target audience', 'B40 youth, 18–30'], ['Topic', 'AI literacy'], ['Duration', '8 weeks'], ['Location', 'Klang Valley']].map(([l, v]) => <div key={l}><p className="text-[12px] font-semibold text-neutral-500 mb-1">{l}</p><input defaultValue={v} className="w-full h-10 px-3 rounded-lg border border-neutral-200 text-sm focus:outline-none focus:border-primary" /></div>)}
          </div>
          <div className="mt-5 flex justify-end"><button onClick={() => setGen(true)} className="h-10 px-5 rounded-full bg-[#4338CA] text-white text-sm font-semibold inline-flex items-center gap-2 hover:brightness-110"><Icon name="spark" size={15} /> Generate with AI</button></div>
        </>) : (<>
          <p className="mt-4 text-[12px] font-bold uppercase tracking-wide text-neutral-400">Generated brief</p>
          <div className="mt-2 rounded-xl border border-neutral-200 bg-neutral-50 p-4 text-[14px] text-neutral-700 leading-relaxed">{brief}</div>
          <div className="mt-4 flex justify-end gap-2"><button onClick={() => setGen(false)} className="h-10 px-4 rounded-full border border-neutral-200 text-sm font-semibold hover:bg-neutral-50">Regenerate</button><button onClick={onClose} className="h-10 px-5 rounded-full bg-ink text-white text-sm font-semibold hover:bg-black">Use this brief</button></div>
        </>)}
      </div>
    </div>
  );
}

/* ---------- "Add to SEEK Pass" ---------- */
function SeekPassButton({ credential }) {
  const on = useFeature('seekpass');
  const [open, setOpen] = React.useState(false);
  const [added, setAdded] = React.useState(false);
  if (!on) return null;
  return (<>
    <button onClick={() => setOpen(true)} className="h-11 px-5 rounded-full text-white text-[15px] font-bold inline-flex items-center gap-2 hover:brightness-105" style={{ background: '#0D3880' }}><span className="w-5 h-5 rounded bg-white/20 flex items-center justify-center text-[10px] font-black">✓</span> Add to SEEK Pass</button>
    {open && (
      <div className="fixed inset-0 z-[130] flex items-center justify-center px-4 bg-black/50 backdrop-blur-sm" onClick={() => setOpen(false)}>
        <div className="w-full max-w-md bg-white rounded-2xl shadow-2xl p-6 text-left" onClick={e => e.stopPropagation()}>
          {!added ? (<>
            <div className="flex items-start justify-between"><div className="flex items-center gap-2"><span className="w-9 h-9 rounded-lg text-white flex items-center justify-center font-black text-sm" style={{ background: '#0D3880' }}>SP</span><h3 className="text-lg font-bold text-ink" style={{ fontFamily: _pp }}>Add to SEEK Pass</h3></div><button onClick={() => setOpen(false)} className="text-neutral-400 hover:text-neutral-700"><Icon name="close" size={20} /></button></div>
            <p className="mt-3 text-[14px] text-neutral-600 leading-relaxed">Add this Mereka credential as a <span className="font-semibold text-ink">verified credential</span> in your SEEK Pass. Share it with employers on Jobstreet — verified candidates are ~16% more likely to be shortlisted.</p>
            <div className="mt-4 rounded-xl border border-neutral-200 p-3 text-sm"><p className="font-bold text-ink">{credential || 'AI4U Learning Path — Certificate of Completion'}</p><p className="text-neutral-500 text-[13px]">Issued by Mereka · Verified ✓</p></div>
            <p className="mt-3 text-[12px] text-neutral-400">You control your data and can unshare this credential from SEEK Pass at any time.</p>
            <div className="mt-5 flex justify-end gap-2"><button onClick={() => setOpen(false)} className="h-10 px-4 rounded-full border border-neutral-200 text-sm font-semibold hover:bg-neutral-50">Cancel</button><button onClick={() => setAdded(true)} className="h-10 px-5 rounded-full text-white text-sm font-semibold hover:brightness-105" style={{ background: '#0D3880' }}>Add credential</button></div>
          </>) : (
            <div className="text-center py-4"><div className="w-14 h-14 rounded-2xl mx-auto flex items-center justify-center mb-3 text-white" style={{ background: '#0D3880' }}><Icon name="check" size={30} /></div><h4 className="font-bold text-ink text-lg" style={{ fontFamily: _pp }}>Added to SEEK Pass</h4><p className="text-sm text-neutral-600 mt-1">Your verified credential is now in SEEK Pass and ready to share on Jobstreet.</p><button onClick={() => { setOpen(false); }} className="mt-4 h-10 px-5 rounded-full bg-ink text-white text-sm font-semibold hover:bg-black">Done</button></div>
          )}
        </div>
      </div>
    )}
  </>);
}

/* ---------- Learning Path Journey (living profile) ---------- */
function ProgrammeJourney() {
  const on = useFeature('journey');
  if (!on) return null;
  const icon = { programme: 'programme', course: 'courses', certificate: 'award', assessment: 'check', employment: 'briefcase' };
  const col = { programme: '#1F3F7C', course: '#1FA3A6', certificate: '#E8B23A', assessment: '#1FA85B', employment: '#5C7DB8' };
  return (
    <div className="bg-white border border-neutral-200 rounded-2xl p-6">
      <div className="flex items-center gap-2 mb-4"><h3 className="text-xl font-bold text-ink" style={{ fontFamily: _pp }}>Learning Path Journey</h3><span className="text-[11px] font-semibold text-neutral-400">auto-updated by Agent E</span></div>
      <div className="relative pl-2">
        {NEOL_JOURNEY.map((e, i) => (
          <div key={i} className="flex gap-3 pb-5 last:pb-0 relative">
            {i < NEOL_JOURNEY.length - 1 && <span className="absolute left-[15px] top-8 bottom-0 w-px bg-neutral-200" />}
            <span className="w-8 h-8 rounded-full flex items-center justify-center text-white flex-shrink-0 relative z-10" style={{ background: e.done ? col[e.kind] : '#CBD5E1' }}><Icon name={icon[e.kind]} size={15} /></span>
            <div className="min-w-0"><div className="flex items-center gap-2 flex-wrap"><span className="font-bold text-ink text-sm">{e.title}</span><span className="text-[11px] text-neutral-400">{e.date}</span>{!e.done && <span className="px-1.5 h-4 inline-flex items-center rounded-full bg-[#EAF0F8] text-support text-[10px] font-bold">In progress</span>}</div><p className="text-[13px] text-neutral-500">{e.detail}</p></div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ---------- Feature-flags switcher (bottom-right) ---------- */
function FeatureFlagsPanel() {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  const gami = (typeof useGamiOn === 'function') ? useGamiOn() : true;
  const applications = useFeature('applications');
  const trainers = useFeature('trainers');
  const seekpass = useFeature('seekpass');
  const journey = useFeature('journey');
  const aibrief = useFeature('aibrief');
  const dockOpen = useDockOpen();
  React.useEffect(() => { if (!open) return; const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }; document.addEventListener('click', h); return () => document.removeEventListener('click', h); }, [open]);
  const rows = [
    ['Gamification', gami, (v) => (typeof setGamiOn === 'function') && setGamiOn(v), 'Points, quests, badges, streak, membership'],
    ['Applications & AI review', applications, (v) => setFeature('applications', v), 'Agent E application evaluation + Respond.io'],
    ['Trainer Network', trainers, (v) => setFeature('trainers', v), 'NL search, AI match, invite, CSV import'],
    ['SEEK Pass credential', seekpass, (v) => setFeature('seekpass', v), '"Add to SEEK Pass" on certificates'],
    ['Learning Path Journey', journey, (v) => setFeature('journey', v), 'Living profile timeline on learner page'],
    ['AI Brief (AI writer)', aibrief, (v) => setFeature('aibrief', v), 'Draft learning path briefs in the wizard'],
  ];
  const Switch = ({ v, on }) => <span onClick={() => on(!v)} className={`inline-flex items-center h-5 w-9 rounded-full p-0.5 cursor-pointer transition-colors flex-shrink-0 ${v ? 'bg-primary' : 'bg-neutral-300'}`}><span className={`w-4 h-4 rounded-full bg-white shadow transform transition-transform ${v ? 'translate-x-4' : ''}`} /></span>;
  if (!dockOpen) return null;
  return ReactDOM.createPortal(
    <div className="fixed bottom-[128px] right-0 z-50" ref={ref}>
      {open && (
        <div className="absolute bottom-[calc(100%+10px)] right-2 w-[300px] max-w-[92vw] bg-white rounded-2xl border border-neutral-200 overflow-hidden" style={{ boxShadow: '0 18px 48px rgba(0,0,0,0.18)' }}>
          <div className="px-4 py-3 border-b border-neutral-100"><p className="font-bold text-ink text-sm" style={{ fontFamily: _pp }}>Feature switcher</p><p className="text-[11px] text-neutral-400">Show or hide prototype features</p></div>
          <div className="max-h-[60vh] overflow-y-auto">
            {rows.map(([label, v, on, desc]) => (
              <div key={label} className="flex items-start gap-3 px-4 py-3 border-b border-neutral-50 last:border-0"><div className="min-w-0 flex-1"><p className="text-[13px] font-semibold text-ink">{label}</p><p className="text-[11px] text-neutral-400 leading-snug">{desc}</p></div><Switch v={v} on={on} /></div>
            ))}
          </div>
        </div>
      )}
      <button onClick={() => setOpen(o => !o)} className="inline-flex items-center gap-2 pl-4 pr-5 py-2.5 rounded-l-full shadow-lg bg-ink text-white hover:bg-black transition-all">
        <Icon name="settings" size={16} /> Features
      </button>
    </div>, document.body);
}


/* ---------- Unified dev dock: Features + Pages (cohesive, animated) ---------- */
function DevDock() {
  const open = useDockOpen();
  const [featOpen, setFeatOpen] = React.useState(false);
  const [pagesOpen, setPagesOpen] = React.useState(false);
  const [q, setQ] = React.useState('');
  const ref = React.useRef(null);
  const gami = (typeof useGamiOn === 'function') ? useGamiOn() : true;
  const applications = useFeature('applications');
  const trainers = useFeature('trainers');
  const seekpass = useFeature('seekpass');
  const journey = useFeature('journey');
  const aibrief = useFeature('aibrief');
  const rows = [
    ['Gamification', gami, (v) => (typeof setGamiOn === 'function') && setGamiOn(v), 'Points, quests, badges, streak, membership'],
    ['Applications & AI review', applications, (v) => setFeature('applications', v), 'Agent E application evaluation + Respond.io'],
    ['Trainer Network', trainers, (v) => setFeature('trainers', v), 'NL search, AI match, invite, CSV import'],
    ['SEEK Pass credential', seekpass, (v) => setFeature('seekpass', v), '"Add to SEEK Pass" on certificates'],
    ['Learning Path Journey', journey, (v) => setFeature('journey', v), 'Living profile timeline on learner page'],
    ['AI Brief (AI writer)', aibrief, (v) => setFeature('aibrief', v), 'Draft learning path briefs in the wizard'],
  ];
  const Switch = ({ v, on }) => <span onClick={(e) => { e.stopPropagation(); on(!v); }} className={`inline-flex items-center h-5 w-9 rounded-full p-0.5 cursor-pointer transition-colors flex-shrink-0 ${v ? 'bg-primary' : 'bg-neutral-300'}`}><span className={`w-4 h-4 rounded-full bg-white shadow transform transition-transform ${v ? 'translate-x-4' : ''}`} /></span>;
  const all = React.useMemo(() => (typeof SITEMAP_GROUPS !== 'undefined' ? SITEMAP_GROUPS : []).flatMap(g => g.routes.map(r => ({ ...r, g: g.title }))), []);
  const filtered = q ? all.filter(r => (r.l + ' ' + r.p + ' ' + r.g).toLowerCase().includes(q.toLowerCase())) : all;
  React.useEffect(() => {
    const h = (e) => {
      if ((e.metaKey || e.ctrlKey) && (e.key === 'k' || e.key === 'K')) { e.preventDefault(); setPagesOpen(o => !o); }
      if (e.key === 'Escape') { setPagesOpen(false); setFeatOpen(false); }
    };
    window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h);
  }, []);
  React.useEffect(() => {
    if (!featOpen) return;
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setFeatOpen(false); };
    document.addEventListener('mousedown', h); return () => document.removeEventListener('mousedown', h);
  }, [featOpen]);
  const collapse = () => { setFeatOpen(false); setDockOpen(!open); };

  return ReactDOM.createPortal(<>
    <div ref={ref} className="fixed right-0 bottom-6 z-[60] transition-transform duration-300 ease-out" style={{ transform: open ? 'translateX(0)' : 'translateX(100%)' }}>
      {/* grip handle (rides to the edge when collapsed) */}
      <button onClick={collapse} aria-label={open ? 'Hide tools' : 'Show tools'} title={open ? 'Hide tools' : 'Show tools'}
        className="absolute right-full top-1/2 -translate-y-1/2 w-6 h-16 rounded-l-xl bg-ink text-white/70 hover:text-white flex items-center justify-center transition-colors"
        style={{ boxShadow: '-6px 0 18px rgba(0,0,0,0.14)' }}>
        <Icon name={open ? 'chevronRight' : 'chevronLeft'} size={15} />
      </button>

      {/* feature switcher popup */}
      <div className={`absolute bottom-[calc(100%+10px)] right-0 w-[300px] max-w-[86vw] bg-white rounded-2xl border border-neutral-200 overflow-hidden origin-bottom-right transition-all duration-200 ease-out ${featOpen ? 'opacity-100 scale-100 translate-y-0 pointer-events-auto' : 'opacity-0 scale-95 translate-y-1 pointer-events-none'}`} style={{ boxShadow: '0 18px 48px rgba(0,0,0,0.20)' }}>
        <div className="px-4 py-3 border-b border-neutral-100"><p className="font-bold text-ink text-sm" style={{ fontFamily: _pp }}>Feature switcher</p><p className="text-[11px] text-neutral-400">Show or hide prototype features</p></div>
        <div className="max-h-[56vh] overflow-y-auto">
          {rows.map(([label, v, on, desc]) => (
            <div key={label} onClick={() => on(!v)} className="flex items-start gap-3 px-4 py-3 border-b border-neutral-50 last:border-0 cursor-pointer hover:bg-neutral-50"><div className="min-w-0 flex-1"><p className="text-[13px] font-semibold text-ink">{label}</p><p className="text-[11px] text-neutral-400 leading-snug">{desc}</p></div><Switch v={v} on={on} /></div>
          ))}
        </div>
      </div>

      {/* cohesive dark card: Features + Pages rows */}
      <div className="rounded-l-2xl bg-ink text-white overflow-hidden w-[186px]" style={{ boxShadow: '0 12px 40px rgba(0,0,0,0.28)' }}>
        <button onClick={() => setFeatOpen(o => !o)} className={`w-full flex items-center gap-2.5 px-4 h-12 text-[15px] font-medium transition-colors ${featOpen ? 'bg-white/10' : 'hover:bg-white/[0.07]'}`}>
          <Icon name="settings" size={17} /> Features <Icon name="chevronDown" size={14} className={`ml-auto text-white/45 transition-transform duration-200 ${featOpen ? 'rotate-180' : ''}`} />
        </button>
        <div className="h-px bg-white/10" />
        <button onClick={() => setPagesOpen(true)} className="w-full flex items-center gap-2.5 px-4 h-12 text-[15px] font-medium hover:bg-white/[0.07] transition-colors">
          <Icon name="layers" size={17} /> Pages <kbd className="ml-auto hidden md:inline-flex items-center px-1.5 py-0.5 bg-white/10 rounded text-[11px] font-mono text-white/70">⌘K</kbd>
        </button>
      </div>
    </div>

    {/* Pages jump modal */}
    {pagesOpen && (
      <div className="fixed inset-0 z-[100] flex items-start justify-center pt-24 px-4 bg-black/50 backdrop-blur-sm" onClick={() => setPagesOpen(false)}>
        <div className="w-full max-w-xl bg-white rounded-2xl shadow-2xl overflow-hidden" onClick={e => e.stopPropagation()}>
          <div className="flex items-center gap-3 px-4 py-3 border-b border-neutral-200">
            <Icon name="search" size={16} className="text-neutral-400" />
            <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="Jump to a page…" className="flex-1 text-sm focus:outline-none placeholder:text-neutral-400" />
            <button className="text-xs px-2 py-1 text-neutral-500 hover:bg-neutral-100 rounded" onClick={() => setPagesOpen(false)}>Esc</button>
          </div>
          <div className="max-h-[60vh] overflow-y-auto scrollbar-thin">
            {filtered.length === 0 && <div className="p-8 text-center text-sm text-neutral-500">No matches.</div>}
            {filtered.slice(0, 40).map((r) => (
              <button key={r.p} onClick={() => { navigate(r.p); setPagesOpen(false); }} className="w-full text-left px-4 py-2.5 hover:bg-neutral-50 flex items-center justify-between border-b border-neutral-50 last:border-0">
                <div><div className="text-sm font-medium">{r.l}</div><div className="text-[12px] text-neutral-500">{r.g}</div></div>
                <span className="text-[11px] font-mono text-neutral-400">{r.p}</span>
              </button>
            ))}
          </div>
          <div className="px-4 py-2 text-xs text-neutral-500 bg-neutral-50 border-t border-neutral-100 flex items-center justify-between">
            <span>{all.length} pages total</span>
            <Link to="/sitemap" onClick={() => setPagesOpen(false)} className="text-primary font-medium hover:underline">Open full sitemap →</Link>
          </div>
        </div>
      </div>
    )}
  </>, document.body);
}

Object.assign(window, {
  useFeature, getFeature, setFeature, DevDock,
  NeolApplicationsPage, NeolApplicationDetailPage, NeolTrainersPage, NeolTrainerDetailPage,
  NeolAiBriefModal, NeolCsvModal, SeekPassButton, ProgrammeJourney, FeatureFlagsPanel,
  useDockOpen, setDockOpen, DevDockToggle,
});
