/* Castle Connolly AI search (v2). Engine (streaming, citations, sections) from open-search-v3; shell, URL state, nav variants, brand switch, structured form and mock account are ours. */
const Icon = window.Icon;
const Message = window.AlmaMessage;
const ES = window.EHSearch;
const C = window.EHCards;
const { Svg, Header, Logo, BRANDS } = window.EH;
const { useState: useS, useEffect: useE, useRef: useR, useMemo: useM, useCallback } = React;

const SCOPES = ES.SCOPES;
const scopeById = (id) => SCOPES.find((s) => s.id === id) || SCOPES[0];
window.sectionScope = (s) => (s && (s.scope || s.tab)) || 'ask';
const DATA = () => window.EHData || {};
const PROFILE = () => DATA().PROFILE || { name: 'Jordan Ellis', firstName: 'Jordan', initials: 'JE', location: 'Boston, MA 02116', plan: 'Aetna', family: [], savedIds: [], recentSearches: [] };

/* Recent list: signed out shows the public flows, signed in shows the account's recent searches. */
const flowRows = (user) => ES.RECOMMENDED_ROWS.filter((r) => user || !r.user);
const historyFor = (user) => {
  const rows = user ? (PROFILE().recentSearches || []).map((q) => ({ q, to: (ES.RECOMMENDED_ROWS.find((r) => r.text === q) || {}).to || ES.resolveKey(q) })) : flowRows(false).map((r) => ({ q: r.text, to: r.to }));
  return rows.filter((r) => r.to).map((r, i) => ({ id: 'h' + i, ...r }));
};

const SPECIALTY_OPTIONS = ['Cardiology', 'Dermatology', 'Endocrinology', 'Family Medicine', 'Gastroenterology', 'Internal Medicine', 'Neurology', 'Obstetrics & Gynecology', 'Oncology', 'Orthopedic Surgery', 'Pediatrics', 'Psychiatry', 'Urology', 'General Dentistry', 'Pediatric Dentistry', 'Orthodontics'];
const INSURANCE_OPTIONS = ['Aetna', 'Blue Cross Blue Shield of MA', 'Cigna', 'Harvard Pilgrim Health Care', 'Mass General Brigham Health Plan', 'Medicare', 'Tufts Health Plan', 'UnitedHealthcare', 'WellSense Health Plan', 'Delta Dental', 'MetLife Dental', 'Cigna Dental', 'Guardian Dental'];
const DISTANCE_OPTIONS = ['5 mi', '10 mi', '25 mi', '50 mi', 'Any distance'];

/* ---------- URL state ---------- */
function readUrl() {
  const p = new URLSearchParams(location.search);
  return { q: p.get('q') || '', scope: p.get('scope') || '', nav: ES.navOf(), user: p.get('user') === '1', brand: window.EH.brandOf(), view: p.get('view') || '' };
}
function writeUrl(state) {
  const params = {};
  if (state.q) params.q = state.q;
  if (state.scope && state.scope !== 'ask') params.scope = state.scope;
  if (state.user) params.user = '1';
  if (state.brand === 'ehcare') params.brand = 'ehcare';
  if (state.view) params.view = state.view;
  history.replaceState(null, '', ES.searchUrl(state.nav, params));
}
const homeHref = (nav, st) => { const p = []; if (st && st.user) p.push('user=1'); if (st && st.brand === 'ehcare') p.push('brand=ehcare'); const base = ES.homeUrl(nav); return base + (p.length ? (base.includes('?') ? '&' : '?') + p.join('&') : ''); };

/* ---------- Input ---------- */
/* Response mode (v3 affordance, made real): Quick trims the answer to its first sentences and the top three results; Detailed is the full answer. */
const RESPONSE_MODES = [
  { id: 'quick', label: 'Quick', desc: 'One-line answer and the top three results' },
  { id: 'detailed', label: 'Detailed', desc: 'Full answer with every result, hospitals, topics and sources' },
];
const SpeechRec = window.SpeechRecognition || window.webkitSpeechRecognition || null;
function InputBar({ value, onChange, onSubmit, large, placeholder, autoFocus, scope, onFocus, onBlur, mode, onMode, attachments, onAttach, onRemoveAttachment }) {
  const ta = useR(null);
  const [modeOpen, setModeOpen] = useS(false);
  const [addOpen, setAddOpen] = useS(false);
  const [listening, setListening] = useS(false);
  const recRef = useR(null);
  const fileRef = useR(null);
  const wrap = useR(null);
  useE(() => { if (!ta.current) return; if (!value) { ta.current.style.height = ''; return; } ta.current.style.height = 'auto'; ta.current.style.height = Math.min(ta.current.scrollHeight, 180) + 'px'; }, [value]);
  useE(() => { if (autoFocus && ta.current) ta.current.focus(); }, [autoFocus]);
  useE(() => {
    if (!modeOpen && !addOpen) return;
    const close = (e) => { if (wrap.current && !wrap.current.contains(e.target)) { setModeOpen(false); setAddOpen(false); } };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [modeOpen, addOpen]);
  useE(() => () => { if (recRef.current) { try { recRef.current.abort(); } catch (_) {} } }, []);
  const submit = () => { const q = value.replace(/\s+$/, '').trim(); if (q) onSubmit(q); };
  const handleKey = (e) => { if ((e.key === 'Enter' || e.keyCode === 13) && !e.shiftKey) { e.preventDefault(); e.stopPropagation(); submit(); } };
  const handleChange = (e) => onChange(e.target.value);
  /* Voice: the browser's own speech recognition fills the bar; the presenter still presses Search. Hidden where unsupported so nothing dead ships. */
  const toggleVoice = () => {
    if (!SpeechRec) return;
    if (listening && recRef.current) { recRef.current.stop(); return; }
    const rec = new SpeechRec();
    rec.lang = 'en-US'; rec.interimResults = true; rec.continuous = false; rec.maxAlternatives = 1;
    const base = value ? value.replace(/\s+$/, '') + ' ' : '';
    rec.onresult = (e) => { let t = ''; for (let i = 0; i < e.results.length; i++) t += e.results[i][0].transcript; onChange(base + t.replace(/^\s+/, '').replace(/^\w/, (c) => c.toUpperCase())); };
    rec.onend = () => { setListening(false); recRef.current = null; if (ta.current) ta.current.focus(); };
    rec.onerror = () => { setListening(false); recRef.current = null; };
    recRef.current = rec; setListening(true);
    try { rec.start(); } catch (_) { setListening(false); recRef.current = null; }
  };
  const current = RESPONSE_MODES.find((m) => m.id === mode) || RESPONSE_MODES[1];
  const chips = attachments || [];
  return (
    <div className={'input-shell' + (large ? ' input-shell--large' : '') + (listening ? ' is-listening' : '')} ref={wrap}>
      <div className="input__textarea-wrap">
        <span className="input__lead">{listening ? Icon.Mic() : Icon.Search()}</span>
        {chips.length > 0 && <span className="input__chips">{chips.map((c) => <span key={c.id} className="input__chip" title={c.title}>{Icon[c.icon]()}<span>{c.label}</span><button type="button" className="input__chip-x" onClick={() => onRemoveAttachment && onRemoveAttachment(c.id)} aria-label={'Remove ' + c.label}>{Icon.X()}</button></span>)}</span>}
        <textarea ref={ta} className="input__textarea" placeholder={listening ? 'Listening…' : (chips.length || window.innerWidth <= 640) ? 'Ask anything…' : placeholder} value={value}
          onChange={handleChange} onKeyDown={handleKey} onFocus={onFocus} onBlur={onBlur} rows={1} aria-label="Search" />
      </div>
      <div className="input__row">
        <div className="input__tools">
          {scope && scope !== 'ask' ? <span className="input__scope">{Icon[scopeById(scope).icon]()}<span>{scopeById(scope).label}</span></span> : null}
          {onAttach && (
            <div className="input__add-wrap">
              <button type="button" className={'icon-btn input__tool' + (addOpen ? ' icon-btn--open' : '')} title="Add" aria-label="Add to your search" aria-expanded={addOpen} onMouseDown={(e) => e.preventDefault()} onClick={() => { setAddOpen((o) => !o); setModeOpen(false); }}>{Icon.Plus()}</button>
              {addOpen && (
                <div className="input__add-menu input__add-menu--up">
                  <button type="button" className="input__add-item" onMouseDown={(e) => e.preventDefault()} onClick={() => { setAddOpen(false); fileRef.current && fileRef.current.click(); }}><span className="input__add-item-icon">{Icon.Image()}</span><span className="input__add-item-label">Add insurance card</span></button>
                  <button type="button" className="input__add-item" onMouseDown={(e) => e.preventDefault()} onClick={() => { setAddOpen(false); onAttach('location'); }}><span className="input__add-item-icon">{Icon.MapPin()}</span><span className="input__add-item-label">Use my location</span></button>
                </div>
              )}
              <input ref={fileRef} type="file" accept="image/*" className="input__file" tabIndex={-1} aria-hidden="true" onChange={(e) => { if (e.target.files && e.target.files.length) onAttach('card', e.target.files[0]); e.target.value = ''; }} />
            </div>
          )}
          {SpeechRec && <button type="button" className={'icon-btn input__tool input__mic' + (listening ? ' is-on' : '')} title={listening ? 'Stop listening' : 'Search by voice'} aria-label={listening ? 'Stop listening' : 'Search by voice'} aria-pressed={listening} onMouseDown={(e) => e.preventDefault()} onClick={toggleVoice}>{Icon.Mic()}</button>}
        </div>
        <div className="input__right">
          {onMode && (
            <div className="input__mode-wrap">
              <button type="button" className={'input__mode' + (modeOpen ? ' input__mode--open' : '')} aria-haspopup="listbox" aria-expanded={modeOpen} onMouseDown={(e) => e.preventDefault()} onClick={() => { setModeOpen((o) => !o); setAddOpen(false); }}><span>{current.label}</span><span className="input__mode-caret">{Icon.ChevronDown()}</span></button>
              {modeOpen && (
                <div className="input__mode-menu input__mode-menu--up" role="listbox">
                  {RESPONSE_MODES.map((m) => <button key={m.id} type="button" role="option" aria-selected={mode === m.id} className={'input__mode-item' + (mode === m.id ? ' input__mode-item--active' : '')} onMouseDown={(e) => e.preventDefault()} onClick={() => { onMode(m.id); setModeOpen(false); }}><span className="input__mode-item-label">{m.label}</span><span className="input__mode-item-desc">{m.desc}</span></button>)}
                </div>
              )}
            </div>
          )}
          {large
            ? <button className="input__send input__send--label" disabled={!value.trim()} onClick={submit}><span>Search</span>{Icon.ArrowRight()}</button>
            : <button className="input__send" disabled={!value.trim()} onClick={submit} title="Search" aria-label="Search">{Icon.ArrowRight()}</button>}
        </div>
      </div>
    </div>
  );
}

function SearchPanel({ draft, scope, onSelect }) {
  /* onSelect(text, to): the row's flow key travels with the text so the pick always resolves. */
  const suggestions = ES.getSuggestions(draft, scope, 6);
  if (!draft.trim() || !suggestions.length) return null;
  const q = draft.trim().toLowerCase();
  return (
    <div className="search-panel search-panel--typeahead">
      {suggestions.map((s) => {
        const lo = s.text.toLowerCase(); const idx = lo.indexOf(q);
        return (
          <button key={s.text} className="search-panel__item" onMouseDown={(e) => { e.preventDefault(); onSelect(s.text, s.to); }}>
            <span className="search-panel__item-icon">{Icon.Search()}</span>
            <span className="search-panel__item-text">
              {idx > -1 ? <><span className="search-panel__match">{s.text.slice(0, idx)}</span><span className="search-panel__rest">{s.text.slice(idx, idx + q.length)}</span><span className="search-panel__match">{s.text.slice(idx + q.length)}</span></> : <span className="search-panel__rest">{s.text}</span>}
            </span>
            <span className="search-panel__tag">{s.tag || scopeById(s.scope).tag}</span>
          </button>
        );
      })}
    </div>
  );
}

/* ---------- Structured search: a compact row under the Doctors / Dentists pill (mirrors castleconnolly.com's Find Top Doctors form) ---------- */
const DOCTOR_SPECIALTIES = SPECIALTY_OPTIONS.slice(0, 13);
const DENTAL_SPECIALTIES = SPECIALTY_OPTIONS.slice(13);
const MEDICAL_INSURERS = INSURANCE_OPTIONS.slice(0, 9);
const DENTAL_INSURERS = INSURANCE_OPTIONS.slice(9);
function ScopeRow({ scope, user, onSubmit }) {
  const profile = PROFILE();
  const dental = scope === 'dentists';
  const familyPlan = dental && profile.family && profile.family[0] && profile.family[0].dentalPlan;
  const fromProfile = user ? { location: profile.location, insurance: dental ? (familyPlan || '') : profile.plan } : {};
  const [f, setF] = useS({ specialty: dental ? 'Pediatric Dentistry' : 'Cardiology', location: fromProfile.location || 'Boston, MA', insurance: fromProfile.insurance || '', distance: '10 mi' });
  useE(() => { setF((p) => ({ ...p, location: user ? profile.location : (p.location || 'Boston, MA'), insurance: user ? (dental ? (familyPlan || '') : profile.plan) : p.insurance })); }, [user]);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const hint = (k) => (user && fromProfile[k] && f[k] === fromProfile[k] ? <em className="sform__from" title={k === 'insurance' && dental ? 'Maya\u2019s dental plan, from your profile' : 'From your profile'}>from your profile</em> : null);
  const [needSpec, setNeedSpec] = useS(false);
  const specRef = useR(null);
  const submit = (e) => { e.preventDefault(); if (!f.specialty) { setNeedSpec(true); specRef.current && specRef.current.focus(); return; } onSubmit(f); };
  const specialties = dental ? DENTAL_SPECIALTIES : DOCTOR_SPECIALTIES;
  const insurers = dental ? DENTAL_INSURERS : MEDICAL_INSURERS;
  return (
    <form className="sform sform--row" onSubmit={submit} aria-label={dental ? 'Find Top Dentists' : 'Find Top Doctors'}>
      <label className="sform__field">
        <span className="sform__label">Specialty</span>
        <select ref={specRef} value={f.specialty} onChange={(e) => { set('specialty', e.target.value); setNeedSpec(false); }} className={needSpec ? 'is-invalid' : ''} aria-invalid={needSpec}>
          <option value="">Choose a specialty</option>
          {specialties.map((x) => <option key={x} value={x}>{x}</option>)}
        </select>
      </label>
      <label className="sform__field">
        <span className="sform__label">Location {hint('location')}</span>
        <span className="sform__input">{Icon.MapPin()}<input value={f.location} onChange={(e) => set('location', e.target.value)} placeholder="City or ZIP" /></span>
      </label>
      <label className="sform__field">
        <span className="sform__label">Insurance {hint('insurance')}</span>
        <select value={f.insurance} onChange={(e) => set('insurance', e.target.value)}>
          <option value="">Any insurance</option>
          {insurers.map((x) => <option key={x} value={x}>{x}</option>)}
        </select>
      </label>
      <label className="sform__field sform__field--sm">
        <span className="sform__label">Distance</span>
        <select value={f.distance} onChange={(e) => set('distance', e.target.value)}>
          {DISTANCE_OPTIONS.map((x) => <option key={x} value={x}>{x}</option>)}
        </select>
      </label>
      <button type="submit" className="sform__submit">{Icon.Search()}<span>{dental ? 'Find Top Dentists' : 'Find Top Doctors'}</span></button>
      {needSpec && <span className="sform__note sform__note--warn">Choose a specialty to search.</span>}
    </form>
  );
}

/* ---------- Find a Top Doctor: one smart field with grouped suggestions (specialties, conditions and procedures, doctors), then the secondary filters under it. The pattern the best directories use. ---------- */
const CONDITIONS = [
  { name: 'Heart disease', specialty: 'Cardiology' }, { name: 'Atrial fibrillation', specialty: 'Cardiology' }, { name: 'Heart valve replacement', specialty: 'Cardiology' }, { name: 'Coronary artery bypass (CABG)', specialty: 'Cardiology' }, { name: 'High blood pressure', specialty: 'Cardiology' }, { name: 'Chest pain', specialty: 'Cardiology' }, { name: 'Cardiac catheterization', specialty: 'Cardiology' }, { name: 'Heart murmur', specialty: 'Cardiology' },
  { name: 'Well-child checkup', specialty: 'Pediatrics' }, { name: 'Childhood asthma', specialty: 'Pediatrics' }, { name: 'Newborn care', specialty: 'Pediatrics' }, { name: 'Vaccinations', specialty: 'Pediatrics' }, { name: 'Ear infection', specialty: 'Pediatrics' },
  { name: 'Teeth cleaning', specialty: 'Pediatric Dentistry' }, { name: 'Cavity filling', specialty: 'Pediatric Dentistry' }, { name: 'Dental sealants', specialty: 'Pediatric Dentistry' }, { name: 'First dental visit', specialty: 'Pediatric Dentistry' }, { name: 'Braces', specialty: 'Orthodontics' }, { name: 'Invisalign', specialty: 'Orthodontics' },
];
const isDentalSpec = (x) => /Dent|Ortho/.test(x);
function matchSpecialty(q, dental) { const s = q.trim().toLowerCase(); if (!s) return null; const list = dental ? DENTAL_SPECIALTIES : DOCTOR_SPECIALTIES; return list.find((x) => x.toLowerCase() === s) || list.find((x) => x.toLowerCase().startsWith(s) && s.length >= 4) || null; }
function matchCondition(q, dental) { const s = q.trim().toLowerCase(); if (!s) return null; return CONDITIONS.find((c) => isDentalSpec(c.specialty) === dental && c.name.toLowerCase() === s) || null; }
function smartMatches(q, dental) {
  const s = q.trim().toLowerCase(); if (s.length < 2) return null;
  const specs = (dental ? DENTAL_SPECIALTIES : DOCTOR_SPECIALTIES).filter((x) => x.toLowerCase().includes(s)).slice(0, 4);
  const conds = CONDITIONS.filter((c) => isDentalSpec(c.specialty) === dental && c.name.toLowerCase().includes(s)).slice(0, 5);
  const docs = Object.values(DATA().PROVIDERS || {}).filter((p) => ((p.programs || []).includes('Top Dentist')) === dental && p.name.toLowerCase().includes(s)).slice(0, 4);
  if (!specs.length && !conds.length && !docs.length) return null;
  return { specs, conds, docs };
}
function SmartPanel({ draft, dental, onSpecialty, onCondition, onDoctor }) {
  const m = smartMatches(draft, dental); if (!m) return null;
  const q = draft.trim().toLowerCase();
  const hi = (text) => { const lo = text.toLowerCase(); const i = lo.indexOf(q); return i < 0 ? text : <>{text.slice(0, i)}<mark>{text.slice(i, i + q.length)}</mark>{text.slice(i + q.length)}</>; };
  const Group = ({ title, icon, children }) => <div className="smart__group"><div className="smart__head"><span>{title}</span>{icon}</div>{children}</div>;
  return (
    <div className="search-panel search-panel--typeahead smart">
      {m.specs.length > 0 && <Group title="Specialties" icon={Icon.Stethoscope()}>{m.specs.map((x) => <button key={x} type="button" className="smart__item" onMouseDown={(e) => { e.preventDefault(); onSpecialty(x); }}><span className="smart__text">{hi(x)}</span><span className="smart__meta">Top {dental ? 'Dentists' : 'Doctors'} near you</span></button>)}</Group>}
      {m.conds.length > 0 && <Group title="Conditions and procedures" icon={Icon.Heart()}>{m.conds.map((c) => <button key={c.name} type="button" className="smart__item" onMouseDown={(e) => { e.preventDefault(); onCondition(c); }}><span className="smart__text">{hi(c.name)}</span><span className="smart__meta">{c.specialty}</span></button>)}</Group>}
      {m.docs.length > 0 && <Group title={dental ? 'Dentists' : 'Doctors'} icon={Icon.Person()}>{m.docs.map((p) => <button key={p.id} type="button" className="smart__item smart__item--doc" onMouseDown={(e) => { e.preventDefault(); onDoctor(p); }}><span className="rail__saved-avatar">{p.initials}</span><span className="smart__text">{hi(p.name)}</span><span className="smart__meta">{p.specialty} · {p.hospital || p.practice}</span></button>)}</Group>}
    </div>
  );
}
/* One finder bar for Doctors and Dentists (the Zocdoc, Cedars-Sinai and UCSF shape): search, location and insurance as three cells in one card, one green button, a quiet chip row under it. The chat box steps aside on these tabs. */
function FinderBar({ scope, user, draft, setDraft, f, setF, onSubmit, onPickDoctor, onUseLocation }) {
  const dental = scope === 'dentists';
  const profile = PROFILE();
  const [focused, setFocused] = useS(false);
  const [picked, setPicked] = useS(false);
  const { menu, setMenu, wrap } = C.useFacetMenu();
  const input = useR(null);
  useE(() => { if (input.current) input.current.focus(); }, [scope]);
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  const insurers = dental ? DENTAL_INSURERS : MEDICAL_INSURERS;
  const planOnFile = dental ? (((profile.family || [])[0] || {}).dentalPlan || '') : profile.plan;
  const fromProfile = user && f.insurance && f.insurance === planOnFile;
  const hasDraft = draft.trim().length > 0;
  /* A pick from the panel fills the Search cell and closes the panel; the Find button or Enter runs the search, so location and insurance can still change. Picking a named doctor opens that doctor. */
  const pick = (text) => { setDraft(text); setPicked(true); if (input.current) input.current.focus(); };
  const chip = (props) => <C.FacetChip menu={menu} setMenu={setMenu} {...props} />;
  const moreOn = (f.gender && f.gender !== 'Any') || (f.lang && f.lang !== 'Any') || (f.sched && f.sched !== 'Any time');
  return (
    <div className="finder-wrap" ref={wrap}>
      <div className={'finder' + (focused ? ' is-focused' : '')}>
        <div className="finder__cell finder__cell--q" onBlur={(e) => { if (wrap.current && wrap.current.contains(e.relatedTarget)) return; setFocused(false); }}>
          <span className="finder__label">Search</span>
          <div className="finder__inputwrap">{Icon.Search()}<input ref={input} value={draft} onChange={(e) => { setDraft(e.target.value); setPicked(false); }} onFocus={() => setFocused(true)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); onSubmit(draft); } }} placeholder={dental ? 'Specialty, procedure or name' : 'Specialty, condition or name'} aria-label="Search" autoComplete="off" /></div>
          {hasDraft && focused && !picked && <SmartPanel draft={draft} dental={dental} onSpecialty={(x) => pick(x)} onCondition={(c) => pick(c.name)} onDoctor={onPickDoctor} />}
        </div>
        <div className="finder__cell finder__cell--loc">
          <span className="finder__label">Location{f.__loc === 'device' ? <em title="From your device">device</em> : (user && f.location === profile.location) ? <em title="From your profile">profile</em> : null}</span>
          <div className="finder__inputwrap">{Icon.MapPin()}<input value={f.location || ''} onChange={(e) => { const v = e.target.value; setF((p) => ({ ...p, location: v, __loc: null })); }} placeholder="City or ZIP" aria-label="Location" /><button type="button" className="finder__geo" onClick={onUseLocation} title="Use my location" aria-label="Use my location">{Icon.Compass()}</button></div>
        </div>
        <div className="finder__cell finder__cell--ins">
          <span className="finder__label">Insurance{fromProfile ? <em title="From your profile">profile</em> : null}</span>
          <div className="finder__inputwrap">{Icon.Shield()}<select value={f.insurance || ''} onChange={(e) => set('insurance', e.target.value)} aria-label="Insurance"><option value="">Add insurance</option>{insurers.map((x) => <option key={x} value={x}>{x}</option>)}</select></div>
        </div>
        <button type="button" className="finder__go" onClick={() => onSubmit(draft)}>{Icon.Search()}<span>Find Top {dental ? 'Dentists' : 'Doctors'}</span></button>
      </div>
      <div className="finder__chips">
        {chip({ id: 'distance', label: 'Distance', value: f.distance || '10 mi', children: DISTANCE_OPTIONS.map((d) => <C.FacetOpt key={d} label={d} on={(f.distance || '10 mi') === d} onPick={() => { set('distance', d); setMenu(null); }} />) })}
        {chip({ id: 'new', label: 'Accepting new patients', on: !!f.acceptingNew, onClick: () => set('acceptingNew', !f.acceptingNew) })}
        {chip({ id: 'book', label: 'Online booking', on: !!f.bookOnline, onClick: () => set('bookOnline', !f.bookOnline) })}
        {chip({ id: 'tele', label: 'Telehealth', on: !!f.telehealth, onClick: () => set('telehealth', !f.telehealth) })}
        {chip({ id: 'top', label: dental ? 'Top Dentists only' : 'Top Doctors only', on: !!f.topOnly, onClick: () => set('topOnly', !f.topOnly) })}
        {chip({ id: 'more', label: 'More filters', icon: Icon.Sliders(), on: !!moreOn, wide: true, children: <C.FacetMore groups={[['gender', 'Gender', ['Any', 'Woman / Female', 'Man / Male', 'Non-binary / X']], ['lang', 'Language', ['Any', 'Spanish', 'Portuguese', 'Mandarin', 'Haitian Creole', 'Korean']], ['sched', 'Scheduling', ['Any time', 'This week', 'This month', 'Evenings']], ['type', 'Type', ['Doctor', 'Doctor practice', 'Hospital']]]} values={f} onSet={set} /> })}
      </div>
    </div>
  );
}

function Landing({ onAsk, onStructured, onPickDoctor, draft, setDraft, scope, setScope, nav, user, brand, onSignIn, onProfile, mode, onMode, attachments, onAttach, onRemoveAttachment }) {
  const [focused, setFocused] = useS(false);
  const wrapRef = useR(null);
  const profile = PROFILE();
  const hasDraft = draft.trim().length > 0;
  const onBlur = (e) => { if (wrapRef.current && wrapRef.current.contains(e.relatedTarget)) return; setFocused(false); };
  const rows = ES.promptsFor(scope, user).slice(0, 4);
  const structuredScope = scope === 'doctors' || scope === 'dentists';
  const dental = scope === 'dentists';
  const planFor = (d) => (user ? (d ? (((profile.family || [])[0] || {}).dentalPlan || '') : profile.plan) : '');
  const [sf, setSf] = useS(() => ({ location: user ? profile.location : 'Boston, MA', insurance: planFor(dental), distance: '10 mi' }));
  useE(() => { setSf((p) => ({ ...p, location: user ? profile.location : (p.__loc === 'device' ? p.location : 'Boston, MA'), insurance: planFor(dental) })); }, [user, dental]);
  const find = (specialty, condition) => { const spec = specialty || matchSpecialty(draft, dental) || (dental ? 'Pediatric Dentistry' : 'Cardiology'); onStructured({ specialty: spec, condition: condition || null, location: sf.location || 'Boston, MA', insurance: sf.insurance || '', distance: sf.distance || '10 mi', acceptingNew: !!sf.acceptingNew, topOnly: !!sf.topOnly, bookOnline: !!sf.bookOnline, telehealth: !!sf.telehealth, gender: sf.gender || 'Any', lang: sf.lang || 'Any', __loc: sf.__loc || null }); };
  const submitBar = (q) => { if (!structuredScope) { onAsk(q, scope); return; } if (!q || !q.trim()) { find(); return; } const c = matchCondition(q, dental); const spec = matchSpecialty(q, dental); if (c) { find(c.specialty, c.name); return; } if (spec) { find(spec); return; } onAsk(q, scope); };
  return (
    <div className="landing landing--flat fade-in">
      <section className="band band--flat">
        <div className="band__inner">
          {user
            ? <button type="button" className="landing__banner landing__banner--user landing__banner--band" onClick={onProfile}><span className="landing__banner-icon">{Icon.Person()}</span><span className="landing__banner-text">Welcome back, <strong>{profile.firstName}</strong>. Your location and plan shape every answer.</span><span className="landing__banner-arrow">{Icon.ArrowRight()}</span></button>
            : <button type="button" className="landing__banner landing__banner--band" onClick={onSignIn}><span className="landing__banner-icon">{Icon.Sparkle()}</span><span className="landing__banner-text"><strong>Create a free account</strong> to see which Top Doctors take your plan, save doctors and book online</span><span className="landing__banner-arrow">{Icon.ArrowRight()}</span></button>}
          <h1 className="landing__title">{brand.tagline}</h1>
        </div>
      </section>
      <div className="landing__body">
        <div className="search-tabs landing__tabs" role="tablist">
          {SCOPES.map((s) => (
            <button key={s.id} type="button" role="tab" aria-selected={scope === s.id} className={'search-tab' + (scope === s.id ? ' search-tab--active' : '')} onMouseDown={(e) => e.preventDefault()} onClick={() => setScope(s.id)}>
              <span className="search-tab__icon">{Icon[s.icon]()}</span><span className="search-tab__label">{s.label}</span>
            </button>
          ))}
        </div>
        {structuredScope
          ? <FinderBar key={scope} scope={scope} user={user} draft={draft} setDraft={setDraft} f={sf} setF={setSf} onSubmit={submitBar} onPickDoctor={(p) => onPickDoctor(p)} onUseLocation={() => setSf((p) => ({ ...p, location: 'Boston, MA 02116', __loc: 'device' }))} />
          : (
            <div className="landing__input" ref={wrapRef} onBlur={onBlur}>
              <InputBar value={draft} onChange={setDraft} onSubmit={submitBar} autoFocus scope={scope} onFocus={() => setFocused(true)} placeholder={scopeById(scope).placeholder} mode={mode} onMode={onMode} attachments={attachments} onAttach={onAttach} onRemoveAttachment={onRemoveAttachment} />
              {hasDraft && focused && <SearchPanel draft={draft} scope={scope} onSelect={(q, to) => onAsk(q, scope, to)} />}
            </div>
          )}
        <div className="landing__suggest">
          {scope !== 'ask' && <div className="landing__suggest-label">Popular in {scopeById(scope).label}</div>}
          <div className="default-suggestions">
            {rows.map((r) => {
              const tag = scopeById(r.scope).tag;
              return (
                <button key={r.text} type="button" className="default-suggestions__item" onMouseDown={(e) => e.preventDefault()} onClick={() => onAsk(r.text, scope, r.to)} title={r.text}>
                  <span className="default-suggestions__icon">{Icon.Search()}</span><span className="default-suggestions__text">{r.short || r.text}</span>
                  <span className="search-panel__tag">{tag}</span>
                </button>
              );
            })}
          </div>
        </div>
        <div className="landing__scale"><span>{ES.scale.physicians} physicians · {ES.scale.dentists} dentists · {ES.scale.hospitals} hospitals and practices, with Castle Connolly recognition</span></div>
      </div>
    </div>
  );
}

/* ---------- Account (concept: Castle Connolly has no consumer account today) ---------- */
function AccountControl({ user, onSignIn, onSignOut, savedCount, onSaved, onProfile, onPrefs, light }) {
  const [open, setOpen] = useS(false);
  const ref = useR(null);
  const profile = PROFILE();
  useE(() => {
    if (!open) return;
    const close = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [open]);
  if (!user) return <button type="button" className={'acct__signin' + (light ? ' acct__signin--light' : '')} onClick={onSignIn}>{Icon.Person()}<span>Sign in</span></button>;
  return (
    <div className="acct" ref={ref}>
      <button type="button" className={'acct__chip' + (open ? ' is-open' : '')} onClick={() => setOpen((o) => !o)} aria-expanded={open} aria-haspopup="menu">
        <span className="acct__avatar">{profile.initials}</span><span className="acct__name">{profile.name}</span>{Icon.ChevronDown()}
      </button>
      {open && (
        <div className="acct__menu" role="menu">
          <div className="acct__who"><strong>{profile.name}</strong><span>{profile.location} · {profile.plan}</span></div>
          <button type="button" className="acct__item" role="menuitem" onClick={() => { setOpen(false); onProfile && onProfile(); }}>{Icon.Person()}<span>My care profile</span></button>
          <button type="button" className="acct__item" role="menuitem" onClick={() => { setOpen(false); onPrefs && onPrefs(); }}>{Icon.Sliders()}<span>Search preferences</span></button>
          <button type="button" className="acct__item" role="menuitem" onClick={() => setOpen(false)}>{Icon.Alert()}<span>Notifications</span><em className="acct__trail">Reminders on</em></button>
          <button type="button" className="acct__item" role="menuitem" onClick={() => setOpen(false)}>{Icon.Settings()}<span>Settings</span></button>
          <button type="button" className="acct__item" role="menuitem" onClick={() => setOpen(false)}>{Icon.Globe()}<span>Language</span><em className="acct__trail">English</em></button>
          <button type="button" className="acct__item" role="menuitem" onClick={() => { setOpen(false); onSignOut(); }}>{Icon.LogOut()}<span>Sign out</span></button>
          <div className="acct__note">Demo account. Castle Connolly has no consumer account today; this shows what one could add.</div>
        </div>
      )}
    </div>
  );
}

/* ---------- Auth dialog (v3 shape): step one logs in or signs up, step two sets up the profile. Nothing is real: every path lands on the same demo account. ---------- */
const GoogleG = () => (
  <svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true">
    <path fill="#4285F4" d="M21.6 12.23c0-.7-.06-1.22-.2-1.77H12v3.21h5.5c-.11.83-.71 2.07-2.04 2.91l-.02.12 2.96 2.3.2.02c1.88-1.74 2.97-4.29 2.97-7.31" />
    <path fill="#34A853" d="M12 21.6c2.7 0 4.96-.89 6.6-2.41l-3.15-2.44c-.84.59-1.97 1-3.45 1-2.64 0-4.88-1.74-5.68-4.14l-.12.01-3.08 2.38-.04.11C4.72 19.39 8.08 21.6 12 21.6" />
    <path fill="#FBBC04" d="M6.32 13.61A5.95 5.95 0 0 1 6 12c0-.56.1-1.1.31-1.6L6.3 10.27 3.18 7.85l-.1.05A9.59 9.59 0 0 0 2.4 12c0 1.55.37 3.02 1.03 4.32l3.08-2.38" />
    <path fill="#EA4335" d="M12 5.86c1.88 0 3.14.81 3.86 1.49l2.82-2.75C16.96 3.04 14.7 2.4 12 2.4 8.08 2.4 4.72 4.61 3.08 7.85l3.23 2.45C7.12 8.16 9.36 5.86 12 5.86" />
  </svg>
);
const AppleLogo = () => (
  <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor" aria-hidden="true">
    <path d="M17.07 12.41c-.03-2.51 2.05-3.72 2.14-3.78-1.17-1.71-2.99-1.94-3.63-1.97-1.55-.16-3.02.91-3.81.91-.79 0-2-.89-3.29-.86-1.69.03-3.25.98-4.12 2.5-1.76 3.05-.45 7.57 1.27 10.05.84 1.21 1.84 2.57 3.15 2.52 1.27-.05 1.75-.82 3.28-.82s1.96.82 3.3.79c1.36-.02 2.22-1.23 3.05-2.45.96-1.41 1.36-2.78 1.38-2.85-.03-.01-2.65-1.01-2.68-4.04zM14.7 5.07c.69-.84 1.16-2 1.03-3.16-1 .04-2.22.67-2.93 1.5-.64.74-1.2 1.93-1.05 3.06 1.12.09 2.26-.57 2.95-1.4z" />
  </svg>
);
const EMAIL_OK = /^\S+@\S+\.\S+$/;
function AuthModal({ brand, step: initialStep, mode, onClose, onComplete }) {
  const profile = PROFILE();
  const fam = (profile.family && profile.family[0]) || {};
  const isProfile = mode === 'profile';
  const [step, setStep] = useS(initialStep || 'login');
  const [email, setEmail] = useS('');
  const [f, setF] = useS({ name: profile.name, zip: profile.zip || '02116', plan: profile.plan, famName: fam.name || '', famAge: fam.age || '', famPlan: fam.dentalPlan || '', telehealth: !!(profile.preferences || {}).telehealth, evening: !!(profile.preferences || {}).eveningAppointments });
  const set = (k, v) => setF((p) => ({ ...p, [k]: v }));
  useE(() => { const esc = (e) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', esc); return () => document.removeEventListener('keydown', esc); }, [onClose]);
  const emailValid = EMAIL_OK.test(email.trim());
  const next = () => setStep('profile');
  const titleId = 'auth-title';
  return (
    <div className="auth-modal" role="dialog" aria-modal="true" aria-labelledby={titleId} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className={'auth-modal__card fade-in' + (step === 'profile' ? ' auth-modal__card--profile' : '')}>
        <button type="button" className="auth-modal__close" onClick={onClose} aria-label="Close">{Icon.X()}</button>
        {step === 'login' ? (
          <>
            <Logo brand={brand} className="auth-modal__logo" />
            <h2 id={titleId} className="auth-modal__title">Log in or sign up</h2>
            <p className="auth-modal__sub">See which Top Doctors take your plan, save doctors and book online. One click signs you in as the demo account.</p>
            <div className="auth-modal__providers">
              <button type="button" className="auth-provider" onClick={onComplete}><span className="auth-provider__icon"><GoogleG /></span><span>Continue with Google</span></button>
              <button type="button" className="auth-provider" onClick={onComplete}><span className="auth-provider__icon"><AppleLogo /></span><span>Continue with Apple</span></button>
              <button type="button" className="auth-provider" onClick={onComplete}><span className="auth-provider__icon">{Icon.Phone()}</span><span>Continue with phone</span></button>
            </div>
            <div className="auth-modal__divider"><span>or</span></div>
            <form className="auth-modal__email" onSubmit={(e) => { e.preventDefault(); if (emailValid) onComplete(); }}>
              <input type="email" className="auth-modal__input" placeholder="Email address" value={email} onChange={(e) => setEmail(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); if (emailValid) onComplete(); } }} autoFocus autoComplete="off" aria-label="Email address" />
              <button type="submit" className="auth-modal__continue" disabled={!emailValid}>Continue</button>
            </form>
            <p className="auth-modal__legal">By continuing you agree to {brand.shortName}’s Terms of Use and Privacy Policy.</p>
          </>
        ) : (
          <>
            {!isProfile && <button type="button" className="auth-modal__back" onClick={() => setStep('login')} aria-label="Back">{Icon.CornerUpLeft()}</button>}
            <h2 id={titleId} className="auth-modal__title">{isProfile ? 'My care profile' : 'Set up your profile'}</h2>
            <p className="auth-modal__sub">{isProfile ? 'What every answer knows about you. Edit anything.' : 'Your location, plan and family shape every answer. Edit anything.'}</p>
            <form className="auth-modal__form" onSubmit={(e) => { e.preventDefault(); isProfile ? onClose() : onComplete(); }} onKeyDown={(e) => { if (e.key === 'Enter' && e.target.tagName === 'INPUT') { e.preventDefault(); isProfile ? onClose() : onComplete(); } }}>
              <div className="auth-modal__grid">
                <label className="auth-modal__field auth-modal__field--wide"><span className="auth-modal__label">Name</span><input className="auth-modal__input" value={f.name} onChange={(e) => set('name', e.target.value)} autoFocus={!isProfile} /></label>
                <label className="auth-modal__field auth-modal__field--sm"><span className="auth-modal__label">ZIP</span><input className="auth-modal__input" value={f.zip} onChange={(e) => set('zip', e.target.value)} inputMode="numeric" maxLength={5} /></label>
                <label className="auth-modal__field auth-modal__field--full"><span className="auth-modal__label">Insurance plan</span>
                  <select className="auth-modal__input" value={f.plan} onChange={(e) => set('plan', e.target.value)}>{MEDICAL_INSURERS.map((x) => <option key={x} value={x}>{x}</option>)}</select></label>
              </div>
              <div className="auth-modal__label auth-modal__label--group">Family <em>optional</em></div>
              <div className="auth-modal__grid auth-modal__grid--family">
                <label className="auth-modal__field"><span className="auth-modal__label">Name</span><input className="auth-modal__input" value={f.famName} onChange={(e) => set('famName', e.target.value)} placeholder="Name" /></label>
                <label className="auth-modal__field auth-modal__field--xs"><span className="auth-modal__label">Age</span><input className="auth-modal__input" value={f.famAge} onChange={(e) => set('famAge', e.target.value)} inputMode="numeric" maxLength={3} /></label>
                <label className="auth-modal__field"><span className="auth-modal__label">Dental plan</span>
                  <select className="auth-modal__input" value={f.famPlan} onChange={(e) => set('famPlan', e.target.value)}><option value="">None</option>{DENTAL_INSURERS.map((x) => <option key={x} value={x}>{x}</option>)}</select></label>
              </div>
              <div className="auth-modal__label auth-modal__label--group">Preferences</div>
              <div className="auth-modal__chips">
                <button type="button" className={'auth-chip' + (f.telehealth ? ' is-on' : '')} aria-pressed={f.telehealth} onClick={() => set('telehealth', !f.telehealth)}>{Icon.Video()}<span>Telehealth OK</span></button>
                <button type="button" className={'auth-chip' + (f.evening ? ' is-on' : '')} aria-pressed={f.evening} onClick={() => set('evening', !f.evening)}>{Icon.Clock()}<span>Evening appointments</span></button>
              </div>
              <button type="submit" className="auth-modal__continue auth-modal__primary">{isProfile ? 'Done' : 'Create account'}{!isProfile && Icon.ArrowRight()}</button>
            </form>
          </>
        )}
        <p className="auth-modal__foot">Concept only. Castle Connolly has no consumer account today; the RFP defines a provider portal.</p>
      </div>
    </div>
  );
}

/* ---------- Account features (v3 locked-item pattern): dimmed with a lock glyph signed out, a hover promo invites in; full strength once the account exists ---------- */
const SAVED_FEATURE = { id: 'saved', icon: 'Bookmark', label: 'Saved', title: 'Keep a shortlist', desc: 'Sign in to save doctors, hospitals, guides and searches from any answer and find them here.' };
/* Tools (the health-system demo's "agents", grounded in what castleconnolly.com and everydayhealth.care do): structured Top Doctor search, coverage check, side-by-side compare, online booking. Two need the account. */
const TOOLS = [
  { id: 'find', icon: 'Stethoscope', label: 'Find a Top Doctor', auth: false },
  { id: 'coverage', icon: 'ShieldCheck', label: 'Check my coverage', auth: true, title: 'See who takes your plan', desc: 'Sign in and every answer checks your insurance before it shows a doctor.' },
  { id: 'compare', icon: 'Grid', label: 'Compare doctors', auth: true, title: 'Compare two Top Doctors', desc: 'Sign in to lay saved doctors side by side on recognition, distance, plan and availability.' },
  { id: 'book', icon: 'Calendar', label: 'Book online', auth: true, title: 'Book with one tap', desc: 'Sign in to book a Top Doctor online through Zocdoc, as castleconnolly.com offers today.' },
];
const FEATURES = TOOLS.filter((t) => t.auth);
function RailLockedItem({ icon, label, title, desc, onSignIn, placement, className }) {
  const [hover, setHover] = useS(false);
  const [pos, setPos] = useS({ top: 0, left: 0 });
  const ref = useR(null);
  const timer = useR(null);
  const show = () => {
    clearTimeout(timer.current);
    if (ref.current) { const r = ref.current.getBoundingClientRect(); setPos(placement === 'below' ? { top: r.bottom + 8, left: Math.min(r.left, window.innerWidth - 256) } : { top: r.top, left: r.right + 6 }); }
    setHover(true);
  };
  const hide = () => { clearTimeout(timer.current); timer.current = setTimeout(() => setHover(false), 120); };
  useE(() => () => clearTimeout(timer.current), []);
  const go = (e) => { e.stopPropagation(); setHover(false); onSignIn && onSignIn(); };
  return (
    <div className={'rail__locked' + (className ? ' ' + className : '')} ref={ref} onMouseEnter={show} onMouseLeave={hide} onFocus={show} onBlur={hide}>
      <div className={'rail__item rail__item--locked' + (hover ? ' rail__item--locked-hover' : '')} role="button" aria-disabled="true" tabIndex={0} onClick={go} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') go(e); }} title={title}>
        <span className="rail__item-icon">{Icon[icon]()}</span>
        <span className="rail__text">{label}</span>
        <span className="rail__item-trail rail__item-trail--lock">{Icon.Lock()}</span>
      </div>
      {hover && (
        <div className={'rail__promo' + (placement === 'below' ? ' rail__promo--below' : '')} role="tooltip" onMouseEnter={show} onMouseLeave={hide} style={{ top: pos.top, left: pos.left }}>
          <div className="rail__promo-title">{title}</div>
          <div className="rail__promo-desc">{desc}</div>
          <button type="button" className="rail__promo-btn" onClick={go}>Sign up</button>
        </div>
      )}
    </div>
  );
}

/* Signed in: the same three rows, unlocked. Saved doctors and Book online expand the saved list in place; My care profile opens the profile sheet. */
function SavedRows({ list, mode, onPick }) {
  if (!list.length) return <div className="rail__empty">Save a doctor from any answer and it lands here.</div>;
  return list.map((p) => (
    <div key={p.id} className={'rail__recent rail__saved' + (mode === 'book' ? ' rail__saved--book' : '')} onClick={() => onPick(p)} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter') onPick(p); }} title={p.name + ' · ' + p.specialty + ' · ' + (p.hospital || p.practice)}>
      <span className="rail__saved-avatar">{p.initials}</span>
      <span className="rail__recent-text"><strong>{p.name}</strong><span>{mode === 'book' ? 'Next available ' + p.nextAvailable : p.specialty + ' · ' + (p.hospital || p.practice)}</span></span>
      {mode === 'book' && <a className="btn btn--primary rail__book" href={p.profileUrl || '#'} target="_blank" rel="noreferrer" onClick={(e) => e.stopPropagation()}>{Icon.Calendar()}<span>Book online</span></a>}
    </div>
  ));
}
function RailSaved({ user, count, onSignIn, onOpenSaved }) {
  if (!user) return <RailLockedItem {...SAVED_FEATURE} onSignIn={onSignIn} />;
  return <button className="rail__item" onClick={onOpenSaved} data-rail-tip="Saved"><span className="rail__item-icon">{Icon.Bookmark()}</span><span className="rail__text">Saved</span><span className="rail__item-trail"><span className="rail__count">{count}</span></span></button>;
}
function RailFeatures({ user, savedList, onSignIn, onPickSaved, onTool }) {
  const [open, setOpen] = useS(null);
  useE(() => { if (!user) setOpen(null); }, [user]);
  return (
    <div className="rail__section rail__section--features">
      <div className="rail__label rail__section-head">Tools</div>
      {TOOLS.map((t) => {
        if (t.auth && !user) return <RailLockedItem key={t.id} {...t} onSignIn={onSignIn} />;
        if (t.id === 'book') return (
          <React.Fragment key={t.id}>
            <button className={'rail__item' + (open === t.id ? ' rail__item--open' : '')} onClick={() => setOpen((o) => (o === t.id ? null : t.id))} aria-expanded={open === t.id} data-rail-tip={t.label}>
              <span className="rail__item-icon">{Icon[t.icon]()}</span><span className="rail__text">{t.label}</span>
              <span className="rail__item-trail">{open === t.id ? Icon.Up() : Icon.ChevronDown()}</span>
            </button>
            {open === t.id && <div className="rail__sublist fade-in"><SavedRows list={savedList} mode="book" onPick={onPickSaved} /></div>}
          </React.Fragment>
        );
        return <button key={t.id} className="rail__item" onClick={() => onTool(t.id)} data-rail-tip={t.label}><span className="rail__item-icon">{Icon[t.icon]()}</span><span className="rail__text">{t.label}</span><span className="rail__item-trail">{Icon.ArrowRight()}</span></button>;
      })}
    </div>
  );
}

/* Rail footer: sign-in callout signed out, the user row signed in (v3). */
function RailFooter({ user, onSignIn, onSignOut, onOpenProfile, onOpenSaved, onOpenPrefs }) {
  const [menu, setMenu] = useS(false);
  const ref = useR(null);
  const profile = PROFILE();
  useE(() => {
    if (!menu) return;
    const close = (e) => { if (ref.current && !ref.current.contains(e.target)) setMenu(false); };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [menu]);
  useE(() => { if (!user) setMenu(false); }, [user]);
  if (!user) return (
    <div className="signin-callout">
      <div className="signin-callout__title">Create a free account</div>
      <div className="signin-callout__desc">Log in for results matched to your plan, saved doctors and your past searches.</div>
      <div className="signin-callout__actions">
        <button type="button" className="signin-callout__primary" onClick={onSignIn}>Log in</button>
        <button type="button" className="signin-callout__secondary" onClick={onSignIn}>Sign up</button>
      </div>
    </div>
  );
  return (
    <div className="rail__user-wrap" ref={ref}>
      {menu && (
        <div className="user-menu" role="menu">
          <button type="button" className="user-menu__item" role="menuitem" onClick={() => { setMenu(false); onOpenProfile(); }}><span className="user-menu__icon">{Icon.Person()}</span><span>My care profile</span></button>
          <button type="button" className="user-menu__item" role="menuitem" onClick={() => { setMenu(false); onOpenPrefs(); }}><span className="user-menu__icon">{Icon.Sliders()}</span><span>Search preferences</span></button>
          <button type="button" className="user-menu__item" role="menuitem" onClick={() => setMenu(false)}><span className="user-menu__icon">{Icon.Alert()}</span><span>Notifications</span><span className="user-menu__trail">Reminders on</span></button>
          <button type="button" className="user-menu__item" role="menuitem" onClick={() => setMenu(false)}><span className="user-menu__icon">{Icon.Settings()}</span><span>Settings</span></button>
          <button type="button" className="user-menu__item" role="menuitem" onClick={() => setMenu(false)}><span className="user-menu__icon">{Icon.Globe()}</span><span>Language</span><span className="user-menu__trail">English</span></button>
          <div className="user-menu__divider"></div>
          <button type="button" className="user-menu__item user-menu__item--danger" role="menuitem" onClick={() => { setMenu(false); onSignOut(); }}><span className="user-menu__icon">{Icon.LogOut()}</span><span>Sign out</span></button>
        </div>
      )}
      <div className={'rail__user' + (menu ? ' rail__user--open' : '')} onClick={() => setMenu((m) => !m)} role="button" tabIndex={0} aria-expanded={menu} aria-haspopup="menu" onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setMenu((m) => !m); } }}>
        <div className="rail__user-avatar">{profile.initials}</div>
        <div className="rail__user-text"><div className="rail__user-name">{profile.name}</div><div className="rail__user-sub">Signed in</div></div>
        <span className="rail__user-action">{Icon.ChevronUpDown()}</span>
      </div>
    </div>
  );
}

/* ---------- Saved (v3 pattern): one page for everything the account keeps. Doctors reuse the answer card; hospitals and topics reuse the answer sections. ---------- */
const collectByKind = (kind) => { const out = {}; Object.values(DATA()).forEach((t) => { if (!t || !Array.isArray(t.sections)) return; t.sections.forEach((s) => { if (s.kind === kind) (s.items || []).forEach((it) => { if (it && it.id && !out[it.id]) out[it.id] = it; }); }); }); return out; };
const SAVED_TABS = [['all', 'All'], ['doctors', 'Doctors'], ['hospitals', 'Hospitals'], ['topics', 'Topics'], ['searches', 'Searches']];
function SavedSection({ title, count, children }) {
  return <section className="saved-section"><div className="saved-section__head"><h2 className="saved-section__title">{title}<span className="saved-section__count">{count}</span></h2></div>{children}</section>;
}
function SavedPage({ saved, savedH, savedT, savedQ, onRemove, ctx, onSearch }) {
  const [tab, setTab] = useS('all');
  const profile = PROFILE();
  const when = (id) => (profile.savedAt || {})[id] || 'just now';
  const doctors = [...saved].map((id) => (DATA().PROVIDERS || {})[id]).filter(Boolean);
  const hospitalsAll = collectByKind('hospitals');
  const topicsAll = collectByKind('articles');
  const hospitals = [...savedH].map((id) => hospitalsAll[id]).filter(Boolean);
  const topics = [...savedT].map((id) => topicsAll[id]).filter(Boolean);
  const searches = savedQ.filter((r) => r.to);
  const total = doctors.length + hospitals.length + topics.length + searches.length;
  const show = (id) => tab === 'all' || tab === id;
  const isDentist = (p) => (p.programs || []).includes('Top Dentist');
  const RemoveX = ({ id, kind, label }) => <button type="button" className="saved-card__unsave saved-card__unsave--static" onClick={(e) => { e.stopPropagation(); onRemove(kind, id); }} title="Remove from Saved" aria-label={'Remove ' + label + ' from Saved'}>{Icon.X()}</button>;
  return (
    <div className="saved-page fade-in">
      <div className="saved-page__head"><div><h1 className="saved-page__title">Saved</h1><p className="saved-page__subtitle">{total} item{total === 1 ? '' : 's'} kept across your searches. Visible only to you.</p></div></div>
      <div className="saved-tabs" role="tablist">{SAVED_TABS.map(([id, label]) => <button key={id} type="button" role="tab" aria-selected={tab === id} className={'saved-tabs__btn' + (tab === id ? ' saved-tabs__btn--active' : '')} onClick={() => setTab(id)}>{label}</button>)}</div>
      {show('doctors') && (
        <SavedSection title="Doctors and dentists" count={doctors.length}>
          {doctors.length ? <div className="saved-list">{doctors.map((p) => (
            <div key={p.id} className="saved-item">
              <C.ProviderCard p={p} dentist={isDentist(p)} ctx={ctx} />
              <div className="saved-card__foot saved-card__foot--inline"><span className="saved-card__when">Saved {when(p.id)}</span><button type="button" className="saved-remove" onClick={() => onRemove('doctor', p.id)}>{Icon.X()}<span>Remove</span></button></div>
            </div>
          ))}</div> : <p className="saved-empty">Save a doctor from any answer and it lands here.</p>}
        </SavedSection>
      )}
      {show('hospitals') && (
        <SavedSection title="Hospitals" count={hospitals.length}>
          {hospitals.length ? <div className="saved-list">{hospitals.map((h) => (
            <div key={h.id} className="saved-item saved-item--card">
              <C.SectionBody section={{ id: 'saved-' + h.id, kind: 'hospitals', items: [h] }} ctx={ctx} />
              <div className="saved-card__foot saved-card__foot--inline"><span className="saved-card__when">Saved {when(h.id)}</span><button type="button" className="saved-remove" onClick={() => onRemove('hospital', h.id)}>{Icon.X()}<span>Remove</span></button></div>
            </div>
          ))}</div> : <p className="saved-empty">Save a hospital from any Hospitals tab and it lands here.</p>}
        </SavedSection>
      )}
      {show('topics') && (
        <SavedSection title="Topics" count={topics.length}>
          {topics.length ? <div className="saved-item saved-item--card">
            <C.SectionBody section={{ id: 'saved-topics', kind: 'articles', items: topics }} ctx={ctx} />
            <div className="saved-card__foot saved-card__foot--inline">{topics.map((t) => <button key={t.id} type="button" className="saved-remove" onClick={() => onRemove('topic', t.id)}>{Icon.X()}<span>Remove “{t.title}”</span></button>)}</div>
          </div> : <p className="saved-empty">Save a guide from any Topics tab and it lands here.</p>}
        </SavedSection>
      )}
      {show('searches') && (
        <SavedSection title="Searches" count={searches.length}>
          {searches.length ? <ul className="saved-pages-list">{searches.map((r) => (
            <li key={r.q} className="saved-page-row saved-search-row" onClick={() => onSearch(r)} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter') onSearch(r); }}>
              <RemoveX id={r.q} kind="search" label="this search" />
              <span className="saved-search-row__icon">{Icon.Search()}</span>
              <div className="saved-search-row__body"><div className="saved-search-row__q">{r.q}</div><div className="saved-card__foot saved-card__foot--inline"><span className="saved-card__when">Saved {r.at || 'just now'} · Run again</span></div></div>
            </li>
          ))}</ul> : <p className="saved-empty">Save a search from any answer and rerun it from here.</p>}
        </SavedSection>
      )}
      <p className="saved-page__foot">Concept only. Castle Connolly has no consumer account today; the RFP defines a provider portal.</p>
    </div>
  );
}

/* ---------- My care profile as a page (v3 pattern): what every answer knows, how complete it is, and where to change it. ---------- */
function ProfilePage({ prefs, saved, savedTotal, onEdit, onOpenPrefs, onOpenSaved, onPickSaved }) {
  const p = PROFILE();
  const fam = (p.family && p.family[0]) || null;
  const prefsOn = p.preferences || {};
  const [tab, setTab] = useS('basics');
  const fields = [!!p.name, !!(p.zip || p.location), !!p.plan, !!fam, !!(prefsOn.telehealth || prefsOn.eveningAppointments), !!p.phone, !!p.preferredHospital];
  const pct = Math.round((fields.filter(Boolean).length / fields.length) * 100);
  const hints = [!p.phone && ['Add your phone number for appointment reminders.', 'basics'], !p.preferredHospital && ['Add a preferred hospital to sort results near it.', 'preferences']].filter(Boolean);
  const Row = ({ label, value, empty }) => <div className="prow"><div className="prow__label">{label}</div><div className={'prow__value' + (empty ? ' prow__value--empty' : '')}>{value}</div></div>;
  const sortLabel = { top: 'Top Doctor status', distance: 'Distance', available: 'Next available' }[(prefs || {}).sort] || 'Top Doctor status';
  const savedDocs = [...saved].map((id) => (DATA().PROVIDERS || {})[id]).filter(Boolean);
  const TABS = [['basics', 'Basics'], ['location', 'Location'], ['insurance', 'Insurance'], ['family', 'Family'], ['care', 'Care team'], ['preferences', 'Preferences'], ['privacy', 'Privacy']];
  const Bar = ({ badge, note }) => <div className="ptab__bar">{badge ? <span className="ptab__badge">{Icon.ShieldCheck()}{badge}</span> : <span className="ptab__note">{note}</span>}<button type="button" className="btn ptab__edit" onClick={onEdit}>{Icon.Edit()}<span>Edit</span></button></div>;
  const body = {
    basics: <><Bar note="Account details. Your name appears on bookings." /><div className="prow-grid"><Row label="Name" value={p.name} /><Row label="Phone" value={p.phone || 'Not added'} empty={!p.phone} /><Row label="Preferred contact" value="Email" /><Row label="Language" value="English" /></div></>,
    location: <><Bar note="Where “near me” points. Answers measure distance from here." /><div className="prow-grid"><Row label="Home ZIP" value={p.zip || '02116'} /><Row label="City" value={p.city || 'Boston, MA'} /><Row label="Default search radius" value="10 miles" /><Row label="Use my device location when offered" value="On" /></div></>,
    insurance: <><Bar badge="On file" /><div className="prow-grid"><Row label="Carrier" value={p.plan} /><Row label="Plan" value={p.planFull || p.plan} /><Row label="Plan type" value={/POS/.test(p.planFull || '') ? 'POS' : 'PPO'} /><Row label="Member ID" value="•••• 4471" /><Row label="Subscriber" value="Self" />{fam && fam.dentalPlan && <Row label={fam.name + '’s dental plan'} value={fam.dentalPlan} />}</div><p className="profile-page__note">Every answer filters to doctors who accept this plan and marks them <strong>In your network</strong>. Add a card from the search bar’s + menu to update it.</p></>,
    family: <><Bar note="People you search for. Each can carry their own plan." /><div className="prow-grid"><Row label={p.firstName + ' (you)'} value={(p.planFull || p.plan) + ' · ' + p.location} />{fam && <Row label={fam.name + ' · ' + fam.relation + ' · age ' + fam.age} value={(fam.dentalPlan ? fam.dentalPlan + ' · ' : '') + 'shares your location'} />}</div><button type="button" className="btn ptab__add" onClick={onEdit}>{Icon.Plus()}<span>Add a partner or child</span></button><p className="profile-page__note">Ask for “my 7-year-old” and the answer uses {fam ? fam.name + '’s' : 'their'} record and plan.</p></>,
    care: <><Bar note="Doctors you have saved or booked. Saved doctors appear here automatically." /><div className="prow-grid"><Row label="Primary care doctor" value="Not added" empty />{savedDocs.map((d) => <div key={d.id} className="prow prow--doc"><div className="prow__label">{d.specialty}</div><div className="prow__value"><button type="button" className="ptab__link" onClick={() => onPickSaved(d)}>{d.name}</button><span className="pcard__muted"> · {d.hospital || d.practice}</span></div></div>)}</div><p className="profile-page__note">{savedTotal} items in <button type="button" className="ptab__link" onClick={onOpenSaved}>Saved</button>.</p></>,
    preferences: <><Bar note="How you like to be seen and how results are ranked." /><div className="prow-grid"><Row label="Telehealth" value={prefsOn.telehealth ? 'OK' : 'No preference'} /><Row label="Appointment times" value={prefsOn.eveningAppointments ? 'Evenings preferred' : 'No preference'} /><Row label="Preferred hospital" value={p.preferredHospital || 'Not added'} empty={!p.preferredHospital} /><Row label="Provider gender" value="No preference" /><Row label="Default sort" value={sortLabel + ((prefs || {}).bookOnlineFirst ? ', doctors who book online first' : '')} /></div><p className="profile-page__note">Ranking and result types live in <button type="button" className="ptab__link" onClick={onOpenPrefs}>Search preferences</button>.</p></>,
    privacy: <><Bar note="What the account keeps, and what it does with it." /><div className="prow-grid"><Row label="Stored" value="Name, ZIP, insurance plan, family, saved items, recent searches" /><Row label="Used for" value="Shaping your answers and filters. Never shown to doctors or hospitals." /><Row label="Shared with hospitals or insurers" value="Off" /><Row label="Search history" value="Kept for 90 days" /></div><div className="ptab__actions"><button type="button" className="btn">{Icon.FileText()}<span>Download my data</span></button><button type="button" className="btn ptab__danger">{Icon.X()}<span>Delete account</span></button></div></>,
  };
  return (
    <div className="saved-page profile-page fade-in">
      <div className="saved-page__head"><div><div className="prefs__badge"><span className="prefs__badge-icon">{Icon.Person()}</span>My care profile</div><h1 className="saved-page__title">My care profile</h1><p className="saved-page__subtitle">Keep these details current so every answer knows your plan, your location and who you are searching for. You control what is saved.</p></div></div>
      <div className="completion">
        <div className="completion__head"><span className="completion__label">Profile completion</span><span className="completion__pct">{pct}%</span></div>
        <div className="completion__bar"><div className="completion__fill" style={{ width: pct + '%' }} /></div>
        {hints.length > 0 && <ul className="completion__hints">{hints.map(([h, t]) => <li key={h}><button type="button" className="completion__hint" onClick={() => setTab(t)}><span className="completion__plus">{Icon.Plus()}</span><span>{h}</span></button></li>)}</ul>}
      </div>
      <div className="care-profile__tabnav" role="tablist">{TABS.map(([id, label]) => <button key={id} type="button" role="tab" aria-selected={tab === id} className={'ptab-btn' + (tab === id ? ' ptab-btn--active' : '')} onClick={() => setTab(id)}>{label}</button>)}</div>
      <div className="ptab">{body[tab]}</div>
      <p className="saved-page__foot">Concept only. Castle Connolly has no consumer account today; the RFP defines a provider portal.</p>
    </div>
  );
}

/* ---------- Search preferences as a page (v3 layout). Sort reorders the answer on screen; result types apply to the next search. ---------- */
const SORT_OPTIONS = [['top', 'Top Doctor status'], ['distance', 'Distance'], ['available', 'Next available']];
function PrefSection({ num, title, children }) {
  return <section className="prefs__section"><div className="prefs__section-head"><span className="prefs__section-num">{num}</span><h2 className="prefs__section-title">{title}</h2></div><div className="prefs__section-body">{children}</div></section>;
}
function PrefsPage({ prefs, onSave, onCancel, onProfile }) {
  const [f, setF] = useS(prefs);
  const types = SCOPES.filter((sc) => sc.id !== 'ask');
  const toggleType = (id) => setF((p) => { const has = p.types.includes(id); if (has && p.types.length === 1) return p; return { ...p, types: has ? p.types.filter((t) => t !== id) : [...p.types, id] }; });
  const Toggle = ({ k }) => <button type="button" role="switch" aria-checked={!!f[k]} className={'ptoggle' + (f[k] ? ' ptoggle--on' : '')} onClick={() => setF((p) => ({ ...p, [k]: !p[k] }))}><span className="ptoggle__knob" /></button>;
  return (
    <div className="prefs fade-in">
      <div className="prefs__head">
        <div className="prefs__badge"><span className="prefs__badge-icon">{Icon.Sliders()}</span>Search preferences</div>
        <h1 className="prefs__title">Search preferences</h1>
        <p className="prefs__sub">Control how results are ranked and what appears. Your plan, location and family live in <button type="button" className="prefs__link" onClick={onProfile}>My care profile</button>.</p>
      </div>
      <PrefSection num="01" title="Results">
        <div className="prefs__field">
          <span className="prefs__field-label">Default sort</span>
          <div className="prefs__radio-row" role="radiogroup">{SORT_OPTIONS.map(([id, label]) => <button key={id} type="button" role="radio" aria-checked={f.sort === id} className={'prefs__radio' + (f.sort === id ? ' prefs__radio--active' : '')} onClick={() => setF((p) => ({ ...p, sort: id }))}>{label}</button>)}</div>
        </div>
        <div className="prefs__field">
          <span className="prefs__field-label">Result types to include</span>
          <div className="prefs__chip-row">{types.map((sc) => <button key={sc.id} type="button" aria-pressed={f.types.includes(sc.id)} className={'prefs__chip' + (f.types.includes(sc.id) ? ' prefs__chip--active' : '')} onClick={() => toggleType(sc.id)}>{f.types.includes(sc.id) && <span className="prefs__chip-check">{Icon.Check()}</span>}{sc.label}</button>)}</div>
        </div>
      </PrefSection>
      <PrefSection num="02" title="Behavior">
        <div className="prefs__field prefs__field--row"><div><span className="prefs__field-label">Prioritize doctors who book online</span><div className="prefs__field-hint">Doctors with online booking through Zocdoc sort first.</div></div><Toggle k="bookOnlineFirst" /></div>
        <div className="prefs__field prefs__field--row"><div><span className="prefs__field-label">Open answers on the results</span><div className="prefs__field-hint">Land on the Doctors or Dentists tab instead of the narrative answer.</div></div><Toggle k="resultsFirst" /></div>
      </PrefSection>
      <div className="prefs__footer">
        <div className="prefs__footer-note">Visible only to you. Sort applies to the answer on screen; result types apply to your next search.</div>
        <div className="prefs__footer-actions"><button type="button" className="prefs__btn-secondary" onClick={onCancel}>Cancel</button><button type="button" className="prefs__btn-primary" onClick={() => onSave(f)}>{Icon.Check()}<span>Save preferences</span></button></div>
      </div>
      <p className="saved-page__foot">Concept only. Castle Connolly has no consumer account today; the RFP defines a provider portal.</p>
    </div>
  );
}

/* ---------- Tools are tools, not chats: a coverage check sheet and a compare page built from the same records the answers use. ---------- */
function CoverageSheet({ saved, onClose, onProfile }) {
  const p = PROFILE();
  const [plan, setPlan] = useS(p.plan);
  useE(() => { const esc = (e) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', esc); return () => document.removeEventListener('keydown', esc); }, [onClose]);
  const fam = (p.family && p.family[0]) || null;
  const savedDocs = [...saved].map((id) => (DATA().PROVIDERS || {})[id]).filter(Boolean);
  const inNet = (d) => (d.insurance || []).includes(plan) || (fam && fam.dentalPlan && (d.insurance || []).includes(fam.dentalPlan));
  const all = Object.values(DATA().PROVIDERS || {});
  const count = all.filter((d) => (d.insurance || []).includes(plan)).length;
  return (
    <div className="auth-modal" role="dialog" aria-modal="true" aria-labelledby="cov-title" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="auth-modal__card auth-modal__card--profile fade-in">
        <button type="button" className="auth-modal__close" onClick={onClose} aria-label="Close">{Icon.X()}</button>
        <h2 id="cov-title" className="auth-modal__title">Check my coverage</h2>
        <p className="auth-modal__sub">Your plan on file filters every answer to doctors who accept it. Change it here to see who else you could see.</p>
        <label className="auth-modal__field auth-modal__field--full"><span className="auth-modal__label">Your plan</span>
          <select className="auth-modal__input" value={plan} onChange={(e) => setPlan(e.target.value)}>{MEDICAL_INSURERS.map((x) => <option key={x} value={x}>{x}</option>)}</select></label>
        <div className="cov__stat"><strong>{count}</strong> of the {all.length} Top Doctors and Top Dentists in this demo accept {plan}{fam && fam.dentalPlan ? <>; {fam.name}'s dental plan is <strong>{fam.dentalPlan}</strong></> : null}.</div>
        <div className="auth-modal__label auth-modal__label--group">Your saved doctors</div>
        <ul className="cov__list">{savedDocs.length ? savedDocs.map((d) => <li key={d.id} className={'cov__row' + (inNet(d) ? ' is-in' : ' is-out')}>{inNet(d) ? Icon.ShieldCheck() : Icon.Alert()}<span><strong>{d.name}</strong><em>{d.specialty} · {d.hospital || d.practice}</em></span><b>{inNet(d) ? 'In network' : 'Not in network'}</b></li>) : <li className="cov__row">Save a doctor from any answer to check them here.</li>}</ul>
        <button type="button" className="auth-modal__continue auth-modal__primary" onClick={onClose}>Done</button>
        <p className="auth-modal__alt">Plan and family live in <button type="button" className="auth-modal__link" onClick={onProfile}>My care profile</button>.</p>
        <p className="auth-modal__foot">Concept only. Coverage is read from directory records, not from your insurer.</p>
      </div>
    </div>
  );
}
function ComparePage({ ctx, saved }) {
  const D = DATA();
  const tpl = D.COMPARE_HOSPITAL;
  const src = tpl && (tpl.sections || []).find((s) => s.kind === 'compare');
  const section = src && { ...src, intro: null, columns: (src.columns || []).map(({ label, ...c }) => c) };
  const names = section && section.columns ? section.columns.map((c) => ((D.PROVIDERS || {})[c.providerId] || {}).name) : [];
  return (
    <div className="saved-page compare-page fade-in">
      <div className="saved-page__head"><div><div className="prefs__badge"><span className="prefs__badge-icon">{Icon.Grid()}</span>Compare doctors</div><h1 className="saved-page__title">Compare doctors</h1><p className="saved-page__subtitle">Two Top Doctors side by side on recognition, hospital, distance, plan and availability. Never a ranking.</p></div></div>
      <div className="compare-page__pick"><span className="compare-page__label">Comparing</span>{names.map((n) => <span key={n} className="auth-chip is-on">{Icon.Person()}<span>{n}</span></span>)}<span className="compare-page__hint">Pick any two from Saved or an answer to compare them here.</span></div>
      {section ? <div className="compare-page__body"><C.SectionBody section={section} ctx={ctx} /></div> : <p className="saved-empty">Save two doctors to compare them.</p>}
      <p className="saved-page__foot">Concept only. Castle Connolly recognizes doctors and hospitals; it does not rank one doctor against another.</p>
    </div>
  );
}

/* ---------- Left rail ---------- */
function LeftRail({ onNew, onPickHistory, onTool, activeKey, nav, user, brand, saved, savedTotal, onPickSaved, urlState, controls, onSignIn, onSignOut, onOpenProfile, onOpenSaved, onOpenPrefs, open }) {
  const history = historyFor(user);
  const savedList = user ? [...saved].map((id) => (DATA().PROVIDERS || {})[id]).filter(Boolean) : [];
  return (
    <aside className={'rail' + (open ? ' rail--open' : '')}>
      <div className="rail__header">
        <a className="rail__brand" href={homeHref(nav, urlState)} data-rail-tip={brand.site} title={brand.name}><Logo brand={brand} className="rail__logo" /></a>
      </div>
      <div className="rail__divider rail__divider--header"></div>
      <div className="rail__section">
        <button className="rail__item" onClick={onNew} data-rail-tip="New search"><span className="rail__item-icon">{Icon.NewChat()}</span><span className="rail__text">New search</span></button>
        <RailSaved user={user} count={savedTotal} onSignIn={onSignIn} onOpenSaved={onOpenSaved} />
      </div>
      <div className="rail__divider"></div>
      <RailFeatures user={user} savedList={savedList} onSignIn={onSignIn} onPickSaved={onPickSaved} onTool={onTool} />
      {user && (
        <>
          <div className="rail__divider"></div>
          <div className="rail__section rail__section--recent">
            <div className="rail__label rail__section-head">Recent</div>
            {history.map((h) => (
              <button key={h.id} className={'rail__recent' + (activeKey === h.to ? ' rail__recent--active' : '')} onClick={() => onPickHistory(h)} title={h.q}>
                <span className="rail__recent-text">{h.q}</span>
              </button>
            ))}
          </div>
        </>
      )}
      <div style={{ flex: 1 }}></div>
      <div className="rail__foot"><RailFooter user={user} onSignIn={onSignIn} onSignOut={onSignOut} onOpenProfile={onOpenProfile} onOpenSaved={onOpenSaved} onOpenPrefs={onOpenPrefs} />{controls}</div>
    </aside>
  );
}

function ScopeTabs({ sections, activeScope, onChange, className, filters }) {
  const present = useM(() => { const p = new Set(['ask']); (sections || []).forEach((s) => p.add(window.sectionScope(s))); return SCOPES.filter((sc) => p.has(sc.id)); }, [sections]);
  return (
    <div className={className || 'chat-header__tabs'} role="tablist">
      {present.map((sc) => (
        <button key={sc.id} role="tab" aria-selected={sc.id === activeScope} className={'chat-tab' + (sc.id === activeScope ? ' chat-tab--active' : '')} onClick={() => onChange(sc.id)}>
          <span className="chat-tab__icon">{Icon[sc.icon]()}</span><span className="chat-tab__label">{sc.label}</span>
          {sc.id !== 'ask' && <span className="chat-tab__count">{(sections || []).filter((s) => window.sectionScope(s) === sc.id).reduce((n, s) => n + (s.kind === 'providers' ? C.applyFilters(s.items, filters || {}).length : s.items ? s.items.length : 1), 0)}</span>}
        </button>
      ))}
    </div>
  );
}

/* The short label only earns its place when the question itself does not already carry its terms. */
const labelRedundant = (label, q) => { const ql = (q || '').toLowerCase(); const terms = (label || '').split('·').map((t) => t.trim().toLowerCase()).filter(Boolean); return terms.length > 0 && terms.every((t) => ql.includes(t.slice(0, 6))); };
function ChatHeader({ chatLabel, query, sections, activeScope, onScopeChange, filters, account }) {
  const showLabel = chatLabel && !labelRedundant(chatLabel, query);
  return (
    <div className="chat-header">
      <div className="chat-header__left">{showLabel && <div className="chat-header__name" title={chatLabel}>{chatLabel}</div>}</div>
      <ScopeTabs sections={sections} activeScope={activeScope} onChange={onScopeChange} filters={filters} />
      <div className="chat-header__right">{account}</div>
    </div>
  );
}

/* Follow-ups sit last, closest to the composer, as prompt chips. */
function FollowUpChips({ chips, onPick, personal }) {
  const items = (chips || []).slice(0, 3);
  if (!items.length) return null;
  return (
    <div className="fchips fade-in" aria-label="Suggested follow-ups">
      <div className="fchips__label">{personal ? 'Keep going · based on your profile' : 'Keep going'}</div>
      <div className="fchips__row">
        {items.map((c, i) => (
          <button key={i} type="button" className={'fchip' + (personal ? ' fchip--personal' : '')} onClick={() => onPick(c)}>{personal ? Icon.Person() : Icon.Sparkle()}<span>{(c && c.q) || c}</span></button>
        ))}
      </div>
    </div>
  );
}

function NoAnswer({ msg, idx, onPick, user }) {
  return (
    <div className="message fade-in" data-msg-id={msg.id} data-msg-idx={idx} data-sources="[]">
      <h1 className="query">{msg.query}</h1>
      <div className="noflow">
        <div className="noflow__title">{Icon.Info()}<span>This demo answers a fixed set of questions</span></div>
        <p className="noflow__body">The live product would search the full Castle Connolly directory: {ES.scale.physicians} physicians, {ES.scale.dentists} dentists and {ES.scale.hospitals} hospitals and practices. For the walkthrough, try one of these:</p>
        <div className="default-suggestions noflow__list">
          {flowRows(user).map((r) => (
            <button key={r.text} type="button" className="default-suggestions__item" onClick={() => onPick(r)}>
              <span className="default-suggestions__icon">{Icon.Search()}</span><span className="default-suggestions__text">{r.text}</span>
            </button>
          ))}
        </div>
      </div>
    </div>
  );
}

/* Top-nav variant: product bar beneath the site header (design option 1a). Scopes are the horizontal nav; recents live in a dropdown. */
function ProductBar({ hasMessages, last, activeScope, onScope, onNew, onPickHistory, filters, user, controls, saved, savedTotal, onSignIn, onPickSaved, onOpenProfile, onOpenSaved, onTool }) {
  const [open, setOpen] = useS(false);
  const [feat, setFeat] = useS(null);
  const ref = useR(null);
  const fref = useR(null);
  useE(() => {
    if (!open && !feat) return;
    const close = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); if (fref.current && !fref.current.contains(e.target)) setFeat(null); };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, [open, feat]);
  useE(() => { if (!user) setFeat(null); }, [user]);
  const savedList = user ? [...(saved || [])].map((id) => (DATA().PROVIDERS || {})[id]).filter(Boolean) : [];
  const sections = hasMessages && last && last.data ? last.data.sections : null;
  const present = (id) => id === 'ask' || !sections || sections.some((s) => window.sectionScope(s) === id);
  const count = (id) => sections ? sections.filter((s) => window.sectionScope(s) === id).reduce((n, s) => n + (s.kind === 'providers' ? C.applyFilters(s.items, filters || {}).length : s.items ? s.items.length : 1), 0) : 0;
  const history = historyFor(user);
  return (
    <div className="pbar">
      <div className="pbar__inner">
        <nav className="pbar__nav" aria-label="Search scopes">
          {SCOPES.map((sc) => {
            const active = sc.id === activeScope;
            const has = present(sc.id);
            return (
              <button key={sc.id} className={'pbar__item' + (active ? ' is-active' : '') + (hasMessages && !has ? ' is-muted' : '')} onClick={() => onScope(sc.id)} title={hasMessages && !has ? 'Start a new ' + sc.label.toLowerCase() + ' search' : sc.label}>
                <span className="pbar__icon">{Icon[sc.icon]()}</span>
                <span>{sc.label}</span>
                {hasMessages && has && sc.id !== 'ask' && <span className="pbar__count">{count(sc.id)}</span>}
              </button>
            );
          })}
        </nav>
        <div className="pbar__right">
          {controls}
          <div className="pbar__features" ref={fref}>
            {user
              ? [SAVED_FEATURE, ...FEATURES.filter((f) => f.id !== 'compare')].map((f) => f.id === 'saved'
                ? <button key={f.id} className="pbar__ghost pbar__feat" onClick={onOpenSaved}>{Icon.Bookmark()}<span>Saved</span><span className="pbar__count">{savedTotal}</span></button>
                : f.id === 'coverage'
                ? <button key={f.id} className="pbar__ghost pbar__feat" onClick={() => onTool('coverage')}>{Icon[f.icon]()}<span>{f.label}</span></button>
                : (
                  <div key={f.id} className="pbar__recent">
                    <button className={'pbar__ghost pbar__feat' + (feat === f.id ? ' is-open' : '')} onClick={() => setFeat((o) => (o === f.id ? null : f.id))} aria-expanded={feat === f.id}>{Icon[f.icon]()}<span>{f.label}</span>{Icon.ChevronDown()}</button>
                    {feat === f.id && <div className="pbar__menu pbar__menu--saved"><div className="pbar__menu-label">Book a saved doctor</div><SavedRows list={savedList} mode={f.id} onPick={(p) => { setFeat(null); onPickSaved(p); }} /></div>}
                  </div>
                ))
              : <>
                  {[SAVED_FEATURE, ...FEATURES.filter((f) => f.id !== 'compare')].map((f) => <RailLockedItem key={f.id} {...f} onSignIn={onSignIn} placement="below" className="pbar__locked" />)}
                  <button type="button" className="pbar__signup" onClick={onSignIn}>Sign up</button>
                </>}
          </div>
          {user && <div className="pbar__recent" ref={ref}>
            <button className={'pbar__ghost' + (open ? ' is-open' : '')} onClick={() => setOpen((o) => !o)} aria-expanded={open}>{Icon.History()}<span>Recent</span>{Icon.ChevronDown()}</button>
            {open && (
              <div className="pbar__menu">
                <div className="pbar__menu-label">Recent searches</div>
                {history.map((h) => (
                  <button key={h.id} className={'pbar__menu-item' + (last && last.key === h.to ? ' is-active' : '')} onClick={() => { setOpen(false); onPickHistory(h); }}>{Icon.Search()}<span>{h.q}</span></button>
                ))}
              </div>
            )}
          </div>}
          <button className="pbar__new" onClick={onNew}>{Icon.NewChat()}<span>New search</span></button>
        </div>
      </div>
    </div>
  );
}

/* Presenter controls: which Castle Connolly directory site is shown, and the layout variant. Live in the rail footer or the product bar, never over the composer. */
function PresenterToggles({ nav, onNav, brand, onBrand, compact }) {
  return (
    <div className={'ptoggles' + (compact ? ' ptoggles--bar' : ' ptoggles--rail')}>
      <div className="nav-toggle" role="group" aria-label="Brand" title="Presenter control: castleconnolly.com and everydayhealth.care, the two directory sites of the Castle Connolly business unit, from one source"><span className="nav-toggle__label">Brand</span>
        <button className={'nav-toggle__btn' + (brand === 'cc' ? ' is-on' : '')} onClick={() => onBrand('cc')}><span>{compact ? 'CC' : 'Castle Connolly'}</span></button>
        <button className={'nav-toggle__btn' + (brand === 'ehcare' ? ' is-on' : '')} onClick={() => onBrand('ehcare')}><span>{compact ? 'EH-CARE' : 'EH‑CARE'}</span></button>
      </div>
      <div className="nav-toggle" role="group" aria-label="Navigation variant" title="Presenter control: switch navigation layout"><span className="nav-toggle__label">Layout</span>
        <button className={'nav-toggle__btn' + (nav === 'rail' ? ' is-on' : '')} onClick={() => onNav('rail')}>{Icon.Sidebar()}<span>{compact ? 'Rail' : 'Left rail'}</span></button>
        <button className={'nav-toggle__btn' + (nav === 'top' ? ' is-on' : '')} onClick={() => onNav('top')}>{Icon.Menu()}<span>{compact ? 'Top' : 'Top nav'}</span></button>
      </div>
    </div>
  );
}

/* ---------- App ---------- */
function App() {
  const init = useR(readUrl()).current;
  const [nav, setNav] = useS(init.nav);
  const [brandId, setBrandId] = useS(init.brand);
  const [user, setUser] = useS(init.user);
  const [saved, setSaved] = useS(() => new Set(PROFILE().savedIds || []));
  const [auth, setAuth] = useS(null); /* null | { step: 'login' | 'profile', mode: 'signup' | 'profile' } */
  const [view, setView] = useS(['saved', 'profile', 'prefs', 'compare'].includes(init.view) && init.user ? init.view : null); /* 'saved' | 'profile' | 'prefs' | 'compare' | null; &view= */
  const [prefs, setPrefs] = useS(() => PROFILE().searchPrefs || { sort: 'top', types: ['doctors', 'dentists', 'hospitals', 'topics'], bookOnlineFirst: false, resultsFirst: false });
  const [prefsFrom, setPrefsFrom] = useS(null); /* view to return to after Save or Cancel on the preferences page */
  const [mode, setMode] = useS('detailed'); /* response mode: 'quick' | 'detailed' */
  const [drawer, setDrawer] = useS(false); /* phone: the rail is a drawer behind a menu button (engine pattern) */
  const [attachments, setAttachments] = useS([]); /* insurance card and device location, mocked: they seed filters and are labeled */
  const attach = (type) => {
    if (type === 'card') {
      const plan = PROFILE().plan || 'Aetna';
      setAttachments((l) => [...l.filter((c) => c.id !== 'card'), { id: 'card', icon: 'Shield', label: 'Reading card…', title: 'Insurance card' }]);
      setTimeout(() => setAttachments((l) => l.map((c) => (c.id === 'card' ? { ...c, label: plan + ' · from your card', plan, title: 'Plan read from your insurance card. Nothing is stored.' } : c))), 900);
    } else if (type === 'location') {
      setAttachments((l) => [...l.filter((c) => c.id !== 'loc'), { id: 'loc', icon: 'MapPin', label: 'Boston, MA 02116 · from your device', location: 'Boston, MA 02116', title: 'Location from your device, used for this search only' }]);
    }
  };
  const detach = (id) => setAttachments((l) => l.filter((c) => c.id !== id));
  const [savedH, setSavedH] = useS(() => new Set(PROFILE().savedHospitalIds || []));
  const [savedT, setSavedT] = useS(() => new Set(PROFILE().savedTopicIds || []));
  const [savedQ, setSavedQ] = useS(() => (PROFILE().savedSearches || []).map((q, i) => ({ q, to: (ES.RECOMMENDED_ROWS.find((r) => r.text === q) || {}).to || ES.resolveKey(q), at: (PROFILE().savedAt || {})['s' + i] })));
  const openAuth = () => setAuth({ step: 'login', mode: 'signup' });
  const openProfile = () => setAuth({ step: 'profile', mode: 'profile' });
  const closeAuth = useCallback(() => setAuth(null), []);
  const [messages, setMessages] = useS([]);
  const [draft, setDraft] = useS('');
  const [landingScope, setLandingScope] = useS(init.scope || 'ask');
  const [activeTab, setActiveTab] = useS('ask');
  const [filtersById, setFiltersById] = useS({}); /* filters are per turn: an earlier answer keeps its own refinements when a later one is asked */
  const setFiltersFor = (id, f) => setFiltersById((prev) => ({ ...prev, [id]: typeof f === 'function' ? f(prev[id] || {}) : f }));
  const [scrollEl, setScrollEl] = useS(null);
  const scrollRef = useR(null);
  const attachScroll = useCallback((el) => { scrollRef.current = el; setScrollEl(el); }, []);
  const brand = BRANDS[brandId];
  const stateRef = useR({}); stateRef.current = { nav, user, brand: brandId, prefs, mode, attachments };
  const urlState = { user, brand: brandId };

  useE(() => { document.body.classList.toggle('nav-top', nav === 'top'); }, [nav]);
  useE(() => { setDrawer(false); }, [messages.length, view, landingScope, user, auth]);
  useE(() => { document.body.classList.toggle('body--locked', drawer); return () => document.body.classList.remove('body--locked'); }, [drawer]);
  useE(() => { window.EH.applyBrand(brandId); }, [brandId]);

  const scrollToTurn = useCallback((msgId) => {
    const run = () => {
      const sc = scrollRef.current;
      const el = document.querySelector('[data-msg-id="' + msgId + '"]');
      if (!sc || !el) return;
      const turn = el.closest('.turn') || el;
      const top = sc.scrollTop + turn.getBoundingClientRect().top - sc.getBoundingClientRect().top - 24;
      sc.scrollTo({ top: Math.max(0, top), behavior: 'smooth' });
    };
    setTimeout(run, 0);
    setTimeout(run, 120);
  }, []);

  /* Seed filters from the template, then the profile (labeled), then an explicit form submission. */
  const seedFilters = (raw, opts, signedIn) => {
    const profile = PROFILE();
    const base = raw.filters ? { ...raw.filters } : {};
    if (raw.structured) { base.specialty = base.specialty || raw.structured.specialty; base.distance = base.distance || raw.structured.distance; }
    const from = {};
    if (signedIn && Array.isArray(raw.profileUse)) {
      if (raw.profileUse.includes('location')) { base.location = profile.location; from.location = 'profile'; }
      if (raw.profileUse.includes('plan')) { base.insurance = profile.plan; from.insurance = 'profile'; }
      if (raw.profileUse.includes('family') && profile.family && profile.family[0] && profile.family[0].dentalPlan) { base.insurance = profile.family[0].dentalPlan; from.insurance = 'family'; }
    }
    if (opts && opts.filters) { Object.assign(base, opts.filters); Object.keys(opts.filters).forEach((k) => { if (from[k] && opts.filters[k] !== base[k]) delete from[k]; }); }
    if (opts && opts.from) Object.assign(from, opts.from);
    if (!base.location) base.location = 'Boston, MA 02116';
    return { ...base, __from: from, __base: { ...base } };
  };

  const ask = useCallback((q, scopeId, forceKey, fresh, opts) => {
    const st = stateRef.current;
    setView(null);
    const D = DATA();
    const key = (forceKey && D[forceKey]) ? forceKey : ES.resolveKey(q);
    const raw = key ? D[key] : null;
    if (!raw) {
      const msgId = 'm-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7);
      const nfMsg = { id: msgId, kind: 'noflow', query: q, status: 'done', data: { sections: [], sources: [], summary: [] } };
      setMessages((m) => (fresh ? [nfMsg] : [...m, nfMsg]));
      setDraft('');
      setActiveTab('ask');
      writeUrl({ q, scope: 'ask', ...st });
      scrollToTurn(msgId);
      return;
    }
    const data = C.toEngineTemplate(raw);
    /* Attachments (insurance card, device location) seed filters for this search and are labeled in the filter bar. */
    const card = (st.attachments || []).find((c) => c.id === 'card' && c.plan);
    const loc = (st.attachments || []).find((c) => c.id === 'loc');
    if (card || loc) { opts = { ...(opts || {}), filters: { ...((opts && opts.filters) || {}), ...(card ? { insurance: card.plan } : {}), ...(loc ? { location: loc.location } : {}) }, from: { ...((opts && opts.from) || {}), ...(card ? { insurance: 'card' } : {}), ...(loc ? { location: 'device' } : {}) } }; }
    /* Quick mode: first sentences of the answer and the top three results; hospitals, topics and the rest wait for Detailed. */
    const mode = (opts && opts.mode) || st.mode || 'detailed';
    if (mode === 'quick') {
      const out = []; let len = 0;
      for (const t of data.summary) {
        const m = /[.!?](?=\s|$)/.exec(t.text);
        if (m && len + m.index + 1 > 60) { out.push({ ...t, text: t.text.slice(0, m.index + 1) }); break; }
        out.push(t); len += t.text.length;
      }
      data.summary = out;
      const primary = data.sections.find((s) => s.kind === 'compare') || data.sections.find((s) => s.kind === 'providers') || data.sections[0];
      data.sections = primary ? [primary.kind === 'providers' ? { ...primary, items: primary.items.slice(0, 3), quick: true } : primary].map((s) => ({ ...s, body: (ctx) => <C.SectionBody section={s} ctx={ctx} /> })) : [];
    }
    /* Search preferences: result types the account switched off are left out of new answers. */
    if (st.user && st.prefs && Array.isArray(st.prefs.types)) data.sections = data.sections.filter((s) => window.sectionScope(s) === 'ask' || st.prefs.types.includes(window.sectionScope(s)));
    const msgId = 'm-' + Date.now() + '-' + Math.random().toString(36).slice(2, 7);
    const newMsg = { id: msgId, key, query: q, mode, entry: (opts && opts.entry) || 'natural', data: { ...data, query: q }, status: 'thinking', sectionsVisible: 0 };
    setMessages((m) => (fresh ? [newMsg] : [...m, newMsg]));
    setDraft('');
    setFiltersFor(msgId, seedFilters(raw, opts, st.user));
    const scopes = new Set(data.sections.map(window.sectionScope));
    let tab = scopeId && scopeId !== 'ask' && scopes.has(scopeId) ? scopeId : (raw.defaultScope && scopes.has(raw.defaultScope) ? raw.defaultScope : 'ask');
    if (tab === 'ask' && st.user && st.prefs && st.prefs.resultsFirst) { const pref = ['doctors', 'dentists'].find((sc) => scopes.has(sc)); if (pref) tab = pref; }
    setActiveTab(tab);
    writeUrl({ q, scope: tab, ...st });
    const update = (changes) => setMessages((m) => m.map((mm) => (mm.id === msgId ? { ...mm, ...changes } : mm)));
    setTimeout(() => { update({ status: 'summary' }); scrollToTurn(msgId); }, 900);
    const summaryDur = data.summary.length * 220 + 400;
    setTimeout(() => update({ status: 'sections', sectionsVisible: 1 }), 900 + summaryDur);
    data.sections.forEach((_, idx) => setTimeout(() => update({ sectionsVisible: idx + 1 }), 900 + summaryDur + idx * 500));
    setTimeout(() => update({ status: 'done', sectionsVisible: data.sections.length }), 900 + summaryDur + data.sections.length * 500 + 200);
    scrollToTurn(msgId);
  }, [scrollToTurn]);

  useE(() => { if (init.q) ask(init.q, init.scope || null); }, []);

  const structured = (f) => {
    const key = ES.resolveStructured(f);
    const label = [f.condition ? f.condition + ' (' + f.specialty + ')' : f.specialty, f.location, f.insurance || 'Any insurance', f.distance === 'Any distance' ? 'any distance' : 'within ' + f.distance].join(' · ');
    const scope = /dent|ortho/i.test(f.specialty) ? 'dentists' : 'doctors';
    const filters = { specialty: f.specialty, insurance: f.insurance || '', location: f.location, distance: f.distance };
    if (f.acceptingNew) filters.acceptingNew = true;
    if (f.topOnly) filters.topOnly = true;
    if (f.bookOnline) filters.bookOnline = true;
    if (f.telehealth) filters.telehealth = true;
    if (f.gender && f.gender !== 'Any' && f.gender !== 'Non-binary / X') filters.gender = f.gender;
    if (f.lang && f.lang !== 'Any') filters.language = f.lang;
    ask(label, scope, key, false, { entry: 'structured', filters, from: f.__loc === 'device' ? { location: 'device' } : undefined });
  };

  const newSearch = () => { setView(null); setMessages([]); setDraft(''); setActiveTab('ask'); setLandingScope('ask'); writeUrl({ nav, user, brand: brandId }); };
  const [coverageOpen, setCoverageOpen] = useS(false);
  const runTool = (id) => {
    if (id === 'find') { pickScope('doctors'); return; }
    if (!user) { openAuth(); return; }
    if (id === 'coverage') { setAuth(null); setCoverageOpen(true); return; }
    if (id === 'compare') { setAuth(null); setView('compare'); writeUrl({ nav, user, brand: brandId, view: 'compare' }); return; }
  };
  const openSavedPage = () => { setAuth(null); setView('saved'); writeUrl({ nav, user, brand: brandId, view: 'saved' }); };
  const openProfilePage = () => { if (!user) { openAuth(); return; } setAuth(null); setView('profile'); writeUrl({ nav, user, brand: brandId, view: 'profile' }); };
  const openPrefs = () => { if (!user) { openAuth(); return; } setAuth(null); setPrefsFrom(view); setView('prefs'); writeUrl({ nav, user, brand: brandId, view: 'prefs' }); };
  const leavePrefs = () => { const back = prefsFrom && prefsFrom !== 'prefs' ? prefsFrom : null; setView(back); const last = messages[messages.length - 1]; writeUrl(back ? { nav, user, brand: brandId, view: back } : { q: last ? last.query : '', scope: activeTab, nav, user, brand: brandId }); };
  const flip = (setter) => (id) => setter((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  const toggleSaveH = (id) => { if (!user) { openAuth(); return; } flip(setSavedH)(id); };
  const toggleSaveT = (id) => { if (!user) { openAuth(); return; } flip(setSavedT)(id); };
  const isSavedQ = (q) => savedQ.some((r) => r.q === q);
  const toggleSaveQ = (q, to) => { if (!user) { openAuth(); return; } setSavedQ((list) => (list.some((r) => r.q === q) ? list.filter((r) => r.q !== q) : [{ q, to, at: 'just now' }, ...list])); };
  const removeSaved = (kind, id) => { if (kind === 'doctor') flip(setSaved)(id); else if (kind === 'hospital') flip(setSavedH)(id); else if (kind === 'topic') flip(setSavedT)(id); else setSavedQ((list) => list.filter((r) => r.q !== id)); };
  const savedTotal = saved.size + savedH.size + savedT.size + savedQ.length;
  const changeNav = (v) => { setNav(v); const last = messages[messages.length - 1]; writeUrl({ q: last ? last.query : '', scope: activeTab, nav: v, user, brand: brandId }); };
  const changeBrand = (b) => { setBrandId(b); const last = messages[messages.length - 1]; writeUrl({ q: last ? last.query : '', scope: activeTab, nav, user, brand: b }); };
  const signIn = () => {
    setUser(true); setAuth(null);
    const last = messages[messages.length - 1];
    writeUrl({ q: last ? last.query : '', scope: activeTab, nav, user: true, brand: brandId });
    /* Re-seed the current answer's filters from the profile so "from your profile" appears without re-asking. */
    if (last && last.key && DATA()[last.key]) setFiltersFor(last.id, seedFilters(DATA()[last.key], null, true));
  };
  const signOut = () => {
    setUser(false); setView(null); setCoverageOpen(false);
    const last = messages[messages.length - 1];
    writeUrl({ q: last ? last.query : '', scope: activeTab, nav, user: false, brand: brandId });
    if (last && last.key && DATA()[last.key]) setFiltersFor(last.id, seedFilters(DATA()[last.key], null, false));
  };
  const toggleSave = (id) => { if (!user) { openAuth(); return; } setSaved((s) => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; }); };
  const onFollowUp = (c) => ask((c && c.q) || c, null, c && c.to);
  const pickScope = (id) => {
    const last = messages[messages.length - 1];
    const has = id === 'ask' || (last && last.data && last.data.sections && last.data.sections.some((s) => window.sectionScope(s) === id));
    setView(null);
    if (last && has) { setActiveTab(id); writeUrl({ q: last.query, scope: id, nav, user, brand: brandId }); return; }
    setMessages([]); setDraft(''); setActiveTab('ask'); setLandingScope(id); writeUrl({ scope: id, nav, user, brand: brandId });
  };
  const changeTab = (id) => { setActiveTab(id); const last = messages[messages.length - 1]; writeUrl({ q: last ? last.query : '', scope: id, nav, user, brand: brandId }); };
  /* A saved doctor opens the flow that lists them. */
  const pickSaved = (p) => {
    const D = DATA();
    const entry = Object.values(D).find((t) => t && t.sections && t.sections.some((s) => (s.items || []).some((it) => it.id === p.id)));
    if (entry) ask(entry.query, entry.defaultScope || 'doctors', entry.key, false);
  };
  const openSaved = () => openSavedPage();

  /* Citation popover (engine pattern): a.cite inside .message[data-sources] */
  const [citePop, setCitePop] = useS(null);
  useE(() => {
    const handler = (e) => {
      const a = e.target.closest && e.target.closest('a.cite');
      if (!a) return;
      e.preventDefault(); e.stopPropagation();
      const msg = a.closest('.message'); if (!msg) return;
      let sources = []; try { sources = JSON.parse(msg.getAttribute('data-sources') || '[]'); } catch (_) {}
      const n = Number((a.textContent || '').trim()) || Number((a.getAttribute('href') || '').replace('#src-', ''));
      const source = sources.find((s) => s.num === n); if (!source) return;
      const r = a.getBoundingClientRect();
      setCitePop({ n, source, x: r.left + r.width / 2, y: r.bottom + 6 });
    };
    document.addEventListener('click', handler, true);
    return () => document.removeEventListener('click', handler, true);
  }, []);
  useE(() => {
    if (!citePop) return;
    const close = (e) => { if (e.target.closest && (e.target.closest('.cite-pop') || e.target.closest('a.cite'))) return; setCitePop(null); };
    const esc = (e) => { if (e.key === 'Escape') setCitePop(null); };
    document.addEventListener('mousedown', close); document.addEventListener('keydown', esc);
    return () => { document.removeEventListener('mousedown', close); document.removeEventListener('keydown', esc); };
  }, [citePop]);

  const [turnMin, setTurnMin] = useS(0);
  useE(() => {
    if (!scrollEl) return;
    const measure = () => setTurnMin(Math.max(0, scrollEl.clientHeight - parseFloat(getComputedStyle(scrollEl).paddingBottom || 0) - 24));
    measure();
    window.addEventListener('resize', measure);
    return () => window.removeEventListener('resize', measure);
  }, [scrollEl]);

  const hasMessages = messages.length > 0;
  const last = messages[messages.length - 1];
  const filters = last ? (filtersById[last.id] || {}) : {};
  const ctx = { filters, setFilters: (f) => { if (last) setFiltersFor(last.id, f); }, user, profile: PROFILE(), saved, toggleSave, savedH, toggleSaveH, savedT, toggleSaveT, requireSignIn: openAuth, brand, prefs: user ? prefs : null };
  const ctxFor = (m) => ({ ...ctx, filters: filtersById[m.id] || {}, setFilters: (f) => setFiltersFor(m.id, f) });
  const chipsFor = (m) => { const raw = DATA()[m.key]; if (user && raw && raw.followupsSignedIn && raw.followupsSignedIn.length) return { chips: raw.followupsSignedIn, personal: true }; return { chips: m.data.followups, personal: false }; };
  /* Presenter controls are URL-only: &brand=ehcare, /top or ?nav=top. PresenterToggles stays available but is not rendered. */
  const controls = () => null;
  const showSaved = view === 'saved' && user;
  const showProfile = view === 'profile' && user;
  const showPrefs = view === 'prefs' && user;
  const showCompare = view === 'compare' && user;
  const showView = showSaved || showProfile || showPrefs || showCompare;
  const account = <AccountControl user={user} onSignIn={openAuth} onSignOut={signOut} savedCount={savedTotal} onSaved={openSaved} onProfile={openProfilePage} onPrefs={openPrefs} />;

  return (
    <div className={'app' + (nav === 'top' ? ' app--top' : '') + (user ? ' app--user' : '')}>
      {nav === 'rail' && <button type="button" className="mobile-menu-btn" aria-label={drawer ? 'Close menu' : 'Open menu'} aria-expanded={drawer} onClick={() => setDrawer((o) => !o)}>{drawer ? Icon.X() : Icon.Menu()}</button>}
      {nav === 'rail' && drawer && <div className="rail__backdrop" onClick={() => setDrawer(false)} />}
      {nav === 'rail' && (
        <LeftRail open={drawer} onNew={newSearch} onPickHistory={(h) => ask(h.q, null, h.to, true)} onTool={runTool} activeKey={last && last.key} nav={nav} user={user} brand={brand} saved={saved} onPickSaved={pickSaved} urlState={urlState} savedTotal={savedTotal} controls={controls(false)} onSignIn={openAuth} onSignOut={signOut} onOpenProfile={openProfilePage} onOpenSaved={openSavedPage} onOpenPrefs={openPrefs} />
      )}
      <main className="main">
        {nav === 'top' && (
          <div className="topnav">
            <Header brand={brand} homeHref={homeHref(nav, urlState)} onSearch={newSearch} right={account} />
            <ProductBar hasMessages={hasMessages} last={last} activeScope={hasMessages ? activeTab : landingScope} onScope={pickScope} onNew={newSearch} onPickHistory={(h) => ask(h.q, null, h.to, true)} filters={filters} user={user} controls={controls(true)} saved={saved} savedTotal={savedTotal} onSignIn={openAuth} onPickSaved={pickSaved} onOpenProfile={openProfilePage} onOpenSaved={openSavedPage} onTool={runTool} />
          </div>
        )}
        {nav === 'rail' && hasMessages && !showView && <ChatHeader chatLabel={last.data.chatLabel || last.query} query={last.query} sections={last.data.sections} activeScope={activeTab} onScopeChange={changeTab} filters={filters} account={account} />}
        {nav === 'rail' && (!hasMessages || showView) && <div className="landing-bar">{account}</div>}
        <div className="main__scroll" ref={attachScroll}>
          {showCompare && <ComparePage ctx={ctx} saved={saved} />}
          {showPrefs && <PrefsPage key={String(prefsFrom)} prefs={prefs} onSave={(f) => { setPrefs(f); leavePrefs(); }} onCancel={leavePrefs} onProfile={openProfilePage} />}
          {showProfile && <ProfilePage prefs={prefs} saved={saved} savedTotal={savedTotal} onEdit={openProfile} onOpenPrefs={openPrefs} onOpenSaved={openSavedPage} onPickSaved={pickSaved} />}
          {showSaved && <SavedPage saved={saved} savedH={savedH} savedT={savedT} savedQ={savedQ} onRemove={removeSaved} ctx={ctx} onSearch={(r) => ask(r.q, null, r.to, true)} />}
          {!showView && !hasMessages && <Landing onAsk={(q, s, key) => ask(q, s, key)} onStructured={structured} onPickDoctor={pickSaved} draft={draft} setDraft={setDraft} scope={landingScope} setScope={setLandingScope} nav={nav} user={user} brand={brand} onSignIn={openAuth} onProfile={openProfilePage} mode={mode} onMode={setMode} attachments={attachments} onAttach={attach} onRemoveAttachment={detach} />}
          {!showView && hasMessages && (
            <div className={'col' + (activeTab && activeTab !== 'ask' ? ' col--scoped' : '')}>
              {messages.map((m, i) => (
                <div key={m.id} className={'turn' + (i === messages.length - 1 ? ' turn--current' : '')} style={i > 0 && i === messages.length - 1 ? { minHeight: turnMin } : undefined}>
                  {m.kind === 'noflow' ? <NoAnswer msg={m} idx={i} user={user} onPick={(r) => ask(r.text, null, r.to)} /> : <>
                    <div className="turn__bar">
                      <span className="turn__tags">{m.entry === 'structured' && <span className="entry-tag">{Icon.Sliders()}<span>Structured search</span></span>}{m.mode === 'quick' && <span className="entry-tag entry-tag--quick">{Icon.Sparkle()}<span>Quick answer</span><button type="button" className="entry-tag__link" onClick={() => ask(m.query, activeTab !== 'ask' ? activeTab : null, m.key, false, { mode: 'detailed', entry: m.entry })}>Show the detailed answer</button></span>}</span>
                      <button type="button" className={'turn__save' + (user && isSavedQ(m.query) ? ' is-on' : '')} aria-pressed={!!(user && isSavedQ(m.query))} onClick={() => toggleSaveQ(m.query, m.key)} title={user ? (isSavedQ(m.query) ? 'Remove this search from Saved' : 'Save this search to rerun it later') : 'Sign in to save this search'}>{Icon.Bookmark()}<span>{user ? (isSavedQ(m.query) ? 'Saved search' : 'Save this search') : 'Save this search · sign in'}</span></button>
                    </div>
                    <Message msg={m} idx={i} isLast={false} isCurrent={i === messages.length - 1} activeScope={activeTab || 'ask'} onFollowUp={onFollowUp} loggedIn={user} ctx={ctxFor(m)} />
                    {m.status === 'done' && <C.SourcesList sources={m.data.sources} />}
                    {m.status === 'done' && i === messages.length - 1 && <FollowUpChips {...chipsFor(m)} onPick={onFollowUp} />}
                  </>}
                </div>
              ))}
            </div>
          )}
        </div>
        {hasMessages && !showView && (
          <div className="composer"><div className="composer__inner">
            <InputBar value={draft} onChange={setDraft} onSubmit={(q) => ask(q)} placeholder={user ? 'Ask a follow-up, ' + PROFILE().firstName + '…' : 'Ask a follow-up, or search for something else…'} mode={mode} onMode={setMode} attachments={attachments} onAttach={attach} onRemoveAttachment={detach} />
          </div></div>
        )}
      </main>

      {auth && <AuthModal key={auth.step + auth.mode} brand={brand} step={auth.step} mode={auth.mode} onClose={closeAuth} onComplete={signIn} />}
      {coverageOpen && user && <CoverageSheet saved={saved} onClose={() => setCoverageOpen(false)} onProfile={() => { setCoverageOpen(false); openProfilePage(); }} />}

      {citePop && (
        <div className="cite-pop" role="dialog" style={{ left: Math.max(16, Math.min(citePop.x - 160, window.innerWidth - 336)), top: citePop.y }} onMouseDown={(e) => e.stopPropagation()}>
          <div className="cite-pop__head">
            <span className="cite-pop__num">{citePop.n}</span>
            <span className="cite-pop__source">{citePop.source.name}</span>
            <button className="cite-pop__close" onClick={() => setCitePop(null)} aria-label="Close">{Icon.X()}</button>
          </div>
          <div className="cite-pop__title">{citePop.source.title}</div>
          <div className="cite-pop__meta">
            <span className="cite-pop__date">{citePop.source.date}{citePop.source.type ? ' · ' + ({ directory: 'Directory record', editorial: 'Editorial', external: 'External source', booking: 'Booking partner' })[citePop.source.type] : ''}</span>
            <a className="cite-pop__open" href={citePop.source.url || '#'} target="_blank" rel="noreferrer"><span>Open source</span><span>{Icon.ArrowRight()}</span></a>
          </div>
        </div>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
