// ============================================================================
// Ask Angela — the hero conversation.
//
// Replaces the rotating tagline: the same three statements, but delivered as
// sends in a thread the visitor can reply to. Answers come from a real LLM
// (Claude Sonnet via /api/ask on the Lori Vercel project — the key never
// touches the browser). The PRESET script below is the grounding source for
// that model's system prompt AND the offline fallback: if the API errors,
// rate-limits, or times out, keyword matching serves the hand-written answer
// and the chat never goes dark. Project cards are deep links — clicking one
// drives the Work section to that project.
// ============================================================================

const CHAT_AV = 'assets/angela-portrait.png';
const CHAT_API = 'https://prototype-lori-ax.vercel.app/api/ask';

// id → index in window.PROJECTS (the Work section is scroll-driven by index).
const CHAT_PROJ = {
  '01': { n: 'GenAI Ad Creatives', m: 'Facebook · 2025', a: ['#C8A8E0', '#FF9A6B'], i: 0 },
  '02': { n: 'Lori', m: 'Self-initiated · 2026', a: ['#8AD96B', '#A8E0C0'], i: 1 },
  '03': { n: 'Visual Search', m: 'Facebook · 2022', a: ['#FFC2D4', '#FF9A6B'], i: 2 },
  '04': { n: 'Ad Extension & Mosaic', m: 'Facebook · 2023–25', a: ['#D8C4F5', '#FFC2D4'], i: 3 },
  '05': { n: 'Marketplace Chaining', m: 'Facebook · 2026', a: ['#A8C8F0', '#D8C4F5'], i: 4 },
  '07': { n: 'Ad Format Library', m: 'Facebook · 2022', a: ['#FFB088', '#C896F0'], i: 6 },
  '08': { n: 'Story End Card', m: 'Messenger · 2019', a: ['#FFD4B8', '#FFC2D4'], i: 7 },
};

// Angela's three statements — the same rolling texts the old hero rotator
// cycled, now sent one at a time so a visitor arrives mid-conversation
// instead of at a headline.
const CHAT_INTRO = [
  'Hi — I’m Angela. Product designer, 7 years at Meta.',
  'Currently @Facebook, designing ad experiences across Home Feed, Reels, Marketplace and more — previously @Messenger and @Google AI UX.',
  'I build through vibe-coding and prototyping — lately my own AI products end to end. Ask me anything.',
];

const CHAT_CHIPS = ['Your biggest impact?', 'What kind of designer?', 'Most fun project?'];

// Answers may be a single string or an array of bubbles (sent as separate
// sends, like a person actually texting). `go: 'care'` attaches a jump link
// to the "What I care about" pane of the About section.
const CHAT_SCRIPT = [
  { k: ['ads?', 'advertising', 'reels', 'creative', 'creatives', 'marketplace', 'feed'],
    a: "Ads has been most of my time at Meta — Reels, Feed, Marketplace. The one I'd start with: 73% of Reels ads get skipped in the first two seconds, not because they're irrelevant, but because they look like ads.",
    cards: ['01'], act: 'open work → genai ad creatives' },
  { k: ['ai', 'genai', 'llm', 'model', 'machine learning', 'ml'],
    a: 'Two flavours: shipping AI inside a huge product (GenAI creatives, Visual Search), and building AI products solo (Lori). The second one is where I learned the most.',
    cards: ['01', '02'], act: 'open work → ai' },
  { k: ['lori', 'plant', 'houseplant', 'side project', 'personal'],
    a: "Lori is a houseplant that texts you — and the AI advocates for the plant, not the owner. It's my 9-year-old college thesis, finally buildable.",
    cards: ['02'], act: 'open work → lori' },
  { k: ['impact', 'revenue', 'metric', 'metrics', 'numbers?', 'results?', 'business', 'actually ship(ped)?', 'visual search'],
    a: 'Ad Extension & Mosaic is the big one: $31B+ in shipped revenue, from asking why users are afraid to click ads. Visual Search went from 200K product page views a month to 10× that.',
    cards: ['04', '03'], act: 'open work → shipped impact' },
  { k: ['build', 'code', 'ship', 'engineer', 'prototype', 'vibe', 'figma'],
    a: 'I prototype and vibe-code my own work — this site and Lori are both mine, end to end. It means I argue with engineers about the right things instead of the possible things.',
    cards: [] },
  { k: ['designer', 'process', 'philosophy', 'principles?', 'methodology', 'approach', 'data', 'how do you (work|think|design)', 'strengths?', 'values'],
    a: ['Honestly? A detective — gather every scrap of evidence, find the pattern, rearrange the theory until it fits. Very data-driven: "73% of Reels ads get skipped" is the kind of clue I start from.',
      "The short list: make the invisible legible. Ship systems, not just pixels. Craft I'd use myself. Move fast with whatever tool works. Design is a team sport."],
    cards: [], go: 'care' },
  { k: ['fun', 'enjoy(ed)?', 'favou?rite', 'proud(est)?', 'curiosity', 'curious'],
    a: ["Lori — a houseplant that texts you. I did everything: the voice design, the backend, even the Twilio compliance paperwork. Runner-up: the Ad Format Library — a microsite nobody asked for that became the team's design backbone.",
      'Both started as curiosity, not a roadmap item.'],
    cards: ['02', '07'] },
  { k: ['hire', 'hiring', 'available', 'looking', 'role', 'job', 'open to', 'next', 'leave', 'leaving', 'opportunit(y|ies)', 'career goals?'],
    a: ["I'm enjoying Meta right now — building GenAI creatives for Reels ads. But I'm open to 0→1 work where design shapes the end-to-end experience, and to faster-moving places where prototyping matters as much as the spec.",
      "Your turn — what's on your desk right now? Anything you'd want to build together?"],
    cards: [], cta: true },
  { k: ['weakness', 'weaknesses', 'weak', 'bad at', 'worst at', 'fail', 'failure', 'mistake', 'struggle', 'hard for you'],
    a: ["Haha, honest answer: I get too attached to the \"right\" solution — I need reminding that shipping something good beats perfecting something in a vacuum. I iterated Lori's texting voice for weeks before letting a single stranger test it 😅",
      'I also go deep on systems thinking by default — great for 0→1 work, but sometimes it means overthinking the simple stuff.'],
    cards: ['02'] },
  { k: ['first', 'meta', 'career', 'years', 'background', 'messenger', 'google', 'story', 'stories'],
    a: 'Seven years at Meta, starting on Messenger — with a Google AI UX stint before that. My first launch is still live: turning it off would cost 250M story views a day.',
    cards: ['08'], act: 'open work → story end card' },
  { k: ['based', 'location', 'located', 'remote', 'onsite', 'hybrid', 'relocat(e|ion|ing)', 'bay area', 'timezone', 'time zone', 'where (are|do) you'],
    a: 'Mountain View, CA — open to onsite (SF too) or remote. Just not ready to leave NorCal yet.',
    cards: [] },
];

// Greetings get a real reply but never spend a question. Checked only after
// CHAT_SCRIPT fails, so "hi — what's your biggest impact?" still gets the
// impact answer.
const CHAT_GREET = ['hi', 'hiya', 'hello', 'hey', 'yo', 'sup', "what's up", 'howdy',
  'who are you', 'what do you do', 'what is this', 'how are you', 'nice to meet you',
  'good (morning|afternoon|evening)'];
const CHAT_HELLO = {
  a: ["Hey — what's up. I'm a product designer in the Bay Area, 7 years at Meta.",
    'Ask me something real — or steal one of the chips below.'],
};

// Refusals are PHRASES, matched through the same word-boundary matcher — a
// bare fragment like 'age' fires inside "man-age-rs" and refuses the exact
// vocabulary this thing exists to answer.
const CHAT_REFUSE = [
  'how old', 'your age', 'salary', 'how much do you (make|earn)', 'compensation',
  'boyfriend', 'girlfriend', 'married', 'dating', 'your weight',
  'write (me|my)', 'code for me', 'do my homework', 'recipe', 'the weather',
];

const CHAT_RX = new Map();
const chatHits = (text, k) => {
  if (/[^\x00-\x7F]/.test(k)) return text.includes(k) ? k.length : 0;
  let rx = CHAT_RX.get(k);
  if (!rx) { rx = new RegExp('\\b(?:' + k + ')\\b', 'i'); CHAT_RX.set(k, rx); }
  return rx.test(text) ? k.length : 0;
};
// Scored, not first-match-wins, so the broad entries can't shadow specific ones.
const chatMatch = (text) => {
  let best = null, bestScore = 0;
  for (const s of CHAT_SCRIPT) {
    const score = s.k.reduce((n, k) => n + chatHits(text, k), 0);
    if (score > bestScore) { bestScore = score; best = s; }
  }
  return best;
};

function ChatProjCard({ id, onGo }) {
  const p = CHAT_PROJ[id];
  return (
    <button className="chat-pc" onClick={onGo}>
      <span>
        <span className="n" style={{ display: 'block' }}>{p.n}</span>
        <span className="m" style={{ display: 'block' }}>{p.m}</span>
      </span>
      <span className="go">↗</span>
    </button>
  );
}

// Non-project action links (email, jump to a bio pane) wear the exact same
// card as ChatProjCard — one visual language for everything that follows a
// bubble. Only difference: no meta line, since there's no company/year to
// show. Renders as <a> so the mailto/href stays a real link.
function ChatActionCard({ label, href, onGo }) {
  return (
    <a className="chat-pc" href={href} onClick={onGo}>
      <span className="n">{label}</span>
      <span className="go">↗</span>
    </a>
  );
}

function HeroChat() {
  const QUOTA = 3;
  const [shut, setShut] = React.useState(false);
  const [log, setLog] = React.useState([]);
  const [draft, setDraft] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [used, setUsed] = React.useState(0);
  const [chipsUsed, setChipsUsed] = React.useState([]);
  const [lockH, setLockH] = React.useState(0);
  const logRef = React.useRef(null);
  const taRef = React.useRef(null);
  const streamRef = React.useRef(null);
  const left = Math.max(0, QUOTA - used);

  // Staged intro. Each send is a bubble that FIRST appears as the typing
  // indicator and then fills with text — same DOM node throughout, so the dots
  // morph into the message instead of being replaced by a new bubble below.
  React.useEffect(() => {
    const timers = [];
    CHAT_INTRO.forEach((txt, i) => {
      const at = 700 + i * 1550;
      timers.push(setTimeout(() => setLog((l) => [...l, { role: 'bot', a: '', intro: true, typing: true }]), at - 620));
      timers.push(setTimeout(() => setLog((l) => l.map((m, k) => k === l.length - 1 ? { ...m, a: txt, typing: false } : m)), at));
    });
    return () => timers.forEach(clearTimeout);
  }, []);
  React.useEffect(() => () => { if (streamRef.current) streamRef.current.abort(); }, []);

  // Collapsing the thread also compacts the hero shell (releases its 70vh
  // centering — .hero-compact in chat.css) so Selected Work surfaces earlier.
  // The fold changes page height WITHOUT firing scroll events, and the Work
  // section's --work-dock / --nav-shift / --stage-shift only recompute on
  // scroll/resize — left stale they strand the columns mid-interpolation
  // (content lifted, blank band at the bottom of the viewport). Nudge a
  // resize once the 0.44s min-height transition settles, and once mid-way.
  React.useEffect(() => {
    const hero = document.querySelector('.hero');
    if (!hero) return;
    hero.classList.toggle('hero-compact', shut);
    const t1 = setTimeout(() => window.dispatchEvent(new Event('resize')), 250);
    const t2 = setTimeout(() => window.dispatchEvent(new Event('resize')), 500);
    return () => { clearTimeout(t1); clearTimeout(t2); hero.classList.remove('hero-compact'); };
  }, [shut]);

  // Pin to the bottom. Direct scrollTop (never smooth) so streaming updates
  // can't restart an in-flight animation and strand the view at the top.
  React.useLayoutEffect(() => {
    const el = logRef.current;
    if (!el) return;
    const pin = () => { el.scrollTop = el.scrollHeight; };
    pin();
    const r1 = requestAnimationFrame(pin);
    const r2 = requestAnimationFrame(() => requestAnimationFrame(pin));
    const ro = new ResizeObserver(pin);
    Array.from(el.children).forEach((c) => ro.observe(c));
    return () => { cancelAnimationFrame(r1); cancelAnimationFrame(r2); ro.disconnect(); };
  }, [log, busy, lockH]);

  const introDone = log.filter((m) => m.intro).length >= CHAT_INTRO.length;
  const hasUser = log.some((m) => m.role === 'you');

  // Cards are deep links: drive the scroll-jacked Work section to that project.
  const goProject = (id) => {
    const i = CHAT_PROJ[id].i;
    if (window.__jumpToProject) window.__jumpToProject(i);
    else {
      const work = document.getElementById('work');
      if (work) window.scrollTo({ top: work.offsetTop, behavior: 'smooth' });
    }
  };

  // The principles answer links into the About section's "What I care about"
  // pane (index 1 of the bio tabs) instead of a project.
  const goCare = () => {
    if (window.__jumpToBio) window.__jumpToBio(1, 'instant');
    else {
      const about = document.getElementById('about');
      if (about) about.scrollIntoView();
    }
  };

  const push = (m) => setLog((l) => [...l, m]);

  // Answers reveal progressively, driven by ELAPSED TIME on rAF (a throttled
  // tab catches up instead of losing progress), with a hard safety timeout so
  // the cards and the re-enabled composer are never only reachable through the
  // animation's happy path. An answer may be an ARRAY of bubbles — they send
  // one after another like real texting; cards/CTA/links ride the last bubble.
  const stream = (msg) => {
    const bubbles = Array.isArray(msg.a) ? msg.a : [msg.a];
    const MS_PER_CHAR = 11;
    if (streamRef.current) streamRef.current.abort();
    let raf = 0, safety = 0, gap = 0, dead = false;
    streamRef.current = { abort: () => { dead = true; cancelAnimationFrame(raf); clearTimeout(safety); clearTimeout(gap); } };
    const setLast = (patch) => setLog((l) => l.map((m, k) => k === l.length - 1 ? { ...m, ...patch } : m));
    const one = (i) => {
      if (dead) return;
      const full = bubbles[i];
      const last = i === bubbles.length - 1;
      push({ role: 'bot', a: '', typing: true,
        ...(i === 0 && msg.act ? { act: msg.act } : {}),
        ...(last ? { cards: msg.cards, cta: msg.cta, go: msg.go } : {}) });
      const t0 = performance.now();
      let done = false;
      const finish = () => {
        if (done || dead) return;
        done = true;
        cancelAnimationFrame(raf); clearTimeout(safety);
        setLast({ a: full, typing: false });
        if (last) setBusy(false);
        else gap = setTimeout(() => one(i + 1), 420);
      };
      const step = () => {
        if (dead) return;
        const chars = Math.round((performance.now() - t0) / MS_PER_CHAR);
        if (chars >= full.length) return finish();
        setLast({ a: full.slice(0, chars) });
        raf = requestAnimationFrame(step);
      };
      safety = setTimeout(finish, full.length * MS_PER_CHAR + 1200);
      raf = requestAnimationFrame(step);
    };
    one(0);
  };

  // Ship the visible conversation (minus intro + typing bubbles) as model
  // context, so follow-ups like "how did you build it?" resolve.
  const buildHistory = () =>
    log
      .filter((m) => !m.intro && !m.typing && m.a)
      .slice(-8)
      .map((m) => ({ role: m.role === 'you' ? 'user' : 'assistant', content: m.a }));

  // Live-streamed answer: the endpoint relays the model's words as SSE events
  // ({t:'d'} text delta, {t:'b'} bubble break, {t:'m'} metadata), so the reply
  // types itself out in real time instead of arriving all at once. `on` gets
  // each event; resolves true if any text was rendered (past the point of
  // falling back), throws if the stream failed before producing anything.
  const askApiStream = async (q, history, on) => {
    const ctrl = new AbortController();
    const timer = setTimeout(() => ctrl.abort(), 30000);
    let gotText = false;
    try {
      const r = await fetch(CHAT_API, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ q, history }),
        signal: ctrl.signal,
      });
      if (!r.ok || !r.body) throw new Error('api ' + r.status);
      const reader = r.body.getReader();
      const dec = new TextDecoder();
      let buf = '';
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        buf += dec.decode(value, { stream: true });
        let cut;
        while ((cut = buf.indexOf('\n\n')) >= 0) {
          const line = buf.slice(0, cut).trim();
          buf = buf.slice(cut + 2);
          if (!line.startsWith('data: ')) continue;
          let ev;
          try { ev = JSON.parse(line.slice(6)); } catch { continue; }
          if (ev.t === 'e') throw new Error('upstream');
          if (ev.t === 'd' && ev.x) gotText = true;
          on(ev);
        }
      }
      if (!gotText) throw new Error('empty stream');
      return true;
    } finally {
      clearTimeout(timer);
    }
  };

  const send = (text) => {
    const q = (text || '').trim();
    if (!q || busy) return;
    // Freeze the log at the height the intro settled to — no jump between
    // "tall enough for three statements" and "scroll window".
    if (!lockH && logRef.current) setLockH(Math.max(280, logRef.current.offsetHeight));
    setDraft('');
    if (taRef.current) { taRef.current.style.height = ''; taRef.current.style.overflowY = ''; }
    const history = buildHistory();
    push({ role: 'you', a: q });

    if (left <= 0) {
      setBusy(true);
      setTimeout(() => stream({ role: 'bot', cta: true,
        a: "That's your three — which is the point where a real conversation beats this one. Email me and ask the hard version." }), 420);
      return;
    }
    const lower = q.toLowerCase();
    if (CHAT_CHIPS.includes(q)) setChipsUsed((c) => [...c, q]);
    setBusy(true);

    // Free, instant, no-API paths: hard refusals and bare greetings never
    // spend a question or a model call.
    if (CHAT_REFUSE.some((r) => chatHits(lower, r) > 0)) {
      setTimeout(() => stream({ role: 'bot', a: "Out of scope — I only talk about my own work. Ask me about the ads work, Lori, or what I'm bad at." }), 480);
      return;
    }
    if (q.length <= 30 && !chatMatch(lower) && CHAT_GREET.some((g) => chatHits(lower, g) > 0)) {
      setTimeout(() => stream({ role: 'bot', ...CHAT_HELLO }), 480);
      return;
    }

    // Everything else goes to the model, streamed live: dots hold the floor
    // until the first words arrive (~1s), then the reply writes itself out in
    // real time. On any failure BEFORE text appears (offline, rate-limited,
    // API down) fall back to the preset script so the chat degrades instead
    // of dying; a failure mid-answer just ends the reply where it got to.
    push({ role: 'bot', a: '', typing: true });
    const setLast = (patch) => setLog((l) => l.map((m, k) => k === l.length - 1 ? { ...m, ...patch } : m));
    const appendLast = (x) => setLog((l) => l.map((m, k) => k === l.length - 1 ? { ...m, a: m.a + x } : m));
    let sawText = false;
    askApiStream(q, history, (ev) => {
      if (ev.t === 'd') { sawText = true; appendLast(ev.x); }
      else if (ev.t === 'b') {
        setLast({ typing: false });
        push({ role: 'bot', a: '', typing: true });
      } else if (ev.t === 'm') {
        setLast({ typing: false, cards: ev.cards || [], cta: !!ev.cta,
          go: ev.care_link ? 'care' : undefined });
      }
    })
      .then(() => {
        setUsed((u) => u + 1);
        setBusy(false);
      })
      .catch(() => {
        if (sawText) {
          // Mid-answer drop: keep what arrived, close out gracefully.
          setLast({ typing: false });
          setBusy(false);
          setUsed((u) => u + 1);
          return;
        }
        setLog((l) => l.slice(0, -1)); // dots bubble out; stream() re-adds
        const hit = chatMatch(lower);
        if (hit) {
          setUsed((u) => u + 1);
          return stream({ role: 'bot', ...hit });
        }
        stream({ role: 'bot', cta: true,
          a: "Haha, honestly — you've got me on that one. If it actually matters to you, email me and I'll give you a proper answer." });
      });
  };

  const lastBot = (log.filter((m) => m.role !== 'you').slice(-1)[0] || {}).a;

  return (
    <div className="chat">
      <div className={'chat-hdr ' + (shut ? 'is-shut' : 'is-open')} onClick={() => setShut((s) => !s)}>
        <div className="chat-av"><img src={CHAT_AV} alt="Angela Xie" /><span className="live" /></div>
        <div className="chat-id">
          <h1 className="hero-name chat-nm">Angela Xie</h1>
          {shut
            ? <div className="chat-peek">{lastBot || 'Ask me anything about my work'}</div>
            : <div className="chat-st">Product designer · usually replies instantly</div>}
        </div>
        <button className="chat-chev" aria-label={shut ? 'Open conversation' : 'Collapse conversation'}>
          <svg width="13" height="13" viewBox="0 0 13 13" fill="none"><path d="M2.5 4.5L6.5 8.5L10.5 4.5" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" /></svg>
        </button>
      </div>
      <div className={'chat-fold' + (shut ? ' is-shut' : '')}><div>
        <div className={'chat-log' + (lockH ? ' is-window' : '')} ref={logRef} style={lockH ? { height: lockH } : null}>
          {log.map((m, i) => {
            const bot = m.role !== 'you';
            const sameAbove = i > 0 && (log[i - 1].role !== 'you') === bot;
            const sameBelow = i < log.length - 1 && (log[i + 1].role !== 'you') === bot;
            const grp = sameAbove && sameBelow ? ' gp-mid' : sameBelow ? ' gp-first' : sameAbove ? ' gp-last' : '';
            return (
              <div key={i} className={'chat-msg ' + (bot ? 'is-bot' : 'is-you')}>
                {bot && <div className="chat-sender">{!sameAbove && <img src={CHAT_AV} alt="Angela Xie" />}</div>}
                <div className="chat-stack">
                  {m.act && !m.typing && <div className="chat-act"><span className="dot" />{m.act}</div>}
                  <div className={'bub' + grp + (m.typing && !m.a ? ' is-typing' : '')}>
                    {m.typing && !m.a
                      ? <span className="dots"><span /><span /><span /></span>
                      : <span className="bub-t">{m.a}</span>}
                  </div>
                  {!m.typing && m.cards && m.cards.map((id) => (
                    <ChatProjCard key={id} id={id} onGo={() => goProject(id)} />
                  ))}
                  {!m.typing && m.cta && (
                    <ChatActionCard label="Email Angela" href="mailto:xzm1008@gmail.com" />
                  )}
                  {!m.typing && m.go === 'care' && (
                    <ChatActionCard label="What I care about" href="#about"
                      onGo={(e) => { e.preventDefault(); goCare(); }} />
                  )}
                </div>
              </div>
            );
          })}
        </div>
        {/* Suggested replies are training wheels: they exist to show a fresh
            visitor what kind of conversation this is. The first chip click
            proves the lesson landed — after that the whole row retires for
            good (no per-chip filtering, no quota-state replacement; the email
            path already lives in the bot's own CTA bubbles). */}
        {left > 0 && chipsUsed.length === 0 && (
          <div className="chat-chips">
            {CHAT_CHIPS.map((c) =>
              <button key={c} className="chat-chip" onClick={() => send(c)}>{c}</button>)}
          </div>
        )}
        <form className="chat-form" onSubmit={(e) => { e.preventDefault(); send(draft); }}>
          <textarea
            ref={taRef}
            value={draft}
            rows={1}
            placeholder={left > 0
              ? (window.matchMedia && window.matchMedia('(max-width: 640px)').matches
                ? 'Your turn…'
                : 'Your turn… what do you want to know?')
              : 'out of questions — but the email works'}
            onChange={(e) => {
              setDraft(e.target.value);
              e.target.style.height = 'auto';
              e.target.style.height = Math.min(82, e.target.scrollHeight) + 'px';
              // Scroll only once the draft is taller than the 82px cap —
              // otherwise the box hides its scrollbar (CSS default).
              e.target.style.overflowY = e.target.scrollHeight > 82 ? 'auto' : '';
            }}
            onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(draft); } }} />
          <div className={'chat-hint' + (draft.trim() ? ' is-on' : '')}>↵ send</div>
          <button className="chat-send" type="submit" disabled={!draft.trim() || busy} aria-label="Send">
            <svg width="15" height="15" viewBox="0 0 15 15" fill="none"><path d="M7.5 12.5V2.5M7.5 2.5L3 7M7.5 2.5L12 7" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" /></svg>
          </button>
        </form>
        <div className="chat-foot">
          {left > 0
            ? `${left} question${left === 1 ? '' : 's'}, then let’s talk for real`
            : 'out of questions — let’s talk for real'}
        </div>
      </div></div>
    </div>
  );
}

window.HeroChat = HeroChat;
