// landing.jsx — Editorial directory landing
const Rolodex = () => {
  // Decorative wheel — fictional example cards (NOT real listings), so the spinning
  // display never features real unclaimed providers. Covers a range of disciplines.
  const cards = [
    { name:'Amber Ellen',        credentials:'LMT',      specialty:'TMJ Massage' },
    { name:'Strat Poulson',      credentials:'DC',       specialty:'Chiropractor' },
    { name:'Maya Ellison',       credentials:'DDS, MS',  specialty:'Orofacial Pain Specialist' },
    { name:'Dr. Owen Hegarty',   credentials:'DMD',      specialty:'TMJ-trained Dentist' },
    { name:'Priya Raman',        credentials:'DPT, OCS', specialty:'Physical Therapist' },
    { name:'Dr. Hannah Vos',     credentials:'DDS',      specialty:'Neuromuscular Dentist' },
    { name:'Tomás Albright',     credentials:'COM',      specialty:'Myofunctional Therapist' },
    { name:'Dr. Elise Fontaine', credentials:'DMD',      specialty:'Sleep & Airway' },
  ];
  const N = cards.length;
  const radius = 90; // px — distance from center axis
  return (
    <div className="ed-rolo" aria-hidden="true">
      {/* Metal stand silhouette */}
      <svg className="ed-rolo-stand" viewBox="0 0 280 240" fill="none" preserveAspectRatio="xMidYMid meet">
        <defs>
          {/* Tube body gradient — chrome highlight */}
          <linearGradient id="chrome-tube" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="#c8ccd1"/>
            <stop offset=".18" stopColor="#f5f6f8"/>
            <stop offset=".42" stopColor="#a8acb3"/>
            <stop offset=".62" stopColor="#5e6168"/>
            <stop offset="1"   stopColor="#2c2e33"/>
          </linearGradient>
          {/* Base bar — top-lit chrome */}
          <linearGradient id="chrome-base" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="#e6e8ec"/>
            <stop offset=".4" stopColor="#9fa3aa"/>
            <stop offset="1" stopColor="#3a3c42"/>
          </linearGradient>
          {/* Hub gradient — radial */}
          <radialGradient id="chrome-hub" cx=".35" cy=".3" r=".8">
            <stop offset="0" stopColor="#fafbfc"/>
            <stop offset=".4" stopColor="#9aa0a8"/>
            <stop offset="1" stopColor="#1f2126"/>
          </radialGradient>
          {/* End cap (collar) */}
          <linearGradient id="collar" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="#d8dbe0"/>
            <stop offset=".5" stopColor="#7d8088"/>
            <stop offset="1" stopColor="#2a2c30"/>
          </linearGradient>
        </defs>

        {/* contact shadow on table */}
        <ellipse cx="140" cy="222" rx="100" ry="5" fill="rgba(0,0,0,.22)"/>

        {/* Back tube (behind wheel) — for depth */}
        <path d="M 50 215 Q 50 215 50 165 Q 50 130 90 130 L 190 130 Q 230 130 230 165 L 230 215"
              fill="none" stroke="url(#chrome-tube)" strokeWidth="9" strokeLinecap="round" opacity=".55"/>

        {/* Front horizontal base bar */}
        <rect x="40" y="208" width="200" height="13" rx="6.5" fill="url(#chrome-base)"/>
        {/* Base bar highlight */}
        <rect x="46" y="210" width="188" height="2" rx="1" fill="rgba(255,255,255,.7)"/>

        {/* End feet */}
        <ellipse cx="46" cy="221" rx="9" ry="3.5" fill="#1a1c20"/>
        <ellipse cx="234" cy="221" rx="9" ry="3.5" fill="#1a1c20"/>

        {/* Front uprights — U arms */}
        <path d="M 70 215 L 70 168 Q 70 138 100 138" stroke="url(#chrome-tube)" strokeWidth="8" strokeLinecap="round" fill="none"/>
        <path d="M 210 215 L 210 168 Q 210 138 180 138" stroke="url(#chrome-tube)" strokeWidth="8" strokeLinecap="round" fill="none"/>

        {/* Highlight slivers on uprights */}
        <path d="M 67 175 L 67 200" stroke="rgba(255,255,255,.65)" strokeWidth="1.5" strokeLinecap="round"/>
        <path d="M 207 175 L 207 200" stroke="rgba(255,255,255,.65)" strokeWidth="1.5" strokeLinecap="round"/>

        {/* Axle hubs — left and right */}
        <circle cx="100" cy="138" r="13" fill="url(#chrome-hub)"/>
        <circle cx="100" cy="138" r="5" fill="#16181c"/>
        <circle cx="98"  cy="135" r="2.5" fill="rgba(255,255,255,.85)"/>

        <circle cx="180" cy="138" r="13" fill="url(#chrome-hub)"/>
        <circle cx="180" cy="138" r="5" fill="#16181c"/>
        <circle cx="178" cy="135" r="2.5" fill="rgba(255,255,255,.85)"/>

        {/* Collar / clip on right upright */}
        <rect x="200" y="186" width="20" height="22" rx="3" fill="url(#collar)"/>
        <rect x="203" y="189" width="14" height="2" rx="1" fill="rgba(255,255,255,.6)"/>
        <rect x="203" y="194" width="14" height="1.2" rx=".6" fill="rgba(0,0,0,.35)"/>
        <rect x="203" y="198" width="14" height="1.2" rx=".6" fill="rgba(0,0,0,.35)"/>
      </svg>

      <div className="ed-rolo-shadow"/>

      <div className="ed-rolo-wheel">
        {Array.from({length:N}).map((_,i)=>{
          const angle = (360 / N) * i;
          const card = cards[i] || { name:'—', credentials:'—', specialty:'—' };
          const initials = (card.name||'').split(' ').filter(s=>!s.endsWith('.')).slice(0,2).map(s=>s[0]).join('') || 'TM';
          return (
            <div
              key={i}
              className="ed-rolo-card"
              style={{ transform:`rotateX(${angle}deg) translateZ(${radius}px)` }}
            >
              <span className="ed-rolo-card-tab">{card.specialty||''}</span>
              <div className="ed-rolo-card-name">{card.name}</div>
              <div className="ed-rolo-card-cred">{card.credentials}</div>
              <div className="ed-rolo-card-rule">
                <span>№ {String(i+1).padStart(3,'0')}</span>
                <span>{initials}</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
};

const Landing = ({ onSearch }) => {
  const [zip, setZip] = React.useState('');
  const [spec, setSpec] = React.useState('');
  const [insurance, setInsurance] = React.useState('');

  return (
    <main className="pt-main">
      {/* HERO — editorial display */}
      <section className="ed-hero">
        <div className="ed-hero-inner">
          <h1 className="ed-display">
            TMJD is complicated.<br/>
            Finding <span className="ital">help</span><br/>
            shouldn't be.
          </h1>

          <div className="ed-sub-row">
            <div className="ed-sub-col">
              <div className="ed-sub-eyebrow">A note</div>
              Temporomandibular disorders sit at the seam of dentistry, neurology, and musculoskeletal medicine. Most patients see four or five providers before finding one who treats the whole picture.
            </div>
            <div className="ed-orb" style={{display:'none'}}/>
            <Rolodex/>
            <div className="ed-sub-col r">
              <div className="ed-sub-eyebrow">What we do</div>
              We index vetted TMJ-trained clinicians across eleven disciplines so you can find them in a single search — wherever you live, whatever insurance you carry.
            </div>
          </div>

          <div className="ed-search" role="search" aria-label="Search TMJ specialists">
            <div className="ed-search-cell">
              <label htmlFor="loc-input">City, state or ZIP</label>
              <input id="loc-input" value={zip} onChange={e=>setZip(e.target.value)} placeholder="e.g. 64152 or Austin, TX"/>
            </div>
            <div className="ed-search-cell">
              <label htmlFor="spec-select">Specialty</label>
              <select id="spec-select" value={spec} onChange={e=>setSpec(e.target.value)}>
                <option value="">Any specialty</option>
                {SPECIALTIES.map(s=>(<option key={s.key} value={s.key}>{s.label}</option>))}
              </select>
            </div>
            <div className="ed-search-cell">
              <label htmlFor="ins-select">Insurance</label>
              <select id="ins-select" value={insurance} onChange={e=>setInsurance(e.target.value)}>
                <option value="">Any insurance</option>
                <option>Aetna</option>
                <option>BlueCross BlueShield</option>
                <option>Cigna</option>
                <option>United Healthcare</option>
                <option>Medicare</option>
                <option>Self-pay</option>
              </select>
            </div>
            <button className="ed-search-go" onClick={()=>onSearch({zip, spec, insurance})} aria-label="Search specialists">
              Search <span aria-hidden="true" style={{fontSize:16}}>↗</span>
            </button>
          </div>

          <div style={{marginTop:18,fontSize:14.5,color:'var(--ink-2)'}}>
            Not sure who to see first?{' '}
            <a href="quiz.html" style={{textDecoration:'underline',fontWeight:600,color:'var(--accent-ink)'}}>
              Take the 2-minute "where should I start?" quiz →
            </a>
          </div>
        </div>
      </section>

      {/* MARQUEE strip */}
      <section className="ed-marquee" aria-label="Directory statistics">
        <div className="ed-marquee-track" aria-hidden="true">
          {Array.from({length:2}).map((_,i)=>(
            <div key={i} className="ed-marquee-item">
              <span>4,851 specialists</span>
              <span className="star">✦</span>
              <span className="ital">in</span>
              <span>11 disciplines</span>
              <span className="star">✦</span>
              <span className="ital">verified</span>
              <span>weekly</span>
              <span className="star">✦</span>
            </div>
          ))}
        </div>
        <span className="sr-only">Directory contains 4,851 specialists in 11 disciplines, verified weekly.</span>
      </section>
      <section className="ed-section">
        <div className="ed-section-head">
          <div className="ed-num">001 / 04<strong>Disciplines</strong></div>
          <h2 className="ed-section-title">
            Eleven specialties — <span className="ital">one condition.</span>
          </h2>
        </div>
        <div className="ed-disc">
          {SPECIALTIES.map((s,i)=>(
            <div key={s.key} className="ed-disc-row" onClick={()=>onSearch({spec:s.key})}>
              <span className="ed-disc-num">{String(i+1).padStart(2,'0')}</span>
              <span className="ed-disc-title">{s.label}</span>
              <span className="ed-disc-meta">Specialists<strong>{s.count.toLocaleString()}</strong></span>
            </div>
          ))}
        </div>
      </section>

      {/* QUOTE */}
      <section className="ed-quote">
        <div className="ed-quote-mark">"</div>
        <div className="ed-quote-inner">
          <blockquote>
            I saw seven providers across <span className="ital">three states</span> before I found a clinician who actually understood what was happening to my jaw.
          </blockquote>
          <div className="ed-quote-cite">— Anonymous patient · Survey, 2025</div>
        </div>
      </section>

      {/* FEATURED — editorial cards */}
      <section className="ed-section">
        <div className="ed-section-head">
          <div className="ed-num">002 / 04<strong>Featured</strong></div>
          <h2 className="ed-section-title">
            Recently joined the <span className="ital">directory.</span>
          </h2>
        </div>
        <div className="ed-feat-grid">
          {PROVIDERS
            .filter(p => (p.status === 'premium' || p.premium || p.status === 'claimed') && p.rating != null && p.bio)
            .sort((a,b) => (Number(b.rating)||0) - (Number(a.rating)||0))
            .slice(0,3)
            .map((p,i)=>(
            <article key={p.id} className="ed-feat" onClick={()=>onSearch({focus:p.id})}>
              <div className="ed-feat-photo">
                <Placeholder label={p.photoLabel} style={{width:'100%',height:'100%',borderRadius:0}}/>
                <span className="ed-feat-cat">{p.specialty}</span>
                <span className="ed-feat-num">{String(i+1).padStart(2,'0')}</span>
              </div>
              <div className="ed-feat-body">
                <h3 className="ed-feat-name">{p.name}</h3>
                <div className="ed-feat-cred">{p.credentials}</div>
                <div className="ed-feat-loc">{p.city}{p.state?`, ${p.state}`:''} · {p.country}</div>
                <p className="ed-feat-bio">"{p.bio}"</p>
                <div className="ed-feat-foot">
                  {p.rating != null ? (
                    <span className="ed-feat-rating">★ {Number(p.rating).toFixed(1)} <span style={{color:'var(--muted)'}}>({p.reviews ?? '—'})</span></span>
                  ) : <span className="ed-feat-rating" style={{color:'var(--muted)'}}>New listing</span>}
                  <span className="ed-feat-arrow">→</span>
                </div>
              </div>
            </article>
          ))}
        </div>
        <div style={{textAlign:'center',marginTop:48}}>
          <button className="ed-cta-inline" onClick={()=>onSearch({})}>
            See all 4,851 specialists <span style={{fontSize:15}}>↗</span>
          </button>
        </div>
      </section>

      {/* UNDERSTAND — info cards */}
      <section className="ed-section" style={{borderTop:0}}>
        <div className="ed-section-head">
          <div className="ed-num">003 / 04<strong>Layers</strong></div>
          <h2 className="ed-section-title">
            TMJD isn't <span className="ital">one thing.</span>
          </h2>
        </div>
        <div className="pt-info-grid" style={{maxWidth:1280, margin:'0 auto'}}>
          {[
            { t:'Joint dysfunction', c:'var(--accent)', d:'Disc displacement, clicking, locking, arthritic change. Treated by orofacial pain specialists, oral surgeons, TMJ-trained dentists.' },
            { t:'Muscle pain', c:'var(--gold)', d:'Masseter, temporalis, pterygoid, SCM trigger points referring pain to teeth, ears, scalp. Treated by physical therapists, massage and myofascial therapists.' },
            { t:'Nerve & headache', c:'var(--plum)', d:'Trigeminal involvement, migraine overlap, central sensitization. Treated by neurologists, headache specialists, ENTs.' },
            { t:'Behavior & sleep', c:'var(--accent-ink)', d:'Bruxism, posture, sleep architecture, stress. Treated by sleep dentists, behavioral psychologists, osteopaths.' },
            { t:'Airway & breathing', c:'var(--plum)', d:'Mouth breathing, narrow airway, tongue posture, and sleep-disordered breathing that drive jaw tension and clenching. Treated by myofunctional therapists, airway-focused dentists, and ENTs.' },
            { t:'Cervical & postural', c:'var(--accent-ink)', d:'Neck and upper-cervical tension, forward-head posture, and old whiplash that refer pain into the jaw and feed clenching. Treated by physical therapists, chiropractors, and upper-cervical specialists.' },
            { t:'Bite & alignment', c:'var(--accent)', d:'Malocclusion, worn or missing teeth, and orthodontic factors that load the joint unevenly. Treated by neuromuscular dentists, orthodontists, and TMJ-trained dentists.' },
            { t:'Psychological & emotional', c:'var(--gold)', d:'Stress, anxiety, trauma, and central sensitization that amplify clenching and how pain is felt. Treated by behavioral psychologists, pain-reprocessing therapists, and biofeedback specialists.' },
          ].map((x,i)=>(
            <div key={i} className="pt-info" style={x.c ? {borderTopColor:x.c} : undefined}>
              <h4>{x.t}</h4>
              <p>{x.d}</p>
            </div>
          ))}
        </div>
      </section>

      {/* MAP TEASER */}
      <section className="ed-section pt-section-alt" style={{borderTop:0,background:'var(--paper)'}}>
        <div className="pt-nearme" style={{maxWidth:1280, margin:'0 auto'}}>
          <div className="pt-nearme-text">
            <div className="ed-num" style={{marginBottom:24}}>004 / 04<strong>Geography</strong></div>
            <h2 className="ed-section-title" style={{margin:0}}>
              Find specialists <span className="ital">near you.</span>
            </h2>
            <p style={{marginTop:24,fontSize:16,lineHeight:1.6,color:'var(--ink-2)',maxWidth:'52ch'}}>
              See TMJD specialists within driving distance — or search any city worldwide. Many TMJD patients travel for the right specialist.
            </p>
            <div className="pt-nearme-actions">
              <button className="pt-cta-primary" onClick={()=>onSearch({nearMe:true})}>
                <Icon name="crosshair" size={14}/> Use my location
              </button>
              <button className="pt-cta-outline" onClick={()=>onSearch({})}>
                Browse the map
              </button>
            </div>
          </div>
          <div className="pt-map-vis">
            <div className="map-grid"/>
            <div className="pulse" style={{top:'42%',left:'42%'}}/>
            <div className="pin"     style={{top:'40%',left:'40%'}}/>
            <div className="pin warm"style={{top:'24%',left:'68%'}}/>
            <div className="pin rose"style={{top:'62%',left:'58%'}}/>
            <div className="pin gold"style={{top:'72%',left:'22%'}}/>
            <div className="pin"     style={{top:'18%',left:'30%'}}/>
          </div>
        </div>
      </section>

      {/* FOOTER */}
      <footer className="ed-foot">
        <h2 className="ed-foot-display">
          Find <span className="ital">relief.</span><br/>
          Find a <span className="ital">specialist.</span>
        </h2>
        <div className="ed-foot-grid">
          <div>
            <h5>TMJDirectory</h5>
            <p style={{fontSize:14,opacity:.85,maxWidth:'34ch',margin:0,lineHeight:1.55}}>
              The global index of temporomandibular disorder specialists. Verified credentials. Patient reviews. Independent — not medical advice.
            </p>
          </div>
          <div>
            <h5>Patients</h5>
            <ul>
              <li><a href="#">Find a specialist</a></li>
              <li><a href="#">Symptom guide</a></li>
              <li><a href="#">Insurance &amp; cost</a></li>
              <li><a href="#">Glossary</a></li>
            </ul>
          </div>
          <div>
            <h5>Providers</h5>
            <ul>
              <li><a href="#">List your practice</a></li>
              <li><a href="#">Verification</a></li>
              <li><a href="#">Referral network</a></li>
            </ul>
          </div>
          <div>
            <h5>About</h5>
            <ul>
              <li><a href="#">Methodology</a></li>
              <li><a href="#">Advisory board</a></li>
              <li><a href="contact.html">Contact</a></li>
            </ul>
          </div>
        </div>
        <div className="ed-foot-bot">
          <span>© 2026 TMJDirectory · <a href="privacy.html">Privacy</a> · <a href="terms.html">Terms</a> · Not medical advice</span>
          <span>Vol. 04 · last reviewed 4 May 2026</span>
        </div>
      </footer>
    </main>
  );
};

const ProviderPreview = ({ profile, photoPreview, premium }) => {
  const businessName = profile.business || profile.photoLabel || 'Clinic listing';

  if (!premium) {
    return (
      <div className="provider-preview provider-preview-locked">
        <div className="provider-preview-card">
          <div className="provider-preview-photo">
            {photoPreview ? <img src={photoPreview} alt="Profile photo"/> : <span>No photo yet</span>}
          </div>
          <div className="provider-preview-body">
            <p className="provider-preview-specialty">{profile.specialty}</p>
            <h3>{profile.name}</h3>
            <p className="provider-preview-business">{businessName}</p>
            <div className="provider-preview-lock">
              Full profile details are locked until this listing is claimed and subscribed to the premium directory.
            </div>
          </div>
        </div>
      </div>
    );
  }

  const socialItems = [
    { label:'Instagram', value:profile.instagram },
    { label:'Facebook', value:profile.facebook },
    { label:'TikTok', value:profile.tiktok },
    { label:'X', value:profile.x },
    { label:'LinkedIn', value:profile.linkedin },
  ].filter(item => item.value);

  const buildSocialUrl = (item) => {
    const value = item.value.trim();
    if (value.startsWith('http')) return value;

    switch(item.label){
      case 'Instagram': return `https://instagram.com/${value.replace(/^@/, '')}`;
      case 'TikTok': return `https://tiktok.com/@${value.replace(/^@/, '')}`;
      case 'X': return `https://x.com/${value.replace(/^@/, '')}`;
      case 'Facebook': return value.includes('facebook.com') ? `https://${value.replace(/^https?:\/\//, '')}` : `https://facebook.com/${value.replace(/^@/, '')}`;
      case 'LinkedIn': return value.includes('linkedin.com') ? `https://${value.replace(/^https?:\/\//, '')}` : `https://linkedin.com/in/${value.replace(/^@/, '')}`;
      default: return value;
    }
  };

  return (
    <div className="provider-preview">
      <div className="provider-preview-card">
        <div className="provider-preview-photo">
          {photoPreview ? <img src={photoPreview} alt="Profile photo"/> : <span>No photo yet</span>}
        </div>
        <div className="provider-preview-body">
          <p className="provider-preview-specialty">{profile.specialty}</p>
          <h3>{profile.name}</h3>
          <p className="provider-preview-business">{businessName}</p>
          <p className="provider-preview-creds">{profile.credentials}</p>
          <p className="provider-preview-bio">{profile.bio}</p>
          {Array.isArray(profile.tags) && profile.tags.length > 0 && (
            <div className="provider-preview-tags">
              {profile.tags.map(tag => (
                <span key={tag} className="provider-preview-tag">{tag}</span>
              ))}
            </div>
          )}
          <div className="provider-preview-contact">
            {profile.addr && <div>{profile.addr}</div>}
            {(profile.city || profile.state || profile.zip) && (
              <div>
                {[profile.city, profile.state].filter(Boolean).join(', ')}
                {profile.zip ? ` ${profile.zip}` : ''}
              </div>
            )}
            {profile.country && <div>{profile.country}</div>}
            <div>{[profile.phone, profile.email].filter(Boolean).join(' · ')}</div>
            {profile.web && <div>{profile.web}</div>}
          </div>
          {socialItems.length > 0 && (
            <div className="provider-preview-social">
              {socialItems.map(item => (
                <a key={item.label} href={buildSocialUrl(item)} target="_blank" rel="noreferrer">
                  {item.label}
                </a>
              ))}
            </div>
          )}
          {(profile.rating || profile.reviews || profile.googleRating) && (
            <div className="provider-preview-rating">
              {profile.rating && <strong>★ {profile.rating}</strong>}
              {profile.reviews && <span> · {profile.reviews} reviews</span>}
              {profile.googleRating && (
                <> · <a href={profile.googleRating} target="_blank" rel="noreferrer">View on Google</a></>
              )}
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

const EMPTY_PROFILE = {
  name:'', credentials:'', specialty:'', business:'',
  addr:'', city:'', state:'', zip:'', country:'',
  phone:'', email:'', web:'', scheduleUrl:'', bio:'',
  tags:[], insurances:[],
  instagram:'', facebook:'', tiktok:'', x:'', linkedin:'', googleRating:'',
  rating:'', reviews:'',
  peerContactOptin:false, preferredContact:'email',
};

function dbRowToProfile(row) {
  if (!row) return EMPTY_PROFILE;
  const socials = row.socials || {};
  const meta = row.source_meta || {};
  return {
    name: row.name || '',
    credentials: row.credentials || '',
    specialty: row.specialty || '',
    business: row.business || '',
    addr: row.addr || '',
    city: row.city || '',
    state: row.state || '',
    zip: row.zip || '',
    country: row.country || '',
    phone: row.phone || '',
    email: row.email || '',
    web: row.web || '',
    scheduleUrl: row.schedule_url || '',
    bio: row.bio || '',
    tags: Array.isArray(row.tags) ? row.tags.slice() : [],
    insurances: Array.isArray(row.insurances) ? row.insurances.slice() : [],
    instagram: socials.instagram || '',
    facebook: socials.facebook || '',
    tiktok: socials.tiktok || '',
    x: socials.x || '',
    linkedin: socials.linkedin || '',
    googleRating: socials.googleRating || '',
    rating: meta.rating != null ? String(meta.rating) : '',
    reviews: meta.reviews != null ? String(meta.reviews) : '',
    peerContactOptin: row.peer_contact_optin === true,
    preferredContact: row.preferred_contact || 'email',
  };
}

// Dashboard analytics: how patients are interacting with the provider's card.
const CardAnalyticsPanel = () => {
  const [data, setData] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [err, setErr] = React.useState('');

  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const a = typeof getMyCardAnalytics === 'function' ? await getMyCardAnalytics() : null;
        if (!cancelled) setData(a);
      } catch (e) { if (!cancelled) setErr(e?.message || 'Could not load analytics.'); }
      finally { if (!cancelled) setLoading(false); }
    })();
    return () => { cancelled = true; };
  }, []);

  const Stat = ({ label, value, sub }) => (
    <div style={{flex:'1 1 120px',minWidth:120,padding:'12px 14px',border:'1px solid var(--line)',borderRadius:8,background:'var(--bg)'}}>
      <div style={{fontFamily:'var(--mono)',fontSize:24,lineHeight:1,color:'var(--ink)'}}>{value}</div>
      <div style={{fontSize:11,letterSpacing:'.1em',textTransform:'uppercase',color:'var(--muted)',marginTop:6}}>{label}</div>
      {sub != null && <div style={{fontSize:12,color:'var(--muted)',marginTop:2}}>{sub}</div>}
    </div>
  );

  const clicksByTarget = (data?.clicks_by_target) || {};
  const targetLabels = { phone:'Phone', email:'Email', web:'Website', schedule:'Schedule', social:'Social', card:'Card' };
  const daily = Array.isArray(data?.daily_views_7d) ? data.daily_views_7d : [];
  const maxDay = Math.max(1, ...daily.map(d => d.views || 0));

  return (
    <div className="provider-subscription" style={{marginTop:18}}>
      <div className="provider-subscription-head">
        <span className="premium-badge" style={{background:'var(--ink)',color:'var(--paper)'}}>▟ Analytics</span>
        <h3>How patients are finding you</h3>
      </div>
      {loading ? <p style={{color:'var(--muted)'}}>Loading…</p> :
        err ? <div className="provider-error" role="alert">{err}</div> :
        !data ? <p style={{color:'var(--muted)',fontSize:14}}>No analytics yet — once your listing is claimed and patients start viewing it, numbers show up here.</p> :
        <>
          <div style={{display:'flex',flexWrap:'wrap',gap:10,marginBottom:14}}>
            <Stat label="Card views" value={data.total_views} sub={`${data.views_7d} in last 7 days`} />
            <Stat label="Contact clicks" value={data.total_clicks} sub={`${data.clicks_7d} in last 7 days`} />
            <Stat label="Patient hearts" value={data.favorite_count} />
            <Stat label="Provider saves" value={data.peer_saved_count} />
          </div>

          <h4 style={{margin:'8px 0 8px',fontSize:13,letterSpacing:'.06em',textTransform:'uppercase',color:'var(--ink-2)'}}>What patients clicked</h4>
          {Object.keys(clicksByTarget).length === 0 ? (
            <p style={{color:'var(--muted)',fontSize:14,margin:'0 0 12px'}}>No clicks yet.</p>
          ) : (
            <div style={{display:'flex',flexWrap:'wrap',gap:8,marginBottom:14}}>
              {Object.entries(clicksByTarget).sort((a,b)=>b[1]-a[1]).map(([t,c])=>(
                <span key={t} className="pill">{targetLabels[t]||t}: <strong>{c}</strong></span>
              ))}
            </div>
          )}

          <h4 style={{margin:'8px 0 8px',fontSize:13,letterSpacing:'.06em',textTransform:'uppercase',color:'var(--ink-2)'}}>Views — last 7 days</h4>
          <div style={{display:'flex',alignItems:'flex-end',gap:6,height:64}}>
            {daily.map((d,i)=>(
              <div key={i} style={{flex:1,textAlign:'center'}}>
                <div style={{height:`${Math.round(((d.views||0)/maxDay)*48)}px`,minHeight:2,background:'var(--accent)',borderRadius:'3px 3px 0 0'}} title={`${d.views} view${d.views===1?'':'s'}`}/>
                <div style={{fontSize:10,color:'var(--muted)',marginTop:4}}>{new Date(d.day).toLocaleDateString(undefined,{weekday:'short'}).slice(0,2)}</div>
              </div>
            ))}
          </div>
          <p style={{fontSize:12,color:'var(--muted)',marginTop:10}}>Views are counted once per visitor per day. Clicks track which contact path patients took from your card.</p>
        </>
      }
    </div>
  );
};

// Provider-to-provider support network panel: search & save other providers,
// see who's saved you, see revealed contacts for opted-in connections.
const PeerNetworkPanel = ({ listingId }) => {
  const [network, setNetwork] = React.useState([]);
  const [savedBy, setSavedBy] = React.useState([]);
  const [loadingNet, setLoadingNet] = React.useState(true);
  const [query, setQuery] = React.useState('');
  const [busyId, setBusyId] = React.useState(null);
  const [err, setErr] = React.useState('');

  const reload = React.useCallback(async () => {
    try {
      const [net, by] = await Promise.all([
        typeof getMyNetwork === 'function' ? getMyNetwork() : [],
        typeof getWhoSavedMe === 'function' ? getWhoSavedMe() : [],
      ]);
      setNetwork(net); setSavedBy(by);
    } catch (e) { setErr(e?.message || 'Could not load your network.'); }
    finally { setLoadingNet(false); }
  }, []);

  React.useEffect(() => { reload(); }, [reload]);

  const savedIds = React.useMemo(() => new Set(network.map(n => n.provider_id)), [network]);

  const results = React.useMemo(() => {
    const q = query.trim().toLowerCase();
    if (q.length < 2) return [];
    const source = typeof PROVIDERS !== 'undefined' ? PROVIDERS : [];
    return source
      .filter(p => p.id !== listingId && !savedIds.has(p.id))
      .filter(p => {
        const hay = [p.name, p.business, p.photoLabel, p.city, p.state, p.specialty].filter(Boolean).join(' ').toLowerCase();
        return hay.includes(q);
      })
      .slice(0, 10);
  }, [query, savedIds, listingId]);

  const add = async (id) => {
    setBusyId(id); setErr('');
    try { await addConnection(id, null); await reload(); }
    catch (e) { setErr(e?.message || 'Could not add to network.'); }
    finally { setBusyId(null); }
  };
  const remove = async (id) => {
    setBusyId(id); setErr('');
    try { await removeConnection(id); await reload(); }
    catch (e) { setErr(e?.message || 'Could not remove from network.'); }
    finally { setBusyId(null); }
  };

  const contactLine = (n) => {
    if (!n.opted_in) return <span style={{color:'var(--muted)',fontSize:13}}>Contact hidden — they haven't opted in</span>;
    const label = { phone:'Call', web:'Visit', email:'Email' }[n.contact_type] || 'Email';
    return <span style={{fontSize:13}}><strong>{label}:</strong> {n.contact_value || '—'}</span>;
  };

  return (
    <div className="provider-subscription" style={{marginTop:18}}>
      <div className="provider-subscription-head">
        <span className="premium-badge" style={{background:'var(--ink)',color:'var(--paper)'}}>◇ Network</span>
        <h3>Your TMJD provider network</h3>
      </div>
      <p>Save other vetted providers in your area to build a referral and support web for your patients. When a provider you save has opted in, you'll see their preferred contact method here.</p>
      {err && <div className="provider-error" role="alert" style={{marginBottom:12}}>{err}</div>}

      {/* Add */}
      <input
        type="search"
        value={query}
        onChange={e=>setQuery(e.target.value)}
        placeholder="Search providers by name, clinic, city, specialty…"
        style={{width:'100%',padding:'10px 14px',borderRadius:8,border:'1px solid var(--line)',background:'var(--bg)',font:'inherit',fontSize:15,marginBottom:10}}
      />
      {query.trim().length >= 2 && results.length === 0 && (
        <p style={{color:'var(--muted)',fontSize:14,margin:'4px 0 12px'}}>No matches (or already in your network).</p>
      )}
      {results.map(p => (
        <div key={p.id} style={{display:'flex',alignItems:'center',justifyContent:'space-between',gap:12,padding:'10px 12px',border:'1px solid var(--line)',borderRadius:8,marginBottom:8,background:'var(--bg)'}}>
          <div>
            <div style={{fontWeight:600,fontSize:14}}>{p.name || p.business}</div>
            <div style={{fontSize:12,color:'var(--muted)'}}>{p.specialty}{(p.city||p.state)?` · ${p.city||''}${p.state?', '+p.state:''}`:''}</div>
          </div>
          <button className="btn btn-dark" type="button" disabled={busyId===p.id} onClick={()=>add(p.id)}>
            {busyId===p.id ? '…' : '+ Add'}
          </button>
        </div>
      ))}

      {/* My network */}
      <h4 style={{margin:'18px 0 8px',fontSize:14,letterSpacing:'.06em',textTransform:'uppercase',color:'var(--ink-2)'}}>
        In your network ({network.length})
      </h4>
      {loadingNet ? <p style={{color:'var(--muted)'}}>Loading…</p> :
        network.length === 0 ? <p style={{color:'var(--muted)',fontSize:14}}>No providers saved yet. Search above to add some.</p> :
        network.map(n => (
          <div key={n.provider_id} style={{display:'flex',alignItems:'center',justifyContent:'space-between',gap:12,padding:'10px 12px',border:'1px solid var(--line)',borderRadius:8,marginBottom:8}}>
            <div>
              <div style={{fontWeight:600,fontSize:14}}>{n.name || n.business}</div>
              <div style={{fontSize:12,color:'var(--muted)'}}>{n.specialty}{(n.city||n.state)?` · ${n.city||''}${n.state?', '+n.state:''}`:''}</div>
              <div style={{marginTop:4}}>{contactLine(n)}</div>
            </div>
            <button className="btn btn-ghost" type="button" disabled={busyId===n.provider_id} onClick={()=>remove(n.provider_id)}>
              {busyId===n.provider_id ? '…' : 'Remove'}
            </button>
          </div>
        ))
      }

      {/* Who saved me */}
      {savedBy.length > 0 && (
        <>
          <h4 style={{margin:'18px 0 8px',fontSize:14,letterSpacing:'.06em',textTransform:'uppercase',color:'var(--ink-2)'}}>
            {savedBy.length} provider{savedBy.length===1?'':'s'} saved you
          </h4>
          {savedBy.map(s => (
            <div key={s.provider_id} style={{fontSize:14,padding:'6px 0',borderBottom:'1px solid var(--line-soft)'}}>
              <strong>{s.name || s.business}</strong> <span style={{color:'var(--muted)'}}>· {s.specialty}{(s.city||s.state)?` · ${s.city||''}${s.state?', '+s.state:''}`:''}</span>
            </div>
          ))}
          <p style={{fontSize:13,color:'var(--muted)',marginTop:10}}>Want them to see your contact details? Turn on "Let other providers contact me" above and pick a preferred method.</p>
        </>
      )}
    </div>
  );
};

// Shown when the signed-in user has no listing matched by email/domain.
// Lets them search the directory, try an auto-claim, and if that fails,
// submit a claim request with evidence for manual review.
const ClaimRequestFlow = ({ session, onBack, onLogout, onClaimed }) => {
  const [claimsLoading, setClaimsLoading] = React.useState(true);
  const [myClaims, setMyClaims] = React.useState([]);
  const [query, setQuery] = React.useState('');
  const [selected, setSelected] = React.useState(null);
  const [fullName, setFullName] = React.useState(session?.user?.user_metadata?.full_name || '');
  const [evidence, setEvidence] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [submittedFor, setSubmittedFor] = React.useState(null);
  const [error, setError] = React.useState('');

  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const c = typeof getMyClaims === 'function' ? await getMyClaims() : [];
        if (!cancelled) setMyClaims(c);
      } catch (e) { /* non-fatal */ }
      finally { if (!cancelled) setClaimsLoading(false); }
    })();
    return () => { cancelled = true; };
  }, []);

  const results = React.useMemo(() => {
    const q = query.trim().toLowerCase();
    if (q.length < 2) return [];
    const source = typeof PROVIDERS !== 'undefined' ? PROVIDERS : [];
    return source
      .filter(p => {
        const hay = [p.name, p.business, p.photoLabel, p.city, p.state].filter(Boolean).join(' ').toLowerCase();
        return hay.includes(q);
      })
      .slice(0, 12);
  }, [query]);

  const pending = myClaims.find(c => c.status === 'pending');

  const tryClaim = async (listing) => {
    setBusy(true); setError('');
    try {
      // First try auto-claim (exact email or website-domain match)
      await claimListing(listing.id);
      onClaimed?.();
    } catch (e) {
      if (String(e?.message || '').includes('AUTOCLAIM_NO_MATCH')) {
        // No auto-match → fall to manual evidence form
        setSelected(listing);
      } else {
        setError(e?.message || 'Could not claim this listing.');
      }
    } finally {
      setBusy(false);
    }
  };

  const submitEvidence = async (e) => {
    e.preventDefault();
    if (!selected) return;
    if (!evidence.trim()) { setError('Please add evidence — license #, NPI, or a practice email.'); return; }
    setBusy(true); setError('');
    try {
      await submitClaim(selected.id, fullName.trim(), evidence.trim());
      setSubmittedFor(selected);
    } catch (e2) {
      setError(e2?.message || 'Could not submit your claim. Try again.');
    } finally {
      setBusy(false);
    }
  };

  return (
    <main className="provider-shell">
      <button className="provider-back" onClick={onBack}>← Back to directory</button>
      <section className="provider-hero">
        <p className="ed-sub-eyebrow">Claim your listing</p>
        <h1>Find your practice in the directory.</h1>
        <p>
          We don't have <strong>{session?.user?.email}</strong> on a listing yet — that's normal for listings we sourced automatically.
          Search for your practice below and claim it. If we can't verify it instantly, you'll send a quick proof and we'll confirm within a few business days.
        </p>
      </section>

      <div className="provider-grid">
        <section className="provider-card">
          {claimsLoading ? (
            <p style={{color:'var(--muted)'}}>Loading…</p>
          ) : submittedFor ? (
            <div className="provider-success" role="status">
              <h3>Claim submitted.</h3>
              <p>We've received your request to claim <strong>{submittedFor.name || submittedFor.business}</strong>. We'll verify your evidence and email <strong>{session?.user?.email}</strong> once it's approved — usually within a few business days.</p>
              <div style={{display:'flex',gap:12,marginTop:16}}>
                <button className="btn" onClick={onBack}>Back to directory</button>
                <button className="btn btn-ghost" onClick={onLogout}>Sign out</button>
              </div>
            </div>
          ) : pending ? (
            <div className="provider-note">
              <h3>Claim pending review.</h3>
              <p>You have a pending claim for listing <strong>{pending.provider_id}</strong>, submitted {new Date(pending.created_at).toLocaleDateString()}. We'll email you once it's reviewed.</p>
              <div style={{display:'flex',gap:12,marginTop:16}}>
                <button className="btn" onClick={onBack}>Back to directory</button>
                <button className="btn btn-ghost" onClick={onLogout}>Sign out</button>
              </div>
            </div>
          ) : selected ? (
            <form className="provider-form" onSubmit={submitEvidence}>
              <div className="provider-card-head">
                <h2>Verify you're {selected.name || selected.business}</h2>
                <p>We couldn't match your email automatically. Send us proof you're affiliated with this practice and we'll approve your claim.</p>
              </div>
              <label htmlFor="claim-name">Your full name</label>
              <input id="claim-name" value={fullName} onChange={e=>setFullName(e.target.value)} placeholder="Dr. Jane Smith" />
              <label htmlFor="claim-evidence">Evidence <span style={{textTransform:'none',letterSpacing:0,color:'var(--muted)'}}>(required)</span></label>
              <textarea id="claim-evidence" rows="4" value={evidence} onChange={e=>setEvidence(e.target.value)}
                placeholder="State license #, NPI number, or a practice email/website that proves you're affiliated with this listing." />
              {error && <div className="provider-error" role="alert">{error}</div>}
              <div className="provider-cta" style={{display:'flex',gap:10}}>
                <button className="btn btn-dark" type="submit" disabled={busy}>{busy ? 'Submitting…' : 'Submit claim'}</button>
                <button className="btn btn-ghost" type="button" onClick={()=>{setSelected(null);setError('');}}>Pick a different listing</button>
              </div>
            </form>
          ) : (
            <div className="provider-form">
              <div className="provider-card-head">
                <h2>Search for your practice</h2>
                <p>Type your name or clinic name. Don't see it? <a href="contact.html" style={{textDecoration:'underline'}}>Request a new listing</a>.</p>
              </div>
              <input
                type="search"
                value={query}
                onChange={e=>setQuery(e.target.value)}
                placeholder="e.g. Relief Massage Method, or Amber Ellen"
                autoFocus
              />
              {error && <div className="provider-error" role="alert" style={{marginTop:12}}>{error}</div>}
              <div style={{marginTop:14, display:'flex', flexDirection:'column', gap:8}}>
                {query.trim().length >= 2 && results.length === 0 && (
                  <p style={{color:'var(--muted)',fontSize:14}}>No matches. Try a different spelling, or <a href="contact.html" style={{textDecoration:'underline'}}>request a new listing</a>.</p>
                )}
                {results.map(p => (
                  <div key={p.id} style={{
                    display:'flex', alignItems:'center', justifyContent:'space-between', gap:12,
                    padding:'12px 14px', border:'1px solid var(--line)', borderRadius:8, background:'var(--bg)',
                  }}>
                    <div>
                      <div style={{fontWeight:600}}>{p.name || p.business}</div>
                      <div style={{fontSize:13,color:'var(--muted)'}}>
                        {p.specialty}{(p.city||p.state)?` · ${p.city||''}${p.state?', '+p.state:''}`:''}
                        {p.status !== 'sourceOnly' ? ' · already claimed' : ''}
                      </div>
                    </div>
                    <button
                      className="btn btn-dark"
                      type="button"
                      disabled={busy || p.status !== 'sourceOnly'}
                      onClick={()=>tryClaim(p)}
                    >
                      {p.status !== 'sourceOnly' ? 'Claimed' : 'This is me'}
                    </button>
                  </div>
                ))}
              </div>
              <div style={{marginTop:20}}>
                <button className="btn btn-ghost" type="button" onClick={onLogout}>Sign out</button>
              </div>
            </div>
          )}
        </section>

        <aside className="provider-info">
          <div className="provider-note">
            <h3>How verification works</h3>
            <p>If your email or your practice's website domain is already on the listing, you're in instantly. Otherwise we manually check the license # or NPI you provide against public records. Either way, your contact details on the listing stay private until you choose to publish them.</p>
          </div>
        </aside>
      </div>
    </main>
  );
};

const ProviderDashboard = ({ session, claimTarget, onBack, onLogout }) => {
  const [loading, setLoading] = React.useState(true);
  const [loadError, setLoadError] = React.useState('');
  const [noListing, setNoListing] = React.useState(false);
  const [reloadKey, setReloadKey] = React.useState(0);
  const [listingId, setListingId] = React.useState(null);
  const [photoFile, setPhotoFile] = React.useState(null);
  const [photoPreview, setPhotoPreview] = React.useState('');
  const [profile, setProfile] = React.useState(EMPTY_PROFILE);
  const [saved, setSaved] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [saveError, setSaveError] = React.useState('');
  const [premium, setPremium] = React.useState(false);
  const [insuranceSearch, setInsuranceSearch] = React.useState('');

  // On mount: resolve listing for the signed-in user, claim if needed, fetch full row.
  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      setLoading(true);
      setLoadError('');
      setNoListing(false);
      try {
        // 1) Find the user's listing (by owner_id or exact-email match)
        let found = typeof findMyListing === 'function' ? await findMyListing() : null;

        // 2) If user navigated here from a "Claim free" card and doesn't own it yet,
        //    attempt the claim (exact email or website-domain match).
        if (!found && claimTarget && typeof claimListing === 'function') {
          try {
            const claimed = await claimListing(claimTarget);
            if (claimed) found = { id: claimed.id, owner_id: claimed.id };
          } catch (e) {
            // No auto-match → fall through to the manual claim flow below.
            if (!String(e?.message || '').includes('AUTOCLAIM_NO_MATCH')) throw e;
          }
        }

        // 3) If owner_id is null on the matched row, claim it now (auto-claim by email).
        if (found && !found.owner_id && typeof claimListing === 'function') {
          try { await claimListing(found.id); }
          catch (e) { if (!String(e?.message || '').includes('AUTOCLAIM_NO_MATCH')) throw e; }
        }

        if (!found) {
          if (!cancelled) { setNoListing(true); setLoading(false); }
          return;
        }

        // 4) Fetch the full row (PII included, RLS allows owner)
        const row = await fetchMyProviderRow(found.id);
        if (cancelled) return;
        setListingId(row.id);
        setProfile(dbRowToProfile(row));
        setPhotoPreview(row.photo || '');
        setPremium(row.status === 'premium');
      } catch (err) {
        console.error('[dashboard] load failed', err);
        if (!cancelled) setLoadError(err?.message || 'Could not load your listing.');
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, [session?.user?.id, claimTarget, reloadKey]);

  React.useEffect(() => {
    if (!photoFile) return;
    const reader = new FileReader();
    reader.onload = () => setPhotoPreview(reader.result);
    reader.readAsDataURL(photoFile);
  }, [photoFile]);

  const updateField = key => event => {
    setProfile(prev => ({ ...prev, [key]: event.target.value }));
    setSaved(false);
  };

  const toggleTag = (tag) => {
    setProfile(prev => ({
      ...prev,
      tags: prev.tags.includes(tag)
        ? prev.tags.filter(t => t !== tag)
        : [...prev.tags, tag],
    }));
    setSaved(false);
  };

  const addInsurance = (name) => {
    const trimmed = (name || '').trim();
    if (!trimmed || profile.insurances.includes(trimmed)) return;
    setProfile(prev => ({ ...prev, insurances: [...prev.insurances, trimmed] }));
    setInsuranceSearch('');
    setSaved(false);
  };
  const removeInsurance = (name) => {
    setProfile(prev => ({ ...prev, insurances: prev.insurances.filter(i => i !== name) }));
    setSaved(false);
  };
  const filteredInsurances = React.useMemo(() => {
    const list = typeof INSURANCE_OPTIONS !== 'undefined' ? INSURANCE_OPTIONS : [];
    const q = insuranceSearch.toLowerCase().trim();
    return list
      .filter(name => !profile.insurances.includes(name))
      .filter(name => !q || name.toLowerCase().includes(q))
      .slice(0, 12);
  }, [insuranceSearch, profile.insurances]);
  const customInsuranceCandidate = React.useMemo(() => {
    const trimmed = insuranceSearch.trim();
    if (!trimmed) return null;
    const list = typeof INSURANCE_OPTIONS !== 'undefined' ? INSURANCE_OPTIONS : [];
    const exists = list.some(name => name.toLowerCase() === trimmed.toLowerCase());
    if (exists) return null;
    if (profile.insurances.some(name => name.toLowerCase() === trimmed.toLowerCase())) return null;
    return trimmed;
  }, [insuranceSearch, profile.insurances]);

  const handlePhoto = event => {
    const file = event.target.files?.[0];
    setPhotoFile(file || null);
    setSaved(false);
  };

  const submitChanges = async () => {
    if (!listingId) return;
    setSaving(true);
    setSaveError('');
    setSaved(false);
    try {
      const patch = {
        name: profile.name || null,
        credentials: profile.credentials || null,
        specialty: profile.specialty || null,
        business: profile.business || null,
        bio: profile.bio || null,
        addr: profile.addr || null,
        city: profile.city || null,
        state: profile.state || null,
        zip: profile.zip || null,
        country: profile.country || null,
        phone: profile.phone || null,
        email: profile.email || null,
        web: profile.web || null,
        schedule_url: profile.scheduleUrl || null,
        socials: {
          ...(profile.instagram && { instagram: profile.instagram }),
          ...(profile.facebook && { facebook: profile.facebook }),
          ...(profile.tiktok && { tiktok: profile.tiktok }),
          ...(profile.x && { x: profile.x }),
          ...(profile.linkedin && { linkedin: profile.linkedin }),
          ...(profile.googleRating && { googleRating: profile.googleRating }),
        },
        tags: profile.tags,
        insurances: profile.insurances,
        peer_contact_optin: !!profile.peerContactOptin,
        preferred_contact: profile.peerContactOptin ? (profile.preferredContact || 'email') : null,
      };
      await saveMyProviderRow(listingId, patch);
      setSaved(true);
    } catch (err) {
      console.error('[dashboard] save failed', err);
      setSaveError(err?.message || 'Could not save changes. Try again.');
    } finally {
      setSaving(false);
    }
  };

  // Premium upgrade is a future flow (Stripe etc). For now this just flips local state
  // so the preview shows the premium look — the actual status change to 'premium' is
  // service-role only and will be done at billing time.
  const activatePremium = () => {
    setPremium(true);
    setSaved(false);
  };

  // Loading / no-listing / error early returns
  if (loading) {
    return (
      <main className="provider-shell">
        <p style={{textAlign:'center',padding:80,color:'var(--muted)'}}>Loading your listing…</p>
      </main>
    );
  }
  if (noListing) {
    return (
      <ClaimRequestFlow
        session={session}
        onBack={onBack}
        onLogout={onLogout}
        onClaimed={() => setReloadKey(k => k + 1)}
      />
    );
  }
  if (loadError) {
    return (
      <main className="provider-shell">
        <button className="provider-back" onClick={onBack}>← Back to directory</button>
        <section className="provider-hero">
          <p className="ed-sub-eyebrow">Something went wrong</p>
          <h1>We couldn't load your listing.</h1>
          <p>{loadError}</p>
          <div style={{display:'flex',gap:12,marginTop:24,justifyContent:'center'}}>
            <button className="btn btn-dark" onClick={() => setReloadKey(k => k + 1)}>Try again</button>
            <button className="btn btn-ghost" onClick={onLogout}>Sign out</button>
          </div>
        </section>
      </main>
    );
  }

  return (
    <main className="provider-shell">
      <button className="provider-back" onClick={onBack}>← Back to directory</button>
      <section className="provider-hero">
        <p className="ed-sub-eyebrow">Provider dashboard</p>
        <h1>Manage your TMJDirectory listing.</h1>
        <p>
          Review your clinic profile, update your contact details and specialties, and submit edits for approval. This dashboard is a preview of the provider experience.
        </p>
      </section>

      <div className="provider-grid">
        <section className="provider-card">
          <div className="provider-card-head">
            <h2>Profile details</h2>
            <p>Update the information patients see in search results and on your listing page.</p>
          </div>

          <div className="provider-form provider-dashboard-form">
            <label htmlFor="dashboard-name">Provider name</label>
            <input id="dashboard-name" value={profile.name} onChange={updateField('name')} />

            <label htmlFor="dashboard-creds">Credentials</label>
            <input id="dashboard-creds" value={profile.credentials} onChange={updateField('credentials')} />

            <label htmlFor="dashboard-business">Business / clinic name</label>
            <input id="dashboard-business" value={profile.business} onChange={updateField('business')} placeholder="Your clinic or practice name" />

            <label htmlFor="dashboard-specialty">Specialty</label>
            <input id="dashboard-specialty" value={profile.specialty} onChange={updateField('specialty')} />

            <label htmlFor="dashboard-bio">Practice summary</label>
            <textarea id="dashboard-bio" rows="5" value={profile.bio} onChange={updateField('bio')} />

            <label htmlFor="dashboard-photo">Profile photo</label>
            <input id="dashboard-photo" type="file" accept="image/*" onChange={handlePhoto} />
            {photoPreview && (
              <div className="photo-preview" aria-label="Photo preview">
                <img src={photoPreview} alt="Profile preview" />
              </div>
            )}

            <label>Tags / highlights</label>
            <p className="field-hint">Select the tags that describe your practice. Patients filter the directory by these — you can't add custom tags so listings stay consistent.</p>
            <div className="tag-picker">
              {(typeof TAG_CATEGORIES !== 'undefined' ? TAG_CATEGORIES : []).map(category => (
                <div key={category.label} className="tag-group">
                  <span className="tag-group-label">{category.label}</span>
                  <div className="tag-group-chips">
                    {category.tags.map(tag => {
                      const selected = profile.tags.includes(tag);
                      return (
                        <button
                          key={tag}
                          type="button"
                          className={`tag-chip ${selected ? 'tag-chip-selected' : ''}`}
                          onClick={() => toggleTag(tag)}
                          aria-pressed={selected}
                        >
                          {tag}
                        </button>
                      );
                    })}
                  </div>
                </div>
              ))}
            </div>

            <label htmlFor="dashboard-insurance">Insurance accepted</label>
            <p className="field-hint">Select all insurances you accept. Patients filter the directory by these — <strong>not shown publicly on your card</strong>, only used for matching searches in your area.</p>
            <div className="insurance-picker">
              {profile.insurances.length > 0 && (
                <div className="insurance-selected">
                  {profile.insurances.map(name => (
                    <span key={name} className="insurance-chip">
                      {name}
                      <button type="button" onClick={() => removeInsurance(name)} aria-label={`Remove ${name}`}>×</button>
                    </span>
                  ))}
                </div>
              )}
              <input
                id="dashboard-insurance"
                type="text"
                className="insurance-search"
                placeholder="Search insurances (e.g. Aetna, BCBS, Medicare)..."
                value={insuranceSearch}
                onChange={e => setInsuranceSearch(e.target.value)}
              />
              {(filteredInsurances.length > 0 || customInsuranceCandidate) && (
                <div className="insurance-options">
                  {filteredInsurances.map(name => (
                    <button
                      key={name}
                      type="button"
                      className="insurance-option"
                      onClick={() => addInsurance(name)}
                    >+ {name}</button>
                  ))}
                  {customInsuranceCandidate && (
                    <button
                      type="button"
                      className="insurance-option insurance-option-custom"
                      onClick={() => addInsurance(customInsuranceCandidate)}
                    >+ Add "{customInsuranceCandidate}" as custom</button>
                  )}
                </div>
              )}
            </div>

            <div className="social-grid">
              <div>
                <label htmlFor="dashboard-instagram">Instagram</label>
                <input id="dashboard-instagram" value={profile.instagram} onChange={updateField('instagram')} placeholder="@yourhandle" />
              </div>
              <div>
                <label htmlFor="dashboard-tiktok">TikTok</label>
                <input id="dashboard-tiktok" value={profile.tiktok} onChange={updateField('tiktok')} placeholder="@yourhandle" />
              </div>
              <div>
                <label htmlFor="dashboard-x">X</label>
                <input id="dashboard-x" value={profile.x} onChange={updateField('x')} placeholder="@yourhandle" />
              </div>
              <div>
                <label htmlFor="dashboard-facebook">Facebook</label>
                <input id="dashboard-facebook" value={profile.facebook} onChange={updateField('facebook')} placeholder="https://facebook.com/yourpage" />
              </div>
              <div>
                <label htmlFor="dashboard-linkedin">LinkedIn</label>
                <input id="dashboard-linkedin" value={profile.linkedin} onChange={updateField('linkedin')} placeholder="https://linkedin.com/in/yourname" />
              </div>
            </div>

            <label htmlFor="dashboard-google-rating">Google business URL</label>
            <input id="dashboard-google-rating" value={profile.googleRating} onChange={updateField('googleRating')} placeholder="https://g.page/yourbusiness" />
            <p className="field-hint">Link to your Google business page where reviews are visible — not the <code>/review</code> link.</p>

            <div className="social-grid">
              <div>
                <label htmlFor="dashboard-rating">Star rating</label>
                <input id="dashboard-rating" type="number" step="0.1" min="0" max="5" value={profile.rating} onChange={updateField('rating')} placeholder="4.9" />
              </div>
              <div>
                <label htmlFor="dashboard-reviews">Review count</label>
                <input id="dashboard-reviews" type="number" min="0" value={profile.reviews} onChange={updateField('reviews')} placeholder="142" />
              </div>
            </div>

            <label htmlFor="dashboard-address">Street address</label>
            <input id="dashboard-address" value={profile.addr} onChange={updateField('addr')} placeholder="123 Main St, Suite 4" />

            <div className="social-grid">
              <div>
                <label htmlFor="dashboard-city">City</label>
                <input id="dashboard-city" value={profile.city} onChange={updateField('city')} placeholder="Portland" />
              </div>
              <div>
                <label htmlFor="dashboard-state">State / region</label>
                <input id="dashboard-state" value={profile.state} onChange={updateField('state')} placeholder="OR" />
              </div>
              <div>
                <label htmlFor="dashboard-zip">ZIP / postal code</label>
                <input id="dashboard-zip" value={profile.zip} onChange={updateField('zip')} placeholder="97214" />
              </div>
              <div>
                <label htmlFor="dashboard-country">Country</label>
                <input id="dashboard-country" value={profile.country} onChange={updateField('country')} placeholder="USA" />
              </div>
            </div>

            <label htmlFor="dashboard-phone">Phone</label>
            <input id="dashboard-phone" value={profile.phone} onChange={updateField('phone')} />

            <label htmlFor="dashboard-email">Email</label>
            <input id="dashboard-email" value={profile.email} onChange={updateField('email')} />

            <label htmlFor="dashboard-web">Website</label>
            <input id="dashboard-web" value={profile.web} onChange={updateField('web')} placeholder="reliefmassagemethod.com" />

            <label htmlFor="dashboard-schedule">Scheduling link</label>
            <input id="dashboard-schedule" value={profile.scheduleUrl} onChange={updateField('scheduleUrl')} placeholder="https://calendly.com/yourname or your booking page URL" />
            <p className="field-hint">Where the <strong>Schedule</strong> button on your card sends patients. Use your Calendly, Acuity, Jane, or other booking link.</p>

            {/* Peer-contact opt-in */}
            <div style={{margin:'18px 0 6px',padding:'14px 16px',border:'1px solid var(--line)',borderRadius:8,background:'var(--bg)'}}>
              <label style={{display:'flex',alignItems:'flex-start',gap:10,cursor:'pointer'}}>
                <input
                  type="checkbox"
                  checked={!!profile.peerContactOptin}
                  onChange={e=>{ setProfile(prev=>({...prev,peerContactOptin:e.target.checked})); setSaved(false); }}
                  style={{marginTop:3,accentColor:'var(--accent-ink)'}}
                />
                <span>
                  <strong>Let other providers contact me directly.</strong>
                  <span style={{display:'block',fontSize:13,color:'var(--muted)',marginTop:2}}>
                    When another provider saves you to their network, your preferred contact method below is shown to them only — never on your public card.
                  </span>
                </span>
              </label>
              {profile.peerContactOptin && (
                <div style={{marginTop:10,display:'flex',alignItems:'center',gap:10}}>
                  <label htmlFor="dashboard-preferred" style={{fontSize:13,color:'var(--ink-2)'}}>Preferred contact:</label>
                  <select
                    id="dashboard-preferred"
                    value={profile.preferredContact || 'email'}
                    onChange={e=>{ setProfile(prev=>({...prev,preferredContact:e.target.value})); setSaved(false); }}
                    style={{padding:'6px 10px',borderRadius:6,border:'1px solid var(--line)',background:'var(--paper)',font:'inherit',fontSize:14}}
                  >
                    <option value="email">Email</option>
                    <option value="phone">Phone</option>
                    <option value="web">Website</option>
                  </select>
                </div>
              )}
              <p className="field-hint" style={{marginTop:8}}>Saved with your other changes when you click "Save changes".</p>
            </div>

            {/* Peer network management (immediate — not part of the save) */}
            {listingId && <PeerNetworkPanel listingId={listingId} />}

            {/* Card analytics */}
            {listingId && <CardAnalyticsPanel />}

            {/* What's included with a claimed (free) listing */}
            <div className="provider-subscription provider-subscription-active" style={{borderColor:'var(--accent-ink)'}}>
              <div className="provider-subscription-head">
                <span className="premium-badge" style={{background:'var(--accent-ink)',color:'var(--paper)'}}>✓ Claimed</span>
                <h3>What's included with your free claim</h3>
              </div>
              <ul className="premium-perks">
                <li><strong>Live editing of your listing</strong> — name, credentials, photo, bio, address, phone, website, social links, scheduling URL. Edits queue for a quick review, then go live.</li>
                <li><strong>Insurance, tag, and treatment filters</strong> — pick exactly which patient searches you appear in.</li>
                <li><strong>Verified badge</strong> on your card — replaces the "claim it free" prompt so patients see a real practitioner.</li>

                <li style={{marginTop:14}}><strong>Provider network search</strong> — find other vetted TMJD providers in your area (orofacial dentists, PTs, sleep specialists, myofunctional therapists, somatic practitioners) and save them to your support web for patient referrals.</li>
                <li><strong>Be discoverable to peers (opt-in)</strong> — toggle on and other providers can save you to their network. Your preferred contact method is revealed only to providers who save you — never publicly.</li>
                <li><strong>"Saved by X providers" badge</strong> on your card — show patients you're trusted by other TMJD specialists in their area.</li>

                <li style={{marginTop:14}}><strong>Engagement analytics</strong> — weekly breakdown of card views, plus exactly which contact path each patient took: phone, email, website, social, schedule link.</li>
                <li><strong>Favorites count</strong> — see how many patients hearted your card and how many providers added you to their support network.</li>
                <li><strong>Specialty-filter insight</strong> — know which searches drove your traffic so you can sharpen your tags.</li>
              </ul>
            </div>

            <div className={`provider-subscription ${premium ? 'provider-subscription-active' : ''}`}>
              <div className="provider-subscription-head">
                <span className="premium-badge">★ Premium</span>
                <h3>{premium ? 'Premium active' : 'Upgrade to Premium — $7.99 / month'}</h3>
              </div>
              <p>
                {premium
                  ? 'Your listing has Premium perks active — top-of-search placement, the verified badge, dedicated page, and more.'
                  : 'Premium adds discovery and presentation perks that drive more referrals on top of your free claim:'}
              </p>
              {!premium && (
                <ul className="premium-perks">
                  <li><strong>Top-of-search placement</strong> — your listing surfaces above unclaimed ones in patient searches.</li>
                  <li><strong>"★ Premium" gold badge</strong> on your card — strongest trust signal.</li>
                  <li><strong>Dedicated provider page</strong> — full-page profile with photo gallery, treatments offered, and FAQ.</li>
                  <li><strong>Multiple photos</strong> — show your office, team, and treatment rooms (basic listings get one photo).</li>
                  <li><strong>"Leave a Google review" CTA</strong> — patients can leave reviews from your listing in one tap.</li>
                  <li><strong>Priority support</strong> — direct email to the directory team for listing edits and disputes.</li>
                </ul>
              )}
              {!premium && (
                <button className="btn btn-dark" type="button" onClick={activatePremium}>
                  Upgrade to Premium
                </button>
              )}
            </div>

            {saveError && (
              <div className="provider-error" role="alert" style={{marginTop:16}}>{saveError}</div>
            )}
            <div className="provider-dashboard-actions">
              <button className="btn btn-dark" type="button" onClick={submitChanges} disabled={saving}>
                {saving ? 'Saving…' : (saved ? 'Saved ✓' : 'Save changes')}
              </button>
              <button className="btn btn-ghost" type="button" onClick={onLogout}>Sign out</button>
            </div>
          </div>
        </section>

        <aside className="provider-info">
          <ProviderPreview profile={profile} photoPreview={photoPreview} premium={premium} />
          <div className="provider-summary">
            <h2>What changes you can send</h2>
            <div className="provider-benefits">
              {[
                'Contact details and clinic address.',
                'Treatment approach, specialties, and insurance accepted.',
                'Scheduling notes and telehealth availability.',
                'Professional credentials and verified profile details.',
              ].map(text=>(
                <div key={text} className="provider-benefit">
                  <span className="benefit-dot" aria-hidden="true" />
                  <span>{text}</span>
                </div>
              ))}
            </div>
          </div>

          {saved ? (
            <div className="provider-success" role="status">
              <h3>Saved.</h3>
              <p>Your changes are live. Patients will see the updated listing on their next page load.</p>
            </div>
          ) : (
            <div className="provider-note">
              <h3>Edit your live listing.</h3>
              <p>Changes save directly to your listing — no review queue. Email, phone, social, and scheduling URLs are shown to patients exactly as you enter them.</p>
            </div>
          )}
        </aside>
      </div>
    </main>
  );
};

const ProviderLogin = ({ onBack, claimTarget }) => {
  const [email, setEmail] = React.useState('');
  const [phase, setPhase] = React.useState('loading'); // loading | login | sent | dashboard
  const [session, setSession] = React.useState(null);
  const [sending, setSending] = React.useState(false);
  const [error, setError] = React.useState('');

  const claimingProvider = React.useMemo(() => {
    if (!claimTarget) return null;
    const source = typeof getMergedProviders === 'function' ? getMergedProviders() : (typeof PROVIDERS !== 'undefined' ? PROVIDERS : []);
    return source.find(p => p.id === claimTarget) || null;
  }, [claimTarget]);

  // Detect existing session on mount + subscribe to auth changes (magic-link callback)
  React.useEffect(() => {
    let mounted = true;
    (async () => {
      const existing = typeof getSession === 'function' ? await getSession() : null;
      if (!mounted) return;
      if (existing) {
        setSession(existing);
        setPhase('dashboard');
      } else {
        setPhase('login');
      }
    })();
    const unsub = typeof onAuthChange === 'function' ? onAuthChange((s) => {
      if (!mounted) return;
      setSession(s);
      setPhase(s ? 'dashboard' : 'login');
    }) : () => {};
    return () => { mounted = false; unsub(); };
  }, []);

  const handleSendLink = async (event) => {
    event.preventDefault();
    setError('');
    const e = email.trim().toLowerCase();
    if (!e) { setError('Please enter your work email.'); return; }
    setSending(true);
    try {
      await sendMagicLink(e);
      setPhase('sent');
    } catch (err) {
      console.error('[providerLogin] magic link error', err);
      setError(err?.message || 'Could not send the sign-in link. Try again in a moment.');
    } finally {
      setSending(false);
    }
  };

  const handleLogout = async () => {
    if (typeof signOut === 'function') await signOut();
    setSession(null);
    setEmail('');
    setPhase('login');
  };

  if (phase === 'dashboard' && session) {
    return <ProviderDashboard session={session} claimTarget={claimTarget} onBack={onBack} onLogout={handleLogout} />;
  }

  if (phase === 'loading') {
    return (
      <main className="provider-shell">
        <p style={{textAlign:'center',padding:80,color:'var(--muted)'}}>Loading…</p>
      </main>
    );
  }

  return (
    <main className="provider-shell">
      <button className="provider-back" onClick={onBack}>← Back to directory</button>
      <section className="provider-hero">
        <p className="ed-sub-eyebrow">{claimingProvider ? 'Claim listing' : 'Provider login'}</p>
        <h1>
          {claimingProvider
            ? <>Claim {claimingProvider.name}'s listing.</>
            : 'Claim your listing and keep your profile current.'}
        </h1>
        <p>
          {claimingProvider
            ? 'Confirm this is your practice, sign in with your work email, and we’ll route you to your dashboard to fill in the rest.'
            : 'Providers listed on TMJDirectory can sign in to verify credentials, claim their profile, and submit edits for review. This portal is the first step toward owning your listing and maintaining accurate information for patients.'}
        </p>
      </section>

      {claimingProvider && (
        <section className="claim-confirm">
          <div className="claim-confirm-row">
            <div className="claim-confirm-mark" aria-hidden="true">{claimingProvider.specialty?.[0] || '•'}</div>
            <div>
              <div className="claim-confirm-label">You're claiming</div>
              <div className="claim-confirm-name">{claimingProvider.name}</div>
              <div className="claim-confirm-meta">
                {claimingProvider.specialty}
                {claimingProvider.business ? <> · {claimingProvider.business}</> : null}
              </div>
            </div>
          </div>
          <p className="claim-confirm-note">
            Only the public-facing fields (name, specialty, business) are visible right now. Sign in to add address, phone, website, photo and more.
          </p>
        </section>
      )}

      <div className="provider-grid">
        <section className="provider-card">
          <div className="provider-card-head">
            <h2>
              {phase === 'sent'
                ? 'Check your inbox'
                : (claimingProvider ? 'Sign in to continue' : 'Sign in or claim your listing')}
            </h2>
            <p>
              {phase === 'sent'
                ? <>We sent a sign-in link to <strong>{email}</strong>. Click it from any device — you'll land back here, signed in.</>
                : (claimingProvider
                    ? 'Use the email on file for this practice. We\'ll send a one-time sign-in link — no password to remember.'
                    : <>Enter the email on your listing and we'll send you a one-time sign-in link. <strong>Not in the directory yet?</strong> Use the contact form to request a listing first.</>)
              }
            </p>
          </div>

          {phase === 'sent' ? (
            <div className="provider-form">
              <div style={{
                padding:'24px 20px', borderRadius:8,
                background:'var(--bg)', border:'1px solid var(--line)',
                textAlign:'center', marginBottom:16,
              }}>
                <div style={{fontSize:32, marginBottom:8}}>✉️</div>
                <p style={{margin:0, color:'var(--ink-2)'}}>
                  The link expires in 1 hour. Didn't see it? Check your spam folder, or{' '}
                  <button type="button" onClick={()=>setPhase('login')} style={{color:'var(--accent-ink)',textDecoration:'underline',background:'none',border:0,padding:0,cursor:'pointer'}}>send to a different email</button>.
                </p>
              </div>
            </div>
          ) : (
            <form className="provider-form" onSubmit={handleSendLink}>
              <label htmlFor="provider-email">Work email</label>
              <input
                id="provider-email"
                type="email"
                value={email}
                onChange={e=>setEmail(e.target.value)}
                placeholder="you@clinic.com"
                required
                autoComplete="email"
              />

              {error && (
                <div className="provider-error" role="alert">{error}</div>
              )}

              <div className="provider-cta">
                <button className="btn btn-dark" type="submit" disabled={sending}>
                  {sending ? 'Sending link…' : 'Email me a sign-in link →'}
                </button>
              </div>
              <p className="field-hint" style={{marginTop:12,fontSize:13,color:'var(--muted)'}}>
                We don't store passwords. Each sign-in uses a fresh link from Supabase Auth.
              </p>
            </form>
          )}

          <div className="provider-support">
            <p>Sign-in only works for the email on a listing. To add a new practice, use the <a href="contact.html" style={{textDecoration:'underline'}}>contact form</a> and we'll get you set up.</p>
            <p><strong>Need help?</strong> Email provider-support@tmjdirectory.example</p>
          </div>
        </section>

        <aside className="provider-info">
          <div className="provider-summary">
            <h2>What you get when you claim</h2>

            <h3 style={{margin:'18px 0 6px',fontSize:14,letterSpacing:'.08em',textTransform:'uppercase',color:'var(--accent-ink)'}}>Own your listing</h3>
            <div className="provider-benefits">
              {[
                'Edit your name, credentials, photo, bio, address, phone, website, social links, and scheduling URL — changes go live after a quick review.',
                'Add your accepted insurances, treatment tags, and telehealth availability so patients filter directly to you.',
                'Replace the "claim it free" prompt on your card with a verified ★ badge.',
              ].map(text=>(
                <div key={text} className="provider-benefit">
                  <span className="benefit-dot" aria-hidden="true" />
                  <span>{text}</span>
                </div>
              ))}
            </div>

            <h3 style={{margin:'24px 0 6px',fontSize:14,letterSpacing:'.08em',textTransform:'uppercase',color:'var(--accent-ink)'}}>Build a TMJD provider network</h3>
            <div className="provider-benefits">
              {[
                'Search and save other vetted providers in your area — orofacial dentists, PTs, sleep specialists, myofunctional therapists — to build a support web around each patient.',
                'Opt in to be reachable by other providers. Your preferred contact method is revealed only to providers who save you to their network — never publicly.',
                'See how many other providers have saved you as a referral partner. Wear it as a trust signal on your card.',
              ].map(text=>(
                <div key={text} className="provider-benefit">
                  <span className="benefit-dot" aria-hidden="true" />
                  <span>{text}</span>
                </div>
              ))}
            </div>

            <h3 style={{margin:'24px 0 6px',fontSize:14,letterSpacing:'.08em',textTransform:'uppercase',color:'var(--accent-ink)'}}>See real patient engagement</h3>
            <div className="provider-benefits">
              {[
                'Weekly analytics: how many patients viewed your card, and exactly what they clicked — phone, email, website, social, schedule link.',
                'Track how many patients saved you to their favorites, and how many providers saved you to their support network.',
                'Spot which specialty filters drove the most views so you can sharpen your tags.',
              ].map(text=>(
                <div key={text} className="provider-benefit">
                  <span className="benefit-dot" aria-hidden="true" />
                  <span>{text}</span>
                </div>
              ))}
            </div>

            <h3 style={{margin:'24px 0 6px',fontSize:14,letterSpacing:'.08em',textTransform:'uppercase',color:'var(--accent-ink)'}}>Premium add-ons</h3>
            <div className="provider-benefits">
              {[
                'Top-of-search placement above unclaimed listings.',
                'Dedicated full-page provider profile with photo gallery and FAQ.',
                'Priority support direct to the directory team.',
              ].map(text=>(
                <div key={text} className="provider-benefit">
                  <span className="benefit-dot" aria-hidden="true" />
                  <span>{text}</span>
                </div>
              ))}
            </div>
          </div>

          <div className="provider-note">
            <h3>New to TMJDirectory?</h3>
            <p>Claiming a listing is free and takes about 2 minutes. If your practice isn't in the directory yet, sign in with a new email and we'll start a fresh listing for you.</p>
          </div>
        </aside>
      </div>
    </main>
  );
};

if (typeof window !== 'undefined') Object.assign(window, { Landing, ProviderLogin });
