/* =====================================================================
   Contact — Split view: AI chat agent + form that fills itself live.
   Mobile: agent-first with floating form preview.
   ===================================================================== */

const { useEffect: useEffectCt, useRef: useRefCt, useState: useStateCt } = React;

// `optional: true` means the user can skip via a one-click button
const FIELDS = [
  { k: 'name',        label: 'Name',              type: 'text',     placeholder: 'Your full name' },
  { k: 'business',    label: 'Business name',     type: 'text',     placeholder: 'Company / business' },
  { k: 'email',       label: 'Email',             type: 'email',    placeholder: 'you@example.com' },
  { k: 'phone',       label: 'Phone',             type: 'tel',      placeholder: '(405) 555-0100', optional: true },
  { k: 'projectType', label: 'What kind of site',    type: 'select',   options: ['Simple one-pager', 'Full business website', 'Online store', 'Listings (cars, real estate, etc.)', 'Google presence & SEO only', 'AI helper / chatbot only', 'Custom / not sure yet'] },
  { k: 'budget',      label: 'Budget range',      type: 'select',   options: ['Under $3k', '$3–8k', '$8–25k', '$25k+', 'Not sure yet'] },
  { k: 'timeline',    label: 'Timeline',          type: 'select',   options: ['ASAP (this month)', '1–3 months', '3–6 months', 'Flexible'] },
  { k: 'description', label: 'What you need',     type: 'textarea', placeholder: 'Tell us a bit about your business and what you need' },
  { k: 'referral',    label: 'How did you hear about us', type: 'select', options: ['Google search', 'Referral', 'Social media', 'Saw our work', 'Other'], optional: true },
];

// Infer business category from business name — returns a sub-type question the
// agent asks opportunistically before `projectType`.
function inferBusinessContext(businessName) {
  if (!businessName) return null;
  const n = businessName.toLowerCase();
  const categories = [
    { match: /(design|studio|creative|graphic|decal|print|sign)/, label: 'design / creative',
      chips: ['Graphic / logo design', 'Decals & signage', 'Architectural / interior', 'Auto / car wraps', 'Fine art / illustration', 'Web / digital design'] },
    { match: /(auto|motor|garage|tire|body shop|detail|car wash|dealership)/, label: 'automotive',
      chips: ['Repair / mechanic shop', 'Dealership / sales', 'Detailing / car wash', 'Body shop / collision', 'Tires / parts', 'Custom / performance'] },
    { match: /(realty|real estate|homes|properties|realtor|broker)/, label: 'real estate',
      chips: ['Residential agent', 'Commercial broker', 'Property management', 'New construction', 'Short-term rentals'] },
    { match: /(law|legal|attorney|firm)/, label: 'legal',
      chips: ['Personal injury', 'Family law', 'Business / corporate', 'Criminal defense', 'Estate / probate'] },
    { match: /(restaurant|cafe|café|coffee|bbq|bar|grill|kitchen|bakery|pizza|taco|deli|eatery)/, label: 'food / hospitality',
      chips: ['Sit-down restaurant', 'Fast casual / counter', 'Coffee / bakery', 'Food truck', 'Catering', 'Bar / brewery'] },
    { match: /(salon|spa|barber|beauty|nails|hair|wellness)/, label: 'beauty / wellness',
      chips: ['Hair salon / barber', 'Nail salon', 'Day spa', 'Medical spa', 'Massage / wellness'] },
    { match: /(fitness|gym|yoga|crossfit|pilates|training)/, label: 'fitness',
      chips: ['Gym / membership', 'Personal training', 'Yoga / pilates studio', 'CrossFit / group', 'Physical therapy'] },
    { match: /(clinic|dental|dentist|medical|health|chiro|physio|vet)/, label: 'healthcare',
      chips: ['Dental practice', 'Medical clinic', 'Chiropractic', 'Veterinary', 'Mental health'] },
    { match: /(construction|build|contractor|roof|plumb|hvac|electric|remodel|paint)/, label: 'trades / construction',
      chips: ['General contractor', 'Roofing', 'Plumbing / HVAC', 'Electrical', 'Remodeling', 'Painting'] },
    { match: /(boutique|shop|store|apparel|clothing|goods|market)/, label: 'retail',
      chips: ['Clothing / apparel', 'Home goods', 'Specialty / gift shop', 'Online-first brand', 'Farmers market / local'] },
    { match: /(consult|advisory|strateg|coach)/, label: 'consulting',
      chips: ['Business consulting', 'Executive coaching', 'Marketing / growth', 'Financial advisory', 'Ops / strategy'] },
    { match: /(church|ministry|nonprofit|foundation|community)/, label: 'nonprofit / faith',
      chips: ['Church / ministry', 'Nonprofit org', 'Community group', 'Foundation'] },
  ];
  for (const c of categories) {
    if (c.match.test(n)) {
      return { label: c.label, chips: [...c.chips, 'Something else — I\'ll describe it later'] };
    }
  }
  return null;
}

// Agent tones
const TONES = [
  { k: 'neutral', label: 'Professional', desc: 'Confident, technical, unfussy — our default' },
  { k: 'warm',    label: 'Warm',         desc: 'Conversational, fewer words, human' },
  { k: 'dry',     label: 'Dry wit',      desc: 'Midwest deadpan' },
];

// Tone-specific prompts (agent asks questions this way)
function agentPrompts(tone) {
  const P = {
    neutral: {
      intro: "I'll get your project scoped in about 2 minutes. Start whenever you're ready — I'll ask the essentials, fill the form on your right, and a human will answer within one business day.",
      name: "First — who am I talking to? Just your full name.",
      business: "And your business or company name?",
      email: "Best email to reach you?",
      phone: "Phone number — in case a quick call is faster. (Optional.)",
      projectType: "What kind of site are you thinking? A simple one-pager, a full business website, online store, a listings site for cars or real estate — or something custom? Not sure is a fine answer.",
      budget: "Ballpark budget? A rough number helps us suggest the right fit — no commitment.",
      timeline: "When would you like to launch? ASAP, a few months out, flexible?",
      currentSite: "Do you have a website right now? If so, drop the link. (Optional.)",
      description: "Last one — in a few sentences, what are you hoping this website will do for your business?",
      referral: "How'd you hear about us?",
      done: "All set. I've filled in the form on the right — review it, edit anything that's off, and send it. We answer in a business day.",
    },
    warm: {
      intro: "Hey — I'll help you get this over the wall. Two minutes, tops. Ready?",
      name: "What's your name?",
      business: "Business name?",
      email: "Where should we email you?",
      phone: "Phone number? Totally optional.",
      projectType: "What are we building? One-pager, listings, store, internal tool, data stuff, AI — whatever fits.",
      budget: "Rough budget? Doesn't have to be exact.",
      timeline: "When do you need it?",
      currentSite: "Current site URL? If you have one.",
      description: "Tell me about the project — just a couple sentences.",
      referral: "How'd you find us?",
      done: "That's it! Look over what I filled in on the right, tweak anything, hit send. We'll reply in a day.",
    },
    dry: {
      intro: "Fine. Two minutes. I ask, you answer, the form fills itself. That's the arrangement.",
      name: "Name. Full one.",
      business: "Business name. If there is one.",
      email: "Email. Where we'll send the response you definitely won't miss.",
      phone: "Phone. Optional. Oklahoma area code implied.",
      projectType: "What are we building? Small site, listings, store, dashboard, data pipeline, AI — the usual.",
      budget: "Budget. Ballpark. Nobody's holding you to it.",
      timeline: "Timeline. When does this need to exist?",
      currentSite: "Current site. URL. Skip if there isn't one.",
      description: "Describe the thing. Couple sentences.",
      referral: "How'd you find us? Not that it matters.",
      done: "Done. Form's on the right. Check it, send it. We reply in a business day. That's the deal.",
    },
  };
  return P[tone] || P.neutral;
}

function Contact() {
  // stage: 'choose' -> pick Agent or Form
  //        'tone'   -> Agent path: pick tone (auto-starts convo)
  //        'chat'   -> conversation running
  //        'form'   -> direct-form path
  const [stage, setStage] = useStateCt('choose');
  const [tone, setTone] = useStateCt(null);
  const [formRevealed, setFormRevealed] = useStateCt(false);
  const [values, setValues] = useStateCt({});
  const [skipped, setSkipped] = useStateCt({});
  const [submitted, setSubmitted] = useStateCt(false);
  const [submitting, setSubmitting] = useStateCt(false);
  const ref = useRefCt(null);
  useReveal(ref);

  const submit = () => {
    setSubmitting(true);
    setTimeout(() => { setSubmitting(false); setSubmitted(true); }, 1600);
  };

  const activeFields = FIELDS;

  return (
    <section id="contact" ref={ref} className="mw-reveal" style={{ position: 'relative', padding: 'clamp(64px, 10vh, 100px) clamp(16px, 4vw, 32px) clamp(48px, 8vh, 80px)', borderTop: '1px solid var(--border)', overflow: 'hidden' }}>
      {/* Background shader */}
      <div style={{ position: 'absolute', inset: 0, opacity: 0.45 }}>
        <AsciiField/>
      </div>
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, var(--bg) 0%, color-mix(in oklab, var(--bg) 65%, transparent) 30%, color-mix(in oklab, var(--bg) 75%, transparent) 70%, var(--bg) 100%)' }}/>

      <div style={{ position: 'relative', maxWidth: 1440, margin: '0 auto' }}>
        {/* Header */}
        <div style={{ marginBottom: 32 }}>
          <SectionHead
            eyebrow="003 / Book a consultation"
            title={<>Tell us what<br/><em style={{ fontFamily: 'var(--font-editorial)', fontStyle: 'italic', fontWeight: 400, color: 'var(--accent)' }}>you're building.</em></>}
            kicker="Free 30-minute consult. We answer in one business day. Talk to our intake agent below, or fill out the form directly — your choice."
            right={
              stage !== 'choose' ? (
                <button onClick={() => { setStage('choose'); setTone(null); setFormRevealed(false); }} style={{
                  padding: '6px 10px', fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase',
                  background: 'transparent', color: 'var(--fg-3)', border: '1px solid var(--border-strong)', cursor: 'pointer',
                }}>← Back</button>
              ) : null
            }
          />
        </div>

        {submitted ? <Submitted values={values} activeFields={activeFields}/> : (
          <>
            {stage === 'choose' && (
              <ChooseStage
                onAgent={() => setStage('tone')}
                onForm={() => setStage('form')}
              />
            )}
            {stage === 'tone' && (
              <ToneStage
                onPick={(k) => { setTone(k); setStage('chat'); }}
              />
            )}
            {stage === 'chat' && (
              <div className={'mw-contact-split' + (formRevealed ? ' mw-form-revealed' : ' mw-form-hidden')}>
                <AgentPane
                  tone={tone} setTone={setTone}
                  activeFields={activeFields} values={values} setValues={setValues}
                  skipped={skipped} setSkipped={setSkipped}
                  onSubmit={submit} submitting={submitting}
                  onFirstQuestion={() => setFormRevealed(true)}
                />
                <FormPane activeFields={activeFields} values={values} setValues={setValues} skipped={skipped} onSubmit={submit} submitting={submitting} agentMode={true} revealed={formRevealed}/>
              </div>
            )}
            {stage === 'form' && (
              <div style={{ maxWidth: 720, margin: '0 auto' }}>
                <FormPane activeFields={activeFields} values={values} setValues={setValues} skipped={skipped} onSubmit={submit} submitting={submitting} agentMode={false} revealed={true}/>
              </div>
            )}
          </>
        )}
      </div>
    </section>
  );
}

/* ===== Stage 1: Choose Agent or Form ===== */
function ChooseStage({ onAgent, onForm }) {
  const Card = ({ glyph, eyebrow, title, desc, cta, onClick, accent }) => (
    <button onClick={onClick} style={{
      flex: 1, minWidth: 0, textAlign: 'left', padding: 'clamp(28px, 4vw, 44px)',
      background: accent ? 'color-mix(in oklab, var(--accent) 6%, var(--bg-elev-1))' : 'var(--bg-elev-1)',
      border: '1px solid ' + (accent ? 'var(--accent)' : 'var(--border-strong)'),
      cursor: 'pointer', color: 'inherit', position: 'relative', overflow: 'hidden',
      transition: 'transform .35s var(--ease-out), background .25s',
      display: 'flex', flexDirection: 'column', gap: 24, minHeight: 320,
    }}
    onMouseEnter={e => { e.currentTarget.style.transform = 'translateY(-4px)'; }}
    onMouseLeave={e => { e.currentTarget.style.transform = 'translateY(0)'; }}
    >
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.18em', color: accent ? 'var(--accent)' : 'var(--fg-4)', textTransform: 'uppercase' }}>{eyebrow}</div>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 40, lineHeight: 1, color: accent ? 'var(--accent)' : 'var(--fg-3)' }}>{glyph}</div>
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 'clamp(26px, 3vw, 36px)', fontWeight: 500, letterSpacing: '-0.03em', lineHeight: 1.05, color: 'var(--fg-1)' }}>{title}</div>
        <p style={{ fontSize: 14, color: 'var(--fg-3)', marginTop: 12, lineHeight: 1.55 }}>{desc}</p>
      </div>
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.16em', textTransform: 'uppercase', color: accent ? 'var(--accent)' : 'var(--fg-2)', display: 'inline-flex', alignItems: 'center', gap: 8 }}>
        {cta} <span style={{ display: 'inline-block', transition: 'transform .2s' }}>→</span>
      </div>
    </button>
  );
  return (
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))', gap: 16, animation: 'mwFadeIn .4s var(--ease-out)' }}>
      <Card
        accent
        glyph="◆"
        eyebrow="OPTION A · RECOMMENDED"
        title={<>Talk to our <em style={{ fontFamily: 'var(--font-editorial)', fontStyle: 'italic', fontWeight: 400, color: 'var(--accent)' }}>intake agent</em>.</>}
        desc="A two-minute conversation. The agent asks, you answer, and an inquiry form fills itself out live. This is one of the things we build."
        cta="Start conversation"
        onClick={onAgent}
      />
      <Card
        glyph="▦"
        eyebrow="OPTION B"
        title={<>Fill the form <em style={{ fontFamily: 'var(--font-editorial)', fontStyle: 'italic', fontWeight: 400 }}>yourself</em>.</>}
        desc="Prefer the classic route? Skip the chat and type directly into the inquiry form. Same inbox, same one-business-day reply."
        cta="Open form"
        onClick={onForm}
      />
    </div>
  );
}

/* ===== Stage 2: Pick tone — auto-starts conversation ===== */
function ToneStage({ onPick }) {
  return (
    <div style={{ maxWidth: 860, margin: '0 auto', animation: 'mwFadeIn .4s var(--ease-out)' }}>
      <div style={{ textAlign: 'center', marginBottom: 24 }}>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.18em', color: 'var(--fg-4)', textTransform: 'uppercase', marginBottom: 10 }}>— STEP 2 OF 2 · PICK A VOICE</div>
        <div style={{ fontFamily: 'var(--font-display)', fontSize: 'clamp(28px, 3.6vw, 44px)', fontWeight: 500, letterSpacing: '-0.03em', lineHeight: 1.05 }}>
          How would you like <em style={{ fontFamily: 'var(--font-editorial)', fontStyle: 'italic', fontWeight: 400, color: 'var(--accent)' }}>the agent</em> to speak?
        </div>
        <p style={{ color: 'var(--fg-3)', marginTop: 10, fontSize: 14 }}>Pick one — the conversation starts immediately.</p>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(220px, 1fr))', gap: 12 }}>
        {TONES.map((t, i) => {
          const samples = {
            neutral: "First — who am I talking to? Just your full name.",
            warm:    "Hey — what's your name?",
            dry:     "Name. Full one.",
          };
          return (
            <button key={t.k} onClick={() => onPick(t.k)} style={{
              padding: '24px 22px', textAlign: 'left',
              background: 'var(--bg-elev-1)', border: '1px solid var(--border-strong)',
              cursor: 'pointer', color: 'inherit', transition: 'all .25s',
              display: 'flex', flexDirection: 'column', gap: 14, minHeight: 180,
            }}
            onMouseEnter={e => { e.currentTarget.style.borderColor = 'var(--accent)'; e.currentTarget.style.background = 'color-mix(in oklab, var(--accent) 5%, var(--bg-elev-1))'; }}
            onMouseLeave={e => { e.currentTarget.style.borderColor = 'var(--border-strong)'; e.currentTarget.style.background = 'var(--bg-elev-1)'; }}
            >
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.18em', color: 'var(--fg-4)' }}>0{i + 1}</div>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '0.14em', color: 'var(--fg-4)' }}>VOICE</div>
              </div>
              <div>
                <div style={{ fontFamily: 'var(--font-display)', fontSize: 24, fontWeight: 500, letterSpacing: '-0.02em', color: 'var(--fg-1)' }}>{t.label}</div>
                <div style={{ fontSize: 12, color: 'var(--fg-3)', marginTop: 4, lineHeight: 1.4 }}>{t.desc}</div>
              </div>
              <div style={{ marginTop: 'auto', padding: '10px 12px', background: 'var(--bg)', border: '1px solid var(--border)', fontSize: 12, color: 'var(--fg-2)', fontStyle: 'italic', lineHeight: 1.4 }}>
                “{samples[t.k]}”
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// ----- AGENT PANE -----
// Driven by POST /api/chat — the model returns the next reply, 3–6 tailored
// click-chips, any fields it extracted from the last user turn, and a done
// flag. Scripted prompts below are kept as a graceful fallback for local dev
// without AI_GATEWAY_API_KEY set, or any upstream failure.
// RFC-4122 v4 UUID. Used as the client-generated session key for chat-log
// rows in Neon — one per conversation, regenerated on page refresh.
function makeSessionId() {
  try {
    if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
      return crypto.randomUUID();
    }
  } catch (_) { /* fall through */ }
  // Fallback for older browsers — not cryptographically strong, but unique
  // enough for log keys, and the server validates the UUID shape anyway.
  const r = (n) => Math.floor(Math.random() * n).toString(16);
  const s = (n) => Array.from({ length: n }, () => r(16)).join('');
  return `${s(8)}-${s(4)}-4${s(3)}-${(8 + Math.floor(Math.random() * 4)).toString(16)}${s(3)}-${s(12)}`;
}

function AgentPane({ tone, setTone, activeFields, values, setValues, skipped, setSkipped, onSubmit, submitting, onFirstQuestion }) {
  const [messages, setMessages] = useStateCt([]);
  const [suggestions, setSuggestions] = useStateCt([]);
  const [activeFieldKey, setActiveFieldKey] = useStateCt(null);
  const [done, setDone] = useStateCt(false);
  const [input, setInput] = useStateCt('');
  const [typing, setTyping] = useStateCt(false);
  const [apiDown, setApiDown] = useStateCt(false);
  const scrollRef = useRefCt(null);
  const bootedRef = useRefCt(false);
  const firedFirstQ = useRefCt(false);
  const sessionIdRef = useRefCt(null);
  if (!sessionIdRef.current) sessionIdRef.current = makeSessionId();
  // Mirror state into refs so async callbacks always see the latest snapshot
  // without re-subscribing to the fetch in useEffect.
  const valuesRef = useRefCt(values);
  valuesRef.current = values;
  const skippedRef = useRefCt(skipped);
  skippedRef.current = skipped;
  const toneRef = useRefCt(tone);
  toneRef.current = tone;

  useEffectCt(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages, typing, suggestions]);

  const schemaForApi = activeFields.map(f => ({
    key: f.k, label: f.label, type: f.type, optional: !!f.optional, options: f.options,
  }));

  const isSkipAnswer = (s) => {
    const v = String(s || '').trim().toLowerCase();
    return v === '—' || v === 'skip' || v === 'skip for now' || v === 'skip it';
  };

  // Scripted fallback — used when /api/chat is unavailable. Walks the same
  // field list with the hardcoded tone prompts from above.
  const scriptedStep = () => {
    const prompts = agentPrompts(toneRef.current);
    const v = valuesRef.current;
    const sk = skippedRef.current;
    const next = activeFields.find(f => !v[f.k] && !sk[f.k]);
    if (!next) {
      setMessages(m => [...m, { r: 'bot', t: prompts.done, id: Date.now() + Math.random() }]);
      setDone(true);
      setSuggestions([]);
      setActiveFieldKey(null);
      return;
    }
    const text = prompts[next.k] || `Tell me about ${next.label.toLowerCase()}.`;
    const chips = next.options
      ? [...next.options, ...(next.optional ? ['Skip for now'] : [])]
      : (next.optional ? ['Skip for now'] : []);
    setMessages(m => [...m, { r: 'bot', t: text, id: Date.now() + Math.random() }]);
    setSuggestions(chips);
    setActiveFieldKey(next.k);
  };

  const callAgent = async (transcript) => {
    setTyping(true);
    try {
      const res = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          sessionId: sessionIdRef.current,
          messages: transcript.map(m => ({
            role: m.r === 'bot' ? 'assistant' : 'user',
            content: m.t,
          })),
          values: valuesRef.current,
          skipped: Object.keys(skippedRef.current).filter(k => skippedRef.current[k]),
          tone: toneRef.current,
          schema: schemaForApi,
        }),
      });
      if (!res.ok) throw new Error('agent_' + res.status);
      const data = await res.json();

      // Fold any fields the model pulled out of the last user message into
      // the form. Only accept keys the schema knows about.
      if (data.extracted && typeof data.extracted === 'object') {
        const validKeys = new Set(activeFields.map(f => f.k));
        const clean = {};
        Object.keys(data.extracted).forEach(k => {
          const v = data.extracted[k];
          if (validKeys.has(k) && typeof v === 'string' && v.trim()) clean[k] = v.trim();
        });
        if (Object.keys(clean).length) {
          setValues(v => ({ ...v, ...clean }));
        }
      }

      const reply = typeof data.reply === 'string' && data.reply.trim() ? data.reply : '…';
      setMessages(m => [...m, { r: 'bot', t: reply, id: Date.now() + Math.random() }]);
      setSuggestions(Array.isArray(data.suggestions) ? data.suggestions.slice(0, 6) : []);
      setActiveFieldKey(typeof data.nextField === 'string' ? data.nextField : null);
      setDone(Boolean(data.done));
    } catch (err) {
      if (!apiDown && typeof console !== 'undefined') {
        console.warn('[intake] live agent unavailable, scripted fallback:', err);
      }
      setApiDown(true);
      scriptedStep();
    } finally {
      setTyping(false);
      if (!firedFirstQ.current) {
        firedFirstQ.current = true;
        onFirstQuestion && onFirstQuestion();
      }
    }
  };

  // Boot conversation once tone is picked.
  useEffectCt(() => {
    if (bootedRef.current) return;
    bootedRef.current = true;
    callAgent([]);
  }, []);

  const answer = (text) => {
    const val = String(text || '').trim();
    if (!val || done || typing) return;
    if (activeFieldKey) {
      if (isSkipAnswer(val)) {
        setSkipped(s => ({ ...s, [activeFieldKey]: true }));
        skippedRef.current = { ...skippedRef.current, [activeFieldKey]: true };
      } else {
        setValues(v => ({ ...v, [activeFieldKey]: val }));
        valuesRef.current = { ...valuesRef.current, [activeFieldKey]: val };
      }
    }
    const nextTranscript = [...messages, { r: 'user', t: val, id: Date.now() + Math.random() }];
    setMessages(nextTranscript);
    setSuggestions([]);
    setInput('');
    callAgent(nextTranscript);
  };

  const activeField = activeFieldKey ? activeFields.find(f => f.k === activeFieldKey) : null;
  const filledCount = activeFields.filter(f => values[f.k]).length;
  const accountedCount = activeFields.filter(f => values[f.k] || skipped[f.k]).length;
  const progressPct = Math.min(100, (accountedCount / Math.max(1, activeFields.length)) * 100);

  return (
    <div className="mw-agent-pane" style={{ background: 'var(--bg-elev-2)', border: '1px solid var(--border-strong)', display: 'flex', flexDirection: 'column', minHeight: 640, position: 'relative', overflow: 'hidden' }}>
      {/* Header */}
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 12 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 28, height: 28, background: 'var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: 'var(--font-display)', fontWeight: 600, color: 'var(--accent-ink)', fontSize: 13 }}>M</div>
          <div>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.1em', color: 'var(--fg-1)' }}>INTAKE AGENT</div>
            <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '0.16em', color: apiDown ? 'var(--fg-4)' : 'var(--accent)', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
              <DotTrace size={3} color={apiDown ? 'var(--fg-4)' : 'var(--accent)'}/> {apiDown ? 'OFFLINE' : 'LIVE'}
            </div>
          </div>
        </div>
        <select value={tone} onChange={e => setTone(e.target.value)} style={{
          background: 'transparent', border: '1px solid var(--border-strong)', color: 'var(--fg-3)',
          fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.12em', padding: '4px 6px', cursor: 'pointer',
        }}>
          {TONES.map(t => <option key={t.k} value={t.k}>{t.label.toUpperCase()}</option>)}
        </select>
      </div>

      {/* Messages */}
      <div ref={scrollRef} style={{ flex: 1, overflowY: 'auto', padding: '20px 18px', display: 'flex', flexDirection: 'column', gap: 12, minHeight: 420, maxHeight: 560 }}>
        {messages.map((m) => <Message key={m.id} m={m}/>)}
        {typing && <TypingIndicator/>}
      </div>

      {/* Input */}
      {!done && (
        <div style={{ borderTop: '1px solid var(--border)', padding: 14, background: 'var(--bg-elev-1)' }}>
          {/* Tailored chips — the primary input. Typing is the fallback. */}
          {suggestions.length > 0 && (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 }}>
              {suggestions.map(o => (
                <button key={o} onClick={() => answer(o)} disabled={typing} style={{
                  padding: '6px 10px', fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase',
                  background: 'transparent', color: 'var(--fg-2)', border: '1px solid var(--border-strong)',
                  cursor: typing ? 'default' : 'pointer', opacity: typing ? 0.5 : 1,
                  transition: 'all .15s',
                }} onMouseEnter={e => { if (typing) return; e.currentTarget.style.background = 'var(--accent)'; e.currentTarget.style.color = 'var(--accent-ink)'; e.currentTarget.style.borderColor = 'var(--accent)'; }}
                   onMouseLeave={e => { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--fg-2)'; e.currentTarget.style.borderColor = 'var(--border-strong)'; }}>
                  {o}
                </button>
              ))}
            </div>
          )}
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', background: 'var(--bg)', border: '1px solid var(--border-strong)', padding: '4px 4px 4px 12px' }}>
            <input
              type="text" value={input}
              onChange={e => setInput(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') answer(input); }}
              placeholder={activeField ? `Or type your ${activeField.label.toLowerCase()}...` : 'Type your answer...'}
              disabled={typing}
              style={{ flex: 1, background: 'transparent', border: 'none', outline: 'none', color: 'var(--fg-1)', fontFamily: 'var(--font-body)', fontSize: 14, padding: '10px 0' }}/>
            {activeField?.optional && (
              <button onClick={() => answer('Skip for now')} disabled={typing} style={{
                padding: '8px 10px', background: 'transparent', color: 'var(--fg-4)',
                border: 'none', borderRight: '1px solid var(--border)', cursor: typing ? 'default' : 'pointer',
                fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.12em', textTransform: 'uppercase',
                transition: 'color .15s',
                whiteSpace: 'nowrap',
              }}
              onMouseEnter={e => { if (!typing) e.currentTarget.style.color = 'var(--fg-2)'; }}
              onMouseLeave={e => e.currentTarget.style.color = 'var(--fg-4)'}>Skip</button>
            )}
            <button onClick={() => answer(input)} disabled={!input.trim() || typing} style={{
              padding: '8px 14px', background: input.trim() && !typing ? 'var(--accent)' : 'var(--bg-elev-1)',
              color: input.trim() && !typing ? 'var(--accent-ink)' : 'var(--fg-4)',
              border: 'none', cursor: input.trim() && !typing ? 'pointer' : 'default',
              fontFamily: 'var(--font-mono)', fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase',
              transition: 'all .15s',
            }}>Send ↵</button>
          </div>
          {/* Progress — tracks filled fields, not question index, so extracted
              multi-fills show up immediately. */}
          <div style={{ marginTop: 10, display: 'flex', alignItems: 'center', gap: 8 }}>
            <div style={{ flex: 1, height: 2, background: 'var(--border-strong)', position: 'relative' }}>
              <div style={{ height: '100%', background: 'var(--accent)', width: `${progressPct}%`, transition: 'width .4s var(--ease-out)' }}/>
            </div>
            <span style={{ fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--fg-4)', letterSpacing: '0.14em' }}>{filledCount} / {activeFields.length}</span>
          </div>
        </div>
      )}
      {done && (
        <div style={{ borderTop: '1px solid var(--border)', padding: 16, background: 'var(--bg-elev-1)', display: 'flex', gap: 10, justifyContent: 'center' }}>
          <MagButton variant="primary" size="lg" onClick={onSubmit} noArrow>
            {submitting ? <><OrbitArc size={16}/> SENDING...</> : '✓ Send inquiry'}
          </MagButton>
        </div>
      )}
    </div>
  );
}

function Message({ m }) {
  const isBot = m.r === 'bot';
  const [shown, setShown] = useStateCt(isBot ? '' : m.t);
  useEffectCt(() => {
    if (!isBot) return;
    let i = 0;
    const speed = 12 + Math.random() * 12;
    const t = setInterval(() => {
      i++;
      setShown(m.t.slice(0, i));
      if (i >= m.t.length) clearInterval(t);
    }, speed);
    return () => clearInterval(t);
  }, []);
  return (
    <div style={{
      display: 'flex', flexDirection: 'column', gap: 4,
      alignItems: isBot ? 'flex-start' : 'flex-end',
      animation: 'mwFadeIn .3s var(--ease-out)',
    }}>
      <div style={{
        fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '0.16em', color: 'var(--fg-4)',
      }}>{isBot ? '— AGENT' : '— YOU'}</div>
      <div style={{
        maxWidth: '85%',
        padding: '10px 14px',
        background: isBot ? 'var(--bg)' : 'var(--accent)',
        color: isBot ? 'var(--fg-1)' : 'var(--accent-ink)',
        border: '1px solid ' + (isBot ? 'var(--border-strong)' : 'var(--accent)'),
        fontSize: 14, lineHeight: 1.5, whiteSpace: 'pre-wrap', textAlign: 'left',
      }}>{shown}{isBot && shown.length < m.t.length && <span style={{ display: 'inline-block', width: '0.4em', height: '1em', background: 'var(--accent)', marginLeft: 2, verticalAlign: '-0.1em', animation: 'mwBreathe 1s steps(2) infinite' }}/>}</div>
    </div>
  );
}

function TypingIndicator() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4, alignItems: 'flex-start' }}>
      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '0.16em', color: 'var(--fg-4)' }}>— AGENT</div>
      <div style={{ padding: '12px 16px', background: 'var(--bg)', border: '1px solid var(--border-strong)' }}>
        <DotTrace color="var(--fg-3)" size={5}/>
      </div>
    </div>
  );
}

// ----- FORM PANE -----
function FormPane({ activeFields, values, setValues, skipped = {}, onSubmit, submitting, agentMode, revealed = true }) {
  const [justFilled, setJustFilled] = useStateCt({});
  const prevValues = useRefCt({});
  useEffectCt(() => {
    const filled = {};
    Object.keys(values).forEach(k => {
      if (values[k] !== prevValues.current[k]) filled[k] = true;
    });
    if (Object.keys(filled).length) {
      setJustFilled(f => ({ ...f, ...filled }));
      setTimeout(() => {
        setJustFilled({});
      }, 1400);
    }
    prevValues.current = { ...values };
  }, [values]);

  const handleChange = (k, v) => setValues(vs => ({ ...vs, [k]: v }));
  const canSubmit = activeFields.every(f => f.optional || values[f.k]);
  const accountedCount = activeFields.filter(f => values[f.k] || skipped[f.k]).length;

  return (
    <div className="mw-form-pane" style={{
      background: 'var(--bg-elev-1)', border: '1px solid var(--border-strong)',
      padding: 'clamp(20px, 3vw, 28px)', display: 'flex', flexDirection: 'column', gap: 18,
      position: 'relative',
      opacity: revealed ? 1 : 0,
      transform: revealed ? 'translateX(0)' : 'translateX(40px)',
      transition: 'opacity .55s var(--ease-out), transform .55s var(--ease-out)',
      pointerEvents: revealed ? 'auto' : 'none',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', borderBottom: '1px solid var(--border)', paddingBottom: 12 }}>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.16em', color: 'var(--fg-3)' }}>— INQUIRY FORM</div>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 9, letterSpacing: '0.14em', color: 'var(--fg-4)' }}>
          {agentMode ? 'LIVE · AUTO-FILLING' : `${accountedCount} / ${activeFields.length} FILLED`}
        </div>
      </div>
      {activeFields.map(f => (
        <FormField key={f.k} field={f} value={values[f.k] || ''} onChange={v => handleChange(f.k, v)} justFilled={justFilled[f.k]} readOnly={agentMode}/>
      ))}
      <div style={{ display: 'flex', gap: 12, alignItems: 'center', marginTop: 8, flexWrap: 'wrap' }}>
        <MagButton variant="primary" size="lg" onClick={onSubmit} noArrow style={{ opacity: canSubmit ? 1 : 0.5, pointerEvents: canSubmit ? 'auto' : 'none' }}>
          {submitting ? <><OrbitArc size={16}/> SENDING</> : 'Send inquiry →'}
        </MagButton>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--fg-4)', letterSpacing: '0.14em' }}>WE ANSWER IN 1 BUSINESS DAY</span>
      </div>
    </div>
  );
}

function FormField({ field, value, onChange, justFilled, readOnly }) {
  const [focus, setFocus] = useStateCt(false);
  const highlight = justFilled;
  const borderColor = highlight ? 'var(--accent)' : (focus ? 'var(--fg-2)' : 'var(--border-strong)');
  const labelEl = (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 5 }}>
      <label style={{ fontFamily: 'var(--font-mono)', fontSize: 10, letterSpacing: '0.16em', textTransform: 'uppercase', color: highlight ? 'var(--accent)' : 'var(--fg-3)', transition: 'color .3s' }}>
        {field.label}
      </label>
      {highlight && (
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 9, color: 'var(--accent)', letterSpacing: '0.14em', display: 'inline-flex', alignItems: 'center', gap: 5, animation: 'mwFadeIn .3s' }}>
          <DotTrace size={3}/> FILLING
        </span>
      )}
    </div>
  );
  const commonStyle = {
    background: 'transparent', border: 'none', borderBottom: `1px solid ${borderColor}`,
    padding: '10px 0', color: 'var(--fg-1)', fontFamily: 'var(--font-display)', fontSize: 16, fontWeight: 400,
    outline: 'none', width: '100%', transition: 'border-color .25s, background .4s',
    backgroundColor: highlight ? 'color-mix(in oklab, var(--accent) 8%, transparent)' : 'transparent',
  };
  return (
    <div style={{ position: 'relative' }}>
      {labelEl}
      {field.type === 'textarea' ? (
        <textarea value={value} onChange={e => onChange(e.target.value)} onFocus={() => setFocus(true)} onBlur={() => setFocus(false)}
          placeholder={field.placeholder} rows={3} style={{ ...commonStyle, resize: 'vertical', fontFamily: 'var(--font-body)', fontSize: 14, lineHeight: 1.5 }}/>
      ) : field.type === 'select' ? (
        <select value={value} onChange={e => onChange(e.target.value)} onFocus={() => setFocus(true)} onBlur={() => setFocus(false)} style={{ ...commonStyle, cursor: 'pointer' }}>
          <option value="" style={{ background: 'var(--bg-elev-2)' }}>—</option>
          {field.options.map(o => <option key={o} value={o} style={{ background: 'var(--bg-elev-2)' }}>{o}</option>)}
        </select>
      ) : (
        <input type={field.type} value={value} onChange={e => onChange(e.target.value)} onFocus={() => setFocus(true)} onBlur={() => setFocus(false)} placeholder={field.placeholder} style={commonStyle}/>
      )}
    </div>
  );
}

function Submitted({ values, activeFields }) {
  return (
    <div style={{ maxWidth: 640, margin: '40px auto', textAlign: 'center', padding: '48px 20px', border: '1px solid var(--accent)', background: 'color-mix(in oklab, var(--accent) 4%, var(--bg-elev-1))' }}>
      <div style={{ display: 'inline-flex', width: 64, height: 64, background: 'var(--accent)', alignItems: 'center', justifyContent: 'center', color: 'var(--accent-ink)', fontSize: 28, marginBottom: 20 }}>✓</div>
      <h3 style={{ margin: 0, fontFamily: 'var(--font-display)', fontSize: 'clamp(28px, 4vw, 44px)', fontWeight: 500, letterSpacing: '-0.03em' }}>
        Got it — <em style={{ fontFamily: 'var(--font-editorial)', fontStyle: 'italic', fontWeight: 400, color: 'var(--accent)' }}>we'll reply</em> in a day.
      </h3>
      <p style={{ color: 'var(--fg-3)', marginTop: 14, fontSize: 15, lineHeight: 1.5 }}>
        Expect an email from hello@midwest.tech. We'll confirm scope, propose a call time, and if needed — send back clarifying questions.
      </p>
      <div style={{ marginTop: 28, display: 'inline-flex', flexDirection: 'column', gap: 8, padding: 20, background: 'var(--bg)', border: '1px solid var(--border)', textAlign: 'left' }}>
        {activeFields.filter(f => values[f.k]).slice(0, 5).map(f => (
          <div key={f.k} style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg-3)' }}>
            <span style={{ color: 'var(--fg-4)', letterSpacing: '0.14em' }}>{f.label.toUpperCase()} →</span> <span style={{ color: 'var(--fg-1)' }}>{String(values[f.k]).slice(0, 50)}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

Object.assign(window, { Contact });
