/* WPSiteBeam Scanner — Contact Tab
   Auto-split from Scanner.jsx.
*/
(function () {
  'use strict';
  const ScanEmptyState = window.ScanEmptyState;
  const Icon = window.Icon;

function ScannerContactTab({ data, payloads }) {
  const { useState } = React;
  /* 2026-05-18 v3 per Jordan: format phone numbers from raw +1XXXXXXXXXX
     E.164 to readable "(XXX) XXX-XXXX". Was "bad display format (coding)" —
     showing the raw "+17855796146" instead of "(785) 579-6146". Handles US
     10-digit (with or without leading +1) and falls back to original string
     for non-US/non-10-digit numbers. */
  const formatPhone = (raw) => {
    if (!raw) return '';
    const digits = String(raw).replace(/\D/g, '');
    // US 11-digit (with leading 1)
    if (digits.length === 11 && digits.startsWith('1')) {
      return `(${digits.slice(1,4)}) ${digits.slice(4,7)}-${digits.slice(7)}`;
    }
    // US 10-digit
    if (digits.length === 10) {
      return `(${digits.slice(0,3)}) ${digits.slice(3,6)}-${digits.slice(6)}`;
    }
    return String(raw);
  };
  /* Session A defensive reading: server.js may return contact as either
     legacy bare strings ("sales@foo.com") OR labeled objects ({email, label}).
     Normalize both shapes to the same internal rendering shape so the UI
     works regardless of which server version is deployed. */
  const normEmail = (e) => {
    if (!e) return null;
    if (typeof e === 'object') return { addr: e.email || e.value || '', label: e.label || 'Email' };
    return { addr: String(e), label: 'Email' };
  };
  const normPhone = (p) => {
    if (!p) return null;
    if (typeof p === 'object') return { num: p.number || p.value || '', label: p.label || p.type || 'Phone', type: p.type || 'Phone' };
    return { num: String(p), label: 'Phone', type: 'Phone' };
  };

  /* Placeholder detection — strips out fake/example phone numbers that
     creep in from form placeholder attributes ("(999) 999-9999"),
     tutorial copy, or tel: links pointing at sample numbers. We only
     filter if the digit pattern is OBVIOUSLY fake — all same digit
     (1111111111), sequential (1234567890), or a known tutorial number
     (555-prefixed in US/Canada is reserved for fictional use). */
  const isPlaceholderPhone = (numStr) => {
    if (!numStr) return false;
    const digits = String(numStr).replace(/\D/g, '');
    if (digits.length < 7) return true;  /* Too short to be real */
    /* All same digit */
    if (/^(\d)\1+$/.test(digits)) return true;
    /* Sequential ascending: 1234567890, 0123456789 */
    if (/^0?12345678/.test(digits) || /^1234567890$/.test(digits)) return true;
    /* US 555-prefix in area code OR exchange (reserved for fiction) */
    /* Normalize to 10-digit US format if leading 1 */
    const normalized = digits.length === 11 && digits.startsWith('1') ? digits.slice(1) : digits;
    if (normalized.length === 10) {
      const exchange = normalized.slice(3, 6);
      if (exchange === '555') return true;  /* (xxx) 555-xxxx is fictional */
    }
    return false;
  };

  const emails = (data?.contact?.emails || []).map(normEmail).filter(x => x && x.addr);
  /* Phones: primary filter happens upstream in ScannerData.normalizeScanData.
     Apply isPlaceholderPhone here too as defensive backstop in case
     legacy/cached data slipped through. */
  const phones = (data?.contact?.phones || [])
    .map(normPhone)
    .filter(x => x && x.num)
    .filter(x => !isPlaceholderPhone(x.num));
  const socials = (data?.contact?.socials || data?.contact?.social || []);
  const address = data?.contact?.address || null;

  /* Multi-location TABS (2026-05-18 v2 per Jordan):
     Replaces v1 grouped-sections render. When ≥2 distinct phone labels exist
     (e.g. KPCHC with "Junction City", "Manhattan", "Pharmacy" × 2, "After Hours Care"),
     render a vertical tab strip on the left + filtered location content on the right.
     Primary address is paired with the location tab whose label matches the city
     (best-effort string match). Falls back to flat single-card view when there's
     only one phone or one label (single-location site). */
  const locationTabs = (() => {
    if (phones.length < 2) return null;
    const groups = new Map();
    for (const p of phones) {
      const key = (p.label || 'Phone').trim();
      if (!groups.has(key)) groups.set(key, []);
      groups.get(key).push(p);
    }
    if (groups.size < 2) return null;
    // Try to match primary address city to a location label
    const primaryAddr = data?.contact?.address || '';
    const addrLower = primaryAddr.toLowerCase();
    const tabs = [
      { key: '__all__', label: 'All', phones, addressForLoc: primaryAddr || null, isAll: true },
    ];
    for (const [label, locPhones] of groups.entries()) {
      // Address pairs with a location tab if the address text contains the label
      // (e.g. "Junction City" tab matches "361 Grant Ave Junction City, KS 66441")
      const matchesAddr = primaryAddr && addrLower.includes(label.toLowerCase());
      tabs.push({
        key: label,
        label,
        phones: locPhones,
        addressForLoc: matchesAddr ? primaryAddr : null,
        isAll: false,
      });
    }
    return tabs;
  })();
  const [selectedLocKey, setSelectedLocKey] = useState('__all__');
  const activeTab = locationTabs ? (locationTabs.find(t => t.key === selectedLocKey) || locationTabs[0]) : null;

  const hasContact = emails.length > 0 || phones.length > 0 || socials.length > 0 || !!address;
  if (!hasContact) {
    return <ScanEmptyState tab="contact" reason="No emails, phone numbers, social links, or address could be extracted from this site's homepage or /contact page. The site may load its contact info dynamically (via JavaScript), hide it behind a form, or simply not include any on public pages." />;
  }
  return (
    <div style={{ display:'flex', flexDirection:'column', gap:16 }}>
      <div className="grid grid-2">
      {/* LEFT 50%: Contact Info — consolidated emails + phones + address.
          Previously 3 separate cards (emails & phones, address, social full-width);
          merged into one "Contact Info" card so users scan one block for everything
          a CRM needs, and Social gets its own 50% card on the right. */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">Contact Info</h2>
          <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbDownload(`${data.site}-contacts.csv`, payloads.contactCsv, 'text/csv')}>
            <Icon name="download" size={12}/>CSV
          </button>
        </div>
        <div className="card-body">
          {(emails.length === 0 && phones.length === 0 && !address) && (
            <div style={{ padding:'16px 0', textAlign:'center', color:'var(--muted)', fontSize:'.82rem' }}>
              No emails, phone numbers, or address found in this site's HTML.
            </div>
          )}

          {/* MULTI-LOCATION VERTICAL TABS (2026-05-18 v2 per Jordan).
              Renders left-rail location tabs + filtered content on the right
              when ≥2 phone labels exist. Single-location sites fall through to
              the flat rendering below this block. */}
          {locationTabs && activeTab && (
            <div style={{ display:'flex', gap:12, alignItems:'stretch', minHeight:180 }}>
              {/* Left rail — vertical location tabs */}
              <div role="tablist" aria-label="Locations / departments" style={{ display:'flex', flexDirection:'column', gap:2, minWidth:130, maxWidth:160, borderRight:'1px solid var(--border)', paddingRight:8 }}>
                {locationTabs.map(t => {
                  const isActive = t.key === selectedLocKey;
                  return (
                    <button key={t.key}
                            role="tab"
                            aria-selected={isActive}
                            tabIndex={isActive ? 0 : -1}
                            onClick={() => setSelectedLocKey(t.key)}
                            style={{
                              all:'unset', cursor:'pointer',
                              padding:'8px 10px', borderRadius:5,
                              fontSize: t.isAll ? '.74rem' : '.72rem',
                              fontWeight: isActive ? 600 : 400,
                              color: isActive ? 'var(--text)' : 'var(--muted)',
                              background: isActive ? 'var(--surface-2, rgba(255,255,255,.04))' : 'transparent',
                              borderLeft: '2px solid ' + (isActive ? 'var(--accent, #00C2D1)' : 'transparent'),
                              display:'flex', alignItems:'center', justifyContent:'space-between', gap:6,
                            }}>
                      <span style={{ overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{t.label}</span>
                      <span style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>{t.phones.length}</span>
                    </button>
                  );
                })}
              </div>
              {/* Right pane — selected location's content */}
              <div style={{ flex:1, minWidth:0 }}>
                {/* 2026-05-18 v3 per Jordan: heading row at top of the right pane
                    showing the active location's name + count summary + a link
                    to the site's actual contact page (since the scanner can
                    miss locations / addresses — Jordan flagged Chapman missing
                    + only Junction City had an address). The "View source" link
                    gives the user a fast escape hatch to verify against the
                    real page. */}
                <div style={{ display:'flex', alignItems:'baseline', gap:8, paddingBottom:8, marginBottom:6, borderBottom:'1px solid var(--border)' }}>
                  <div style={{ fontSize:'.92rem', fontWeight:700, color:'var(--text)' }}>{activeTab.label}</div>
                  <div style={{ fontSize:'.68rem', color:'var(--dim)', fontFamily:'var(--font-mono)' }}>
                    {activeTab.phones.length} {activeTab.phones.length === 1 ? 'phone' : 'phones'}
                    {activeTab.addressForLoc ? ' · 1 address' : ''}
                    {activeTab.isAll && emails.length > 0 ? ` · ${emails.length} email${emails.length===1?'':'s'}` : ''}
                  </div>
                  <a href={(data.siteUrl || ('https://' + data.site)).replace(/\/$/, '') + '/contact/'}
                     target="_blank" rel="noopener noreferrer"
                     style={{ marginLeft:'auto', fontSize:'.66rem', color:'var(--beam, #00C2D1)', textDecoration:'none' }}
                     title="Open the site's contact page in a new tab — useful if data looks incomplete">
                    View source page ↗
                  </a>
                </div>
                {/* On "All" tab, show emails section; on other tabs, suppress (most sites share one email across locations) */}
                {activeTab.isAll && emails.map((e, i) => (
                  <div key={'em-'+i+'-'+e.addr} style={{ display:'flex', gap:8, alignItems:'center', padding:'6px 0', borderBottom:'1px solid var(--border)' }}>
                    <Icon name="bell" size={14}/>
                    <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:2 }}>
                      {e.label && e.label !== 'Email' && (
                        <span style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em' }}>{e.label.toUpperCase()}</span>
                      )}
                      <a href={`mailto:${e.addr}`} className="mono" style={{ fontSize:'.78rem', color:'var(--text)', wordBreak:'break-all' }}>{e.addr}</a>
                    </div>
                    <button className="btn btn-ghost btn-sm" style={{ fontSize:'.68rem', padding:'3px 8px' }} onClick={() => window.wpsbCopy(e.addr, `Copied ${e.addr}`)} aria-label={`Copy email ${e.addr}`}>Copy</button>
                  </div>
                ))}
                {/* Phones for the selected location.
                    2026-05-18 v3 per Jordan: disambiguate same-label phones
                    (e.g. "Pharmacy" appearing twice). Pre-compute label counts
                    so duplicate-labeled entries get "#1" / "#2" suffix.
                    Display number is run through formatPhone() — no more raw
                    +17855796146; shows "(785) 579-6146". */}
                {(() => {
                  // Count label occurrences in this tab's phones
                  const labelCounts = new Map();
                  activeTab.phones.forEach(p => {
                    const k = (p.label || 'Phone').trim();
                    labelCounts.set(k, (labelCounts.get(k) || 0) + 1);
                  });
                  // Track running index per label to assign "#N" suffix when dup
                  const seenSoFar = new Map();
                  return activeTab.phones.map((p, i) => {
                    const baseLabel = (p.label || 'Phone').trim();
                    const total = labelCounts.get(baseLabel) || 1;
                    const idx = (seenSoFar.get(baseLabel) || 0) + 1;
                    seenSoFar.set(baseLabel, idx);
                    const displayLabel = total > 1 ? `${baseLabel} #${idx}` : baseLabel;
                    const formattedNum = formatPhone(p.num);
                    return (
                      <div key={'ph-'+activeTab.key+'-'+i+'-'+p.num} style={{ display:'flex', gap:8, alignItems:'center', padding:'6px 0', borderBottom:'1px solid var(--border)' }}>
                        <Icon name="support" size={14}/>
                        <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:2 }}>
                          {p.label && (
                            <span style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em' }}>{displayLabel.toUpperCase()}</span>
                          )}
                          <a href={`tel:${p.num.replace(/[^\d+]/g,'')}`} className="mono" style={{ fontSize:'.82rem', color:'var(--text)' }}>{formattedNum}</a>
                        </div>
                        <button className="btn btn-ghost btn-sm" style={{ fontSize:'.68rem', padding:'3px 8px' }} onClick={() => window.wpsbCopy(formattedNum, `Copied ${formattedNum}`)} aria-label={`Copy phone ${formattedNum}`}>Copy</button>
                      </div>
                    );
                  });
                })()}
                {/* Address — show if this tab has a matched address (or "All") */}
                {activeTab.addressForLoc && (
                  <div style={{ display:'flex', gap:8, alignItems:'flex-start', padding:'10px 0' }}>
                    <Icon name="sites" size={14}/>
                    <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:4 }}>
                      <span style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em' }}>ADDRESS</span>
                      <div style={{ fontSize:'.78rem', lineHeight:1.5, color:'var(--text)' }}>{activeTab.addressForLoc}</div>
                      <div style={{ display:'flex', gap:6, marginTop:2 }}>
                        <button className="btn btn-ghost btn-sm" style={{ fontSize:'.66rem', padding:'3px 7px' }}
                                onClick={() => window.open(`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(activeTab.addressForLoc)}`, '_blank', 'noopener')}>
                          <Icon name="sites" size={11}/>Open in Maps
                        </button>
                        <button className="btn btn-ghost btn-sm" style={{ fontSize:'.66rem', padding:'3px 7px' }}
                                onClick={() => window.wpsbCopy(activeTab.addressForLoc, 'Address copied')}>Copy</button>
                      </div>
                    </div>
                  </div>
                )}
                {!activeTab.isAll && !activeTab.addressForLoc && (
                  <div style={{ fontSize:'.7rem', color:'var(--muted)', padding:'10px 0', fontStyle:'italic', lineHeight:1.5 }}>
                    No address extracted for <strong>{activeTab.label}</strong>.
                    The scanner may have missed it — check the source page link above, or see the Embedded Maps section below for location coordinates.
                  </div>
                )}
              </div>
            </div>
          )}

          {/* SINGLE-LOCATION / no-tabs fallback — original flat rendering */}
          {!locationTabs && (
            <React.Fragment>
              {/* Emails */}
              {emails.map((e, i) => (
                <div key={'em-'+i+'-'+e.addr} style={{ display:'flex', gap:8, alignItems:'center', padding:'8px 0', borderBottom:'1px solid var(--border)' }}>
                  <Icon name="bell" size={14}/>
                  <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:2 }}>
                    {e.label && e.label !== 'Email' && (
                      <span style={{ fontSize:'.65rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em' }}>
                        {e.label.toUpperCase()}
                      </span>
                    )}
                    <a href={`mailto:${e.addr}`} className="mono" style={{ fontSize:'.82rem', color:'var(--text)', wordBreak:'break-all' }}>{e.addr}</a>
                  </div>
                  <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbCopy(e.addr, `Copied ${e.addr}`)} aria-label={`Copy email ${e.addr}`}>Copy</button>
                </div>
              ))}
              {/* Phones — flat list */}
              {phones.map((p, i) => (
                <div key={'ph-'+i+'-'+p.num} style={{ display:'flex', gap:8, alignItems:'center', padding:'8px 0', borderBottom:'1px solid var(--border)' }}>
                  <Icon name="support" size={14}/>
                  <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:2 }}>
                    {p.label && p.label !== 'Phone' && (
                      <span style={{ fontSize:'.65rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em' }}>
                        {p.label.toUpperCase()}
                      </span>
                    )}
                    <a href={`tel:${p.num.replace(/[^\d+]/g,'')}`} className="mono" style={{ fontSize:'.82rem', color:'var(--text)' }}>{p.num}</a>
                  </div>
                  <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbCopy(p.num, `Copied ${p.num}`)} aria-label={`Copy phone ${p.num}`}>Copy</button>
                </div>
              ))}
              {/* Addresses — flat */}
              {(() => {
                const addr = data.contact.address;
                const extras = (data.contact.city_state_zip || [])
                  .filter(x => x && x !== addr)
                  .filter(x => !addr || !addr.includes(x));
                const all = [];
                if (addr) all.push(addr);
                extras.forEach(x => { if (!all.includes(x)) all.push(x); });
                if (all.length === 0) return null;
                return all.map((a, i) => (
                  <div key={'ad-'+i} style={{ display:'flex', gap:8, alignItems:'flex-start', padding:'10px 0', borderBottom: i < all.length - 1 ? '1px solid var(--border)' : 'none' }}>
                    <Icon name="sites" size={14}/>
                    <div style={{ flex:1, minWidth:0, display:'flex', flexDirection:'column', gap:4 }}>
                      <span style={{ fontSize:'.65rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em' }}>
                        {i === 0 ? 'ADDRESS' : 'ADDITIONAL LOCATION'}
                      </span>
                      <div style={{ fontSize:'.82rem', lineHeight:1.5, color:'var(--text)' }}>{a}</div>
                      <div style={{ display:'flex', gap:6, marginTop:2 }}>
                        <button className="btn btn-ghost btn-sm" style={{ fontSize:'.68rem', padding:'3px 8px' }}
                                onClick={() => window.open(`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(a)}`, '_blank', 'noopener')}>
                          <Icon name="sites" size={11}/>Open in Maps
                        </button>
                        <button className="btn btn-ghost btn-sm" style={{ fontSize:'.68rem', padding:'3px 8px' }}
                                onClick={() => window.wpsbCopy(a, 'Address copied')}>
                          Copy
                        </button>
                      </div>
                    </div>
                  </div>
                ));
              })()}
            </React.Fragment>
          )}
        </div>
      </div>

      {/* RIGHT 50%: Social channels — moved from full-width to 50% to balance
          with Contact Info. If there are many socials, scroll inside card.

          Each row gets a small colored brand-letter badge in the Platform
          column for visual scannability — e.g. blue F for Facebook, dark
          IG for Instagram. Colors are the platform's official brand color
          where well-known; falls back to neutral gray for unknown
          platforms. Pure inline styling — no Icon component dependency. */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">Social channels</h2>
          {(data.contact.socials || data.contact.social || []).length > 0 && (
            <span className="tag">{(data.contact.socials || data.contact.social || []).length} found</span>
          )}
        </div>
        <div className="card-body" style={{ padding: 0 }}>
          {(data.contact.socials || data.contact.social || []).length === 0 ? (
            <div style={{ padding:'20px', textAlign:'center', color:'var(--muted)', fontSize:'.82rem', lineHeight:1.6 }}>
              No social channels detected in the scanned pages.
              <div style={{ fontSize:'.72rem', color:'var(--dim)', marginTop:6, fontFamily:'var(--font-mono)', letterSpacing:'.02em' }}>
                Checked: Facebook · X/Twitter · Instagram · LinkedIn · YouTube · TikTok · GitHub · Pinterest · Yelp
              </div>
            </div>
          ) : (
            <table className="table">
              <thead><tr><th scope="col">Platform</th><th scope="col">Handle</th><th scope="col"></th></tr></thead>
              <tbody>
                {(data.contact.socials || data.contact.social || []).map(s => {
                  const platform = s.name || s.n || '';
                  const handle   = s.handle || s.h || '';
                  const url      = s.url || '';
                  /* Brand color map — official hex from each platform's
                     style guide. Lowercase key match; fallback gray for
                     unknown. Letter is the first uppercase character of
                     the platform name. */
                  const SOCIAL_BRAND = {
                    facebook:         { bg:'#1877F2', fg:'#ffffff', letter:'f'    },
                    instagram:        { bg:'#E4405F', fg:'#ffffff', letter:'I'    },
                    linkedin:         { bg:'#0A66C2', fg:'#ffffff', letter:'in'   },
                    twitter:          { bg:'#000000', fg:'#ffffff', letter:'X'    },
                    x:                { bg:'#000000', fg:'#ffffff', letter:'X'    },
                    youtube:          { bg:'#FF0000', fg:'#ffffff', letter:'Y'    },
                    tiktok:           { bg:'#000000', fg:'#ffffff', letter:'TT'   },
                    github:           { bg:'#181717', fg:'#ffffff', letter:'GH'   },
                    pinterest:        { bg:'#E60023', fg:'#ffffff', letter:'P'    },
                    yelp:             { bg:'#FF1A1A', fg:'#ffffff', letter:'Yelp' },
                    google:           { bg:'#4285F4', fg:'#ffffff', letter:'G'    },
                    'google business':{ bg:'#EA4335', fg:'#ffffff', letter:'G'    },
                    threads:          { bg:'#000000', fg:'#ffffff', letter:'@'    },
                    mastodon:         { bg:'#6364FF', fg:'#ffffff', letter:'M'    },
                    bluesky:          { bg:'#1185FE', fg:'#ffffff', letter:'B'    },
                  };
                  const platformKey = platform.toLowerCase().replace(/[^a-z]/g, '');
                  const brand = SOCIAL_BRAND[platformKey] || {
                    bg:'rgba(255,255,255,.08)', fg:'var(--muted)',
                    letter: (platform[0] || '?').toUpperCase(),
                  };
                  /* Letter sizing — single chars get bigger, 2-char gets smaller */
                  const fontSize = brand.letter.length === 1 ? '.78rem' :
                                    brand.letter.length === 2 ? '.6rem' : '.5rem';
                  return (
                    <tr key={platform + handle}>
                      <td style={{ fontWeight:600 }}>
                        <span style={{ display:'inline-flex', alignItems:'center', gap:8 }}>
                          <span style={{
                            display:'inline-flex', alignItems:'center', justifyContent:'center',
                            width:22, height:22, borderRadius:'50%',
                            background: brand.bg, color: brand.fg,
                            fontSize, fontWeight:700,
                            fontFamily:'var(--font-sans, inherit)',
                            flexShrink:0,
                          }}>{brand.letter}</span>
                          <span>{platform}</span>
                        </span>
                      </td>
                      <td className="mono" style={{ color:'var(--beam)', fontSize:'.82rem', wordBreak:'break-all' }}>{handle}</td>
                      <td>
                        {url ? <a href={url} target="_blank" rel="noopener noreferrer">Visit →</a> : null}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          )}
        </div>
      </div>
      </div>
      {/* end grid-2: Contact Info + Social channels */}

      {/* Multi-location section — shown when scan detected 2+ location blocks.
          Layout adapts to count: grid cards for 2-5 locations (scannable at a glance),
          vertical tab strip for 6+ (handles Levanders Auto-style 20-30 location sites). */}
      {(() => {
        const locs = Array.isArray(data?.contact?.locations) ? data.contact.locations : [];
        if (locs.length < 2) return null;

        /* ── Shared social row renderer ─────────────────────────────
           Used in both LocationDetail (per-location) and the main
           Social Channels card. Keeps brand badge logic in one place. */
        const SOCIAL_BADGE = {
          facebook:         { bg:'#1877F2', letter:'f'    },
          instagram:        { bg:'#E4405F', letter:'I'    },
          linkedin:         { bg:'#0A66C2', letter:'in'   },
          twitter:          { bg:'#000000', letter:'X'    },
          x:                { bg:'#000000', letter:'X'    },
          youtube:          { bg:'#FF0000', letter:'Y'    },
          tiktok:           { bg:'#000000', letter:'TT'   },
          github:           { bg:'#181717', letter:'GH'   },
          pinterest:        { bg:'#E60023', letter:'P'    },
          yelp:             { bg:'#FF1A1A', letter:'Yelp' },
          'google business':{ bg:'#EA4335', letter:'G'    },
          google:           { bg:'#4285F4', letter:'G'    },
          threads:          { bg:'#000000', letter:'@'    },
          mastodon:         { bg:'#6364FF', letter:'M'    },
          bluesky:          { bg:'#1185FE', letter:'B'    },
        };
        function SocialBadge({ platform }) {
          const key = (platform || '').toLowerCase().replace(/[^a-z ]/g, '');
          const b = SOCIAL_BADGE[key] || { bg:'rgba(255,255,255,.08)', letter:(platform[0]||'?').toUpperCase() };
          const sz = b.letter.length === 1 ? '.78rem' : b.letter.length <= 2 ? '.6rem' : '.5rem';
          return (
            <span style={{
              display:'inline-flex', alignItems:'center', justifyContent:'center',
              width:20, height:20, borderRadius:'50%', flexShrink:0,
              background:b.bg, color:'#fff', fontSize:sz, fontWeight:700,
            }}>{b.letter}</span>
          );
        }
        function SocialRows({ socials }) {
          if (!socials || socials.length === 0) return null;
          return (
            <div>
              {socials.map((s, i) => {
                const platform = s.name || s.n || '';
                const handle   = s.handle || s.h || '';
                const url      = s.url || '';
                return (
                  <div key={platform + handle + i}
                    style={{ display:'flex', gap:8, alignItems:'center', padding:'6px 0',
                      borderBottom: i < socials.length - 1 ? '1px solid var(--border)' : 'none' }}>
                    <SocialBadge platform={platform} />
                    <div style={{ flex:1, minWidth:0 }}>
                      <div style={{ fontSize:'.72rem', fontWeight:600, color:'var(--text)' }}>{platform}</div>
                      {handle && (
                        <div className="mono" style={{ fontSize:'.7rem', color:'var(--beam)', overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{handle}</div>
                      )}
                    </div>
                    {url && (
                      <a href={url} target="_blank" rel="noopener noreferrer"
                        style={{ fontSize:'.68rem', color:'var(--beam)', whiteSpace:'nowrap' }}>Visit →</a>
                    )}
                  </div>
                );
              })}
            </div>
          );
        }

        /* ── Shared location detail renderer ─────────────────────────────
           Used by both layouts. Shows address, phones, emails.
           Per-location socials rendered separately via SocialRows. */
        function LocationDetail({ loc }) {
          return (
            <div style={{ display:'flex', flexDirection:'column', gap:10 }}>
              {loc.address && (
                <div style={{ display:'flex', gap:8, alignItems:'flex-start' }}>
                  <Icon name="sites" size={13} style={{ color:'var(--dim)', marginTop:2, flexShrink:0 }}/>
                  <div style={{ flex:1, minWidth:0 }}>
                    <div style={{ fontSize:'.78rem', color:'var(--text)', lineHeight:1.5 }}>{loc.address}</div>
                    <button onClick={() => window.open(`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(loc.address)}`, '_blank', 'noopener')}
                      style={{ background:'none', border:'none', color:'var(--beam)', fontSize:'.68rem', cursor:'pointer', padding:0, marginTop:2 }}>
                      Open in Maps
                    </button>
                  </div>
                </div>
              )}
              {(loc.phones || []).map((p, pi) => (
                <div key={pi} style={{ display:'flex', gap:8, alignItems:'center' }}>
                  <Icon name="support" size={13} style={{ color:'var(--dim)', flexShrink:0 }}/>
                  <div style={{ flex:1, minWidth:0 }}>
                    {p.label && p.label !== 'Phone' && (
                      <div style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em', textTransform:'uppercase' }}>
                        {p.label}
                      </div>
                    )}
                    <a href={`tel:${(p.number||'').replace(/[^\d+]/g,'')}`}
                       className="mono" style={{ fontSize:'.8rem', color:'var(--text)' }}>{p.number}</a>
                  </div>
                  <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbCopy(p.number, 'Copied')} style={{ fontSize:'.68rem', padding:'2px 8px' }}>Copy</button>
                </div>
              ))}
              {(loc.emails || []).map((e, ei) => (
                <div key={ei} style={{ display:'flex', gap:8, alignItems:'center' }}>
                  <Icon name="bell" size={13} style={{ color:'var(--dim)', flexShrink:0 }}/>
                  <a href={`mailto:${e}`} className="mono" style={{ fontSize:'.78rem', color:'var(--text)', flex:1, minWidth:0, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>{e}</a>
                  <button className="btn btn-ghost btn-sm" onClick={() => window.wpsbCopy(e, 'Copied')} style={{ fontSize:'.68rem', padding:'2px 8px' }}>Copy</button>
                </div>
              ))}
            </div>
          );
        }

        /* ── Grid layout for 2-5 locations ── */
        if (locs.length <= 5) {
          return (
            <div>
              <div style={{ fontWeight:700, color:'var(--dim)', fontSize:'.75rem', textTransform:'uppercase', letterSpacing:'.06em', marginBottom:12 }}>
                📍 {locs.length} Locations Detected
              </div>
              <div style={{ display:'grid', gridTemplateColumns:'repeat(auto-fill, minmax(280px, 1fr))', gap:12 }}>
                {locs.map((loc, li) => (
                  <div key={li} style={{
                    background:'var(--surface)', border: loc.is_primary ? '1px solid var(--beam-dim)' : '1px solid var(--border)',
                    borderRadius:10, overflow:'hidden',
                  }}>
                    <div style={{ padding:'12px 16px', background: loc.is_primary ? 'var(--beam-dim)' : 'var(--surface2)',
                      display:'flex', justifyContent:'space-between', alignItems:'center' }}>
                      <div style={{ fontWeight:700, color: loc.is_primary ? 'var(--beam)' : 'var(--text)', fontSize:'.9rem' }}>
                        {loc.name}
                      </div>
                      {loc.is_primary && (
                        <span style={{ fontSize:'.62rem', fontWeight:700, padding:'2px 7px', borderRadius:4,
                          background:'var(--beam-dim)', color:'var(--beam)', border:'1px solid var(--beam-dim)' }}>
                          PRIMARY
                        </span>
                      )}
                    </div>
                    <div style={{ padding:'12px 16px' }}>
                      <LocationDetail loc={loc} />
                      {/* Socials for this location — shown below contact if present */}
                      {(loc.socials || []).length > 0 && (
                        <div style={{ borderTop:'1px solid var(--border)', marginTop:10, paddingTop:10 }}>
                          <div style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em', textTransform:'uppercase', marginBottom:6 }}>Social</div>
                          <SocialRows socials={loc.socials} />
                        </div>
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          );
        }

        /* ── Vertical tab strip for 6+ locations (Levanders Auto scale) ── */
        function MultiLocationTabStrip({ locs }) {
          const [active, setActive] = React.useState(0);
          const loc = locs[active];
          return (
            <div>
              <div style={{ fontWeight:700, color:'var(--dim)', fontSize:'.75rem', textTransform:'uppercase', letterSpacing:'.06em', marginBottom:12 }}>
                📍 {locs.length} Locations Detected
              </div>
              <div style={{ display:'flex', gap:0, border:'1px solid var(--border)', borderRadius:10, overflow:'hidden', minHeight:320 }}>
                {/* Left tab strip */}
                <div style={{
                  width:200, flexShrink:0,
                  background:'var(--surface2)', borderRight:'1px solid var(--border)',
                  overflowY:'auto', maxHeight:480,
                }}>
                  {locs.map((l, li) => (
                    <button key={li}
                      onClick={() => setActive(li)}
                      style={{
                        width:'100%', textAlign:'left', padding:'10px 14px',
                        background: li === active ? 'var(--beam-dim)' : 'transparent',
                        borderLeft: li === active ? '3px solid var(--beam)' : '3px solid transparent',
                        borderTop:'none', borderRight:'none', borderBottom:'1px solid var(--border)',
                        color: li === active ? 'var(--beam)' : 'var(--text)',
                        fontSize:'.8rem', fontWeight: li === active ? 700 : 400,
                        cursor:'pointer', transition:'all .15s',
                      }}>
                      <div style={{ whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis', maxWidth:160 }}>
                        {l.name || `Location ${li + 1}`}
                      </div>
                      {l.is_primary && (
                        <div style={{ fontSize:'.6rem', color:'var(--beam)', fontFamily:'var(--font-mono)', marginTop:2 }}>PRIMARY</div>
                      )}
                    </button>
                  ))}
                </div>
                {/* Right detail panel */}
                <div style={{ flex:1, padding:'16px 20px', minWidth:0, overflowY:'auto', maxHeight:480 }}>
                  <div style={{ fontWeight:700, color:'var(--text)', fontSize:'.95rem', marginBottom:12, display:'flex', alignItems:'center', gap:8 }}>
                    {loc.name || `Location ${active + 1}`}
                    {loc.is_primary && (
                      <span style={{ fontSize:'.62rem', fontWeight:700, padding:'2px 7px', borderRadius:4,
                        background:'var(--beam-dim)', color:'var(--beam)', border:'1px solid var(--beam-dim)' }}>
                        PRIMARY
                      </span>
                    )}
                  </div>
                  <LocationDetail loc={loc} />
                  {/* Per-location socials — below contact info, primary location first */}
                  {(loc.socials || []).length > 0 && (
                    <div style={{ borderTop:'1px solid var(--border)', marginTop:14, paddingTop:12 }}>
                      <div style={{ fontSize:'.62rem', color:'var(--dim)', fontFamily:'var(--font-mono)', letterSpacing:'.04em', textTransform:'uppercase', marginBottom:8 }}>
                        Social channels
                      </div>
                      <SocialRows socials={loc.socials} />
                    </div>
                  )}
                </div>
              </div>
            </div>
          );
        }
        return <MultiLocationTabStrip locs={locs} />;
      })()}

      {/* Embedded Maps — populated from per-page crawl via extractMapsFromBody */}
      <div className="card">
        <div className="card-head">
          <h2 className="card-title">Embedded Maps</h2>
          {(data.maps || 0) > 0 && <span className="tag">{data.maps}</span>}
        </div>
        <div className="card-body" style={{ padding:0 }}>
          {!(data.mapsList && data.mapsList.length) ? (
            <ScanEmptyState
              bare
              tab="embedded maps"
              reason="No embedded maps were detected. Run a Full or Deep scan to crawl pages — Google Maps iframes, Mapbox, OpenStreetMap, and Leaflet embeds are detected automatically from page HTML."
            />
          ) : (
            <table className="table">
              <thead>
                <tr>
                  <th>Provider</th>
                  <th>Address / Title</th>
                  <th>Page Found</th>
                  <th style={{ textAlign:'right' }}>Preview</th>
                </tr>
              </thead>
              <tbody>
                {data.mapsList.map((m, i) => (
                  <tr key={i}>
                    <td style={{ fontWeight:600, whiteSpace:'nowrap' }}>
                      {m.provider === 'Google Maps' ? '🗺 ' : '📍 '}{m.provider}
                    </td>
                    <td style={{ fontSize:'.8rem', color:'var(--text)' }}>
                      {m.address || m.title || <span style={{ color:'var(--dim)' }}>—</span>}
                    </td>
                    <td style={{ fontSize:'.72rem', color:'var(--dim)', fontFamily:'var(--font-mono)',
                      maxWidth:200, overflow:'hidden', textOverflow:'ellipsis', whiteSpace:'nowrap' }}>
                      {m.page_url ? m.page_url.replace(/^https?:\/\/[^/]+/, '') : '—'}
                    </td>
                    <td style={{ textAlign:'right' }}>
                      {m.address ? (
                        <a href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(m.address)}`}
                           target="_blank" rel="noopener" style={{ fontSize:'.72rem', color:'var(--beam)' }}>
                          Maps →
                        </a>
                      ) : m.src ? (
                        <a href={m.src} target="_blank" rel="noopener" style={{ fontSize:'.72rem', color:'var(--beam)' }}>
                          View →
                        </a>
                      ) : null}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </div>
  );
}


window.ScannerContactTab = ScannerContactTab;
})();
