// ══════════════════════════════════════════════════════════════════════════════
//  GLMario — Mario AI chat (PWA port of gustai-mario-bot WP plugin v2.3.2)
//  Full-screen tab (replaces Profile slot in bottom nav).
//  No backend yet → stub AI replies routed by intent (wholesale, vegan,
//  shipping, human_request, general). Real LLM goes behind `gustaiAskMario()`
//  — swap that one function out for a fetch() to your /chat endpoint.
// ══════════════════════════════════════════════════════════════════════════════

// Default config — overridden at runtime by admin-saved values from GLSettings
const MARIO_DEFAULTS = {
  botName:       'Mario',
  greeting:      "Ciao! I'm Mario 🍝  Ask me anything about Gustai Lab — pasta, sauces, subscriptions, delivery, you name it.",
  afterHoursMsg: "Our team is back at 8am Bangkok time — but I'm here 24/7. Ask me anything!",
  waNumber:      '66837108887',
  hoursStart:    '08:00',
  hoursEnd:      '17:00',
  consentText:   'By chatting, you agree that we may store this conversation to improve service. We never share your data.',
  privacyUrl:    '#privacy',
  language:      'auto',
  soundEnabled:  true,
  quickReplies:  [
    'How does the subscription work?',
    'Tell me about your pasta',
    'Vegan / dairy-free options?',
    'Wholesale for restaurants',
    'Delivery in Phuket?',
    'Talk to a human',
  ],
};

// Admin-saved values arrive via GLSettings.marioConfigSync() (mario_config key).
// If GLSettings isn't loaded yet, we fall through to defaults.
function getMarioConfig() {
  const admin = (window.GLSettings && typeof window.GLSettings.marioConfigSync === 'function')
    ? window.GLSettings.marioConfigSync() : null;
  if (!admin) return MARIO_DEFAULTS;
  return {
    botName:       admin.bot_name        || MARIO_DEFAULTS.botName,
    greeting:      admin.greeting        || MARIO_DEFAULTS.greeting,
    afterHoursMsg: admin.after_hours_msg || MARIO_DEFAULTS.afterHoursMsg,
    waNumber:      admin.whatsapp_number || MARIO_DEFAULTS.waNumber,
    hoursStart:    admin.hours_start     || MARIO_DEFAULTS.hoursStart,
    hoursEnd:      admin.hours_end       || MARIO_DEFAULTS.hoursEnd,
    consentText:   admin.consent_text    || MARIO_DEFAULTS.consentText,
    privacyUrl:    admin.privacy_url     || MARIO_DEFAULTS.privacyUrl,
    language:      admin.ui_language     || MARIO_DEFAULTS.language,
    soundEnabled:  admin.sound_enabled !== false,
    quickReplies:  Array.isArray(admin.quick_replies) && admin.quick_replies.length
                     ? admin.quick_replies
                     : MARIO_DEFAULTS.quickReplies,
  };
}

// Live config — read once per render (cheap synchronous localStorage read).
// Re-evaluated each time GLMario mounts so admin changes apply on next visit.
const MARIO_CONFIG = new Proxy({}, {
  get(_, prop) { return getMarioConfig()[prop]; },
});

// ─── BUSINESS HOURS (Bangkok UTC+7) ─────────────────────────────────────────
function marioIsBusinessHours() {
  const now  = new Date();
  const bkMs = now.getTime() + (now.getTimezoneOffset() + 420) * 60000;
  const bk   = new Date(bkMs);
  const cur  = bk.getHours() * 60 + bk.getMinutes();
  const parts = (s) => { const p = s.split(':'); return parseInt(p[0],10) * 60 + parseInt(p[1] || 0, 10); };
  return cur >= parts(MARIO_CONFIG.hoursStart) && cur < parts(MARIO_CONFIG.hoursEnd);
}

// ─── INTENT DETECTION (lifted from WP plugin) ───────────────────────────────
function marioDetectIntent(text) {
  const t = (text || '').toLowerCase();
  if (/wholesale|bulk|b2b|restaurant|hotel|chef|distributor|supplier|large.?order|minimum.?order/i.test(t)) return 'wholesale';
  if (/vegan|plant.?based|dairy.?free|egg.?free|gluten.?free/i.test(t)) return 'dietary';
  if (/human|person|staff|team|real|agent|speak.?to|talk.?to/i.test(t)) return 'human_request';
  if (/ship|deliver|postage|courier|freight|arrival|dispatch|when.*arrive/i.test(t)) return 'shipping';
  if (/subscribe|subscription|recurring|standing.?order|prepay|how.?does.*work/i.test(t)) return 'subscription';
  if (/menu|pasta|sauce|product|item|set|fresh/i.test(t)) return 'menu';
  if (/price|cost|how.?much|baht|thb|฿/i.test(t)) return 'pricing';
  return 'general';
}

// ─── REAL AI REPLY (calls Supabase edge function `mario-chat`, stub fallback) ─
//   When window.GLMarioAPI is configured (db client wired up), this hits Gemini.
//   Otherwise falls through to the canned per-intent answers below — same UX,
//   no backend required for design / demo.
async function gustaiAskMario(userText, history, opts) {
  opts = opts || {};
  const intent = marioDetectIntent(userText);

  // Try the real backend first
  if (window.GLMarioAPI && window.GLMarioAPI.isConfigured()) {
    const messages = (history || []).map(m => ({
      role:    m.role === 'assistant' ? 'assistant' : 'user',
      content: m.text || m.content || '',
    }));
    const res = await window.GLMarioAPI.chat({
      messages,
      userName:  opts.userName,
      sessionId: opts.sessionId,
      language:  opts.language,
    });
    if (res.ok && res.text) {
      return {
        text: res.text,
        followup: intent === 'wholesale' ? 'wholesale_lead'
                : intent === 'human_request' ? 'whatsapp_handoff'
                : undefined,
      };
    }
    // backend down or not configured → fall through to canned reply
    console.warn('[Mario] backend unavailable, using stub:', res.error);
  }

  // Simulate latency 600–1400ms (only used by stub fallback)
  await new Promise(r => setTimeout(r, 600 + Math.random() * 800));

  switch (intent) {
    case 'wholesale':
      return {
        text: "Our **wholesale program** handles hotels, restaurants and chef-led venues across Phuket and Phang Nga.\n\n• Minimum order: 20 boxes / week\n• 15–25% off retail (volume tiered)\n• Custom pasta shapes & sauce pairings on request\n• Dedicated chef contact + monthly tasting drops\n\nWant me to set up a sample box and a call with our wholesale lead?",
        followup: 'wholesale_lead',
      };
    case 'dietary':
      return {
        text: "Here's the dietary breakdown for our launch sets:\n\n• **Vegetarian**: Truffle Mafaldine, Burrata & Pomodoro, Pesto, Cacio e Pepe\n• **Contains dairy**: Truffle, Burrata, Pesto, Cacio e Pepe\n• **Contains nuts**: Pesto (pine nuts)\n• **Contains shellfish**: Squid Ink Tagliolini\n\nWe can make the **Pesto sauce dairy-free on request** (replace Parmigiano with nutritional yeast). Vegan pasta is on the roadmap — want me to add you to that waitlist?",
      };
    case 'shipping':
      return {
        text: "We deliver **fresh across Phuket** — pasta and sauce arrive cold-packed and ready to cook.\n\n• Free delivery over ฿1000\n• ฿60 flat below that\n• Daily cutoff: **11am** for same-day evening drop (4–7pm)\n• Subscription drops land on your chosen weekday between 4–7pm\n\nWhich neighbourhood are you in? I can confirm cut-off times for your area.",
      };
    case 'subscription':
      return {
        text: "Here's how the **Gustai subscription** works:\n\n1. Pick the pasta + sauce sets you want **in every box** (your standing order)\n2. Choose your **schedule** — weekly, every 2 weeks, or monthly\n3. Choose how many deliveries to **prepay** (we cap at ~6 months so you come back to taste new drops)\n4. Pay once via **PromptPay QR**, we deliver every cycle\n\nNo card on file, no auto-renew surprise — when your prepay runs out you decide if you want another run.\n\nWant me to walk you through building one?",
      };
    case 'pricing':
      return {
        text: "Our pasta + sauce sets are **฿280–฿400 per box** depending on the set.\n\nEach box serves 2 generously and includes:\n• ~200g fresh-extruded pasta\n• Signature sauce (made same day)\n• Aged Parmigiano Reggiano on the side\n\nSubscribe and you save up to **12%** on the per-box price. Want to see the full menu?",
      };
    case 'menu':
      return {
        text: "Our launch menu has **6 pasta + sauce sets**, all bronze-extruded fresh that morning:\n\n• **Truffle Mafaldine** — creamy black truffle (฿350)\n• **Squid Ink Tagliolini** — spicy seafood (฿320)\n• **Classic Rigatoni** — wagyu bolognese (฿280)\n• **Burrata & Pomodoro** — tomato basil (฿400)\n• **Pesto alla Genovese** — pine nut & basil (฿300)\n• **Cacio e Pepe** — pecorino & black pepper (฿290)\n\nWhich one would you try first?",
      };
    case 'human_request':
      return {
        text: marioIsBusinessHours()
          ? "Of course — our team is online right now. Tap below to chat on WhatsApp:"
          : MARIO_CONFIG.afterHoursMsg + "\n\nOr reach the team on WhatsApp:",
        followup: 'whatsapp_handoff',
      };
    case 'general':
    default:
      return {
        text: "I can help with the menu, subscriptions, delivery in Phuket, dietary info, wholesale, or anything else about Gustai Lab. What do you want to know?",
      };
  }
}

// ─── MARKDOWN-LITE RENDERING ────────────────────────────────────────────────
function marioFormat(text) {
  // **bold** → <strong>
  // bullet lines (• or *) → <li>
  // double newline → paragraph break
  if (!text) return '';
  const escape = (s) => s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
  const lines = text.split('\n');
  const out = [];
  let inUl = false;
  lines.forEach(line => {
    const trimmed = line.trim();
    const bullet = /^[•*-]\s+(.+)$/.exec(trimmed);
    if (bullet) {
      if (!inUl) { out.push('<ul>'); inUl = true; }
      out.push('<li>' + escape(bullet[1]).replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') + '</li>');
    } else {
      if (inUl) { out.push('</ul>'); inUl = false; }
      if (trimmed) out.push('<p>' + escape(line).replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>') + '</p>');
    }
  });
  if (inUl) out.push('</ul>');
  return out.join('');
}

// ─── PERSISTENCE ────────────────────────────────────────────────────────────
const MARIO_KEY = 'gl_mario_session_v1';
function loadMarioSession() {
  try { return JSON.parse(localStorage.getItem(MARIO_KEY) || '{}'); } catch (e) { return {}; }
}
function saveMarioSession(s) {
  try { localStorage.setItem(MARIO_KEY, JSON.stringify(s)); } catch (e) {}
}

// ─── MAIN COMPONENT ─────────────────────────────────────────────────────────
function GLMario({ app, go }) {
  const persisted = React.useRef(loadMarioSession()).current;
  const [messages, setMessages]       = React.useState(persisted.messages || []);
  const [consented, setConsented]     = React.useState(!!persisted.consented);
  const [consentChecked, setConsentChecked] = React.useState(false);
  const [leadCaptured, setLeadCaptured] = React.useState(!!persisted.leadCaptured);
  const [leadFormOpen, setLeadFormOpen] = React.useState(false);
  const [leadName, setLeadName]       = React.useState(persisted.userName || (app && app.userName) || '');
  const [leadContact, setLeadContact] = React.useState((app && app.phone) || '');
  const [draft, setDraft]             = React.useState('');
  const [showQR, setShowQR]           = React.useState(true);
  const [typing, setTyping]           = React.useState(false);
  const [showWA, setShowWA]           = React.useState(false);
  const scrollRef = React.useRef(null);

  // Stable session id for analytics + rate-limiting (one per device, persists)
  const sessionId = React.useRef(
    persisted.sessionId ||
    ('s_' + Date.now().toString(36) + Math.random().toString(36).slice(2, 8))
  ).current;
  const sessionStart = React.useRef(persisted.sessionStart || Date.now()).current;
  const intentsSeen = React.useRef(new Set(persisted.intentsSeen || [])).current;

  // Persist on every relevant change
  React.useEffect(() => {
    saveMarioSession({
      messages, consented, leadCaptured,
      userName: leadName,
      sessionId, sessionStart,
      intentsSeen: Array.from(intentsSeen),
    });
  }, [messages, consented, leadCaptured, leadName]);

  // Push session-end analytics on tab close / unmount
  React.useEffect(() => {
    const report = () => {
      if (!window.GLMarioAPI || !consented) return;
      const userMsgs = messages.filter(m => m.role === 'user').length;
      window.GLMarioAPI.report({
        session_id:    sessionId,
        message_count: messages.length,
        user_messages: userMsgs,
        had_lead:      leadCaptured,
        had_handoff:   showWA,
        duration_sec:  Math.round((Date.now() - sessionStart) / 1000),
        intents_seen:  Array.from(intentsSeen),
      });
    };
    window.addEventListener('beforeunload', report);
    return () => { window.removeEventListener('beforeunload', report); report(); };
  }, [messages, leadCaptured, showWA, consented]);

  // Auto-scroll on new messages or typing indicator
  React.useEffect(() => {
    if (!scrollRef.current) return;
    requestAnimationFrame(() => {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    });
  }, [messages, typing]);

  // Greeting on first consent
  React.useEffect(() => {
    if (consented && messages.length === 0) {
      const greetings = [{ role: 'assistant', text: MARIO_CONFIG.greeting, ts: Date.now() }];
      if (!marioIsBusinessHours()) greetings.push({ role: 'assistant', text: MARIO_CONFIG.afterHoursMsg, ts: Date.now() + 1 });
      setMessages(greetings);
    }
  }, [consented]);

  const handleConsent = () => setConsented(true);

  const sendMessage = async (text) => {
    text = (text || '').trim();
    if (!text) return;
    const userMsg = { role: 'user', text, ts: Date.now() };
    const next = [...messages, userMsg];
    setMessages(next);
    setDraft('');
    setShowQR(false);
    setShowWA(false);
    setTyping(true);

    const intent = marioDetectIntent(text);
    intentsSeen.add(intent);
    if (intent === 'human_request') {
      // Skip API — direct WA handoff
      setTimeout(() => {
        setTyping(false);
        const reply = marioIsBusinessHours()
          ? "Of course — our team is online right now. Tap below to chat on WhatsApp:"
          : MARIO_CONFIG.afterHoursMsg + "\n\nOr reach the team on WhatsApp:";
        setMessages(m => [...m, { role: 'assistant', text: reply, ts: Date.now() }]);
        setShowWA(true);
        if (!leadCaptured) setLeadFormOpen(true);
      }, 700);
      return;
    }

    try {
      const res = await gustaiAskMario(text, next, {
        userName:  leadName || (app && app.userName) || undefined,
        sessionId,
        language:  MARIO_CONFIG.language === 'auto' ? undefined : MARIO_CONFIG.language,
      });
      setTyping(false);
      setMessages(m => [...m, { role: 'assistant', text: res.text, ts: Date.now() }]);
      if (res.followup === 'whatsapp_handoff') setShowWA(true);
      if (res.followup === 'wholesale_lead' && !leadCaptured) {
        setTimeout(() => setLeadFormOpen(true), 700);
      }
    } catch (e) {
      setTyping(false);
      setMessages(m => [...m, { role: 'assistant', text: "I'm having connectivity issues. Please try again or tap the WhatsApp button.", ts: Date.now() }]);
      setShowWA(true);
    }
  };

  const submitLead = async () => {
    const name = leadName.trim() || 'Anonymous';
    const contact = leadContact.trim();
    if (!contact) return;
    setLeadCaptured(true);
    setLeadFormOpen(false);

    // Pick the most relevant intent we've seen this session for routing
    const inquiryType =
      intentsSeen.has('wholesale')    ? 'wholesale'
      : intentsSeen.has('subscription') ? 'subscription'
      : intentsSeen.has('dietary')      ? 'dietary'
      : intentsSeen.has('shipping')     ? 'shipping'
      : 'general';

    const transcript = messages.map(m => ({
      role: m.role, content: m.text || '', ts: m.ts,
    }));

    if (window.GLMarioAPI) {
      try {
        await window.GLMarioAPI.captureLead({
          sessionId, name, contact, inquiryType, transcript,
        });
      } catch (e) {
        console.warn('[Mario] lead capture failed:', e);
      }
    }

    const first = name.split(' ')[0];
    setMessages(m => [...m, { role: 'assistant', text: `Got it, ${first}! Our team will be in touch shortly. Is there anything else I can help with?`, ts: Date.now() }]);
  };

  const resetChat = () => {
    setMessages([]);
    setShowQR(true);
    setShowWA(false);
    setLeadFormOpen(false);
    setLeadCaptured(false);
    saveMarioSession({});
    // Greeting will repopulate via useEffect
  };

  const openWhatsApp = () => {
    const txt = encodeURIComponent(`Hi! I was just chatting with Mario on the Gustai app${leadName ? ` — this is ${leadName}` : ''}.`);
    window.open(`https://wa.me/${MARIO_CONFIG.waNumber}?text=${txt}`, '_blank');
  };

  // ─── RENDER ──────────────────────────────────────────────────────────────
  return (
    <div style={{ width: '100%', height: '100%', background: GL.paper, display: 'flex', flexDirection: 'column', position: 'relative' }}>
      {/* Header */}
      <div style={{
        position: 'sticky', top: 0, zIndex: 30,
        background: GL.ink, color: '#fff',
        padding: '64px 18px 14px', height: 104, boxSizing: 'border-box',
        display: 'flex', alignItems: 'center', gap: 12,
        borderBottom: `1px solid ${GL.darkBorder}`,
      }}>
        <div style={{
          width: 44, height: 44, borderRadius: '50%',
          background: GL.teal, display: 'grid', placeItems: 'center',
          fontSize: 22, flexShrink: 0,
        }}>🍝</div>
        <div style={{ flex: 1 }}>
          <div className="gl-display" style={{ fontSize: 18, color: '#fff', letterSpacing: '0.06em' }}>MARIO</div>
          <div style={{ fontSize: 11, color: GL.teal, marginTop: 2, display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ width: 6, height: 6, borderRadius: '50%', background: GL.teal, animation: 'gl-pulse 2s infinite' }}/>
            <span>{marioIsBusinessHours() ? 'Online — replies instantly' : 'AI 24/7 · Team from 8am BKK'}</span>
          </div>
        </div>
        {messages.length > 0 && consented && (
          <button onClick={resetChat} style={{
            fontSize: 10, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase',
            color: GL.teal, padding: '6px 10px', border: `1px solid ${GL.teal}66`, borderRadius: 4,
          }}>New</button>
        )}
      </div>

      {/* Body */}
      <div ref={scrollRef} className="gl-noscroll" style={{
        flex: 1, overflowY: 'auto',
        padding: '18px 16px 16px',
        paddingBottom: leadFormOpen ? 16 : 220,
      }}>
        {!consented ? (
          /* Consent gate */
          <div style={{
            margin: '40px auto', maxWidth: 320, textAlign: 'center',
            padding: 24, background: GL.offwhite, border: `1px solid ${GL.line}`, borderRadius: 12,
          }}>
            <div style={{ fontSize: 36, marginBottom: 12 }}>🍝</div>
            <div className="gl-display" style={{ fontSize: 22, color: GL.ink, marginBottom: 8 }}>Chat with Mario</div>
            <p style={{ fontSize: 13, color: GL.muted, lineHeight: 1.5, margin: '0 0 16px' }}>{MARIO_CONFIG.consentText}</p>
            <label style={{ display: 'flex', alignItems: 'center', gap: 8, justifyContent: 'center', marginBottom: 14, fontSize: 12, color: GL.ink }}>
              <input type="checkbox" checked={consentChecked} onChange={e => setConsentChecked(e.target.checked)}/>
              I agree to the above terms.
            </label>
            <button onClick={handleConsent} disabled={!consentChecked}
              style={{
                width: '100%', padding: '14px 0', borderRadius: 8,
                background: consentChecked ? GL.teal : GL.line,
                color: consentChecked ? GL.ink : GL.muted,
                fontSize: 12, fontWeight: 800, letterSpacing: '0.16em', textTransform: 'uppercase',
                cursor: consentChecked ? 'pointer' : 'not-allowed', transition: 'all .15s',
              }}>
              Start Chatting
            </button>
          </div>
        ) : (
          <>
            {messages.map((m, i) => (
              <MarioMessage key={m.ts + '-' + i} role={m.role} text={m.text}/>
            ))}
            {typing && <MarioTyping/>}
            {showWA && (
              <div style={{ display: 'flex', justifyContent: 'flex-start', gap: 8, marginBottom: 12, paddingLeft: 38 }}>
                <button onClick={openWhatsApp} style={{
                  display: 'inline-flex', alignItems: 'center', gap: 8,
                  padding: '12px 16px', borderRadius: 999,
                  background: '#25D366', color: '#fff', fontWeight: 800, fontSize: 13,
                  boxShadow: '0 2px 8px rgba(37,211,102,0.3)',
                }}>
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
                  Continue on WhatsApp
                </button>
              </div>
            )}
          </>
        )}
      </div>

      {/* Quick replies (collapsible chip row) */}
      {consented && showQR && !leadFormOpen && messages.length <= 2 && (
        <div style={{
          position: 'absolute', left: 0, right: 0, bottom: 156,
          padding: '8px 12px', display: 'flex', flexWrap: 'wrap', gap: 6,
          background: GL.paper, borderTop: `1px solid ${GL.line}`,
        }}>
          {MARIO_CONFIG.quickReplies.map((q, i) => (
            <button key={i} onClick={() => sendMessage(q)} style={{
              padding: '8px 12px', borderRadius: 999, fontSize: 12, fontWeight: 600,
              background: GL.offwhite, color: GL.ink, border: `1px solid ${GL.line}`,
              whiteSpace: 'nowrap',
            }}>{q}</button>
          ))}
        </div>
      )}

      {/* Lead form */}
      {consented && leadFormOpen && (
        <div style={{
          position: 'absolute', left: 0, right: 0, bottom: 80,
          padding: 16, background: GL.paper, borderTop: `1px solid ${GL.line}`,
        }}>
          <p style={{ fontSize: 13, color: GL.ink, margin: '0 0 10px', fontWeight: 600 }}>Before connecting, can we get your name & contact? 🙏</p>
          <input type="text" placeholder="Your name" value={leadName} onChange={e => setLeadName(e.target.value)}
            style={{ width: '100%', padding: '10px 12px', borderRadius: 8, border: `1px solid ${GL.line}`, fontSize: 14, marginBottom: 8, boxSizing: 'border-box' }}/>
          <input type="text" placeholder="Email or phone" value={leadContact} onChange={e => setLeadContact(e.target.value)}
            style={{ width: '100%', padding: '10px 12px', borderRadius: 8, border: `1px solid ${GL.line}`, fontSize: 14, marginBottom: 10, boxSizing: 'border-box' }}/>
          <div style={{ display: 'flex', gap: 8 }}>
            <button onClick={() => setLeadFormOpen(false)} style={{
              flex: 1, padding: '12px 0', borderRadius: 8, background: GL.offwhite, color: GL.muted,
              fontSize: 11, fontWeight: 700, letterSpacing: '0.12em', textTransform: 'uppercase',
            }}>Skip</button>
            <button onClick={submitLead} disabled={!leadContact.trim()} style={{
              flex: 2, padding: '12px 0', borderRadius: 8,
              background: leadContact.trim() ? GL.teal : GL.line,
              color: leadContact.trim() ? GL.ink : GL.muted,
              fontSize: 11, fontWeight: 800, letterSpacing: '0.12em', textTransform: 'uppercase',
              cursor: leadContact.trim() ? 'pointer' : 'not-allowed',
            }}>Continue →</button>
          </div>
        </div>
      )}

      {/* Input area */}
      {consented && !leadFormOpen && (
        <div style={{
          position: 'absolute', left: 0, right: 0, bottom: 80,
          padding: '10px 12px', background: GL.paper, borderTop: `1px solid ${GL.line}`,
          display: 'flex', alignItems: 'flex-end', gap: 8,
        }}>
          <button onClick={() => setShowQR(q => !q)} title="Quick topics" style={{
            width: 38, height: 38, borderRadius: '50%',
            background: showQR ? GL.teal : GL.offwhite,
            color: showQR ? GL.ink : GL.muted, display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>
          </button>
          <textarea value={draft} onChange={e => setDraft(e.target.value)}
            onKeyDown={e => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); sendMessage(draft); } }}
            placeholder="Ask Mario anything…" rows={1}
            style={{
              flex: 1, padding: '10px 14px', borderRadius: 20, border: `1px solid ${GL.line}`,
              fontSize: 14, fontFamily: GL.body, resize: 'none', maxHeight: 100,
              outline: 'none', background: '#fff',
            }}/>
          <button onClick={openWhatsApp} title="WhatsApp" style={{
            width: 38, height: 38, borderRadius: '50%',
            background: GL.offwhite, color: '#25D366', display: 'grid', placeItems: 'center', flexShrink: 0,
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/></svg>
          </button>
          <button onClick={() => sendMessage(draft)} disabled={!draft.trim()} style={{
            width: 38, height: 38, borderRadius: '50%',
            background: draft.trim() ? GL.ink : GL.line,
            color: draft.trim() ? GL.teal : GL.muted, display: 'grid', placeItems: 'center', flexShrink: 0,
            cursor: draft.trim() ? 'pointer' : 'not-allowed',
          }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></svg>
          </button>
        </div>
      )}

      <GLTabBar active="mario" onNav={go} shopMode={app && app.shopMode} cartCount={app ? ((app.shopMode === 'sub' ? (app.subTemplate || []) : app.cart) || []).length : 0}/>
    </div>
  );
}

function MarioMessage({ role, text }) {
  if (role === 'user') {
    return (
      <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 10 }}>
        <div style={{
          maxWidth: '78%', padding: '10px 14px', borderRadius: '16px 16px 4px 16px',
          background: GL.teal, color: GL.ink, fontSize: 14, lineHeight: 1.45, fontWeight: 500,
          wordBreak: 'break-word',
        }}>{text}</div>
      </div>
    );
  }
  return (
    <div style={{ display: 'flex', gap: 8, marginBottom: 10 }}>
      <div style={{
        width: 30, height: 30, borderRadius: '50%', background: GL.teal,
        display: 'grid', placeItems: 'center', flexShrink: 0, fontSize: 14,
      }}>🍝</div>
      <div style={{
        maxWidth: '78%', padding: '10px 14px', borderRadius: '4px 16px 16px 16px',
        background: GL.offwhite, color: GL.ink, fontSize: 14, lineHeight: 1.5,
        wordBreak: 'break-word',
      }} dangerouslySetInnerHTML={{ __html: marioFormat(text) }}/>
    </div>
  );
}

function MarioTyping() {
  return (
    <div style={{ display: 'flex', gap: 8, marginBottom: 10 }}>
      <div style={{
        width: 30, height: 30, borderRadius: '50%', background: GL.teal,
        display: 'grid', placeItems: 'center', flexShrink: 0, fontSize: 14,
      }}>🍝</div>
      <div style={{
        padding: '12px 16px', borderRadius: '4px 16px 16px 16px',
        background: GL.offwhite, display: 'flex', gap: 4, alignItems: 'center',
      }}>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: GL.muted, animation: 'gl-bounce 1.2s infinite', animationDelay: '0s' }}/>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: GL.muted, animation: 'gl-bounce 1.2s infinite', animationDelay: '0.15s' }}/>
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: GL.muted, animation: 'gl-bounce 1.2s infinite', animationDelay: '0.3s' }}/>
      </div>
    </div>
  );
}

// Inject typing-dot keyframes once (mounted CSS via design-system already includes gl-pulse)
(function injectMarioStyles() {
  if (document.getElementById('gl-mario-styles')) return;
  const s = document.createElement('style');
  s.id = 'gl-mario-styles';
  s.textContent = `
    @keyframes gl-bounce { 0%, 80%, 100% { transform: translateY(0); opacity: .4; } 40% { transform: translateY(-4px); opacity: 1; } }
    @keyframes gl-pulse  { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
  `;
  document.head.appendChild(s);
})();

window.GLMario = GLMario;
