// Home + Candidates list + Candidate detail pages

// Warm family/home imagery — Unsplash
const HERO_IMG = 'https://images.unsplash.com/photo-1484820540004-14229fe36ca4?w=1920&q=80'; // cozy home interior with warm light
const HOME_IMG2 = 'https://images.unsplash.com/photo-1609220136736-443140cffec6?w=1600&q=80'; // grandmother with child
const HOME_IMG3 = 'https://images.unsplash.com/photo-1609220136736-443140cffec6?w=1200&q=80';
const HOME_IMG4 = 'https://images.unsplash.com/photo-1581579438747-104c53e7b77f?w=1200&q=80';
const HOME_IMG5 = 'https://images.unsplash.com/photo-1577896851231-70ef18881754?w=1600&q=80';

const HomePage = ({ go }) => {
  const { t } = window.useI18n();
  const { candidates, plans } = window.MOCK_DATA;
  const featured = candidates.filter(c => c.verified).slice(0, 4);
  return (
    <div className="page">
      <div className="container-wide">
        {/* Hero */}
        <section className="hero" style={{marginTop:24}}>
          <div className="hero-image" style={{backgroundImage:`url(${HERO_IMG})`}}/>
          <div className="hero-content">
            <div style={{maxWidth:620}}>
              <div style={{display:'inline-flex', alignItems:'center', gap:8, padding:'6px 12px', background:'rgba(255,255,255,0.15)', backdropFilter:'blur(10px)', borderRadius:99, fontSize:13, fontWeight:500, marginBottom:24, border:'1px solid rgba(255,255,255,0.2)'}}>
                <Icon name="verified" size={14}/> {t('home.heroBadge')}
              </div>
              <h1 className="display" style={{fontSize:'clamp(40px, 6vw, 68px)', color:'white', marginBottom:20}}>
                {t('home.heroTitle')}
              </h1>
              <p style={{fontSize:19, color:'rgba(255,255,255,0.9)', marginBottom:32, maxWidth:560, lineHeight:1.55}}>
                {t('home.heroSub')}
              </p>
              <div style={{display:'flex', gap:12, flexWrap:'wrap'}}>
                <button className="btn btn-primary btn-lg" onClick={() => go('candidates')}>
                  {t('home.ctaBrowse')} <Icon name="arrow"/>
                </button>
                <button className="btn btn-lg" style={{background:'rgba(255,255,255,0.15)', color:'white', backdropFilter:'blur(10px)', border:'1px solid rgba(255,255,255,0.25)'}} onClick={() => go('auth:register')}>
                  {t('home.ctaPostJob')}
                </button>
              </div>
            </div>
          </div>
        </section>

        {/* Trust strip */}
        <section style={{padding:'80px 0 40px', display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:32}}>
          {[
            { n: '2,400+', l: t('home.stats.verified') },
            { n: '15,800+', l: t('home.stats.families') },
            { n: '✓', l: t('home.stats.verifiedBadge') },
            { n: '4.8 / 5', l: t('home.stats.rating') }
          ].map((s, i) => (
            <div key={i} style={{borderLeft: i === 0 ? 'none' : '1px solid var(--t-line)', paddingLeft: i === 0 ? 0 : 32}}>
              <div className="display" style={{fontSize:36, marginBottom:6}}>{s.n}</div>
              <div style={{color:'var(--t-ink-muted)', fontSize:14}}>{s.l}</div>
            </div>
          ))}
        </section>

        {/* How it works */}
        <section className="section">
          <div className="eyebrow">{t('home.howWorks.eyebrow')}</div>
          <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:48, alignItems:'center', marginBottom:40}}>
            <h2 className="display" style={{fontSize:44}}>{t('home.howWorks.title')}</h2>
            <p style={{fontSize:17, color:'var(--t-ink-muted)', lineHeight:1.6}}>
              {t('home.howWorks.body')}
            </p>
          </div>
          <div style={{display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:20}}>
            {[
              { n:'01', img: HOME_IMG4, title: t('home.cards.c1.title'), body: t('home.cards.c1.body')},
              { n:'02', img: HOME_IMG3, title: t('home.cards.c2.title'), body: t('home.cards.c2.body')},
              { n:'03', img: HOME_IMG5, title: t('home.cards.c3.title'), body: t('home.cards.c3.body')},
            ].map((s, i) => (
              <div key={i} className="card" style={{padding:0, overflow:'hidden'}}>
                <div style={{height:200, backgroundImage:`url(${s.img})`, backgroundSize:'cover', backgroundPosition:'center'}}/>
                <div style={{padding:24}}>
                  <div style={{fontSize:12, color:'var(--t-accent)', fontWeight:600, marginBottom:10, fontFamily:'JetBrains Mono, monospace'}}>{s.n}</div>
                  <div style={{fontWeight:600, fontSize:19, marginBottom:8, lineHeight:1.3, letterSpacing:'-0.01em'}}>{s.title}</div>
                  <div style={{color:'var(--t-ink-muted)', fontSize:14, lineHeight:1.6}}>{s.body}</div>
                </div>
              </div>
            ))}
          </div>
        </section>

        {/* Featured candidates */}
        <section className="section">
          <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-end', marginBottom:32}}>
            <div>
              <div className="eyebrow">{t('home.featured.eyebrow')}</div>
              <h2 className="display" style={{fontSize:38}}>{t('home.featured.title')}</h2>
            </div>
            <button className="btn btn-outline" onClick={() => go('candidates')}>{t('home.featured.seeAll')} <Icon name="arrow" size={14}/></button>
          </div>
          <div style={{display:'grid', gridTemplateColumns:'repeat(4,1fr)', gap:20}}>
            {featured.map(c => <CandidateCard key={c.id} candidate={c} go={go} onFav={()=>{}} isFav={false} subscription="premium"/>)}
          </div>
        </section>

        {/* Pricing preview */}
        <section className="section">
          <div style={{background:'var(--t-paper)', borderRadius:'var(--t-radius-lg)', padding:'64px 56px', border:'1px solid var(--t-line)'}}>
            <div style={{display:'grid', gridTemplateColumns:'1fr 1.2fr', gap:64, alignItems:'center'}}>
              <div>
                <div className="eyebrow">{t('home.pricingSection.eyebrow')}</div>
                <h2 className="display" style={{fontSize:40, marginBottom:16}}>{t('home.pricingSection.title')}</h2>
                <p style={{color:'var(--t-ink-muted)', fontSize:16, lineHeight:1.6, marginBottom:24}}>
                  {t('home.pricingSection.body')}
                </p>
                <button className="btn btn-primary btn-lg" onClick={() => go('pricing')}>{t('home.pricingSection.seePlans')} <Icon name="arrow" size={14}/></button>
              </div>
              <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:16}}>
                {plans.slice(1).map(p => (
                  <div key={p.id} className="card-flat" style={{padding:28, background: p.featured ? 'var(--mint-light)' : 'var(--t-paper)', border: p.featured ? '1.5px solid var(--mint)' : '1px solid var(--t-line)'}}>
                    {p.featured && <div style={{fontSize:11, fontWeight:700, letterSpacing:'0.1em', textTransform:'uppercase', color:'var(--mint-dark)', marginBottom:8}}>{t('home.pricingSection.bestValue')}</div>}
                    <div style={{fontSize:14, color:'var(--t-ink-muted)', marginBottom:4}}>{p.name}</div>
                    <div style={{display:'flex', alignItems:'baseline', gap:6, marginBottom:16}}>
                      <span className="display" style={{fontSize:34}}>{p.currency}{p.price.toLocaleString()}</span>
                      <span style={{color:'var(--t-ink-muted)', fontSize:13}}>{t('pricing.perPeriod', {period: p.period})}</span>
                    </div>
                    <ul style={{listStyle:'none', display:'flex', flexDirection:'column', gap:8}}>
                      {p.features.filter(f=>f.yes).slice(0,3).map((f,i) => (
                        <li key={i} style={{display:'flex', alignItems:'center', gap:8, fontSize:13, color:'var(--t-ink)'}}>
                          <Icon name="check" size={14}/> {f.text}
                        </li>
                      ))}
                    </ul>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </section>

        {/* Testimonials */}
        <section className="section">
          <div style={{textAlign:'center', marginBottom:48}}>
            <div className="eyebrow">{t('home.testimonials.eyebrow')}</div>
            <h2 className="display" style={{fontSize:40, maxWidth:700, margin:'0 auto'}}>{t('home.testimonials.title')}</h2>
          </div>
          <div style={{display:'grid', gridTemplateColumns:'repeat(3,1fr)', gap:20}}>
            {[
              { name:'Chen family', city:'Taipei', quote:'Watching Purwanti cook in her assessment video before meeting her was genuinely game-changing. We knew within 10 minutes she was the one.', initial:'C', color:'#E8856A' },
              { name:'Wong family', city:'Hong Kong', quote:'After three agency horror stories, finding HelperMatch felt like a relief. The tier system is honest — C tier candidates look like C tier in person.', initial:'W', color:'#48B8A0' },
              { name:'Lim family', city:'Singapore', quote:'Angela has been with us for two years now. The videos gave us the confidence to skip the agency fees and hire directly.', initial:'L', color:'#B8865B' },
            ].map((t, i) => (
              <div key={i} className="card" style={{padding:28}}>
                <div className="stars">★★★★★</div>
                <p style={{margin:'16px 0 20px', fontSize:15, lineHeight:1.65, color:'var(--t-ink)'}}>"{t.quote}"</p>
                <div style={{display:'flex', alignItems:'center', gap:12}}>
                  <Avatar person={{initials:t.initial, color:t.color}} size={40}/>
                  <div>
                    <div style={{fontWeight:600, fontSize:14}}>{t.name}</div>
                    <div style={{fontSize:13, color:'var(--t-ink-muted)'}}>{t.city}</div>
                  </div>
                </div>
              </div>
            ))}
          </div>
        </section>

        {/* CTA */}
        <section className="section">
          <div style={{background:'var(--ink)', color:'white', borderRadius:'var(--t-radius-lg)', padding:'64px 56px', display:'grid', gridTemplateColumns:'1.5fr 1fr', gap:48, alignItems:'center', backgroundImage:`linear-gradient(135deg, rgba(40,25,15,0.85), rgba(40,25,15,0.95)), url(${HOME_IMG2})`, backgroundSize:'cover', backgroundPosition:'center'}}>
            <div>
              <h2 className="display" style={{fontSize:44, marginBottom:16, color:'white'}}>{t('home.cta.title')}</h2>
              <p style={{fontSize:17, color:'rgba(255,255,255,0.8)', marginBottom:0, maxWidth:500}}>
                {t('home.cta.body')}
              </p>
            </div>
            <div style={{display:'flex', gap:12, flexWrap:'wrap'}}>
              <button className="btn btn-primary btn-lg" onClick={() => go('candidates')}>{t('home.cta.browse')}</button>
              <button className="btn btn-lg" style={{background:'rgba(255,255,255,0.12)', color:'white', border:'1px solid rgba(255,255,255,0.2)'}} onClick={() => go('pricing')}>{t('home.cta.viewPricing')}</button>
            </div>
          </div>
        </section>
      </div>
    </div>
  );
};

// ===== Candidates List =====
// `id` 是來自路由的 segment（HelperMatch.html 從 'candidates:applicants/82979' 拆出）
//   - 'applicants/<jobId>' → 進入 applicant tab，預先選好該 jobId 篩選
//   - 'applicants'         → 進入 applicant tab，jobId 篩選 = 'all my jobs'
//   - undefined / 其他      → 預設 all tab
const CandidatesPage = ({ go, id, favs, toggleFav, subscription }) => {
  const { t } = window.useI18n();
  const { candidates, applications, jobs } = window.MOCK_DATA;
  // Demo 用：myJobs = 雇主自己 post 的 job（同 dashboard 的 slice 0..2 慣例）
  const myJobs = jobs.slice(0, 2);

  // 從路由 id 解析初始 tab + jobId 篩選
  const parsedRoute = React.useMemo(() => {
    if (!id) return { tab: null, jobId: null };
    if (id.startsWith('applicants')) {
      const parts = id.split('/');
      return { tab: 'applicant', jobId: parts[1] ? parseInt(parts[1], 10) : null };
    }
    return { tab: null, jobId: null };
  }, [id]);
  const [filters, setFilters] = useState({
    market: 'Taiwan',
    verification: [],
    hasReference: false,
    hasVideo: false,
    contractStatus: [],
    nationality: [],
    mainSkills: [],
    languages: [],
    // New filters: start date (max date for c.availableDate), candidate location
    // (country of c.locationCountry), job type (any-of c.openJobTypes), exp/age
    // ranges (inclusive). Range tuples are [min, max] in their natural unit.
    startDate: '',
    location: [],
    jobType: [],
    expRange: [0, 25],
    ageRange: [18, 65],
    sort: 'recommended'
  });
  const [search, setSearch] = useState('');
  const [page, setPage] = useState(1);
  // Bucket tab — slices the result list by employer-relationship.
  // 'all' | 'matched' | 'applicant' | 'shortlist'
  const [tab, setTab] = useState(parsedRoute.tab || 'all');
  // Applicant tab 內的 job 篩選；null = 「我所有 job 的應徵者」
  const [applicantJobFilter, setApplicantJobFilter] = useState(parsedRoute.jobId);
  const PER_PAGE = 9; // AI-recommended: 9 cards/page = 3x3 grid, enough to browse without overwhelm

  const toggleMulti = (key, val) => { setPage(1); setFilters(f => {
    const arr = f[key].includes(val) ? f[key].filter(x => x !== val) : [...f[key], val];
    return {...f, [key]: arr};
  }); };

  const activeCount =
    filters.verification.length +
    (filters.hasReference ? 1 : 0) +
    (filters.hasVideo ? 1 : 0) +
    filters.nationality.length +
    filters.mainSkills.length +
    filters.languages.length +
    (filters.startDate ? 1 : 0) +
    filters.location.length +
    filters.jobType.length +
    filters.contractStatus.length +
    ((filters.expRange[0] !== 0 || filters.expRange[1] !== 25) ? 1 : 0) +
    ((filters.ageRange[0] !== 18 || filters.ageRange[1] !== 65) ? 1 : 0);

  const clearAll = () => { setPage(1); setFilters(f => ({...f, verification:[], hasReference:false, hasVideo:false, contractStatus:[], nationality:[], mainSkills:[], languages:[], startDate:'', location:[], jobType:[], expRange:[0,25], ageRange:[18,65]})); };

  const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);

  // baseList = sidebar filters + search applied, no tab filter yet.
  // Used for both the tab counts AND as the input to the tab slice.
  const baseList = useMemo(() => {
    let list = [...candidates];
    if (filters.verification.length) list = list.filter(c => filters.verification.includes(c.verification));
    if (filters.hasReference) list = list.filter(c => c.hasReference);
    if (filters.hasVideo) list = list.filter(c => c.hasVideo);
    if (filters.nationality.length) list = list.filter(c => filters.nationality.includes(c.nationality));
    if (filters.mainSkills.length) list = list.filter(c => filters.mainSkills.some(s => c.typedSkills?.mainSkills?.includes(s)));
    if (filters.languages.length) list = list.filter(c => filters.languages.some(l => c.typedSkills?.languages?.includes(l)));
    if (filters.startDate) list = list.filter(c => c.availableDate && c.availableDate <= filters.startDate);
    if (filters.location.length) list = list.filter(c => filters.location.includes(c.locationCountry));
    if (filters.jobType.length) list = list.filter(c => filters.jobType.some(jt => (c.openJobTypes || []).includes(jt)));
    if (filters.contractStatus.length) list = list.filter(c => filters.contractStatus.includes(c.contractStatus));
    list = list.filter(c => (c.yearsExperience ?? 0) >= filters.expRange[0] && (c.yearsExperience ?? 0) <= filters.expRange[1]);
    list = list.filter(c => (c.age ?? 0) >= filters.ageRange[0] && (c.age ?? 0) <= filters.ageRange[1]);
    if (search) list = list.filter(c => c.name.toLowerCase().includes(search.toLowerCase()));
    if (filters.sort === 'recommended') list.sort((a,b) => (b.verified?1:0) - (a.verified?1:0) || (b.completeness||0) - (a.completeness||0));
    return list;
  }, [candidates, filters, search]);

  // Applicant lookup：依 applicantJobFilter 決定要顯示哪些 job 的應徵者
  // null = 我所有 job 的應徵者（去重）；指定 jobId = 該 job 的應徵者
  const myJobIds = useMemo(() => new Set(myJobs.map(j => j.id)), [myJobs]);
  const applicantCandidateIds = useMemo(() => {
    const filtered = applications.filter(a => {
      if (applicantJobFilter) return a.jobId === applicantJobFilter;
      return myJobIds.has(a.jobId);  // 預設只顯示「我」的 job 的應徵者
    });
    return new Set(filtered.map(a => a.candidateId));
  }, [applications, applicantJobFilter, myJobIds]);

  const tabCounts = useMemo(() => ({
    all:        baseList.length,
    matched:    baseList.filter(c => c.matched).length,
    applicant:  baseList.filter(c => applicantCandidateIds.has(c.id)).length,
    shortlist:  baseList.filter(c => favs.includes(c.id)).length,
  }), [baseList, favs, applicantCandidateIds]);

  const filtered = useMemo(() => {
    if (tab === 'matched')   return baseList.filter(c => c.matched);
    if (tab === 'applicant') return baseList.filter(c => applicantCandidateIds.has(c.id));
    if (tab === 'shortlist') return baseList.filter(c => favs.includes(c.id));
    return baseList;
  }, [baseList, tab, favs, applicantCandidateIds]);

  const totalPages = Math.max(1, Math.ceil(filtered.length / PER_PAGE));
  const curPage = Math.min(page, totalPages);
  const paginated = filtered.slice((curPage-1)*PER_PAGE, curPage*PER_PAGE);

  return (
    <div className="page">
      <div className="container-wide" style={{padding:'32px 32px 80px'}}>
        <div style={{marginBottom:28, display:'flex', alignItems:'flex-end', justifyContent:'space-between', gap:16, flexWrap:'wrap'}}>
          <div>
            <h1 className="display" style={{fontSize:38, marginBottom:4}}>{t('helpers.pageTitle')}</h1>
          </div>
          <button
            className="btn btn-outline btn-sm helpers-mobile-filters-btn"
            onClick={() => setMobileFiltersOpen(true)}
          >
            <Icon name="filter" size={14}/> {t('helpers.filters')} {activeCount > 0 && <span style={{fontSize:11, padding:'1px 7px', borderRadius:99, background:'var(--t-accent)', color:'white', fontWeight:700, marginLeft:2}}>{activeCount}</span>}
          </button>
        </div>

        <div className="helpers-layout" style={{display:'grid', gridTemplateColumns:'260px 1fr', gap:32, alignItems:'flex-start'}}>
          {/* Filter sidebar */}
          <aside className={`helpers-sidebar ${mobileFiltersOpen ? 'open' : ''}`}>
            <div className="helpers-sidebar-scrim" onClick={() => setMobileFiltersOpen(false)}/>
            <div className="helpers-sidebar-panel card-flat" style={{padding:20}}>
              <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:16, gap:12}}>
                <div style={{fontSize:15, fontWeight:700, whiteSpace:'nowrap'}}>{t('helpers.filters')}</div>
                <div style={{display:'flex', gap:8, alignItems:'center'}}>
                  {activeCount > 0 && (
                    <button onClick={clearAll} style={{background:'none', border:'none', color:'var(--trust)', fontSize:12, fontWeight:600, cursor:'pointer', padding:0}}>
                      {t('helpers.clearN', {n: activeCount})}
                    </button>
                  )}
                  <button onClick={() => setMobileFiltersOpen(false)} className="helpers-sidebar-close" aria-label={t('common.close')} style={{background:'none', border:'none', padding:4, cursor:'pointer', color:'var(--t-ink-muted)'}}>
                    <Icon name="x" size={18}/>
                  </button>
                </div>
              </div>

              <div style={{position:'relative', marginBottom:18}}>
                <Icon name="search" size={16} className="helpers-search-icon"/>
                <input
                  className="input"
                  placeholder={t('helpers.searchPlaceholder')}
                  value={search}
                  onChange={e => { setSearch(e.target.value); setPage(1); }}
                  style={{paddingLeft:40}}
                />
                <style>{`.helpers-search-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--t-ink-muted);pointer-events:none}`}</style>
              </div>

              <FilterGroup title={t('helpers.filterGroup.market')}>
                {[
                  ['Taiwan',     t('helpers.markets.taiwan')],
                  ['Hong Kong',  t('helpers.markets.hongKong')],
                  ['Singapore',  t('helpers.markets.singapore')],
                ].map(([id, label]) => (
                  <FilterRadio key={id} name="market" label={label} checked={filters.market===id} onChange={()=>setFilters(f=>({...f,market:id}))} count={candidates.filter(c=>c.market===id).length}/>
                ))}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.startDate')}>
                <div style={{fontSize:11.5, color:'var(--t-ink-muted)', marginBottom:6}}>{t('helpers.startDateLabel')}</div>
                <input type="date" className="input" value={filters.startDate} onChange={e=>{setPage(1); setFilters(f=>({...f, startDate: e.target.value}));}} placeholder={t('helpers.startDatePlaceholder')} style={{width:'100%', fontSize:13}}/>
                {filters.startDate && (
                  <button onClick={()=>setFilters(f=>({...f, startDate:''}))} style={{marginTop:6, background:'none', border:'none', color:'var(--trust)', fontSize:11.5, fontWeight:600, cursor:'pointer', padding:0}}>{t('common.clear')}</button>
                )}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.location')}>
                {['Hong Kong','Indonesia','Taiwan','Singapore','Philippines'].map(id => (
                  <FilterCheckbox key={id} label={t('helpers.locationCountries.' + id)} checked={filters.location.includes(id)} onChange={()=>toggleMulti('location', id)} count={candidates.filter(c=>c.locationCountry===id).length}/>
                ))}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.jobType')}>
                {['full-time','part-time','temporary'].map(jt => (
                  <FilterCheckbox key={jt} label={t('forms.enum.jobType.' + jt)} checked={filters.jobType.includes(jt)} onChange={()=>toggleMulti('jobType', jt)} count={candidates.filter(c=>(c.openJobTypes||[]).includes(jt)).length}/>
                ))}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.contractStatus')} defaultOpen={false}>
                {['Finished Contract','In Home Country','Terminated (Relocation)','First Time','Break Contract','Transfer'].map(cs => (
                  <FilterCheckbox key={cs} label={t('helpers.contractStatusValue.' + cs)} checked={filters.contractStatus.includes(cs)} onChange={()=>toggleMulti('contractStatus', cs)} count={candidates.filter(c=>c.contractStatus===cs).length}/>
                ))}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.experience')} defaultOpen={false}>
                <DualRangeMini min={0} max={25} value={filters.expRange} unit={t('helpers.yrsRangeUnit')} onChange={v=>{setPage(1); setFilters(f=>({...f, expRange:v}));}}/>
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.age')} defaultOpen={false}>
                <DualRangeMini min={18} max={65} value={filters.ageRange} unit={t('helpers.ageRangeUnit')} onChange={v=>{setPage(1); setFilters(f=>({...f, ageRange:v}));}}/>
              </FilterGroup>

              {/* Phase 2: re-enable the Verification filter group.
              <FilterGroup title="Verification">
                <FilterCheckbox label="Official assessment" checked={filters.verification.includes('official')} onChange={()=>toggleMulti('verification','official')} count={candidates.filter(c=>c.verification==='official').length}/>
                <FilterCheckbox label="Agency"              checked={filters.verification.includes('agency')}   onChange={()=>toggleMulti('verification','agency')}   count={candidates.filter(c=>c.verification==='agency').length}/>
                <FilterCheckbox label="Self"                checked={filters.verification.includes('self')}     onChange={()=>toggleMulti('verification','self')}     count={candidates.filter(c=>c.verification==='self').length}/>
              </FilterGroup>
              */}

              <FilterGroup title={t('helpers.filterGroup.reference')}>
                <FilterCheckbox label={t('helpers.withReference')} checked={filters.hasReference} onChange={()=>{setPage(1); setFilters(f=>({...f,hasReference:!f.hasReference}));}} count={candidates.filter(c=>c.hasReference).length}/>
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.video')}>
                <FilterCheckbox label={t('helpers.hasVideo')} checked={filters.hasVideo} onChange={()=>{setPage(1); setFilters(f=>({...f,hasVideo:!f.hasVideo}));}} count={candidates.filter(c=>c.hasVideo).length}/>
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.nationality')} defaultOpen={false}>
                {[
                  ['Indonesia',   t('helpers.nationalities.indonesia')],
                  ['Philippines', t('helpers.nationalities.philippines')],
                ].map(([id, label]) => (
                  <FilterCheckbox key={id} label={label} checked={filters.nationality.includes(id)} onChange={()=>toggleMulti('nationality',id)} count={candidates.filter(c=>c.nationality===id).length}/>
                ))}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.mainSkills')} defaultOpen={false}>
                {window.SKILL_TAXONOMY.mainSkills.slice(0,8).map(s => (
                  <FilterCheckbox key={s.id} label={window.pickLocalised(s, 'label') || s.label} checked={filters.mainSkills.includes(s.id)} onChange={()=>toggleMulti('mainSkills',s.id)}/>
                ))}
              </FilterGroup>

              <FilterGroup title={t('helpers.filterGroup.languages')} defaultOpen={false}>
                {window.SKILL_TAXONOMY.languages.slice(0,6).map(s => (
                  <FilterCheckbox key={s.id} label={<span>{s.flag} {window.pickLocalised(s, 'label') || s.label}</span>} checked={filters.languages.includes(s.id)} onChange={()=>toggleMulti('languages',s.id)}/>
                ))}
              </FilterGroup>

              <div className="helpers-sidebar-actions">
                <button className="btn btn-outline btn-block" onClick={clearAll} disabled={activeCount === 0}>{t('helpers.clearAll')}</button>
                <button className="btn btn-primary btn-block" onClick={() => setMobileFiltersOpen(false)}>{t('helpers.showN', {n: filtered.length})}</button>
              </div>
            </div>
          </aside>

          {/* Results */}
          <div>
            {/* Bucket tabs — slice the result list by employer-relationship.
                Counts reflect each bucket within the current sidebar filters. */}
            <div className="helpers-tabs" role="tablist" style={{
              display:'flex', gap:4, marginBottom:18, padding:4,
              background:'var(--t-bg)', border:'1px solid var(--t-line)',
              borderRadius:'var(--t-radius-sm)', overflowX:'auto',
            }}>
              {[
                { id:'all',       label: t('helpers.tabs.all') },
                { id:'matched',   label: t('helpers.tabs.matched') },
                { id:'applicant', label: t('helpers.tabs.applicant') },
                { id:'shortlist', label: t('helpers.tabs.shortlist') },
              ].map(tabDef => {
                const active = tab === tabDef.id;
                const count = tabCounts[tabDef.id];
                return (
                  <button
                    key={tabDef.id}
                    role="tab"
                    aria-selected={active}
                    onClick={() => { setTab(tabDef.id); setPage(1); }}
                    style={{
                      flex:'1 1 0', minWidth:0,
                      display:'inline-flex', alignItems:'center', justifyContent:'center', gap:8,
                      padding:'9px 14px', border:'none', borderRadius:'calc(var(--t-radius-sm) - 4px)',
                      background: active ? 'var(--t-paper)' : 'transparent',
                      color: active ? 'var(--t-ink)' : 'var(--t-ink-muted)',
                      fontSize:13.5, fontWeight: active ? 600 : 500,
                      cursor:'pointer', whiteSpace:'nowrap',
                      boxShadow: active ? '0 1px 3px rgba(16,24,40,0.08)' : 'none',
                      transition:'background 0.15s, color 0.15s',
                    }}
                  >
                    <span>{tabDef.label}</span>
                    <span style={{
                      display:'inline-flex', alignItems:'center', justifyContent:'center',
                      minWidth:20, height:18, padding:'0 6px', borderRadius:99,
                      fontSize:11, fontWeight:700, lineHeight:1,
                      background: active ? 'var(--t-accent)' : 'var(--t-line)',
                      color: active ? 'white' : 'var(--t-ink-muted)',
                    }}>{count}</span>
                  </button>
                );
              })}
            </div>

            {/* Applicant tab 專屬：依 job 篩選的下拉選單 */}
            {tab === 'applicant' && (
              <div style={{display:'flex', alignItems:'center', gap:10, marginBottom:14, padding:'10px 14px', background:'var(--trust-bg)', border:'1px solid var(--trust)', borderRadius:'var(--t-radius-sm)', flexWrap:'wrap'}}>
                <Icon name="briefcase" size={14} style={{color:'var(--trust-dark)'}}/>
                <label htmlFor="applicant-job-filter" style={{fontSize:13, fontWeight:600, color:'var(--trust-dark)'}}>
                  {t('helpers.applicantJobFilter.label')}：
                </label>
                <select
                  id="applicant-job-filter"
                  className="select"
                  value={applicantJobFilter || ''}
                  onChange={(e) => { setApplicantJobFilter(e.target.value ? parseInt(e.target.value, 10) : null); setPage(1); }}
                  style={{padding:'6px 32px 6px 12px', fontSize:13, flex:'1 1 240px', maxWidth:480, cursor:'pointer'}}
                >
                  <option value="">{t('helpers.applicantJobFilter.all')}</option>
                  {myJobs.map(j => {
                    const count = applications.filter(a => a.jobId === j.id).length;
                    return (
                      <option key={j.id} value={j.id}>
                        {window.pickLocalised ? (window.pickLocalised(j, 'title') || j.title) : j.title} ({count})
                      </option>
                    );
                  })}
                </select>
                {applicantJobFilter && (
                  <button
                    onClick={() => { setApplicantJobFilter(null); setPage(1); }}
                    style={{padding:'6px 10px', fontSize:12, fontWeight:600, color:'var(--trust-dark)', background:'transparent', border:'none', cursor:'pointer', textDecoration:'underline'}}
                  >
                    {t('helpers.applicantJobFilter.clear')}
                  </button>
                )}
              </div>
            )}

            <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:18, flexWrap:'wrap', gap:12}}>
              <div style={{fontSize:14, color:'var(--t-ink-muted)'}}>
                <strong style={{color:'var(--t-ink)'}}>{filtered.length}</strong>{' '}
                {filtered.length === 1 ? t('helpers.unitOne') : t('helpers.unitMany')}
                {activeCount > 0 && ' ' + t('helpers.matchingFilters')}
              </div>
              <div style={{display:'flex', alignItems:'center', gap:8, fontSize:13}}>
                <span style={{color:'var(--t-ink-muted)'}}>{t('helpers.sortBy')}</span>
                <select className="select" value={filters.sort} onChange={e=>setFilters(f=>({...f,sort:e.target.value}))} style={{padding:'6px 28px 6px 12px', fontSize:13, width:'auto'}}>
                  <option value="recommended">{t('helpers.sort.recommended')}</option>
                  <option value="active">{t('helpers.sort.active')}</option>
                  <option value="available">{t('helpers.sort.available')}</option>
                </select>
              </div>
            </div>

            {/* Active filter chips */}
            {activeCount > 0 && (
              <div style={{display:'flex', gap:8, flexWrap:'wrap', marginBottom:18}}>
                {filters.hasReference && <span className="chip chip-coral" style={{cursor:'pointer'}} onClick={()=>setFilters(f=>({...f,hasReference:false}))}>{t('helpers.withReference')} <Icon name="x" size={10}/></span>}
                {filters.hasVideo && <span className="chip chip-coral" style={{cursor:'pointer'}} onClick={()=>setFilters(f=>({...f,hasVideo:false}))}>{t('helpers.hasVideo')} <Icon name="x" size={10}/></span>}
                {/* Phase 2: re-enable verification chips.
                {filters.verification.map(v => <span key={v} className="chip chip-coral" style={{cursor:'pointer'}} onClick={()=>toggleMulti('verification',v)}>{v==='official'?'Official assessment':v==='agency'?'Agency':'Self'} <Icon name="x" size={10}/></span>)}
                */}
                {filters.nationality.map(n => (
                  <span key={n} className="chip chip-coral" style={{cursor:'pointer'}} onClick={()=>toggleMulti('nationality',n)}>
                    {n === 'Indonesia' ? t('helpers.nationalities.indonesia') : n === 'Philippines' ? t('helpers.nationalities.philippines') : n} <Icon name="x" size={10}/>
                  </span>
                ))}
                {filters.mainSkills.map(s => { const item = window.SKILL_TAXONOMY.mainSkills.find(x=>x.id===s); return <span key={s} className="chip chip-coral" style={{cursor:'pointer'}} onClick={()=>toggleMulti('mainSkills',s)}>{(item && (window.pickLocalised(item, 'label') || item.label)) || s} <Icon name="x" size={10}/></span>; })}
                {filters.languages.map(s => { const item = window.SKILL_TAXONOMY.languages.find(x=>x.id===s); return <span key={s} className="chip chip-coral" style={{cursor:'pointer'}} onClick={()=>toggleMulti('languages',s)}>{(item && (window.pickLocalised(item, 'label') || item.label)) || s} <Icon name="x" size={10}/></span>; })}
              </div>
            )}
            <div style={{display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:20}}>
              {paginated.map(c => (
                <CandidateCard key={c.id} candidate={c} go={go} onFav={toggleFav} isFav={favs.includes(c.id)} subscription={subscription}/>
              ))}
            </div>
            {filtered.length === 0 && (
              <div style={{textAlign:'center', padding:64, color:'var(--t-ink-muted)'}}>
                {t('helpers.empty.' + tab)}
              </div>
            )}
            {totalPages > 1 && (
              <div style={{display:'flex', alignItems:'center', justifyContent:'center', gap:6, marginTop:36, flexWrap:'wrap'}}>
                <button className="btn btn-ghost btn-sm" onClick={()=>setPage(p=>Math.max(1,p-1))} disabled={curPage===1}><Icon name="arrowLeft" size={13}/> {t('helpers.pagination.prev')}</button>
                {Array.from({length: totalPages}, (_,i)=>i+1).map(n => (
                  <button key={n} onClick={()=>setPage(n)} className="btn btn-sm" style={{minWidth:36, background: n===curPage?'var(--t-accent)':'transparent', color: n===curPage?'white':'var(--t-ink)', border:'1px solid', borderColor: n===curPage?'var(--t-accent)':'var(--t-line)'}}>{n}</button>
                ))}
                <button className="btn btn-ghost btn-sm" onClick={()=>setPage(p=>Math.min(totalPages,p+1))} disabled={curPage===totalPages}>{t('helpers.pagination.next')} <Icon name="arrow" size={13}/></button>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  );
};

const FilterGroup = ({ title, children, defaultOpen = true }) => {
  const [open, setOpen] = useState(defaultOpen);
  return (
    <div style={{paddingBottom:16, borderBottom:'1px solid var(--t-line)', marginBottom:16}}>
      <button onClick={() => setOpen(!open)} style={{
        display:'flex', justifyContent:'space-between', alignItems:'center', width:'100%',
        background:'none', border:'none', padding:'6px 0', cursor:'pointer',
        fontSize:14, fontWeight:600, letterSpacing:'-0.005em', color:'var(--t-ink)',
        marginBottom: open ? 12 : 0,
      }}>
        {title}
        <span style={{color:'var(--t-ink-muted)', fontSize:14, transform: open ? 'rotate(180deg)' : 'rotate(0deg)', transition:'transform 0.15s'}}>⌄</span>
      </button>
      {open && <div>{children}</div>}
    </div>
  );
};

const FilterCheckbox = ({ label, checked, onChange, count }) => (
  <label style={{display:'flex', alignItems:'center', gap:10, padding:'5px 0', cursor:'pointer', fontSize:13.5, color:'var(--t-ink)'}}>
    <input type="checkbox" checked={checked} onChange={onChange} style={{accentColor:'var(--trust)', width:15, height:15, flexShrink:0}}/>
    <span style={{flex:1}}>{label}</span>
    {count != null && <span style={{fontSize:11, color:'var(--t-ink-muted)'}}>{count}</span>}
  </label>
);

const FilterRadio = ({ label, checked, onChange, count, name }) => (
  <label style={{display:'flex', alignItems:'center', gap:10, padding:'5px 0', cursor:'pointer', fontSize:13.5, color:'var(--t-ink)'}}>
    <input type="radio" name={name} checked={checked} onChange={onChange} style={{accentColor:'var(--trust)', width:15, height:15, flexShrink:0}}/>
    <span style={{flex:1}}>{label}</span>
    {count != null && <span style={{fontSize:11, color:'var(--t-ink-muted)'}}>{count}</span>}
  </label>
);

// Compact two-handle range slider for sidebar filters. Two stacked native
// range inputs (lo/hi) with a track + filled segment. Same pattern as
// RangeSlider in pages-forms.jsx — the magic is the negative margin-top on
// ::-webkit-slider-thumb to center an 18px thumb on the 4px track.
const DualRangeMini = ({ min, max, value, unit = '', onChange }) => {
  const [lo, hi] = value;
  const pct = (v) => ((v - min) / (max - min)) * 100;
  const setLo = (v) => onChange([Math.min(v, hi), hi]);
  const setHi = (v) => onChange([lo, Math.max(v, lo)]);
  return (
    <div>
      <div style={{display:'flex', justifyContent:'space-between', marginBottom:10, fontSize:12.5, fontWeight:600, color:'var(--t-ink)'}}>
        <span>{lo}{unit}</span>
        <span>{hi}{unit}</span>
      </div>
      <div style={{position:'relative', height:22}}>
        {/* visual track */}
        <div style={{position:'absolute', top:9, left:0, right:0, height:4, background:'var(--t-line)', borderRadius:2}}/>
        {/* filled segment */}
        <div style={{position:'absolute', top:9, left:`${pct(lo)}%`, width:`${pct(hi)-pct(lo)}%`, height:4, background:'var(--trust)', borderRadius:2}}/>
        {/* two stacked native inputs — pointer-events:none on the input itself
            so the thumbs (which re-enable pointer-events:auto) are the only
            interactive surface, and neither input blocks the other's thumb. */}
        <input type="range" min={min} max={max} value={lo} onChange={(e)=>setLo(parseInt(e.target.value))} className="hm-dual-range"/>
        <input type="range" min={min} max={max} value={hi} onChange={(e)=>setHi(parseInt(e.target.value))} className="hm-dual-range"/>
        <style>{`
          .hm-dual-range {
            position:absolute; top:0; left:0; width:100%; height:22px;
            background:transparent; border:none; outline:none;
            -webkit-appearance:none; appearance:none;
            pointer-events:none; padding:0; margin:0;
          }
          .hm-dual-range::-webkit-slider-runnable-track { background:transparent; height:4px; border:none; }
          .hm-dual-range::-moz-range-track { background:transparent; height:4px; border:none; }
          .hm-dual-range::-webkit-slider-thumb {
            -webkit-appearance:none; appearance:none; pointer-events:auto;
            width:18px; height:18px; border-radius:50%;
            background:var(--trust); border:2.5px solid white;
            box-shadow:0 2px 5px rgba(0,0,0,0.25); cursor:pointer;
            margin-top:-7px; position:relative; z-index:2;
          }
          .hm-dual-range::-moz-range-thumb {
            pointer-events:auto;
            width:18px; height:18px; border-radius:50%;
            background:var(--trust); border:2.5px solid white;
            box-shadow:0 2px 5px rgba(0,0,0,0.25); cursor:pointer;
          }
          .hm-dual-range:focus { outline:none; }
        `}</style>
      </div>
    </div>
  );
};

// ===== Skills Group (used in Candidate Detail) =====
// SkillsGroup — renders one taxonomy slice (Language / Main / Cooking / Other)
// in a horizontal layout: title-with-icon-tile on the left, tag chips on the
// right (flex-wrap). Use `.hm-skills-row` className so consecutive rows pick
// up a top border via .hm-skills-row + .hm-skills-row in the parent <style>.
//
// All categories render as outline pill + 32px disc + icon + label, matching
// the unified chip style on the form ChipPicker. Languages put the flag emoji
// inside the disc (no flat-icon for languages); other categories use FlatIcon.
const SkillsGroup = ({ title, items, required, category = 'main', headerIconKey }) => {
  if (!items || items.length === 0) return null;
  const { t, lang } = window.useI18n();
  const c = window.SKILL_CAT_COLORS[category] || window.SKILL_CAT_COLORS.main;
  const itemLabel = (x) => window.pickLocalised(x, 'label', lang) || x.label;
  // Header disc — 40×40 with line-art SkillIcon at 24, the original detail-page
  // treatment. The `cat-X` (dash) ids have no flat-icon match, so the SkillIcon
  // alias falls through to the legacy monochrome line-art automatically.
  const headerLegacy = headerIconKey ? window.LegacySkillIcon : null;
  return (
    <div className="hm-skills-row">
      <div style={{display:'flex', alignItems:'center', gap:11, paddingTop:3}}>
        {headerIconKey && (
          <span style={{display:'grid', placeItems:'center', width:40, height:40, borderRadius:10, background:c.bg, color:c.fg, flexShrink:0}}>
            <SkillIcon name={headerIconKey} size={24}/>
          </span>
        )}
        <h4 className="display" style={{fontSize:15, fontWeight:600, letterSpacing:'-0.01em', color:'var(--t-ink)', margin:0}}>{title}</h4>
        {required && <span style={{fontSize:11, color:'var(--t-ink-muted)', fontWeight:500}}>{t('detail.required')}</span>}
      </div>
      <div style={{display:'flex', flexWrap:'wrap', gap:7}}>
        {items.map(x => {
          const flatDef = window.FLAT_ICONS && window.FLAT_ICONS[x.id];
          const discBg = flatDef && window.CAT_BG ? (window.CAT_BG[flatDef.cat] || c.bg) : c.bg;
          const isLang = category === 'language';
          return (
            <div key={x.id} style={{
              display:'inline-flex', alignItems:'center', gap:8,
              padding:'4px 13px 4px 4px', background:'var(--t-paper)',
              border:'1px solid var(--t-line)', borderRadius:99, fontSize:13,
            }}>
              <span style={{
                display:'grid', placeItems:'center', width:26, height:26, borderRadius:99,
                background: discBg, color: c.fg, flexShrink:0,
                fontSize: isLang ? 15 : undefined, lineHeight: 1,
              }}>
                {isLang
                  ? (x.flag || null)
                  : (flatDef
                      ? <window.FlatIcon name={x.id} size={18}/>
                      : <SkillIcon name={x.id} size={14}/>)}
              </span>
              <span style={{fontWeight:500, whiteSpace:'nowrap'}}>{itemLabel(x)}</span>
            </div>
          );
        })}
      </div>
    </div>
  );
};

// ===== Contact Modal =====
// Opens when a paid employer clicks "Contact <name>". Walks through:
//   1. Job confirmation — must have at least one posted job; pick one if many.
//   2. Channel — in-app message OR WhatsApp.
//   3. Compose / confirm — textarea for in-app, redirect for WhatsApp.
const ContactModal = ({ candidate, onClose, go }) => {
  const { t } = window.useI18n();
  const firstName = candidate.name.split(' ')[0];
  const allJobs = window.MOCK_DATA?.jobs || [];
  // Prototype assumption: every job in MOCK_DATA belongs to the current employer.
  const myJobs = allJobs;

  const [jobId, setJobId] = useState(myJobs.length === 1 ? myJobs[0].id : null);
  const [channel, setChannel] = useState(null);  // 'app' | 'whatsapp'
  const [message, setMessage] = useState('');

  const job = myJobs.find(j => j.id === jobId);

  // Derive a sensible default message once both job + channel are picked.
  React.useEffect(() => {
    if (job && !message) {
      setMessage(
        `Hi ${candidate.name.split(' ')[0]}, I'm interested in your profile for the role "${job.title}" in ${job.city}. Would you be open to discussing it further?`
      );
    }
    // eslint-disable-next-line
  }, [job?.id]);

  const close = () => onClose();

  const sendInApp = () => {
    if (!message.trim()) return;
    alert(t('contact.sentAlert', {name: candidate.name}));
    close();
  };

  const openWhatsApp = () => {
    const text = encodeURIComponent(message);
    window.open(`https://wa.me/?text=${text}`, '_blank', 'noopener');
    close();
  };

  // Determine which step to render (early-return-friendly chain).
  const stepNoJob   = myJobs.length === 0;
  const stepJobPick = !stepNoJob && !jobId;
  const stepChannel = !stepNoJob && jobId && !channel;
  const stepCompose = !stepNoJob && jobId && channel === 'app';
  const stepWhats   = !stepNoJob && jobId && channel === 'whatsapp';

  return (
    <div
      onClick={close}
      style={{
        position:'fixed', inset:0, zIndex:200,
        background:'rgba(15,12,10,0.55)', backdropFilter:'blur(4px)',
        display:'grid', placeItems:'center', padding:24,
      }}
    >
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background:'var(--t-paper)', borderRadius:14,
          width:'min(560px, 100%)', maxHeight:'85vh', overflow:'auto',
          boxShadow:'0 24px 80px rgba(0,0,0,0.3)', position:'relative',
          padding:'28px 28px 24px'
        }}
      >
        <button
          aria-label={t('contact.close')}
          onClick={close}
          style={{
            position:'absolute', top:14, right:14,
            width:32, height:32, borderRadius:99,
            background:'transparent', color:'var(--t-ink-muted)',
            border:'none', cursor:'pointer',
            display:'grid', placeItems:'center'
          }}
        >
          <Icon name="x" size={16}/>
        </button>

        {/* No-job state */}
        {stepNoJob && (
          <>
            <div className="display" style={{fontSize:22, marginBottom:8}}>{t('contact.stepNoJob.title')}</div>
            <p style={{fontSize:14, color:'var(--t-ink-muted)', lineHeight:1.55, marginBottom:20}}>
              {t('contact.stepNoJob.body', {first: firstName})}
            </p>
            <div style={{display:'flex', gap:8, justifyContent:'flex-end'}}>
              <button className="btn btn-ghost" onClick={close}>{t('contact.cancel')}</button>
              <button className="btn btn-primary" onClick={() => { close(); go('post-job'); }}>
                {t('contact.stepNoJob.cta')}
              </button>
            </div>
          </>
        )}

        {/* Job picker */}
        {stepJobPick && (
          <>
            <div className="display" style={{fontSize:22, marginBottom:6}}>{t('contact.stepJobPick.title')}</div>
            <p style={{fontSize:13, color:'var(--t-ink-muted)', marginBottom:18}}>
              {t('contact.stepJobPick.sub', {first: firstName})}
            </p>
            <div style={{display:'flex', flexDirection:'column', gap:10}}>
              {myJobs.map(j => (
                <button
                  key={j.id}
                  onClick={() => setJobId(j.id)}
                  style={{
                    textAlign:'left', cursor:'pointer',
                    padding:'14px 16px', borderRadius:'var(--t-radius-sm)',
                    border:'1px solid var(--t-line)', background:'var(--t-paper)',
                    display:'flex', alignItems:'center', gap:14
                  }}
                >
                  <div style={{flex:1, minWidth:0}}>
                    <div style={{fontWeight:600, fontSize:14, marginBottom:3, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}}>{j.title}</div>
                    <div style={{fontSize:12, color:'var(--t-ink-muted)', display:'flex', gap:10, flexWrap:'wrap'}}>
                      <span><Icon name="location" size={11}/> {j.city}</span>
                      <span>{j.salary}</span>
                      <span>{j.type}</span>
                    </div>
                  </div>
                  <Icon name="arrow" size={14}/>
                </button>
              ))}
            </div>
          </>
        )}

        {/* Channel picker */}
        {stepChannel && (
          <>
            <div className="display" style={{fontSize:22, marginBottom:6}}>{t('contact.stepChannel.title')}</div>
            <p style={{fontSize:13, color:'var(--t-ink-muted)', marginBottom:18}}>
              {t('contact.stepChannel.re')} <strong style={{color:'var(--t-ink)'}}>{job.title}</strong>
              {myJobs.length > 1 && (
                <button onClick={() => setJobId(null)} style={{marginLeft:10, fontSize:12, background:'none', border:'none', color:'var(--t-accent)', cursor:'pointer'}}>{t('contact.stepChannel.change')}</button>
              )}
            </p>
            <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:12}}>
              {[
                { id:'app',      icon:'chat', title: t('contact.stepChannel.inApp.title'),    desc: t('contact.stepChannel.inApp.desc', {first: firstName}) },
                { id:'whatsapp', icon:'send', title: t('contact.stepChannel.whatsapp.title'), desc: t('contact.stepChannel.whatsapp.desc') },
              ].map(opt => (
                <button
                  key={opt.id}
                  onClick={() => setChannel(opt.id)}
                  style={{
                    cursor:'pointer', textAlign:'left',
                    padding:'18px 16px', borderRadius:'var(--t-radius-sm)',
                    border:'1px solid var(--t-line)', background:'var(--t-paper)',
                    display:'flex', flexDirection:'column', gap:8, minHeight:130
                  }}
                >
                  <div style={{width:32, height:32, borderRadius:99, background:'var(--t-accent)', color:'white', display:'grid', placeItems:'center'}}>
                    <Icon name={opt.icon} size={14}/>
                  </div>
                  <div style={{fontWeight:600, fontSize:14}}>{opt.title}</div>
                  <div style={{fontSize:12, color:'var(--t-ink-muted)', lineHeight:1.5}}>{opt.desc}</div>
                </button>
              ))}
            </div>
          </>
        )}

        {/* In-app compose */}
        {stepCompose && (
          <>
            <div className="display" style={{fontSize:22, marginBottom:6}}>{t('contact.stepCompose.title', {first: firstName})}</div>
            <p style={{fontSize:13, color:'var(--t-ink-muted)', marginBottom:14}}>
              {t('contact.stepChannel.re')} <strong style={{color:'var(--t-ink)'}}>{job.title}</strong>
              <button onClick={() => setChannel(null)} style={{marginLeft:10, fontSize:12, background:'none', border:'none', color:'var(--t-accent)', cursor:'pointer'}}>{t('contact.stepCompose.changeChannel')}</button>
            </p>
            <textarea
              className="input"
              rows={6}
              value={message}
              onChange={(e) => setMessage(e.target.value)}
              placeholder={t('contact.stepCompose.placeholder')}
              style={{width:'100%', resize:'vertical', minHeight:140, lineHeight:1.55}}
            />
            <div style={{display:'flex', gap:8, justifyContent:'flex-end', marginTop:18}}>
              <button className="btn btn-ghost" onClick={close}>{t('contact.cancel')}</button>
              <button className="btn btn-primary" onClick={sendInApp} disabled={!message.trim()}>
                <Icon name="send" size={13}/> {t('contact.stepCompose.send')}
              </button>
            </div>
          </>
        )}

        {/* WhatsApp confirm */}
        {stepWhats && (
          <>
            <div className="display" style={{fontSize:22, marginBottom:6}}>{t('contact.stepWhats.title')}</div>
            <p style={{fontSize:13, color:'var(--t-ink-muted)', marginBottom:14}}>
              {t('contact.stepChannel.re')} <strong style={{color:'var(--t-ink)'}}>{job.title}</strong>
              <button onClick={() => setChannel(null)} style={{marginLeft:10, fontSize:12, background:'none', border:'none', color:'var(--t-accent)', cursor:'pointer'}}>{t('contact.stepCompose.changeChannel')}</button>
            </p>
            <div style={{padding:14, border:'1px solid var(--t-line)', background:'var(--t-bg)', borderRadius:'var(--t-radius-sm)', fontSize:14, lineHeight:1.6, marginBottom:14, whiteSpace:'pre-wrap'}}>
              {message}
            </div>
            <div style={{padding:'10px 12px', background:'rgba(72,184,160,0.08)', border:'1px solid rgba(72,184,160,0.3)', borderRadius:'var(--t-radius-sm)', fontSize:12, color:'var(--t-ink-soft)', lineHeight:1.5, marginBottom:18, display:'flex', gap:8, alignItems:'flex-start'}}>
              <Icon name="info" size={13}/>
              <span>{t('contact.stepWhats.info', {first: firstName})}</span>
            </div>
            <div style={{display:'flex', gap:8, justifyContent:'flex-end'}}>
              <button className="btn btn-ghost" onClick={close}>{t('contact.cancel')}</button>
              <button className="btn btn-primary" onClick={openWhatsApp}>
                {t('contact.stepWhats.cta')}
              </button>
            </div>
          </>
        )}
      </div>
    </div>
  );
};

// ===== Candidate Detail =====
const CandidateDetailPage = ({ id, go, favs, toggleFav, subscription, setShowUpgrade }) => {
  const { t } = window.useI18n();
  const c = window.MOCK_DATA.candidates.find(x => x.id === parseInt(id));
  if (!c) return <div className="container" style={{padding:60}}>{t('detail.notFound')}</div>;
  const locked = subscription === 'free';
  const firstName = c.name.split(' ')[0];
  const firstVideoCat = window.VIDEO_CATEGORIES.find(cat => c.videos?.[cat.id])?.id || 'cooking';
  const [activeVideo, setActiveVideo] = useState(firstVideoCat);
  const [photoOpen, setPhotoOpen] = useState(false);
  const [contactOpen, setContactOpen] = useState(false);
  const isFav = favs.includes(c.id);
  // Subscribed employer = anything other than 'free'.
  const handleContactClick = () => locked ? setShowUpgrade(true) : setContactOpen(true);

  // Basic row used in At a glance / My Expectations grids — matches the visual
  // language of the JobDetailPage so helper + job pages feel like the same product.
  const BasicRow = ({ icon, label, value }) => (
    <div style={{display:'flex', gap:12, padding:'10px 0', borderBottom:'1px solid var(--t-line)', alignItems:'center'}}>
      <div style={{width:40, height:40, borderRadius:10, background:'var(--trust-bg)', color:'var(--trust)', display:'grid', placeItems:'center', flexShrink:0}}>
        <Icon name={icon} size={20}/>
      </div>
      <div style={{flex:1, minWidth:0}}>
        <div style={{fontSize:11, fontWeight:700, letterSpacing:'0.06em', textTransform:'uppercase', color:'var(--t-ink-muted)', marginBottom:2}}>{label}</div>
        <div style={{fontSize:14, fontWeight:500, color:'var(--t-ink)'}}>{value}</div>
      </div>
    </div>
  );

  return (
    <div className="page has-sticky-cta">
      <div className="container-wide" style={{padding:'24px 32px 80px'}}>
        <button className="btn btn-ghost btn-sm" onClick={()=>go('candidates')} style={{marginBottom:20}}><Icon name="arrowLeft" size={14}/> {t('detail.back')}</button>

        {(() => {
          // "Likely found a job" banner: inactive 14+ days AND Available from date has passed.
          const lastActiveMs = typeof c.lastActiveDays === 'number' ? c.lastActiveDays * 86400000 : null;
          const inactiveDays = lastActiveMs != null ? c.lastActiveDays : (c.inactiveDays ?? null);
          const now = new Date();
          const avail = c.availableDate ? new Date(c.availableDate) : null;
          const availPassed = avail && !isNaN(avail) && avail < now;
          const inactiveEnough = (inactiveDays != null && inactiveDays >= 14) || c._forceFoundJobBanner;
          if (inactiveEnough && availPassed) {
            return (
              <div style={{
                display:'flex', alignItems:'flex-start', gap:14, padding:'16px 20px', marginBottom:20,
                background:'#FFF7E8', border:'1px solid #F3D08A', borderRadius:'var(--t-radius-sm)',
              }}>
                <div style={{
                  flexShrink:0, width:36, height:36, borderRadius:8, background:'#F3D08A',
                  display:'inline-flex', alignItems:'center', justifyContent:'center', color:'#8A5A12',
                }}>
                  <Icon name="info" size={16}/>
                </div>
                <div style={{flex:1, minWidth:0}}>
                  <div style={{fontWeight:700, fontSize:15, color:'#7A4F0F', marginBottom:3}}>
                    {t('detail.foundJobBanner.title', {first: firstName})}
                  </div>
                  <div style={{fontSize:13.5, color:'#8A5A12', lineHeight:1.55}}>
                    {t('detail.foundJobBanner.body', {days: inactiveDays ?? '14+', date: c.availableDate})}
                  </div>
                </div>
              </div>
            );
          }
          return null;
        })()}

        <div style={{display:'grid', gridTemplateColumns:'1fr 380px', gap:40}}>
          <div>
            {/* Header */}
            <div style={{display:'flex', gap:24, marginBottom:24}}>
              <button
                onClick={() => c.photoUrl && setPhotoOpen(true)}
                title={c.photoUrl ? t('detail.viewLargerPhoto') : ''}
                style={{padding:0, border:'none', background:'transparent', cursor: c.photoUrl ? 'zoom-in' : 'default', borderRadius:'50%'}}
              >
                <Avatar person={c} size={120}/>
              </button>
              <div style={{flex:1}}>
                <div style={{display:'flex', alignItems:'center', gap:12, marginBottom:6, flexWrap:'wrap'}}>
                  <h1 className="display" style={{fontSize:36}}>{c.name}</h1>
                  {/* Phase 2: replace the line below with `c.verification ? <VerificationBadge verification={c.verification} size="lg"/> : (c.verified && <VerifiedBadge big/>)` */}
                  {c.verified && <VerifiedBadge big/>}
                </div>
                <div style={{color:'var(--t-ink-muted)', fontSize:15, marginBottom:14}}>
                  {t('detail.sublineCurrentlyIn', {flag: c.flag, nationality: c.nationality, city: c.city})}
                </div>
                <div style={{display:'flex', gap:8, flexWrap:'wrap'}}>
                  <span className="chip">{t('detail.availableChip', {when: c.availableIn})}</span>
                  {(() => {
                    if (!c.lastActiveAt) return null;
                    const daysSince = (Date.now() - new Date(c.lastActiveAt).getTime()) / 86_400_000;
                    if (daysSince > 5) return null;
                    return (
                      <span style={{
                        display:'inline-flex', alignItems:'center', gap:6,
                        padding:'5px 12px', borderRadius:99,
                        background:'var(--t-accent)', color:'white',
                        fontSize:12, fontWeight:700, letterSpacing:'0.02em'
                      }}>
                        <span style={{fontSize:9}}>●</span> {t('detail.veryActive')}
                      </span>
                    );
                  })()}
                </div>
              </div>
            </div>

            {/* Videos — official candidates get 4 skill-category tabs; self/agency get a single intro. */}
            {window.isOfficial(c) && window.getVideoCount(c) > 0 && (() => {
              const [vid, setVid] = [activeVideo, setActiveVideo];
              const videoList = window.getVideoList(c);
              const current = videoList.find(x => x.id === vid) || videoList[0];
              return (
                <div style={{marginBottom:40}}>
                  <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-end', marginBottom:14, gap:12, flexWrap:'wrap'}}>
                    <div>
                      {/* Phase 2: append "· HelperMatch Assessment" once verification ships. */}
                      <div className="eyebrow" style={{marginBottom:6}}>{t('detail.video.skillVideos')}</div>
                      <h2 className="display" style={{fontSize:24}}>{t('detail.video.watchDemo', {first: firstName})}</h2>
                    </div>
                    {locked && <span className="chip chip-sand"><Icon name="lock" size={12}/> {t('detail.video.subscribe')}</span>}
                  </div>
                  {/* Category tabs */}
                  <div style={{display:'grid', gridTemplateColumns:`repeat(${window.VIDEO_CATEGORIES.length},1fr)`, gap:8, marginBottom:12}}>
                    {window.VIDEO_CATEGORIES.map(cat => {
                      const v = c.videos?.[cat.id];
                      const active = current.id === cat.id;
                      return (
                        <button key={cat.id} onClick={() => v && setVid(cat.id)} disabled={!v} style={{
                          padding:'10px 12px',
                          border:'1px solid',
                          borderColor: active ? 'var(--t-accent)' : 'var(--t-line)',
                          background: active ? 'var(--t-accent)' : 'var(--t-paper)',
                          color: active ? 'white' : (v ? 'var(--t-ink)' : 'var(--t-ink-muted)'),
                          borderRadius:'var(--t-radius-sm)',
                          cursor: v ? 'pointer' : 'not-allowed',
                          opacity: v ? 1 : 0.45,
                          display:'flex', alignItems:'center', justifyContent:'center', gap:8,
                          fontWeight:600, fontSize:13, letterSpacing:'-0.01em',
                          transition:'all 0.15s',
                        }}>
                          <Icon name={cat.icon} size={13}/>
                          {t('detail.videoCat.' + cat.id)}
                          {v ? (
                            <span style={{fontSize:11, opacity:0.85, fontWeight:500}}>· {v.duration}</span>
                          ) : (
                            <span style={{fontSize:10, opacity:0.7, fontWeight:500, textTransform:'uppercase', letterSpacing:'0.04em'}}>n/a</span>
                          )}
                        </button>
                      );
                    })}
                  </div>
                  {/* Active video thumbnail */}
                  <div style={{position:'relative'}}>
                    <VideoThumb candidate={c} locked={locked} height={420} onClick={() => locked && setShowUpgrade(true)}/>
                    <div style={{position:'absolute', bottom:14, left:14, padding:'6px 12px', background:'rgba(0,0,0,0.7)', borderRadius:6, color:'white', fontSize:13, fontWeight:600, display:'inline-flex', alignItems:'center', gap:8, backdropFilter:'blur(6px)'}}>
                      <Icon name={current.icon} size={13}/>
                      {t('detail.videoCat.' + current.id)}
                      <span style={{opacity:0.7}}>·</span>
                      <span style={{opacity:0.9, fontWeight:500}}>{current.video.duration}</span>
                    </div>
                  </div>
                </div>
              );
            })()}

            {!window.isOfficial(c) && window.getIntroVideo(c) && (
              <div style={{marginBottom:40}}>
                <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-end', marginBottom:14, gap:12, flexWrap:'wrap'}}>
                  <div>
                    {/* Phase 2: append "· uploaded by helper / agency" based on c.verification. */}
                    <div className="eyebrow" style={{marginBottom:6}}>{t('detail.video.intro')}</div>
                    <h2 className="display" style={{fontSize:24}}>{t('detail.video.meet', {first: firstName})}</h2>
                  </div>
                  {locked && <span className="chip chip-sand"><Icon name="lock" size={12}/> {t('detail.video.subscribe')}</span>}
                </div>
                <VideoThumb candidate={c} locked={locked} height={420} onClick={() => locked && setShowUpgrade(true)}/>
              </div>
            )}

            {/* Sections (single-page) — About → Skills → Work history → My
                Expectations → Assessment (only for officially-assessed). Each
                section is a card-flat block, mirroring the JobDetailPage design
                language so helpers + jobs feel like the same product. Reviews
                and helper-uploaded references are out-of-scope for MVP; the
                c.reviews data shape is preserved on candidates for future use. */}

            {/* Section 1: At a glance — demographics chips + key facts. The
                full "About {first}" bio + Personality chips live in their own
                section after Skills & Languages. */}
            <div className="card-flat" style={{padding:'18px 22px', marginBottom:18}}>
              <h3 className="display" style={{fontSize:20, margin:'4px 0 14px'}}>{t('detail.atGlance')}</h3>
              {c.demographics && (() => {
                // Demographics rendered as outline pills (matching the SkillsGroup
                // language chips). Each chip carries an Icon-tinted dot from the
                // page's shared trust-bg / trust-fg palette so the row reads as
                // part of the same visual language.
                // Height + weight live in the BasicRow grid below (eyebrow label
                // carries the meaning). Chip row keeps the 5 fields that have
                // semantic icon matches.
                const items = [
                  { icon:'user',      v: c.demographics.gender },
                  { icon:'heart',     v: c.demographics.maritalStatus },
                  { icon:'sun',       v: c.age ? `${c.age} ${t('detail.personUnit.yrs')}` : null },
                  { icon:'baby',      v: c.demographics.kids },
                  { icon:'sparkle',   v: c.demographics.religion },
                ].filter(x => x.v);
                return (
                  <div style={{display:'flex', flexWrap:'wrap', gap:6, marginBottom:14}}>
                    {items.map((it, i) => (
                      <div key={i} style={{display:'inline-flex', alignItems:'center', gap:7, padding:'5px 11px 5px 5px', background:'var(--t-paper)', border:'1px solid var(--t-line)', borderRadius:99, fontSize:12.5}}>
                        <span style={{display:'grid', placeItems:'center', width:22, height:22, borderRadius:99, background:'var(--trust-bg)', color:'var(--trust)', flexShrink:0}}>
                          {it.icon === 'baby' ? <SkillIcon name="baby" size={13}/> : <Icon name={it.icon} size={12}/>}
                        </span>
                        <span style={{fontWeight:500, color:'var(--t-ink)', whiteSpace:'nowrap'}}>{it.v}</span>
                      </div>
                    ))}
                  </div>
                );
              })()}
              <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:'0 32px'}}>
                <BasicRow icon="briefcase" label={t('detail.contractStatus')}    value={c.contractStatus}/>
                <BasicRow icon="calendar"  label={t('detail.availableFrom')}     value={c.availableDate}/>
                <BasicRow icon="clock"     label={t('detail.yearsExperience')}   value={t('detail.yearsValue', {n: c.yearsExperience})}/>
                <BasicRow icon="book"      label={t('detail.education')}         value={c.demographics?.education || '—'}/>
                <BasicRow icon="location"  label={t('detail.currentLocation')}   value={c.city}/>
                {/* Single Yes/No reference signal — MVP doesn't surface uploaded
                    letters or employer reviews. */}
                <BasicRow icon="check"     label={t('detail.reference')}         value={c.hasReference ? t('detail.yes') : t('detail.no')}/>
                {/* Height + weight removed from MVP display — schema field
                    (c.demographics.height / .weight) preserved for future use. */}
              </div>

            </div>

            {/* Section 2: Skills — horizontal SkillsGroup rows (title left, tags right). */}
            <div className="card-flat" style={{padding:'18px 22px', marginBottom:18}}>
              <style>{`
                .hm-skills-row { display:grid; grid-template-columns: 170px 1fr; column-gap:20px; padding:13px 0; align-items:flex-start; }
                .hm-skills-row + .hm-skills-row { border-top: 1px solid var(--t-line); }
                @media (max-width: 720px) {
                  .hm-skills-row { grid-template-columns: 1fr; row-gap:8px; }
                }
              `}</style>
              <h3 className="display" style={{fontSize:20, margin:'4px 0 6px'}}>{t('detail.skillsLanguages')}</h3>
              <SkillsGroup
                title={t('detail.skillCat.language')}
                category="language"
                headerIconKey="cat-language"
                items={window.SKILL_TAXONOMY.languages.filter(x => c.typedSkills?.languages?.includes(x.id))}
              />
              <SkillsGroup
                title={t('detail.skillCat.mainSkills')}
                category="main"
                headerIconKey="cat-main"
                items={window.SKILL_TAXONOMY.mainSkills.filter(x => c.typedSkills?.mainSkills?.includes(x.id))}
              />
              <SkillsGroup
                title={t('detail.skillCat.cookingSkills')}
                category="cooking"
                headerIconKey="cat-cooking"
                items={window.SKILL_TAXONOMY.cookingSkills.filter(x => c.typedSkills?.cookingSkills?.includes(x.id))}
              />
              <SkillsGroup
                title={t('detail.skillCat.otherSkills')}
                category="other"
                headerIconKey="cat-other"
                items={window.SKILL_TAXONOMY.otherSkills.filter(x => c.typedSkills?.otherSkills?.includes(x.id))}
              />
              {/* Personality moved into the standalone "About {first}" section
                  below — it sits with the bio paragraph as a soft-skills snapshot. */}
            </div>

            {/* Section: About {first} — bio + personality chips (no chip-group
                header on personality, just the chips themselves). */}
            <div className="card-flat" style={{padding:'18px 22px', marginBottom:18}}>
              <h3 className="display" style={{fontSize:20, margin:'4px 0 12px'}}>{t('detail.about', {first: firstName})}</h3>
              <p style={{fontSize:14.5, lineHeight:1.6, color:'var(--t-ink-soft)', margin:0}}>{window.pickLocalised(c, 'bio') || c.bio}</p>
              {c.typedSkills?.personality?.length > 0 && (() => {
                const persColor = window.SKILL_CAT_COLORS.personality;
                const persItems = window.SKILL_TAXONOMY.personality.filter(x => c.typedSkills.personality.includes(x.id));
                if (persItems.length === 0) return null;
                return (
                  <div style={{display:'flex', flexWrap:'wrap', gap:6, marginTop:14}}>
                    {persItems.map(p => (
                      <div key={p.id} style={{display:'inline-flex', alignItems:'center', gap:7, padding:'5px 12px 5px 5px', background:'var(--t-paper)', border:'1px solid var(--t-line)', borderRadius:99, fontSize:13}}>
                        <span style={{display:'grid', placeItems:'center', width:22, height:22, borderRadius:99, background:persColor.bg, color:persColor.fg, flexShrink:0}}>
                          <SkillIcon name={p.id} size={13}/>
                        </span>
                        <span style={{fontWeight:500, whiteSpace:'nowrap'}}>{window.pickLocalised(p, 'label') || p.label}</span>
                      </div>
                    ))}
                  </div>
                );
              })()}
            </div>

            {/* Section 3: Work history */}
            <div className="card-flat" style={{padding:'18px 22px', marginBottom:18}}>
              <h3 className="display" style={{fontSize:20, margin:'4px 0 14px'}}>{t('detail.workHistory')}</h3>
              <div style={{display:'flex',flexDirection:'column', gap:8}}>
                {[
                  { city: t('detail.workMock.e1City'), years: t('detail.workMock.e1Years'), role: t('detail.workMock.e1Role') },
                  { city: t('detail.workMock.e2City'), years: t('detail.workMock.e2Years'), role: t('detail.workMock.e2Role') },
                  { city: t('detail.workMock.e3City'), years: t('detail.workMock.e3Years'), role: t('detail.workMock.e3Role') },
                ].map((e, i) => (
                  <div key={i} style={{display:'flex', gap:12, padding:'12px 14px', background:'var(--t-paper)', border:'1px solid var(--t-line)', borderRadius:'var(--t-radius-sm)', alignItems:'center'}}>
                    <div style={{width:40, height:40, borderRadius:10, background:'var(--trust-bg)', color:'var(--trust)', display:'grid', placeItems:'center', flexShrink:0}}>
                      <Icon name="briefcase" size={20}/>
                    </div>
                    <div style={{flex:1, minWidth:0}}>
                      <div style={{display:'flex', justifyContent:'space-between', alignItems:'baseline', gap:12, marginBottom:2, flexWrap:'wrap'}}>
                        <div style={{fontWeight:600, fontSize:14}}>{e.role}</div>
                        <div style={{fontSize:12, color:'var(--t-ink-muted)', display:'inline-flex', alignItems:'center', gap:4}}>
                          <Icon name="calendar" size={11}/> {e.years}
                        </div>
                      </div>
                      <div style={{fontSize:12.5, color:'var(--t-ink-muted)', display:'inline-flex', alignItems:'center', gap:4}}>
                        <Icon name="location" size={11}/> {e.city}
                      </div>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* Section 4: My Expectations — pulled from the resume form's
                preferences step (expectedSalary / accommodation / dayOff). */}
            <div className="card-flat" style={{padding:'18px 22px', marginBottom:18}}>
              <h3 className="display" style={{fontSize:20, margin:'4px 0 12px'}}>{t('detail.expectations')}</h3>
              <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:'0 32px'}}>
                <BasicRow icon="dollar" label={t('detail.salary')}        value={c.expectations?.salary || t('detail.tbd')}/>
                <BasicRow icon="home"   label={t('detail.accommodation')} value={c.expectations?.accommodation || t('detail.tbd')}/>
                <BasicRow icon="sun"    label={t('detail.dayOff')}        value={c.expectations?.dayOff || t('detail.tbd')}/>
              </div>
            </div>

            {/* Section 5 (conditional): Assessment — only for officially-assessed candidates */}
            {c.verification === 'official' && (
              <div className="card-flat" style={{padding:'18px 22px', marginBottom:18}}>
                <div style={{display:'flex', alignItems:'center', gap:11, marginBottom:14}}>
                  <span style={{display:'inline-flex', width:40, height:40, alignItems:'center', justifyContent:'center', background:'var(--trust)', color:'white', borderRadius:10, fontSize:20, fontWeight:800, letterSpacing:'-0.02em'}}>H</span>
                  <h3 className="display" style={{fontSize:20, margin:0}}>{t('detail.assessment.title')}</h3>
                </div>
                <div style={{display:'flex', flexDirection:'column', gap:10}}>
                  {[
                    [t('detail.assessment.rows.cooking'),    9, 'sparkle'],
                    [t('detail.assessment.rows.cleaning'),   8, 'home'],
                    [t('detail.assessment.rows.childcare'),  7, 'heart'],
                    [t('detail.assessment.rows.eldercare'),  9, 'shield'],
                    [t('detail.assessment.rows.english'),    7, 'message'],
                    [t('detail.assessment.rows.mandarin'),   6, 'globe'],
                  ].map(([k,v,iconName]) => (
                    <div key={k}>
                      <div style={{display:'flex', justifyContent:'space-between', marginBottom:4, fontSize:13.5}}>
                        <span style={{fontWeight:500, display:'inline-flex', alignItems:'center', gap:6}}>
                          <Icon name={iconName} size={12}/> {k}
                        </span>
                        <span style={{fontWeight:600}}>{v}/10</span>
                      </div>
                      <div style={{height:7, background:'var(--t-line)', borderRadius:99, overflow:'hidden'}}>
                        <div style={{width:`${v*10}%`, height:'100%', background: v>=8?'var(--mint)':v>=6?'var(--t-accent)':'#D4A554', borderRadius:99}}/>
                      </div>
                    </div>
                  ))}
                </div>
              </div>
            )}
          </div>

          {/* Sticky action */}
          <aside>
            <div style={{position:'sticky', top:96}}>
              <div className="card-flat" style={{padding:28}}>
                <div style={{display:'flex', flexDirection:'column', gap:10}}>
                  <button className="btn btn-primary btn-lg btn-block" onClick={handleContactClick}>
                    {locked ? <><Icon name="lock" size={14}/> {t('detail.sticky.subscribeContact')}</> : <><Icon name="chat" size={14}/> {t('detail.sticky.contactName', {first: firstName})}</>}
                  </button>
                  <button className="btn btn-outline btn-block" onClick={()=>toggleFav(c.id)}>
                    <Icon name={isFav?'heartFill':'heart'} size={14}/> {isFav ? t('detail.sticky.saved') : t('detail.sticky.save')}
                  </button>
                </div>
                <hr className="divider" style={{margin:'24px 0'}}/>
                <div style={{display:'flex', flexDirection:'column', gap:14, fontSize:14}}>
                  <div style={{display:'flex', justifyContent:'space-between'}}>
                    <span style={{color:'var(--t-ink-muted)'}}>{t('detail.sticky.available')}</span>
                    <span style={{fontWeight:500}}>{c.availableIn}</span>
                  </div>
                  <div style={{display:'flex', justifyContent:'space-between'}}>
                    <span style={{color:'var(--t-ink-muted)'}}>{t('detail.sticky.contractStatus')}</span>
                    <span style={{fontWeight:500, textAlign:'right'}}>{c.contractStatus}</span>
                  </div>
                  <div style={{display:'flex', justifyContent:'space-between'}}>
                    <span style={{color:'var(--t-ink-muted)'}}>{t('detail.sticky.lastActive')}</span>
                    <span style={{fontWeight:500}}>{c.active}</span>
                  </div>
                </div>
                {locked && (
                  <div style={{marginTop:20, padding:16, background:'var(--coral-bg)', borderRadius:'var(--t-radius-sm)', fontSize:13, color:'var(--coral-dark)', lineHeight:1.5}}>
                    <strong style={{fontSize:13}}>{t('detail.sticky.unlockTitle')}</strong>
                    <div style={{marginTop:4}}>{t('detail.sticky.unlockBody')}</div>
                    <button className="btn btn-primary btn-sm" style={{marginTop:12}} onClick={()=>go('pricing')}>{t('detail.sticky.unlockCta')}</button>
                  </div>
                )}
              </div>
            </div>
          </aside>
        </div>
      </div>

      {/* Sticky mobile CTA bar */}
      <div className="sticky-cta-bar">
        <button className="btn btn-outline btn-icon" aria-label={isFav ? t('detail.sticky.saved') : t('detail.sticky.save')} onClick={()=>toggleFav(c.id)}>
          <Icon name={isFav?'heartFill':'heart'} size={18}/>
        </button>
        <div className="cta-meta">
          <strong>{firstName}</strong>
          <span>{t('detail.availableChip', {when: c.availableIn})}</span>
        </div>
        <button className="btn btn-primary" onClick={handleContactClick}>
          {locked ? <><Icon name="lock" size={14}/> {t('detail.sticky.subscribeShort')}</> : <><Icon name="chat" size={14}/> {t('detail.sticky.contactShort')}</>}
        </button>
      </div>

      {/* Contact flow — only opens when the employer is on a paid plan. */}
      {contactOpen && <ContactModal candidate={c} onClose={() => setContactOpen(false)} go={go}/>}

      {/* Enlarged-photo modal — opens when the header avatar is clicked.
          Click the backdrop or the close button to dismiss. */}
      {photoOpen && c.photoUrl && (
        <div
          onClick={() => setPhotoOpen(false)}
          style={{
            position:'fixed', inset:0, zIndex:200,
            background:'rgba(15,12,10,0.82)',
            backdropFilter:'blur(6px)',
            display:'grid', placeItems:'center',
            padding:24,
            animation:'hm-photo-fade 0.18s ease-out'
          }}
        >
          <style>{`@keyframes hm-photo-fade { from { opacity: 0 } to { opacity: 1 } }`}</style>
          <button
            aria-label={t('common.close')}
            onClick={() => setPhotoOpen(false)}
            style={{
              position:'absolute', top:20, right:20,
              width:40, height:40, borderRadius:99,
              background:'rgba(255,255,255,0.92)', color:'#3D2B1F',
              border:'none', cursor:'pointer',
              display:'grid', placeItems:'center'
            }}
          >
            <Icon name="x" size={18}/>
          </button>
          <img
            src={c.photoUrl}
            alt={c.name}
            onClick={(e) => e.stopPropagation()}
            style={{
              maxWidth:'min(90vw, 720px)',
              maxHeight:'85vh',
              borderRadius:12,
              boxShadow:'0 24px 80px rgba(0,0,0,0.5)',
              display:'block'
            }}
          />
        </div>
      )}
    </div>
  );
};

Object.assign(window, { HomePage, CandidatesPage, CandidateDetailPage });
