const { useState, useEffect, useRef, useMemo } = React;

/* ========== Stub API ========== */
function _delay(ms) { return new Promise(r => setTimeout(r, ms)); }

async function createCandidate(payload) {
  await _delay(600);
  return { id: 'demo-cand-001', status: 'created' };
}
async function createIntakeSession(payload) {
  await _delay(400);
  return { id: 'demo-sess-001', status: 'created', candidate_id: payload.candidate_id };
}
async function saveIntakeAnswers(sessionId, answers) {
  await _delay(300);
  return { session_id: sessionId, saved: answers.length };
}
async function completeIntakeSession(sessionId) {
  await _delay(800);
  return { session_id: sessionId, status: 'completed', reviewer_card_id: 'demo-card-001', salesforce_outbox_created: false };
}
async function startIntakeFromToken(token) {
  await _delay(400);
  throw new Error('Demo mode: token intake not available');
}
async function getReviewerCandidates() {
  await _delay(500);
  return MOCK_REVIEWER_ROWS;
}
async function getReviewerCard(sessionId) {
  await _delay(400);
  return MOCK_CARDS[sessionId] || MOCK_CARDS['demo-sess-001'];
}
async function getReviewerOutbox(sessionId) {
  await _delay(300);
  return { status: 'pending', operation: 'upsert_candidate_lead' };
}

/* ========== Mock reviewer data ========== */
const MOCK_REVIEWER_ROWS = [
  {
    session_id: 'demo-sess-001',
    name: 'מיכל לוי',
    business_domain: 'מזון',
    business_stage: 'רעיון עסקי',
    status: 'completed',
    reviewer_status: 'needs_missing_info',
    overall_score: 72,
    recommended_next_step: 'route_to_business_idea_track',
  },
  {
    session_id: 'demo-sess-002',
    name: 'סאמר אבו סאלח',
    business_domain: 'אירועים הפקה ועיצוב',
    business_stage: 'עסק פעיל',
    status: 'completed',
    reviewer_status: 'pending',
    overall_score: 81,
    recommended_next_step: 'route_to_existing_business_track',
  },
  {
    session_id: 'demo-sess-003',
    name: 'רות כהן',
    business_domain: 'טקסטיל/ביגוד',
    business_stage: 'עסק פעיל',
    status: 'completed',
    reviewer_status: 'requires_human_attention',
    overall_score: 88,
    recommended_next_step: 'schedule_phone_call',
  },
];

const MOCK_CARDS = {
  'demo-sess-001': {
    title: 'מיכל לוי',
    candidate: { name: 'מיכל לוי', city: 'חיפה', mobile_phone: '052-1234567', email: 'michal@example.com', region: 'מרכז' },
    business_domain: 'מזון',
    business_stage: 'רעיון עסקי',
    employment_status: 'שכירה',
    reviewer_status: 'needs_missing_info',
    recommended_next_step: 'route_to_business_idea_track',
    questionnaire: { status: 'completed' },
    scoring: {
      overall_reviewer_score: 72,
      data_completeness_score: 64,
      economic_fit_score: 75,
      business_readiness_score: 68,
      commitment_score: 80,
    },
    ai_summary: {
      summary: 'מיכל היא שכירה שרוצה לפתוח עסק ביתי לקינוחים. יש לה מוטיבציה ברורה ורעיון מגובש, אך חסרים נתוני תמחור, בדיקת שוק ומידע על זמינות שבועית. הסף הכלכלי לא ברור לגמרי.',
      confidence: 0.72,
    },
    missing_information: ['missing_business_stage', 'missing_economic_snapshot'],
    risk_flags: [],
    strength_indicators: ['מוטיבציה גבוהה', 'רעיון מוגדר', 'ניסיון תחביב בתחום'],
    salesforce_outbox: { status: 'pending', operation: 'upsert_candidate_lead' },
  },
  'demo-sess-002': {
    title: 'סאמר אבו סאלח',
    candidate: { name: 'סאמר אבו סאלח', city: 'נצרת', mobile_phone: '054-9876543', email: '', region: 'הצפון' },
    business_domain: 'אירועים הפקה ועיצוב',
    business_stage: 'עסק פעיל',
    employment_status: 'עצמאית',
    reviewer_status: 'pending',
    recommended_next_step: 'route_to_existing_business_track',
    questionnaire: { status: 'completed' },
    scoring: {
      overall_reviewer_score: 81,
      data_completeness_score: 78,
      economic_fit_score: 82,
      business_readiness_score: 85,
      commitment_score: 79,
    },
    ai_summary: {
      summary: 'סאמר עוסקת בעיצוב חינות ואירועים ומבצעת מכירות בפועל. יש לה ניסיון מעשי ובסיס לקוחות ראשוני, אך חסרה מסגרת עסקית מסודרת ותמחור עקבי.',
      confidence: 0.81,
    },
    missing_information: ['missing_email'],
    risk_flags: [],
    strength_indicators: ['עסק פעיל עם הכנסה', 'לקוחות חוזרים', 'ניסיון מוכח'],
    salesforce_outbox: { status: 'pending', operation: 'upsert_candidate_lead' },
  },
  'demo-sess-003': {
    title: 'רות כהן',
    candidate: { name: 'רות כהן', city: 'באר שבע', mobile_phone: '050-1112233', email: 'ruth@example.com', region: 'הדרום' },
    business_domain: 'טקסטיל/ביגוד',
    business_stage: 'עסק פעיל',
    employment_status: 'עצמאית',
    reviewer_status: 'requires_human_attention',
    recommended_next_step: 'schedule_phone_call',
    questionnaire: { status: 'completed' },
    scoring: {
      overall_reviewer_score: 88,
      data_completeness_score: 85,
      economic_fit_score: 90,
      business_readiness_score: 92,
      commitment_score: 88,
    },
    ai_summary: {
      summary: 'רות מפעילה סטודיו תפירה ותיקונים עם בסיס לקוחות יציב. ההכנסה קבועה אך הצמיחה מוגבלת. סומנה לבדיקה אנושית בגלל נסיבות אישיות שצוינו.',
      confidence: 0.88,
    },
    missing_information: [],
    risk_flags: ['exceptional_circumstances_for_human_review'],
    strength_indicators: ['עסק פעיל', 'הכנסה יציבה', 'בסיס לקוחות מבוסס', 'ניסיון מקצועי רב'],
    salesforce_outbox: { status: 'pending', operation: 'upsert_candidate_lead' },
  },
};

/* ========== SimpleHeader ========== */
function SimpleHeader({ title, subtitle }) {
  return (
    <header className="app-header">
      <div className="app-header-inner">
        <div className="logo">
          <img src="/demo/assets/logo.png" alt="יוזמות עתיד" />
          <div className="product-tag">
            <b>יוזמות עתיד</b>
            <span>{subtitle || title}</span>
          </div>
        </div>
        <div className="app-header-spacer" />
        <div style={{ textAlign: 'right', color: 'var(--fg-3)', fontSize: 13 }}>{title}</div>
      </div>
    </header>
  );
}

/* ========== DemoApp (router) ========== */
function DemoApp() {
  const [view, setView] = useState('apply');

  // Allow Completion screen to navigate to reviewer
  window.__demoNavigate = setView;

  return (
    <div className="app-shell" dir="rtl">
      <header className="app-header">
        <div className="app-header-inner">
          <div className="logo">
            <img src="/demo/assets/logo.png" alt="יוזמות עתיד" />
            <div className="product-tag">
              <b>מלווה קליטה חכם</b>
              <span>גרסת הדגמה</span>
            </div>
          </div>
          <div className="app-header-spacer" />
          <div className="role-switch" role="tablist">
            <button
              className={view === 'apply' ? 'active' : ''}
              onClick={() => setView('apply')}
            >פונה</button>
            <button
              className={view === 'reviewer' ? 'active' : ''}
              onClick={() => setView('reviewer')}
            >מעריכה</button>
          </div>
        </div>
      </header>
      <main className="app-main">
        {view === 'apply' ? <ApplyApp /> : <ReviewerApp />}
      </main>
    </div>
  );
}

/* ========================================================
   APPLY APP
   ======================================================== */

const ALIMONY_AMOUNT_Q = {
  id: 'alimonyAmount',
  q: 'מה הסכום החודשי של המזונות?',
  type: 'number',
  skipLabel: 'אעדיף לדון עם נציגה',
};

const BENEFITS_AMOUNT_Q = {
  id: 'benefitsAmount',
  q: 'מה הסכום החודשי הכולל של הקצבאות או הפנסיה?',
  type: 'number',
  helper: 'קצבאות נחשבות ב-50% מסכומן לחישוב הסף הכלכלי',
  skipLabel: 'אעדיף לדון עם נציגה',
};

const INCOME_FIELDS_TO_VALIDATE = ['salaryIncome', 'businessIncome', 'partnerIncome'];

function buildChatScript() {
  return [
    { id: 'familyStatus', q: 'מה מצבך המשפחתי?', chips: ['נשואה / בזוגיות', 'גרושה / חד הורית / הורות משותפת', 'רווקה', 'אלמנה'] },
    { id: 'householdSize', q: 'כמה אנשים חיים בבית ונמצאים תחת האחריות הכלכלית שלך?', type: 'number', helper: 'כולל אותך ובן הזוג אם יש — הזיני מספר' },
    { id: 'employmentStatus', q: 'מה מצבך התעסוקתי כיום?', chips: ['עצמאית', 'שכירה', 'שכירה ועצמאית', 'מובטלת', 'לא עובדת'] },
    { id: 'alimony', q: 'האם את מקבלת מזונות?', type: 'yesno' },
    { id: 'benefits', q: 'האם יש לך קצבאות (נכות, ילדים, ביטוח לאומי) או פנסיה?', type: 'yesno' },
    {
      id: 'exceptionalCircumstances', sensitive: true,
      helper: 'שאלה זו מיועדת לנסיבות שאינן באות לידי ביטוי בנתונים הכלכליים: מילואים בשנה האחרונה, מגורים בחיפה וצפונה, או נסיבות אישיות משמעותיות. אפשר גם לדלג ולדבר על זה עם נציגה.',
      q: 'האם קיימות נסיבות חיים חריגות שחשוב שנכיר בבדיקת ההתאמה?',
      chips: ['מילואים בשנה האחרונה', 'מגורים בחיפה וצפונה', 'נסיבות אישיות משמעותיות', 'אין נסיבות חריגות'],
      skipLabel: 'דלגי על השאלה',
    },
    { id: 'community', q: 'האם את משתייכת לאחת מהקהילות הבאות? השאלה משפיעה על זכאות למלגות ייעודיות.', chips: ['חרדים', 'אתיופים', 'ערבים', 'דרוזים', 'בדואים', 'ללא שיוך מיוחד'] },
    { id: 'courseCommitment', q: 'הקורס מתקיים פעם בשבוע בבוקר (10:00–13:00), למשך 9 שבועות — נוכחות חובה. האם תוכלי להתחייב?', chips: ['כן', 'לא בטוחה', 'לא'] },
    { id: 'businessStage', q: 'באיזה שלב נמצא היום הרעיון או העסק שלך?', chips: ['רק רעיון ראשוני', 'בדקתי ביקוש', 'כבר מכרתי כמה פעמים', 'יש עסק פעיל'] },
    { id: 'customerExperience', q: 'מה כבר קרה בפועל מול לקוחות?', chips: ['עוד לא פניתי ללקוחות', 'קיבלתי תגובות', 'מכרתי חד פעמית', 'יש לקוחות חוזרים'] },
    { id: 'description', q: 'תארי בקצרה את הרעיון שלך - על מה את חולמת?', type: 'text' },
    { id: 'challenge', q: 'מה הכי עוצר אותך כרגע?', chips: ['לא יודעת לתמחר', 'לא יודעת לשווק', 'חוששת לעזוב עבודה', 'אין הון התחלתי', 'הכל נראה ערפולי'] },
    { id: 'goal', q: 'מה המטרה המרכזית שלך מהתוכנית?', chips: ['להבין אם הרעיון מתאים לי', 'לפתוח עסק מסודר', 'להגדיל הכנסות', 'לבנות תמחור ושיווק'] },
    { id: 'missing', q: 'מה הכי חסר לך כדי להתקדם?', chips: ['תמחור', 'שיווק ולקוחות', 'ניהול כספים', 'ביטחון ותוכנית פעולה'] },
    { id: 'timeInvestment', q: 'כמה זמן תוכלי להשקיע בעבודה על העסק מחוץ למפגשי הקורס?', chips: ['עד 3 שעות בשבוע', '3-6 שעות', '6-10 שעות', 'יותר מ-10 שעות'] },
    { id: 'priorExperience', q: 'האם יש לך ניסיון קודם בתחום העסקי או המקצועי הזה?', chips: ['ניסיון מקצועי', 'תחביב/התנסות אישית', 'לימודים בלבד', 'אין ניסיון עדיין'] },
    { id: 'preferredContact', q: 'מתי נוח שניצור איתך קשר?', chips: ['בוקר 9:00-12:00', 'צהריים 12:00-15:00', 'אחה"צ 15:00-18:00'] },
  ];
}

const REGION_OPTIONS = ['גוש דן', 'מרכז', 'ירושלים והסביבה', 'חיפה', 'הצפון', 'השרון', 'השפלה', 'הדרום', 'יהודה ושומרון', 'אחר'];
const BUSINESS_TYPE_OPTIONS = ['עסק פעיל', 'רעיון עסקי'];
const BUSINESS_DOMAIN_OPTIONS = [
  'אדריכלות ועיצוב פנים','איור וציור',"אימון/קואצ'ינג",'אירועים הפקה ועיצוב','אמנות עבודת יד',
  'בית/גינון','דיגיטלי','הדרכת חוגים/סדנאות/הוראה','חנות כללית','טיפול אלטרנטיבי רפואי',
  'טיפול בילדים','טיפול רגשי','טכנאות','טקסטיל/ביגוד','כלכלה וחשבונאות','כתיבה ועריכה ספרותית',
  'מזון','מכירה באינטרנט','מקצועות היופי','מקצועות מעולם הדת','מקצועות משרד','ספורט',
  'עיצוב גרפי','צילום','רפואה משלימה','תיווך נדלן','תיירות, הפקת טיולים / סיורים','תיירות, צימרים ואכסניות',
];
const REFERRAL_SOURCE_OPTIONS = ['גוגל',"שת\"פ (ארגון/עמותה אחרת)",'פייסבוק','אתר העמותה','פה לאוזן','יזמת עבר','דרך הבנק','טלוויזיה','רדיו','עיתונות ארצית','עיתונות מקומית','פלאיירים/שלטי חוצות','אירועי העמותה','כנס שנתי','מלווה פרילנס','אחר'];

function calcAge(dateStr) {
  const birth = new Date(dateStr);
  if (isNaN(birth.getTime())) return null;
  const today = new Date();
  let age = today.getFullYear() - birth.getFullYear();
  const m = today.getMonth() - birth.getMonth();
  if (m < 0 || (m === 0 && today.getDate() < birth.getDate())) age--;
  return age;
}

function ApplyApp() {
  const [screen, setScreen] = useState('welcome');
  const [formData, setFormData] = useState({
    firstName: '', lastName: '', birthDate: '', phone: '', email: '',
    region: '', city: '', hasBusinessIdea: '', businessDomain: '', referralSource: '',
  });
  const [submitState, setSubmitState] = useState({ loading: false, error: '', result: null });

  const goto = (next) => { setScreen(next); window.scrollTo({ top: 0, behavior: 'smooth' }); };

  async function submitApplication(chatAnswers) {
    setSubmitState({ loading: true, error: '', result: null });
    goto('processing');
    try {
      const candidate = await createCandidate({
        first_name: formData.firstName, last_name: formData.lastName,
        email: formData.email || undefined, mobile_phone: formData.phone,
        city: formData.city || undefined, region: formData.region || 'לא צוין',
        preferred_language: 'עברית', source_channel: 'website', source_detail: 'apply_form', privacy_consent: true,
      });
      const session = await createIntakeSession({ candidate_id: candidate.id, questionnaire_type: _questionnaireType(chatAnswers.businessStage?.value) });
      await saveIntakeAnswers(session.id, _buildAnswers(formData, chatAnswers));
      const completed = await completeIntakeSession(session.id);
      setSubmitState({ loading: false, error: '', result: { candidate, session, completed } });
    } catch (err) {
      setSubmitState({ loading: false, error: err instanceof Error ? err.message : 'השליחה נכשלה', result: null });
    }
  }

  return (
    <>
      {screen === 'welcome'    && <Welcome onStart={() => goto('form')} />}
      {screen === 'form'       && <ApplyForm data={formData} setData={setFormData} onNext={() => goto('chat')} />}
      {screen === 'chat'       && <ChatScreen firstName={formData.firstName} onComplete={(answers) => submitApplication(answers)} />}
      {screen === 'processing' && <Processing loading={submitState.loading} error={submitState.error} result={submitState.result} onDone={() => goto('complete')} onBack={() => goto('chat')} />}
      {screen === 'complete'   && <Completion result={submitState.result} />}
    </>
  );
}

function Welcome({ onStart }) {
  return (
    <section className="welcome-wrap">
      <div className="welcome-eyebrow">בדיקת התאמה · 5 דקות</div>
      <h1>ברוכה הבאה ליוזמות עתיד</h1>
      <p className="welcome-sub">כמה שאלות קצרות יעזרו לנו להבין איפה את נמצאת היום, מה החלום העסקי שלך, ואיזה ליווי יכול להתאים לך.</p>
      <div className="welcome-trust">
        <div className="icon" aria-hidden="true">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M12 2 4 6v6c0 5 3.5 9 8 10 4.5-1 8-5 8-10V6z" />
          </svg>
        </div>
        <p><b>המידע שלך נשמר לצורך בדיקת התאמה בלבד.</b> ההמלצה מסייעת לצוות, וההחלטה הסופית מתקבלת על ידי אדם.</p>
      </div>
      <button className="btn btn-primary" onClick={onStart}>התחילי בדיקת התאמה <span aria-hidden="true">←</span></button>
      <div className="welcome-divider"><img src="/demo/assets/dots.png" alt="" /></div>
    </section>
  );
}

function ApplyForm({ data, setData, onNext }) {
  const set = (key) => (e) => setData({ ...data, [key]: e.target.value });

  const fillExample = () => setData({
    firstName: 'מיכל', lastName: 'לוי', birthDate: '1985-03-15', phone: '0521234567',
    email: 'michal@example.com', region: 'מרכז', city: 'רמת גן',
    hasBusinessIdea: 'רעיון עסקי', businessDomain: 'מזון', referralSource: 'פייסבוק',
  });

  const age = calcAge(data.birthDate);
  const ageError = data.birthDate && age !== null && age < 18 ? 'יש להיות בגירה (18+) כדי להירשם לתוכנית.' : null;
  const todayStr = new Date().toISOString().split('T')[0];
  const canNext = data.firstName.trim() && data.lastName.trim() && data.birthDate && !ageError &&
    data.phone.trim() && data.region && data.hasBusinessIdea && data.businessDomain && data.referralSource;

  return (
    <section className="form-wrap">
      <div className="form-progress">
        <span>שלב 1 מתוך 2</span>
        <div className="dots"><div className="dot cur"></div><div className="dot"></div></div>
      </div>
      <div className="form-card">
        <h2>כמה פרטים ראשוניים</h2>
        <p className="lede">התוכנית כוללת 5-9 מפגשי קורס וליווי מנטורינג אישי של כ-8 מפגשים. נבקש כמה פרטים בסיסיים כדי לבדוק התאמה לתוכנית.</p>
        <div className="form-grid">
          <div className="field">
            <label>שם פרטי <span style={{color:'var(--ya-red)'}}>*</span></label>
            <input value={data.firstName} onChange={set('firstName')} placeholder="שם פרטי" />
          </div>
          <div className="field">
            <label>שם משפחה <span style={{color:'var(--ya-red)'}}>*</span></label>
            <input value={data.lastName} onChange={set('lastName')} placeholder="שם משפחה" />
          </div>
          <div className="field">
            <label>תאריך לידה <span style={{color:'var(--ya-red)'}}>*</span></label>
            <input type="date" value={data.birthDate} onChange={set('birthDate')} max={todayStr} />
            {ageError && <span style={{color:'var(--ya-red)',fontSize:'0.85em',marginTop:4,display:'block'}}>{ageError}</span>}
          </div>
          <div className="field">
            <label>מספר טלפון נייד <span style={{color:'var(--ya-red)'}}>*</span></label>
            <input value={data.phone} onChange={set('phone')} placeholder="050-0000000" inputMode="tel" />
          </div>
          <div className="field">
            <label>דואר אלקטרוני</label>
            <input value={data.email} onChange={set('email')} placeholder="name@example.com" inputMode="email" />
          </div>
          <div className="field">
            <label>אזור מגורים <span style={{color:'var(--ya-red)'}}>*</span></label>
            <select value={data.region} onChange={set('region')}>
              <option value="">אנא בחרי אזור מגורים</option>
              {REGION_OPTIONS.map(o => <option key={o}>{o}</option>)}
            </select>
          </div>
          <div className="field">
            <label>עיר מגורים</label>
            <input value={data.city} onChange={set('city')} placeholder="עיר" />
          </div>
          <div className="field">
            <label>האם יש לך עסק או רעיון עסקי? <span style={{color:'var(--ya-red)'}}>*</span></label>
            <select value={data.hasBusinessIdea} onChange={set('hasBusinessIdea')}>
              <option value="">בחרי מהאפשרויות</option>
              {BUSINESS_TYPE_OPTIONS.map(o => <option key={o}>{o}</option>)}
            </select>
          </div>
          <div className="field">
            <label>סוג העסק <span style={{color:'var(--ya-red)'}}>*</span></label>
            <select value={data.businessDomain} onChange={set('businessDomain')}>
              <option value="">אנא בחרי את סוג העסק</option>
              {BUSINESS_DOMAIN_OPTIONS.map(o => <option key={o}>{o}</option>)}
            </select>
          </div>
          <div className="field">
            <label>איך שמעת והגעת אלינו? <span style={{color:'var(--ya-red)'}}>*</span></label>
            <select value={data.referralSource} onChange={set('referralSource')}>
              <option value="">אנא בחרי מהאפשרויות</option>
              {REFERRAL_SOURCE_OPTIONS.map(o => <option key={o}>{o}</option>)}
            </select>
          </div>
        </div>
        <div className="form-actions">
          <button className="btn btn-secondary btn-sm" onClick={fillExample} type="button">טעני דוגמה</button>
          <button className="btn btn-primary" onClick={onNext} disabled={!canNext}>המשיכי לשאלות המשך <span aria-hidden="true">←</span></button>
        </div>
      </div>
    </section>
  );
}

function ChatScreen({ firstName, onComplete }) {
  const greeting = firstName
    ? `שלום ${firstName}! אני המלווה החכמה של יוזמות עתיד. אשאל כמה שאלות לבדיקת ההתאמה לתוכנית המסובסדת — על מצבך המשפחתי, הכלכלי, והרעיון העסקי שלך. המידע נשמר בדיסקרטיות מלאה.`
    : 'שלום! אני המלווה החכמה של יוזמות עתיד. אשאל כמה שאלות לבדיקת ההתאמה לתוכנית המסובסדת.';

  const [messages, setMessages] = useState([{ from: 'bot', text: greeting }]);
  const [step, setStep] = useState(0);
  const [input, setInput] = useState('');
  const [typing, setTyping] = useState(false);
  const scrollRef = useRef(null);
  const scriptRef = useRef(null);
  const answersRef = useRef({});
  const historyRef = useRef([]);
  const generationRef = useRef(0);

  if (scriptRef.current === null) scriptRef.current = buildChatScript();

  useEffect(() => {
    const gen = generationRef.current;
    const t = setTimeout(() => { if (generationRef.current === gen) askNext(0); }, 700);
    return () => clearTimeout(t);
  }, []);

  useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, typing]);

  function askNext(index) {
    const gen = generationRef.current;
    const item = scriptRef.current[index];
    if (!item) return;
    if (item.isTransition) {
      setTyping(true);
      setTimeout(() => {
        if (generationRef.current !== gen) return;
        setTyping(false);
        setMessages(c => [...c, { from: 'bot', text: item.text }]);
        const next = index + 1;
        setStep(next);
        setTimeout(() => { if (generationRef.current === gen) askNext(next); }, 500);
      }, 800);
      return;
    }
    setTyping(true);
    setTimeout(() => {
      if (generationRef.current !== gen) return;
      setTyping(false);
      const msgs = [];
      if (item.helper) msgs.push({ from: 'helper', text: item.helper });
      const chips = item.type === 'yesno' ? ['כן', 'לא'] : (item.chips || null);
      msgs.push({ from: 'bot', text: item.q, chips, skipLabel: item.skipLabel || null, idx: index });
      setMessages(c => [...c, ...msgs]);
    }, 800);
  }

  function undoLastAnswer() {
    if (historyRef.current.length === 0) return;
    generationRef.current++;
    const prev = historyRef.current.pop();
    scriptRef.current = prev.script;
    answersRef.current = prev.answers;
    setTyping(false);
    setStep(prev.step);
    setMessages(prev.messages);
    setInput('');
  }

  function answer(text, isSkip = false) {
    const cq = scriptRef.current[step];
    historyRef.current.push({ script: [...scriptRef.current], answers: { ...answersRef.current }, step, messages });

    if (cq?.id === 'courseCommitment' && text === 'לא') {
      const gen = generationRef.current;
      setMessages(c => [...c, { from: 'user', text: 'לא' }]);
      setTyping(true);
      setTimeout(() => {
        if (generationRef.current !== gen) return;
        setTyping(false);
        setMessages(c => [...c, { from: 'bot', text: 'תודה רבה על פנייתך. הקורס מחייב נוכחות קבועה בשעות הבוקר. אם יהיה שינוי בלוח הזמנים שלך, את מוזמנת לפנות אלינו שוב. מאחלות לך הצלחה! 💛' }]);
        setTimeout(() => onComplete({ ...answersRef.current, _rejected: 'schedule' }), 1400);
      }, 600);
      return;
    }

    const isConfirm = Boolean(cq?._retryFor);
    if (cq?.id && !isConfirm) {
      answersRef.current[cq.id] = { question: cq.q, value: isSkip ? null : _parseAnswerValue(text, cq.type), text: isSkip ? '' : text, is_sensitive: Boolean(cq.sensitive || cq.type === 'number') };
    }

    if (cq?.id === 'familyStatus' && !isSkip && text !== 'רווקה') {
      scriptRef.current = [...scriptRef.current.slice(0, step + 1), { id: 'children', q: 'כמה ילדים יש לך?', chips: ['אין', '1', '2', '3', '4 ומעלה'] }, ...scriptRef.current.slice(step + 1)];
    }

    if (cq?.id === 'employmentStatus' && !isSkip) {
      const isSalaried = ['שכירה', 'שכירה ועצמאית'].includes(text);
      const isSelfEmployed = ['עצמאית', 'שכירה ועצמאית'].includes(text);
      const isUnemployed = text === 'מובטלת';
      const hasPartner = answersRef.current.familyStatus?.text === 'נשואה / בזוגיות';
      const toInject = [];
      if (isSalaried || isSelfEmployed || isUnemployed || hasPartner) {
        toInject.push({ id: '_finance_intro', isTransition: true, text: 'כמה שאלות על ההכנסה המשפחתית שלך. המידע נשמר בסודיות ומאפשר לחשב את הסף לתוכנית המסובסדת.' });
      }
      if (isSalaried) toInject.push({ id: 'salaryIncome', q: 'מה ההכנסה החודשית שלך כשכירה בממוצע בשלושת החודשים האחרונים (נטו)?', type: 'number', helper: 'ממוצע 3 חודשים אחרונים, נטו', skipLabel: 'אעדיף לדון עם נציגה' });
      if (isSelfEmployed) toInject.push({ id: 'businessIncome', q: 'מה ההכנסה החודשית הממוצעת שלך מהעסק בשלושת החודשים האחרונים?', type: 'number', helper: 'ממוצע 3 חודשים אחרונים, נטו', skipLabel: 'אעדיף לדון עם נציגה' });
      if (isUnemployed) toInject.push({ id: 'unemploymentIncome', q: 'מהו סכום דמי האבטלה שאת מקבלת בחודש?', type: 'number', skipLabel: 'אעדיף לדון עם נציגה' });
      if (hasPartner) toInject.push({ id: 'partnerIncome', q: 'מה ההכנסה החודשית הממוצעת של בן הזוג שלך (נטו) בשלושת החודשים האחרונים?', type: 'number', helper: 'ממוצע 3 חודשים אחרונים, נטו', skipLabel: 'אעדיף לדון עם נציגה' });
      if (toInject.length > 0) scriptRef.current = [...scriptRef.current.slice(0, step + 1), ...toInject, ...scriptRef.current.slice(step + 1)];
    }

    if (cq?.id === 'alimony' && text === 'כן') scriptRef.current = [...scriptRef.current.slice(0, step + 1), ALIMONY_AMOUNT_Q, ...scriptRef.current.slice(step + 1)];
    if (cq?.id === 'benefits' && text === 'כן') scriptRef.current = [...scriptRef.current.slice(0, step + 1), BENEFITS_AMOUNT_Q, ...scriptRef.current.slice(step + 1)];

    if (INCOME_FIELDS_TO_VALIDATE.includes(cq?.id) && !isSkip) {
      const num = _parseAnswerValue(text, 'number');
      if (typeof num === 'number' && num > 0 && num < 500) {
        scriptRef.current = [...scriptRef.current.slice(0, step + 1), { id: `${cq.id}_confirm`, q: `הסכום שהזנת הוא ${num.toLocaleString('he-IL')} ₪. נרצה לוודא — האם זה הסכום המלא?`, chips: ['כן, זה נכון', 'לא, אתקן'], _retryFor: cq.id }, ...scriptRef.current.slice(step + 1)];
      }
    }

    if (isConfirm && text === 'לא, אתקן') {
      const origQ = scriptRef.current.find(q => q.id === cq._retryFor);
      if (origQ) scriptRef.current = [...scriptRef.current.slice(0, step + 1), { ...origQ }, ...scriptRef.current.slice(step + 1)];
    }

    const gen = generationRef.current;
    setMessages(c => [...c, { from: 'user', text: isSkip ? (cq?.skipLabel || 'דלגי על השאלה') : text }]);
    const next = step + 1;
    setStep(next);
    if (next < scriptRef.current.length) {
      setTimeout(() => { if (generationRef.current === gen) askNext(next); }, 400);
    } else {
      setTyping(true);
      setTimeout(() => {
        if (generationRef.current !== gen) return;
        setTyping(false);
        setMessages(c => [...c, { from: 'bot', text: 'תודה רבה ששיתפת! אני בונה כעת תקציר ומסלול מומלץ למעריכה שלנו...' }]);
        setTimeout(() => { if (generationRef.current === gen) onComplete(answersRef.current); }, 1400);
      }, 700);
    }
  }

  function send() { if (!input.trim()) return; answer(input.trim()); setInput(''); }

  const cq = scriptRef.current[step];
  const isNumberQ = cq?.type === 'number';
  const showInput = step < scriptRef.current.length;
  const lastBot = [...messages].reverse().find(m => m.from === 'bot' && (m.chips?.length || m.skipLabel));
  const totalQ = scriptRef.current.filter(q => !q.isTransition && !q._retryFor).length;
  const answeredCount = Math.min(scriptRef.current.slice(0, step).filter(q => !q.isTransition && !q._retryFor).length, totalQ);
  const lastUserIdx = messages.reduce((last, m, i) => m.from === 'user' ? i : last, -1);
  const canUndo = historyRef.current.length > 0;

  return (
    <section className="chat-wrap">
      <div className="chat-shell">
        <div className="chat-head">
          <div className="avatar">AI</div>
          <div className="meta"><b>מלווה קליטה חכם</b><small><span className="live">מקשיבה כעת</span></small></div>
          <div className="chat-progress">{answeredCount}/{totalQ} שאלות</div>
        </div>
        <div className="chat-body" ref={scrollRef}>
          {messages.map((m, i) => {
            const isLastBot = m === lastBot;
            const isLastUser = m.from === 'user' && i === lastUserIdx;
            return (
              <React.Fragment key={i}>
                {m.from === 'helper' ? (
                  <div className="bubble helper"><b>למה אנחנו שואלות?</b><br />{m.text}</div>
                ) : (
                  <div className={`bubble ${m.from}`}>{m.text}</div>
                )}
                {isLastUser && canUndo && (
                  <div style={{display:'flex',justifyContent:'flex-end',marginTop:'-6px',marginBottom:'4px',paddingLeft:'4px'}}>
                    <button onClick={undoLastAnswer} title="ערכי תשובה" style={{background:'none',border:'none',cursor:'pointer',display:'flex',alignItems:'center',gap:'3px',color:'var(--ya-mint-deep)',fontSize:'0.72em',opacity:0.75,padding:'2px 4px',borderRadius:4}}>
                      <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z"/>
                      </svg>
                      ערכי
                    </button>
                  </div>
                )}
                {isLastBot && (m.chips?.length || m.skipLabel) && (
                  <div className="chips">
                    {m.chips?.map(chip => <button className="chip" key={chip} onClick={() => answer(chip)}>{chip}</button>)}
                    {m.skipLabel && <button className="chip skip" onClick={() => answer('', true)}>{m.skipLabel}</button>}
                  </div>
                )}
              </React.Fragment>
            );
          })}
          {typing && <div className="typing"><span></span><span></span><span></span></div>}
        </div>
        <div className="chat-input">
          <input
            placeholder={!showInput ? 'סיימנו, רגע...' : isNumberQ ? 'הכניסי מספר...' : 'כתבי תשובה משלך...'}
            inputMode={isNumberQ ? 'numeric' : undefined}
            value={input}
            onChange={e => setInput(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && send()}
            disabled={!showInput}
          />
          <button onClick={send} disabled={!input.trim() || !showInput} aria-label="שלחי">
            <span style={{transform:'scaleX(-1)',display:'inline-block'}}>➤</span>
          </button>
        </div>
      </div>
    </section>
  );
}

const PROC_STEPS = ['קוראת את התשובות','מחשבת קריטריון כלכלי','מזהה צרכים מרכזיים','בונה תקציר למעריכה','מציעה מסלול המשך','מסמנת שאלות חסרות'];

function Processing({ loading, error, result, onDone, onBack }) {
  const [active, setActive] = useState(0);
  useEffect(() => {
    if (active < PROC_STEPS.length) {
      const t = setTimeout(() => setActive(v => v + 1), 420);
      return () => clearTimeout(t);
    }
    if (!loading && !error && result) {
      const t = setTimeout(onDone, 500);
      return () => clearTimeout(t);
    }
  }, [active, loading, error, result, onDone]);

  return (
    <section className="proc-wrap">
      <div className="proc-orb" />
      <h2>בונה את התקציר שלך...</h2>
      <p>זה ייקח כמה שניות. כל ההמלצות עוברות בדיקה אנושית.</p>
      <div className="proc-steps">
        {PROC_STEPS.map((s, i) => {
          const state = i < active ? 'done' : i === active ? 'active' : '';
          return (
            <div className={`proc-step ${state}`} key={i}>
              <div className="check">{i < active ? '✓' : i === active ? '' : i + 1}</div>
              <span>{s}</span>
            </div>
          );
        })}
      </div>
      {error && (
        <div className="summary-card" style={{borderColor:'var(--ya-red)',marginTop:16}}>
          {error}
          <div className="form-actions" style={{justifyContent:'center'}}>
            <button className="btn btn-secondary" onClick={onBack}>חזרה לשאלון</button>
          </div>
        </div>
      )}
    </section>
  );
}

function Completion({ result }) {
  return (
    <section className="welcome-wrap">
      <div className="welcome-eyebrow">הטופס נשלח בהצלחה</div>
      <h1>תודה על השיתוף</h1>
      <p className="welcome-sub">התשובות שלך התקבלו ונבדקות כרגע על ידי מעריכה אנושית. בקרוב ניצור איתך קשר כדי להתאים את המסלול הנכון.</p>
      <div className="welcome-trust">
        <div className="icon" aria-hidden="true">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M20 6 9 17l-5-5" />
          </svg>
        </div>
        <p>מידע זה נשמר רק לצורך שיפור ההתאמה ולהחלטה אנושית. לא נעשה שימוש מחוץ לתהליך.</p>
      </div>
      <div className="form-actions" style={{justifyContent:'center'}}>
        <button className="btn btn-primary" onClick={() => window.__demoNavigate?.('reviewer')}>פתיחת מסך סוקרת</button>
      </div>
    </section>
  );
}

function _buildAnswers(formData, chatAnswers) {
  const base = [
    { question_key: 'candidate_first_name', answer_value: formData.firstName, answer_text: formData.firstName, is_sensitive: true },
    { question_key: 'candidate_last_name', answer_value: formData.lastName, answer_text: formData.lastName, is_sensitive: true },
    { question_key: 'birth_date', answer_value: formData.birthDate, answer_text: formData.birthDate, is_sensitive: false },
    { question_key: 'candidate_phone', answer_value: formData.phone, answer_text: formData.phone, is_sensitive: true },
    { question_key: 'region', answer_value: formData.region, answer_text: formData.region, is_sensitive: false },
    { question_key: 'business_domain', answer_value: formData.businessDomain, answer_text: formData.businessDomain, is_sensitive: false },
  ];
  const mapped = Object.entries(chatAnswers).flatMap(([key, item]) => {
    if (key.startsWith('_') || key.endsWith('_confirm')) return [];
    return [{ question_key: key, answer_value: item.value, answer_text: item.text, is_sensitive: item.is_sensitive }];
  });
  return [...base, ...mapped].filter(a => a.answer_value !== '' && a.answer_value !== undefined);
}

function _parseAnswerValue(text, type) {
  if (type !== 'number') return text;
  const digits = String(text || '').replace(/[^\d.]/g, '');
  return digits ? Number(digits) : text;
}

function _questionnaireType(stage) {
  if (stage === 'יש עסק פעיל') return 'existing_business';
  if (!stage) return 'unknown';
  return 'business_idea';
}

/* ========================================================
   REVIEWER APP
   ======================================================== */

const _missingLabels = {
  missing_name: 'חסר שם מלא',
  missing_email: 'חסר מייל',
  missing_phone: 'חסר טלפון',
  missing_privacy_consent: 'חסרה הסכמת פרטיות',
  missing_business_stage: 'חסר שלב עסקי',
  missing_business_domain: 'חסר תחום עסקי',
  missing_employment_status: 'חסר מצב תעסוקתי',
  missing_economic_snapshot: 'חסרה תמונה כלכלית מספקת',
};

const _riskLabels = {
  bankruptcy_or_execution_flag: 'דווח סימון פשיטת רגל / הוצאה לפועל',
  exceptional_circumstances_for_human_review: 'דווחו נסיבות חריגות לבדיקה אנושית',
};

const _nextStepLabels = {
  schedule_phone_call: 'לקבוע שיחת טלפון',
  request_missing_information: 'לבקש מידע חסר',
  route_to_business_idea_track: 'לנתב למסלול רעיון עסקי',
  route_to_existing_business_track: 'לנתב למסלול עסק קיים',
  manual_review_required: 'בדיקה ידנית נדרשת',
  not_enough_information: 'אין מספיק מידע',
};

function ReviewerApp() {
  const [rows, setRows] = useState([]);
  const [activeSessionId, setActiveSessionId] = useState('');
  const [card, setCard] = useState(null);
  const [outbox, setOutbox] = useState(null);
  const [search, setSearch] = useState('');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');

  useEffect(() => {
    let alive = true;
    getReviewerCandidates()
      .then(data => {
        if (!alive) return;
        setRows(data);
        const first = data.find(r => r.status === 'completed') || data[0];
        if (first?.session_id) setActiveSessionId(String(first.session_id));
      })
      .catch(err => setError(err instanceof Error ? err.message : 'טעינת מועמדות נכשלה'))
      .finally(() => setLoading(false));
    return () => { alive = false; };
  }, []);

  useEffect(() => {
    if (!activeSessionId) return;
    setCard(null); setOutbox(null);
    Promise.all([
      getReviewerCard(activeSessionId).catch(err => ({ error: err.message })),
      getReviewerOutbox(activeSessionId).catch(() => null),
    ]).then(([cardData, outboxData]) => {
      if (cardData && !cardData.error) setCard(cardData);
      setOutbox(outboxData);
    });
  }, [activeSessionId]);

  const filtered = useMemo(() => {
    const q = search.trim().toLowerCase();
    if (!q) return rows;
    return rows.filter(r => [r.name, r.business_domain, r.business_stage, r.status].filter(Boolean).some(v => String(v).toLowerCase().includes(q)));
  }, [rows, search]);

  const completedCount = rows.filter(r => r.status === 'completed').length;
  const needsInfoCount = rows.filter(r => r.reviewer_status === 'needs_missing_info').length;
  const attentionCount = rows.filter(r => r.reviewer_status === 'requires_human_attention').length;
  const avgScore = Math.round(rows.reduce((s, r) => s + Number(r.overall_score || 0), 0) / Math.max(1, rows.filter(r => r.overall_score !== null).length));

  return (
    <div className="form-wrap" style={{maxWidth:1400}}>
      <h1 className="dash-h1">מועמדות שהוגשו</h1>
      <p className="dash-sub">AI summary: mock · local heuristic until AI provider is enabled</p>

      <div className="metrics">
        <_Metric lbl="סה״כ טפסים" num={rows.length} delta="מה-DB המקומי" />
        <_Metric lbl="הושלמו" num={completedCount} delta="נוצר כרטיס סוקרת" />
        <_Metric lbl="חסר מידע" num={needsInfoCount} delta="לטיפול המשך" warn={needsInfoCount > 0} />
        <_Metric lbl="ציון ממוצע" num={avgScore || '-'} delta="MVP heuristic score" />
      </div>

      {error && <div className="summary-card" style={{borderColor:'var(--ya-red)'}}>{error}</div>}
      {loading ? (
        <div className="summary-card">טוענת מועמדות...</div>
      ) : (
        <div className="dash-cols">
          <aside className="cand-list">
            <div className="cand-list-head"><h3>רשימת מועמדות</h3><span className="count">{filtered.length}</span></div>
            <div className="cand-search">
              <input value={search} onChange={e => setSearch(e.target.value)} placeholder="חיפוש לפי שם, תחום או סטטוס" />
            </div>
            {filtered.map(row => (
              <button key={row.session_id} className={`cand-card ${String(row.session_id) === activeSessionId ? 'active' : ''}`} onClick={() => setActiveSessionId(String(row.session_id))} style={{width:'100%',textAlign:'inherit',background:String(row.session_id) === activeSessionId ? '#fff' : undefined,borderTop:0,borderRight:0,borderBottom:0}}>
                <div className="row">
                  <div>
                    <div className="name">{row.name || 'ללא שם'}</div>
                    <div className="meta">{row.business_domain || 'תחום לא צוין'} · {row.status}</div>
                  </div>
                  <span className="tag tag-track">{row.overall_score ?? '-'}</span>
                </div>
                <div className="biz">{row.business_stage || 'שלב עסקי לא צוין'}</div>
                <div className="badges">
                  <span className="tag tag-status">{row.reviewer_status || 'pending'}</span>
                  {row.recommended_next_step && <span className="tag tag-stage">{_nextStepLabels[row.recommended_next_step] || row.recommended_next_step}</span>}
                </div>
              </button>
            ))}
            {filtered.length === 0 && <div className="summary-card" style={{border:0}}>אין מועמדות להצגה.</div>}
          </aside>

          <_ReviewerPanel card={card} outbox={outbox} activeSessionId={activeSessionId} attentionCount={attentionCount} />
        </div>
      )}
    </div>
  );
}

function _Metric({ lbl, num, delta, warn }) {
  return (
    <div className={`metric ${warn ? 'warn' : ''}`}>
      <div className="lbl">{lbl}</div>
      <div className="num">{num}</div>
      <div className="delta">{delta}</div>
    </div>
  );
}

function _ReviewerPanel({ card, outbox, activeSessionId, attentionCount }) {
  if (!activeSessionId) return <div className="panel"><div className="panel-body"><div className="summary-card">בחרי מועמדת מהרשימה.</div></div></div>;
  if (!card) return <div className="panel"><div className="panel-body"><div className="summary-card">טוענת כרטיס...</div></div></div>;

  const candidate = card.candidate || {};
  const scoring = card.scoring || {};
  const ai = card.ai_summary || {};
  const outboxStatus = outbox?.status || card.salesforce_outbox?.status || 'not_created';

  return (
    <div className="panel">
      <header className="panel-head">
        <div className="top">
          <div className="who">
            <div className="ava">{_initials(candidate.name)}</div>
            <div>
              <h2>{candidate.name || card.title || 'מועמדת'}</h2>
              <div className="who-meta">{candidate.city || 'עיר לא צוינה'} · <b>{card.business_domain || 'תחום לא צוין'}</b> · {card.business_stage || 'שלב לא צוין'}</div>
            </div>
          </div>
          <span className="sensitive-flag">{card.reviewer_status}</span>
        </div>

        <div className="panel-summary">
          <_SummaryItem label="סטטוס שאלון" value={card.questionnaire?.status} />
          <_SummaryItem label="המלצת המשך" value={_nextStepLabels[card.recommended_next_step] || card.recommended_next_step} />
          <_SummaryItem label="ציון כולל" value={`${scoring.overall_reviewer_score ?? '-'} / 100`} />
          <_SummaryItem label="Salesforce outbox" value={outboxStatus} />
        </div>

        <div className="ai-banner">
          <div className="icon" aria-hidden="true">AI</div>
          <div className="text">
            <b>AI summary: mock · local heuristic until AI provider is enabled</b>
            <small>הסיכום מבוסס כרגע על כללים היוריסטיים וטעון AI אנונימי, ללא שליחה לספק חיצוני.</small>
          </div>
          <div className="conf"><b>{Math.round((ai.confidence || 0) * 100)}%</b><small>confidence</small></div>
        </div>
      </header>

      <div className="panel-body">
        <_Section number="1" title="תקציר סוקרת">
          <div className="summary-card">{ai.summary || card.summary || 'אין תקציר עדיין.'}</div>
        </_Section>

        <_Section number="2" title="ציוני MVP heuristic">
          <div className="conf-list" style={{padding:0}}>
            <_ScoreRow label="שלמות מידע" score={scoring.data_completeness_score} />
            <_ScoreRow label="התאמה כלכלית" score={scoring.economic_fit_score} />
            <_ScoreRow label="מוכנות עסקית" score={scoring.business_readiness_score} />
            <_ScoreRow label="מחויבות" score={scoring.commitment_score} />
          </div>
        </_Section>

        <_Section number="3" title="פרטי מועמדת">
          <div className="panel-summary" style={{gridTemplateColumns:'repeat(4,1fr)',marginTop:0}}>
            <_SummaryItem label="טלפון" value={candidate.mobile_phone || '-'} />
            <_SummaryItem label="מייל" value={candidate.email || '-'} />
            <_SummaryItem label="אזור" value={candidate.region || '-'} />
            <_SummaryItem label="מצב תעסוקתי" value={card.employment_status || '-'} />
          </div>
        </_Section>

        <_Section number="4" title="מידע חסר">
          <_BulletList items={card.missing_information} labels={_missingLabels} empty="לא זוהה מידע חסר קריטי." missing />
        </_Section>

        <_Section number="5" title="דגלי סיכון">
          <_BulletList items={card.risk_flags} labels={_riskLabels} empty="לא זוהו דגלי סיכון." />
        </_Section>

        <_Section number="6" title="נקודות חוזקה">
          <_BulletList items={card.strength_indicators} empty="אין נקודות חוזקה מתועדות עדיין." />
        </_Section>

        <_Section number="7" title="תור Salesforce">
          <div className="track-card">
            <span className="badge">{outboxStatus}</span>
            <div className="body">
              <b>{outbox?.operation || card.salesforce_outbox?.operation || 'upsert_candidate_lead'}</b>
              <p>נוצר payload backend-only לשימוש עתידי. אין קריאה אמיתית ל-Salesforce בשלב המקומי.</p>
            </div>
          </div>
        </_Section>
      </div>
    </div>
  );
}

function _SummaryItem({ label, value }) {
  return <div><div className="lbl">{label}</div><div className="val">{value || '-'}</div></div>;
}

function _Section({ number, title, children }) {
  return (
    <div className="section">
      <h3><span className="num">{number}</span>{title}</h3>
      {children}
    </div>
  );
}

function _ScoreRow({ label, score }) {
  const v = Number(score || 0);
  return (
    <div className={`conf-row tier-${v >= 80 ? 'high' : v >= 60 ? 'mid' : 'low'}`}>
      <div className="conf-row-top">
        <div className="conf-label"><b>{label}</b></div>
        <div className="conf-row-score"><span className="conf-pill">{score ?? '-'}</span></div>
      </div>
      <div className="conf-bar"><div className="conf-bar-fill" style={{width:`${Math.min(100, v)}%`}} /></div>
    </div>
  );
}

function _BulletList({ items = [], labels = {}, empty, missing }) {
  if (!items.length) return <div className="summary-card">{empty}</div>;
  return (
    <ul className={`bullets ${missing ? 'missing' : ''}`}>
      {items.map(item => <li key={item}>{labels[item] || item}</li>)}
    </ul>
  );
}

function _initials(name = '') {
  return name.trim().split(/\s+/).slice(0, 2).map(p => p[0]).join('') || 'י';
}

/* ========== Mount ========== */
ReactDOM.createRoot(document.getElementById('root')).render(<DemoApp />);
