// 1Radar Hybrid — Extra screens (AI Chat, AI Image, Transcription, Game, Reddit Extractor)
// Ported from V1, restyled in V3 vocabulary

// ---- AI Chat (full page) ----
const WELCOME_MSG = { role: 'assistant', text: "Hi — I'm Radar AI. I can analyze ads, brands and products you're tracking, draft creative, generate images, and pull insights across the platform. What are we working on today?" };

const isValidMongoId = (id) => /^[a-f\d]{24}$/i.test(id);

const AIChatV3 = ({ chatId, onChatChange }) => {
  const [recents, setRecents] = React.useState([]);           // [{_id, title, updatedAt}]
  const [activeId, setActiveId] = React.useState(chatId && isValidMongoId(chatId) ? chatId : null);
  const [messages, setMessages] = React.useState([WELCOME_MSG]);
  const [input, setInput] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const scrollRef = React.useRef(null);
  const abortRef = React.useRef(null);

  // Load recent chats list on mount
  React.useEffect(() => {
    apiFetch('/chats').then(setRecents).catch(() => {});
  }, []);

  // Load messages when activeId changes
  React.useEffect(() => {
    if (!activeId) { setMessages([WELCOME_MSG]); return; }
    apiFetch(`/chats/${activeId}`)
      .then(chat => setMessages(chat.messages?.length ? chat.messages : [WELCOME_MSG]))
      .catch(() => setMessages([WELCOME_MSG]));
  }, [activeId]);

  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [messages]);

  React.useEffect(() => {
    const validChatId = chatId && isValidMongoId(chatId) ? chatId : null;
    if (validChatId !== activeId) setActiveId(validChatId);
  }, [chatId]);

  const selectChat = (id) => {
    setActiveId(id);
    onChatChange && onChatChange(id);
  };

  const newChat = () => {
    setActiveId(null);
    setInput('');
    onChatChange && onChatChange(null);
  };

  const send = (override) => {
    const text = (override ?? input).trim();
    if (!text || loading) return;
    setInput('');
    setLoading(true);

    const userMsg = { role: 'user', text };
    const prevMsgs = messages.filter(m => m.role !== 'assistant' || m.text); // exclude empty welcome
    // If prevMsgs only has the welcome, start fresh
    const historyMsgs = prevMsgs[0]?.role === 'assistant' && !activeId ? [] : prevMsgs;
    const newMsgs = [...historyMsgs, userMsg];
    const assistantMsg = { role: 'assistant', text: '' };

    setMessages([...newMsgs, assistantMsg]);

    // Stream buffer — accumulates full assistant reply
    let accumulated = '';
    const controller = new AbortController();
    abortRef.current = controller;

    const apiMessages = newMsgs.map(m => ({ role: m.role, content: m.text }));

    streamChat({
      messages: apiMessages,
      conversationId: activeId,
      signal: controller.signal,
      onChunk: (chunk) => {
        accumulated += chunk;
        setMessages(prev => {
          const next = [...prev];
          next[next.length - 1] = { role: 'assistant', text: accumulated };
          return next;
        });
      },
      onDone: async () => {
        setLoading(false);
        const finalMsgs = [...newMsgs, { role: 'assistant', text: accumulated }];
        try {
          if (activeId) {
            await apiFetch(`/chats/${activeId}`, 'PATCH', { messages: finalMsgs });
            setRecents(prev => prev.map(c => c._id === activeId ? { ...c, updatedAt: new Date().toISOString() } : c));
          } else {
            const chat = await apiFetch('/chats', 'POST', {
              title: text.slice(0, 55),
              messages: finalMsgs,
            });
            setActiveId(chat._id);
            setRecents(prev => [chat, ...prev]);
            onChatChange && onChatChange(chat._id);
          }
        } catch {}
      },
      onError: (err) => {
        setMessages(prev => {
          const next = [...prev];
          next[next.length - 1] = { role: 'assistant', text: `Error: ${err}` };
          return next;
        });
        setLoading(false);
      },
    });
  };

  return (
    <>
      <PageHeader
        icon="chat"
        title="AI Chat"
        subtitle="Ask anything about ads, brands and creative"
        right={
          <>
            <button className="btn btn-stroke btn-sm">
              <Icon name="clock" size={14}/> History
            </button>
            <button className="btn btn-night btn-sm" onClick={newChat}>
              <Icon name="plus" size={14}/> New chat
            </button>
          </>
        }
      />

      <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
        {/* Sidebar */}
        <div style={{
          width: 248, borderRight: '1px solid var(--border)',
          padding: 16, display: 'flex', flexDirection: 'column', gap: 4,
          overflowY: 'auto', flexShrink: 0,
        }} className="scroll">
          <div style={{ fontSize: 11, fontWeight: 500, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', padding: '4px 8px 8px' }}>
            Recent chats
          </div>
          {recents.length === 0 && (
            <div style={{ fontSize: 12, color: 'var(--text-faint)', padding: '4px 10px' }}>No chats yet</div>
          )}
          {recents.map((r) => (
            <button key={r.id} onClick={() => selectChat(r.id)} className="nav-item"
              style={{
                background: activeId === r.id ? 'var(--bg-soft)' : 'transparent',
                color: activeId === r.id ? 'var(--text)' : 'var(--text-2)',
                fontWeight: activeId === r.id ? 500 : 400,
              }}>
              <Icon name="chat" size={14} style={{ color: 'var(--text-faint)' }}/>
              <span style={{ flex: 1, textAlign: 'left', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{r.title || 'New chat'}</span>
            </button>
          ))}
        </div>

        {/* Chat */}
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
          <div ref={scrollRef} className="scroll" style={{
            flex: 1, overflowY: 'auto',
            padding: '32px 0',
          }}>
            <div style={{ maxWidth: 760, margin: '0 auto', padding: '0 24px', display: 'flex', flexDirection: 'column', gap: 22 }}>
              {messages.map((m, i) => {
                const isLast = i === messages.length - 1;
                const isStreaming = loading && isLast && m.role === 'assistant';
                return (
                  <div key={i} style={{
                    display: 'flex', gap: 12,
                    alignSelf: m.role === 'user' ? 'flex-end' : 'flex-start',
                    maxWidth: '88%',
                  }}>
                    {m.role === 'assistant' && (
                      <div style={{
                        width: 32, height: 32, borderRadius: 9, flexShrink: 0,
                        background: 'linear-gradient(135deg, var(--accent), #6E8BFF)',
                        display: 'grid', placeItems: 'center', color: '#fff',
                        marginTop: 2,
                      }}>
                        <Icon name="sparkles" size={15}/>
                      </div>
                    )}
                    <div style={{
                      padding: '14px 18px',
                      borderRadius: 16,
                      background: m.role === 'user' ? 'var(--accent)' : 'var(--bg-surface)',
                      color: m.role === 'user' ? '#fff' : 'var(--text)',
                      fontSize: 14, lineHeight: 1.6,
                      border: m.role === 'assistant' ? '1px solid var(--border)' : 'none',
                      boxShadow: m.role === 'assistant' ? 'var(--shadow-card)' : 'none',
                    }}>
                      {m.text ? <MsgContent text={m.text}/> : isStreaming
                        ? <span style={{ display: 'inline-flex', gap: 4, alignItems: 'center', height: 20 }}>
                            {[0,1,2].map(d => <span key={d} style={{ width: 6, height: 6, borderRadius: '50%', background: 'var(--text-faint)', animation: `pulse 1s ease-in-out ${d*0.2}s infinite` }}/>)}
                          </span>
                        : null}
                    </div>
                  </div>
                );
              })}
            </div>
          </div>

          {/* Composer */}
          <div style={{ padding: '16px 200px 24px', borderTop: '1px solid var(--border)' }}>
            <div>
              <div style={{ display: 'flex', gap: 6, marginBottom: 10, flexWrap: 'wrap' }}>
                {['Analyze top 10 winners this week','Draft 5 hooks in Glossier voice','Compare Olipop vs Magic Spoon','Find products like Liquid I.V.'].map(s => (
                  <button key={s} className="chip" style={{ height: 28, fontSize: 12 }} onClick={() => send(s)}>
                    <Icon name="sparkles" size={11} style={{ color: 'var(--accent)' }}/>{s}
                  </button>
                ))}
              </div>
              <div className="fld" style={{
                height: 'auto', minHeight: 50, padding: '10px 8px 10px 16px',
                borderRadius: 14, alignItems: 'flex-end', width: '100%',
              }}>
                <Icon name="sparkles" size={15} style={{ color: 'var(--accent)', marginBottom: 6 }}/>
                <textarea
                  value={input} onChange={(e) => setInput(e.target.value)}
                  onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); }}}
                  placeholder="Message Radar AI…"
                  rows={1}
                  style={{
                    flex: 1, border: 0, outline: 0, background: 'transparent',
                    resize: 'none', padding: '5px 0', fontSize: 14, lineHeight: '22px',
                    maxHeight: 200, fontFamily: 'inherit',
                  }}/>
                <div style={{ display: 'flex', gap: 4 }}>
                  <button className="btn btn-ghost btn-icon" style={{ width: 32, height: 32 }} title="Attach">
                    <Icon name="attach" size={15}/>
                  </button>
                  <button className="btn btn-ghost btn-icon" style={{ width: 32, height: 32 }} title="Voice">
                    <Icon name="mic" size={15}/>
                  </button>
                  <button onClick={() => send()} disabled={loading || !input.trim()} className="btn btn-icon" style={{
                    width: 32, height: 32, background: 'var(--accent)', color: '#fff',
                    opacity: loading || !input.trim() ? 0.5 : 1,
                  }}>
                    <Icon name="send" size={14}/>
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

// ---- AI Image Generation ----
const MAX_ATTACHMENTS = 14;
const AI_IMAGE_MODELS = [
  { id: 'nano-banana-pro', label: 'Nano Banana Pro', desc: 'Highest quality · slower' },
  { id: 'nano-banana-2',   label: 'Nano Banana 2',   desc: 'Faster, balanced quality' },
];
const AI_IMAGE_QUALITIES = ['1K', '2K', '4K'];
const AI_IMAGE_ASPECTS = [
  { id: 'auto',  w: 18, h: 14, dashed: true },
  { id: '16:9',  w: 18, h: 10 },
  { id: '4:3',   w: 16, h: 12 },
  { id: '1:1',   w: 14, h: 14 },
  { id: '3:4',   w: 12, h: 16 },
  { id: '9:16',  w: 10, h: 18 },
];
const AI_IMAGE_COUNTS    = [1, 2, 3, 4];

const AspectGlyph = ({ w, h, dashed, color = 'var(--text-2)' }) => (
  <span style={{
    width: 20, height: 20, flexShrink: 0,
    display: 'inline-grid', placeItems: 'center',
  }}>
    <span style={{
      width: w, height: h,
      border: `1.5px ${dashed ? 'dashed' : 'solid'} ${color}`,
      borderRadius: 2,
    }}/>
  </span>
);

const usePromptLibrary = (storageKey) => {
  const load = () => {
    try { return JSON.parse(localStorage.getItem(storageKey) || '[]'); }
    catch { return []; }
  };
  const [prompts, setPrompts] = React.useState(load);

  const save = ({ text, name, attachments = [] }) => {
    const trimmed = text.trim();
    if (!trimmed) return;
    const entry = {
      id: `p-${Date.now()}`,
      text: trimmed,
      name: (name || '').trim() || trimmed.slice(0, 60),
      attachments, // [{ name, dataUrl }]
      savedAt: Date.now(),
    };
    setPrompts(prev => {
      const next = [entry, ...prev].slice(0, 30);
      try { localStorage.setItem(storageKey, JSON.stringify(next)); } catch {}
      return next;
    });
  };

  const remove = (id) => {
    setPrompts(prev => {
      const next = prev.filter(p => p.id !== id);
      try { localStorage.setItem(storageKey, JSON.stringify(next)); } catch {}
      return next;
    });
  };

  const isSaved = (text, currentAttachments = []) => {
    const trimmed = text.trim();
    const currentNames = currentAttachments.map(a => a.name).sort().join('\0');
    return prompts.some(p => {
      if (p.text !== trimmed) return false;
      const savedNames = (p.attachments || []).map(a => a.name).sort().join('\0');
      return savedNames === currentNames;
    });
  };

  return { prompts, save, remove, isSaved };
};

const useAIItems = () => {
  const [items, setItems] = React.useState([]);
  const [loaded, setLoaded] = React.useState(false);

  React.useEffect(() => {
    apiFetch('/images').then(imgs => {
      setItems(imgs.map(i => ({ ...i, id: i._id })));
      setLoaded(true);
    }).catch(() => setLoaded(true));
  }, []);

  const add = async (item) => {
    const defaultFolder = (window.SAVE_FOLDERS_V3 || []).find(f => f.isDefault);
    const folderId = item.folderId || defaultFolder?.id || null;
    const itemWithFolder = { ...item, folderId };
    // Optimistic UI
    setItems(prev => [{ ...itemWithFolder }, ...prev]);
    try {
      const saved = await apiFetch('/images', 'POST', {
        url: itemWithFolder.url,
        prompt: itemWithFolder.prompt,
        aspect: itemWithFolder.aspect,
        quality: itemWithFolder.quality,
        provider: itemWithFolder.provider,
        folderId,
        type: itemWithFolder.type || 'image',
      });
      // Replace optimistic entry with DB id
      setItems(prev => prev.map(i => i.id === item.id ? { ...saved, id: saved._id } : i));
    } catch {}
  };

  const remove = async (id) => {
    setItems(prev => prev.filter(i => i.id !== id));
    try { await apiFetch(`/images/${id}`, 'DELETE'); } catch {}
  };

  return { items, add, remove, loaded };
};

const FolderChipsBar = ({ selectedFolder, onSelect, aiItems, itemType }) => {
  const [folders, setFolders] = React.useState(() => window.SAVE_FOLDERS_V3 || []);

  React.useEffect(() => {
    const onUpdate = () => setFolders([...(window.SAVE_FOLDERS_V3 || [])]);
    window.addEventListener('folders-updated', onUpdate);
    if (window.loadFolders) window.loadFolders();
    return () => window.removeEventListener('folders-updated', onUpdate);
  }, []);

  const [pinnedFolders, setPinnedFolders] = React.useState(() => {
    const stored = localStorage.getItem('1r-ai-pinned');
    if (stored !== null) {
      try { return new Set(JSON.parse(stored)); } catch {}
    }
    return new Set((window.SAVE_FOLDERS_V3 || []).filter(f => !f.system && !f.parentId).slice(0, 3).map(f => f.id));
  });
  const [openChipMenu, setOpenChipMenu]   = React.useState(null);
  const [showPinPanel, setShowPinPanel]   = React.useState(false);
  const [confirmUnpin, setConfirmUnpin]   = React.useState(null); // folder id

  const togglePin = (id) => {
    setPinnedFolders(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      try { localStorage.setItem('1r-ai-pinned', JSON.stringify([...next])); } catch {}
      return next;
    });
  };

  const handlePin = (id) => {
    if (pinnedFolders.has(id)) {
      setConfirmUnpin(id);
    } else {
      togglePin(id);
    }
  };

  // Selected data + active root (parent if child selected)
  const selectedData    = selectedFolder ? folders.find(f => f.id === selectedFolder) : null;
  const activeRootId    = selectedData?.parentId ?? selectedData?.id ?? null;
  const activeRoot      = activeRootId ? folders.find(f => f.id === activeRootId) : null;

  // Pinned chips + active folder if not already pinned
  const visibleChips = [
    ...folders.filter(f => !f.system && pinnedFolders.has(f.id)),
    ...(activeRoot && !pinnedFolders.has(activeRoot.id) ? [activeRoot] : []),
  ].filter((f, i, a) => a.findIndex(x => x.id === f.id) === i);

  const itemCount = (folderId) => aiItems.items.filter(i => i.type === itemType && i.folderId === folderId).length;

  const chipWrap = (active) => ({
    height: 30, borderRadius: 999, display: 'inline-flex', alignItems: 'center', overflow: 'hidden',
    background: active ? 'var(--bg-surface)' : 'transparent',
    outline: `1px solid ${active ? 'var(--border)' : 'transparent'}`,
    boxShadow: active ? '0 1px 2px rgba(15,20,30,0.04)' : 'none',
  });
  const chipBtn = (active) => ({
    height: '100%', padding: '0 10px', gap: 5, display: 'inline-flex', alignItems: 'center',
    background: 'none', border: 0, cursor: 'pointer', fontFamily: 'inherit',
    fontSize: 12, fontWeight: 500, color: active ? 'var(--text)' : 'var(--text-muted)',
  });
  // Right-side controls wrapper (arrow + pin share a single left border)
  const ctrlWrap = {
    display: 'flex', alignItems: 'center', borderLeft: '1px solid var(--border)',
    height: '100%',
  };
  const ctrlBtn = (accent) => ({
    height: '100%', padding: '0 6px', display: 'grid', placeItems: 'center',
    background: 'none', border: 0, cursor: 'pointer',
    color: accent ? 'var(--accent)' : 'var(--text-faint)',
  });

  const ChildMenu = ({ f, children }) => openChipMenu !== f.id ? null : (
    <div style={{
      position: 'absolute', top: 'calc(100% + 5px)', left: 0, zIndex: 10,
      background: 'var(--bg-surface)', border: '1px solid var(--border)',
      borderRadius: 10, padding: 4, minWidth: 175,
      boxShadow: '0 8px 24px rgba(14,18,27,0.12)',
      display: 'flex', flexDirection: 'column', gap: 1,
    }}>
      <button onClick={() => { onSelect(f.id); setOpenChipMenu(null); }} style={{
        display: 'flex', alignItems: 'center', gap: 6, padding: '6px 10px',
        background: 'transparent', border: 0, borderRadius: 7,
        cursor: 'pointer', fontFamily: 'inherit', fontSize: 12,
        color: 'var(--text-2)', textAlign: 'left',
      }}
      onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-muted)'}
      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
        <Icon name={f.icon} size={12} style={{ color: f.color }}/> All in {f.name}
      </button>
      <div style={{ height: 1, background: 'var(--border)', margin: '2px 4px' }}/>
      {children.map(c => (
        <button key={c.id} onClick={() => { onSelect(c.id); setOpenChipMenu(null); }} style={{
          display: 'flex', alignItems: 'center', gap: 6, padding: '7px 10px 7px 18px',
          background: selectedFolder === c.id ? 'var(--bg-muted)' : 'transparent',
          border: 0, borderRadius: 7, cursor: 'pointer', fontFamily: 'inherit',
          fontSize: 13, color: 'var(--text)', textAlign: 'left',
        }}
        onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-muted)'}
        onMouseLeave={e => e.currentTarget.style.background = selectedFolder === c.id ? 'var(--bg-muted)' : 'transparent'}>
          <Icon name={c.icon} size={13} style={{ color: c.color || 'var(--text-faint)' }}/>
          <span style={{ flex: 1 }}>{c.name}</span>
          {itemCount(c.id) > 0 && <span style={{ fontSize: 10, color: 'var(--text-faint)' }}>{itemCount(c.id)}</span>}
        </button>
      ))}
    </div>
  );

  const renderTree = (parentId = null, depth = 0) =>
    folders.filter(f => !f.system && (f.parentId ?? null) === parentId).map(f => (
      <React.Fragment key={f.id}>
        <div style={{ display: 'flex', alignItems: 'center', borderRadius: 7, paddingLeft: 8 + depth * 14 }}
          onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-muted)'}
          onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
          <button onClick={() => { onSelect(f.id); setShowPinPanel(false); }} style={{
            flex: 1, display: 'flex', alignItems: 'center', gap: 7, padding: '6px 4px',
            background: 'none', border: 0, cursor: 'pointer', textAlign: 'left',
            color: selectedFolder === f.id ? 'var(--accent)' : 'var(--text)',
            fontFamily: 'inherit', fontSize: 13,
          }}>
            <Icon name={f.icon} size={13} style={{ color: f.color || 'var(--text-faint)', flexShrink: 0 }}/>
            <span style={{ flex: 1 }}>{f.name}</span>
            {itemCount(f.id) > 0 && <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{itemCount(f.id)}</span>}
          </button>
          <button onClick={() => togglePin(f.id)} title={pinnedFolders.has(f.id) ? 'Unpin' : 'Pin'} style={{
            width: 26, height: 26, display: 'grid', placeItems: 'center', flexShrink: 0,
            background: 'none', border: 0, cursor: 'pointer', borderRadius: 6, marginRight: 4,
            color: pinnedFolders.has(f.id) ? 'var(--accent)' : 'var(--text-faint)',
          }}
          onMouseEnter={e => e.currentTarget.style.color = 'var(--accent)'}
          onMouseLeave={e => e.currentTarget.style.color = pinnedFolders.has(f.id) ? 'var(--accent)' : 'var(--text-faint)'}>
            <Icon name="pin" size={12}/>
          </button>
        </div>
        {renderTree(f.id, depth + 1)}
      </React.Fragment>
    ));

  return (
    <>
    <div style={{ display: 'flex', gap: 5, alignItems: 'center' }}>
      {(openChipMenu || showPinPanel) && (
        <div onClick={() => { setOpenChipMenu(null); setShowPinPanel(false); }}
          style={{ position: 'fixed', inset: 0, zIndex: 8 }}/>
      )}

      {/* All */}
      <div style={chipWrap(selectedFolder === null)}>
        <button style={chipBtn(selectedFolder === null)} onClick={() => onSelect(null)}>
          <Icon name="grid" size={12}/> All
        </button>
      </div>

      {/* Pinned + active chips */}
      {visibleChips.map(f => {
        const children    = folders.filter(c => c.parentId === f.id);
        const hasChildren = children.length > 0;
        const activeChild = selectedData?.parentId === f.id && !pinnedFolders.has(selectedData.id) ? selectedData : null;
        const active      = selectedFolder === f.id || !!activeChild;
        const isPinned    = pinnedFolders.has(f.id);

        return (
          <div key={f.id} style={{ position: 'relative', zIndex: 9 }}>
            {activeChild ? (
              /* ── Breadcrumb chip: [Parent] › [Child] [child-pin] ── */
              (() => {
                const childPinned = pinnedFolders.has(activeChild.id);
                return (
                  <div style={chipWrap(true)}>
                    <button style={{ ...chipBtn(false), color: 'var(--text-muted)', paddingRight: 4 }}
                      onClick={() => { onSelect(f.id); setOpenChipMenu(null); setShowPinPanel(false); }}>
                      <Icon name={f.icon} size={12} style={{ color: f.color || 'var(--text-faint)' }}/>
                      {f.name}
                    </button>
                    <button style={{ height: '100%', padding: '0 3px', background: 'none', border: 0, cursor: 'pointer', color: 'var(--text-faint)', display: 'grid', placeItems: 'center' }}
                      onClick={(e) => { e.stopPropagation(); setOpenChipMenu(openChipMenu === f.id ? null : f.id); setShowPinPanel(false); }}>
                      <Icon name="arrow-right-s" size={13}/>
                    </button>
                    <button style={{ ...chipBtn(true), paddingLeft: 4, paddingRight: 8 }} onClick={() => {}}>
                      <Icon name={activeChild.icon} size={12} style={{ color: activeChild.color || 'var(--text-faint)' }}/>
                      {activeChild.name}
                    </button>
                    {/* Pin reflects child state — pinning makes the child its own chip */}
                    <div style={ctrlWrap}>
                      <button style={ctrlBtn(childPinned)} title={childPinned ? 'Unpin' : 'Pin to bar'}
                        onClick={(e) => { e.stopPropagation(); handlePin(activeChild.id); }}>
                        <Icon name="pin" size={10}/>
                      </button>
                    </div>
                  </div>
                );
              })()
            ) : (
              /* ── Normal chip: [Folder] [▾?] [pin] ── */
              <div style={chipWrap(active)}>
                <button style={{ ...chipBtn(active), paddingRight: 6 }} onClick={() => { onSelect(f.id); setOpenChipMenu(null); setShowPinPanel(false); }}>
                  <Icon name={f.icon} size={12} style={{ color: f.color || 'var(--text-faint)' }}/>
                  {f.name}
                  {itemCount(f.id) > 0 && <span style={{ fontSize: 10, color: 'var(--text-faint)' }}>{itemCount(f.id)}</span>}
                </button>
                <div style={ctrlWrap}>
                  {hasChildren && (
                    <button style={ctrlBtn(false)} onClick={(e) => { e.stopPropagation(); setOpenChipMenu(openChipMenu === f.id ? null : f.id); setShowPinPanel(false); }}>
                      <Icon name="arrow-down-s" size={11}/>
                    </button>
                  )}
                  <button style={ctrlBtn(isPinned)} title={isPinned ? 'Unpin' : 'Pin'}
                    onClick={(e) => { e.stopPropagation(); handlePin(f.id); }}>
                    <Icon name="pin" size={10}/>
                  </button>
                </div>
              </div>
            )}
            <ChildMenu f={f} children={children}/>
          </div>
        );
      })}

      {/* More / pin panel */}
      <div style={{ position: 'relative', zIndex: 9 }}>
        <div style={chipWrap(showPinPanel)}>
          <button style={chipBtn(showPinPanel)}
            onClick={() => { setShowPinPanel(v => !v); setOpenChipMenu(null); }}
            title="Browse & pin folders">
            <Icon name="plus" size={12}/>
          </button>
        </div>
        {showPinPanel && (
          <div style={{
            position: 'absolute', top: 'calc(100% + 5px)', left: 0, zIndex: 10,
            background: 'var(--bg-surface)', border: '1px solid var(--border)',
            borderRadius: 12, padding: '6px 4px', minWidth: 230,
            boxShadow: '0 8px 28px rgba(14,18,27,0.13)',
          }}>
            <div style={{ padding: '2px 10px 8px', fontSize: 11, fontWeight: 600, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
              Pin folders
            </div>
            <div className="scroll" style={{ maxHeight: 300, overflowY: 'auto' }}>
              {renderTree()}
            </div>
          </div>
        )}
      </div>
    </div>
    {/* Unpin confirmation dialog */}
    {confirmUnpin && (() => {
      const folder = folders.find(f => f.id === confirmUnpin);
      return (
        <div onClick={() => setConfirmUnpin(null)} style={{
          position: 'fixed', inset: 0, zIndex: 200,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          background: 'rgba(8,12,20,0.38)',
          backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
        }}>
          <div onClick={e => e.stopPropagation()} style={{
            background: 'var(--bg-surface)', borderRadius: 14, padding: 22,
            width: 320, maxWidth: 'calc(100vw - 40px)',
            boxShadow: '0 16px 48px rgba(14,18,27,0.2)',
            border: '1px solid var(--border)',
            display: 'flex', flexDirection: 'column', gap: 12,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 9 }}>
              <Icon name={folder?.icon} size={16} style={{ color: folder?.color || 'var(--text-faint)' }}/>
              <span style={{ fontWeight: 600, fontSize: 14, color: 'var(--text)' }}>
                Unpin "{folder?.name}"?
              </span>
            </div>
            <div style={{ fontSize: 13, color: 'var(--text-2)', lineHeight: 1.5 }}>
              This folder will no longer appear in the bar. You can re-pin it from the <strong>+</strong> menu.
            </div>
            <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
              <button onClick={() => setConfirmUnpin(null)} style={{
                height: 32, padding: '0 14px', borderRadius: 8,
                background: 'var(--bg-muted)', border: '1px solid var(--border)',
                color: 'var(--text)', fontSize: 13, fontWeight: 500,
                cursor: 'pointer', fontFamily: 'inherit',
              }}>Cancel</button>
              <button onClick={() => { togglePin(confirmUnpin); setConfirmUnpin(null); }} style={{
                height: 32, padding: '0 14px', borderRadius: 8,
                background: 'var(--accent)', border: 'none',
                color: 'var(--text-on-dark)', fontSize: 13, fontWeight: 600,
                cursor: 'pointer', fontFamily: 'inherit',
                boxShadow: '0 2px 8px -2px var(--accent-shadow)',
              }}>Unpin</button>
            </div>
          </div>
        </div>
      );
    })()}
    </>
  );
};

const AIImageV3 = () => {
  const [prompt, setPrompt] = React.useState('');
  const [aspect, setAspect] = React.useState('1:1');
  const [model, setModel]   = React.useState('nano-banana-pro');
  const [quality, setQuality] = React.useState('1K');
  const [count, setCount]   = React.useState(1);
  const [tab, setTab]       = React.useState('history');
  const [attachments, setAttachments] = React.useState([]); // [{id, url, name}]
  const [openMenu, setOpenMenu] = React.useState(null); // 'model' | 'quality' | 'aspect' | 'count' | null
  const [dragId, setDragId] = React.useState(null);
  const [dragOverId, setDragOverId] = React.useState(null);
  const [lightboxId, setLightboxId] = React.useState(null);
  const [saveDialog, setSaveDialog] = React.useState(null); // null | { name, includeAttachments }
  const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
  const [selectedFolder, setSelectedFolder] = React.useState(null);
  const [slots, setSlots] = React.useState([]); // [{ index, status, url, error, provider }]
  const [genError, setGenError] = React.useState('');
  const abortRef = React.useRef(null);
  const fileInputRef = React.useRef(null);
  const imgPrompts = usePromptLibrary('1r-img-prompts');
  const aiItems = useAIItems();

  React.useEffect(() => { if (openMenu !== 'prompts') setConfirmDeleteId(null); }, [openMenu]);

  const handleGenerate = async () => {
    if (!prompt.trim() || slots.some(s => s.status === 'generating' || s.status === 'queued')) return;
    setGenError('');

    const aspectRatio = aspect === 'auto' ? '1:1' : aspect;

    const formData = new FormData();
    formData.append('prompt', prompt.trim());
    formData.append('aspect_ratio', aspectRatio);
    formData.append('quality', quality);
    formData.append('count', String(count));
    for (const a of attachments) {
      const blob = await fetch(a.url).then(r => r.blob());
      formData.append('images', blob, a.name);
    }

    const token = localStorage.getItem('1radar_token');
    const controller = new AbortController();
    abortRef.current = controller;

    let response;
    try {
      response = await fetch(`${(window.APP_CONFIG && window.APP_CONFIG.API_BASE) || 'http://localhost:3001/api'}/image/generate`, {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${token}` },
        body: formData,
        signal: controller.signal,
      });
    } catch (err) {
      if (err.name !== 'AbortError') setGenError('Cannot reach the backend. Make sure it is running.');
      return;
    }

    if (!response.ok) {
      const data = await response.json().catch(() => ({}));
      setGenError(data.error || 'Generation failed');
      return;
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';

    const parseSSE = (chunk) => {
      buffer += chunk;
      const parts = buffer.split('\n\n');
      buffer = parts.pop();
      for (const block of parts) {
        let eventName = 'message';
        let dataStr = '';
        for (const line of block.split('\n')) {
          if (line.startsWith('event: ')) eventName = line.slice(7).trim();
          else if (line.startsWith('data: ')) dataStr = line.slice(6).trim();
        }
        if (!dataStr) continue;
        try {
          const data = JSON.parse(dataStr);
          if (eventName === 'start') {
            setSlots(Array.from({ length: data.count }, (_, i) => ({ index: i, status: 'queued' })));
          } else if (eventName === 'slot') {
            setSlots(s => s.map(slot => slot.index === data.index ? { ...slot, status: data.status } : slot));
          } else if (eventName === 'result') {
            setSlots(s => s.map(slot => slot.index === data.index ? { ...slot, status: 'done', url: data.url, provider: data.provider } : slot));
            aiItems.add({
              id: `ai-${Date.now()}-${data.index}`,
              type: 'image',
              folderId: selectedFolder,
              prompt: prompt.trim(),
              url: data.url,
              aspect: aspectRatio,
              quality: data.quality,
              provider: data.provider,
              createdAt: Date.now(),
            });
          } else if (eventName === 'result_error') {
            setSlots(s => s.map(slot => slot.index === data.index ? { ...slot, status: 'error', error: data.message } : slot));
          } else if (eventName === 'done') {
            setTimeout(() => setSlots([]), 2000);
          } else if (eventName === 'error') {
            setGenError(data.message || 'Generation error');
            setSlots([]);
          }
        } catch {}
      }
    };

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      parseSSE(decoder.decode(value, { stream: true }));
    }
  };

  const blobToDataUrl = (url) =>
    fetch(url).then(r => r.blob()).then(b => new Promise((res, rej) => {
      const fr = new FileReader(); fr.onload = () => res(fr.result); fr.onerror = rej; fr.readAsDataURL(b);
    }));

  const handleImgSave = async () => {
    let savedAttachments = [];
    if (saveDialog.includeAttachments && attachments.length > 0) {
      const results = await Promise.allSettled(
        attachments.map(a => blobToDataUrl(a.url).then(dataUrl => ({ name: a.name, dataUrl })))
      );
      savedAttachments = results.filter(r => r.status === 'fulfilled').map(r => r.value);
    }
    imgPrompts.save({ text: prompt, name: saveDialog.name, attachments: savedAttachments });
    setSaveDialog(null);
  };

  const applyImgPrompt = (p) => {
    setPrompt(p.text);
    if (p.attachments?.length > 0) {
      setAttachments(p.attachments.map(a => ({
        id: `r-${Date.now()}-${Math.random().toString(36).slice(2,5)}`,
        url: a.dataUrl,
        name: a.name,
      })));
    }
    setOpenMenu(null);
  };

  React.useEffect(() => {
    if (!lightboxId) return;
    const onKey = (e) => { if (e.key === 'Escape') setLightboxId(null); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [lightboxId]);

  const lightboxItem = lightboxId ? attachments.find(a => a.id === lightboxId) : null;

  const modelLabel = AI_IMAGE_MODELS.find(m => m.id === model)?.label ?? '';

  const addAttachments = (files) => {
    const slots = MAX_ATTACHMENTS - attachments.length;
    const accepted = Array.from(files)
      .filter(f => f.type.startsWith('image/'))
      .slice(0, slots)
      .map(f => ({
        id: `${f.name}-${f.lastModified}-${Math.random().toString(36).slice(2,7)}`,
        url: URL.createObjectURL(f),
        name: f.name,
      }));
    if (accepted.length) setAttachments(a => [...a, ...accepted]);
  };
  const removeAttachment = (id) => setAttachments(a => {
    const target = a.find(x => x.id === id);
    if (target) URL.revokeObjectURL(target.url);
    return a.filter(x => x.id !== id);
  });
  const reorderAttachments = (sourceId, targetId) => {
    if (!sourceId || sourceId === targetId) return;
    setAttachments(a => {
      const from = a.findIndex(x => x.id === sourceId);
      const to   = a.findIndex(x => x.id === targetId);
      if (from < 0 || to < 0) return a;
      const next = a.slice();
      const [moved] = next.splice(from, 1);
      next.splice(to, 0, moved);
      return next;
    });
  };

  React.useEffect(() => () => attachments.forEach(a => URL.revokeObjectURL(a.url)), []); // cleanup on unmount

  // Generic chip + popover for the toolbar
  const MenuChip = ({ id, icon, label, children, minWidth = 180 }) => {
    const open = openMenu === id;
    return (
      <div style={{ position: 'relative' }}>
        <button onClick={() => setOpenMenu(open ? null : id)} className="chip" style={{
          height: 30, padding: '0 10px', gap: 6, fontSize: 12, fontWeight: 500,
          borderRadius: 9,
          background: open ? 'rgba(255,255,255,0.85)' : 'rgba(255,255,255,0.55)',
          border: `1px solid ${open ? 'rgba(15,20,30,0.14)' : 'rgba(15,20,30,0.08)'}`,
          color: 'var(--text)',
          backdropFilter: 'blur(8px)',
        }}>
          {icon && <Icon name={icon} size={12} style={{ color: 'var(--text-2)' }}/>}
          {label}
          <Icon name="arrow-up-s" size={12} style={{ color: 'var(--text-faint)' }}/>
        </button>
        {open && (
          <>
            <div onClick={() => setOpenMenu(null)} style={{ position: 'fixed', inset: 0, zIndex: 60 }}/>
            <div role="menu" style={{
              position: 'absolute', bottom: 'calc(100% + 6px)', left: 0,
              minWidth, zIndex: 61,
              background: 'var(--bg-surface)',
              border: '1px solid var(--border)',
              borderRadius: 12,
              boxShadow: '0 12px 32px rgba(14,18,27,0.12)',
              padding: 6,
              display: 'flex', flexDirection: 'column', gap: 2,
            }}>
              {children}
            </div>
          </>
        )}
      </div>
    );
  };

  const MenuItem = ({ active, onClick, children }) => (
    <button onClick={() => { onClick(); setOpenMenu(null); }} style={{
      display: 'flex', alignItems: 'center', gap: 10,
      width: '100%', padding: '8px 10px',
      background: active ? 'var(--bg-muted)' : 'transparent',
      border: 0, borderRadius: 8,
      color: 'var(--text)', fontSize: 13, textAlign: 'left',
      cursor: 'pointer', fontFamily: 'inherit',
    }}
    onMouseEnter={(e) => e.currentTarget.style.background = 'var(--bg-muted)'}
    onMouseLeave={(e) => e.currentTarget.style.background = active ? 'var(--bg-muted)' : 'transparent'}>
      {children}
    </button>
  );

  return (
    <>
      <PageHeader
        icon="image-ai"
        title="AI Image Generation"
        subtitle="Render product shots, hero images and ad creative"
      />

      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column', position: 'relative', overflow: 'hidden',
        background: 'var(--bg-soft)',
      }}>
        {/* Chips header */}
        <div style={{
          padding: '10px 16px', flexShrink: 0,
          borderBottom: '1px solid var(--border)',
          background: 'var(--bg-soft)',
        }}>
          <FolderChipsBar
            selectedFolder={selectedFolder}
            onSelect={setSelectedFolder}
            aiItems={aiItems}
            itemType="image"
          />
        </div>

        {/* Image grid */}
        {(() => {
          const imgs = aiItems.items.filter(i => i.type === 'image' && (selectedFolder === null || i.folderId === selectedFolder));
          const hasContent = imgs.length > 0 || slots.length > 0;
          return (
            <div className="scroll" style={{ flex: 1, overflowY: 'auto', padding: '16px 16px 120px' }}>

              {/* Error banner */}
              {genError && (
                <div style={{
                  background: 'color-mix(in srgb, var(--danger) 10%, transparent)',
                  border: '1px solid color-mix(in srgb, var(--danger) 25%, transparent)',
                  borderRadius: 10, padding: '10px 14px', marginBottom: 12,
                  fontSize: 13, color: 'var(--danger)',
                  display: 'flex', alignItems: 'center', justifyContent: 'space-between',
                }}>
                  {genError}
                  <button onClick={() => setGenError('')} style={{ background: 'none', border: 0, cursor: 'pointer', color: 'var(--danger)', display: 'flex' }}>
                    <Icon name="close" size={14}/>
                  </button>
                </div>
              )}

              {hasContent ? (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8 }}>

                  {/* Generating slots */}
                  {slots.map(slot => (
                    <div key={`slot-${slot.index}`} style={{
                      aspectRatio: '1/1.15', borderRadius: 10, overflow: 'hidden',
                      position: 'relative',
                      background: slot.status === 'error'
                        ? 'color-mix(in srgb, var(--danger) 10%, var(--bg-soft))'
                        : 'var(--bg-soft)',
                      border: `1px solid ${slot.status === 'error' ? 'color-mix(in srgb, var(--danger) 25%, transparent)' : 'var(--border)'}`,
                      display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 8,
                    }}>
                      {slot.status === 'done' && slot.url ? (
                        <img src={slot.url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', position: 'absolute', inset: 0 }}/>
                      ) : slot.status === 'error' ? (
                        <>
                          <Icon name="x" size={20} style={{ color: 'var(--danger)' }}/>
                          <span style={{ fontSize: 11, color: 'var(--danger)', textAlign: 'center', padding: '0 8px', lineHeight: 1.4 }}>{slot.error || 'Failed'}</span>
                        </>
                      ) : (
                        <>
                          <div style={{
                            width: 28, height: 28, borderRadius: '50%',
                            border: '2px solid var(--accent)',
                            borderTopColor: 'transparent',
                            animation: 'spin 0.8s linear infinite',
                          }}/>
                          <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>
                            {slot.status === 'queued' ? 'Queued…' : 'Generating…'}
                          </span>
                        </>
                      )}
                    </div>
                  ))}

                  {/* Generated images */}
                  {imgs.map(item => (
                    <div key={item.id} style={{
                      aspectRatio: '1/1.15', borderRadius: 10, overflow: 'hidden',
                      position: 'relative', cursor: 'pointer',
                      background: item.url ? 'var(--bg-soft)' : AD_THUMBS[(item.thumbIndex || 0) % AD_THUMBS.length],
                    }}>
                      {item.url && (
                        <img src={item.url} alt={item.prompt || ''} style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
                      )}
                      {item.prompt && (
                        <div style={{
                          position: 'absolute', bottom: 0, left: 0, right: 0,
                          padding: '24px 8px 8px',
                          background: 'linear-gradient(transparent, rgba(10,12,20,0.72))',
                          color: '#fff', fontSize: 11, lineHeight: 1.4,
                          overflow: 'hidden', textOverflow: 'ellipsis',
                          display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical',
                          opacity: 0, transition: 'opacity 160ms',
                        }}
                        onMouseEnter={e => e.currentTarget.style.opacity = 1}
                        onMouseLeave={e => e.currentTarget.style.opacity = 0}>
                          {item.prompt}
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              ) : selectedFolder ? (
                <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '60%', gap: 10, color: 'var(--text-faint)' }}>
                  <Icon name="image-ai" size={32}/>
                  <span style={{ fontSize: 14, color: 'var(--text-2)' }}>No images in this folder yet</span>
                  <span style={{ fontSize: 12 }}>Generate something and it will appear here</span>
                </div>
              ) : (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8 }}>
                  {Array.from({ length: 8 }).map((_, i) => (
                    <div key={i} style={{ aspectRatio: '1/1.15', borderRadius: 10, background: AD_THUMBS[i % AD_THUMBS.length] }}/>
                  ))}
                </div>
              )}
            </div>
          );
        })()}

        {/* Floating prompt bar — liquid glass */}
        <div style={{
          position: 'absolute', left: '50%', bottom: 20,
          transform: 'translateX(-50%)',
          width: 'min(880px, calc(100% - 48px))',
          background: 'rgba(255,255,255,0.86)',
          color: 'var(--text)',
          borderRadius: 18,
          padding: '12px 12px 12px 16px',
          display: 'flex', flexDirection: 'column', gap: 10,
          backdropFilter: 'blur(24px) saturate(180%)',
          WebkitBackdropFilter: 'blur(24px) saturate(180%)',
          boxShadow: '0 24px 48px -16px rgba(15,20,30,0.18), 0 4px 14px -4px rgba(15,20,30,0.08), inset 0 1px 0 rgba(255,255,255,0.9)',
          border: '1px solid rgba(255,255,255,0.8)',
          zIndex: 3,
        }}>
          {/* Attachments strip */}
          {attachments.length > 0 && (
            <div style={{
              display: 'flex', gap: 6, flexWrap: 'wrap',
              paddingBottom: 4,
            }}>
              {attachments.map(a => {
                const isDragging = dragId === a.id;
                return (
                  <div key={a.id}
                    draggable
                    role="button"
                    tabIndex={0}
                    onClick={() => { if (!dragId) setLightboxId(a.id); }}
                    onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setLightboxId(a.id); } }}
                    onDragStart={(e) => {
                      setDragId(a.id);
                      e.dataTransfer.effectAllowed = 'move';
                      try { e.dataTransfer.setData('text/plain', a.id); } catch {}
                    }}
                    onDragEnter={() => {
                      if (dragId && dragId !== a.id) reorderAttachments(dragId, a.id);
                    }}
                    onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }}
                    onDrop={(e) => { e.preventDefault(); setDragId(null); }}
                    onDragEnd={() => setDragId(null)}
                    style={{
                      position: 'relative', width: 56, height: 56,
                      borderRadius: 10, overflow: 'hidden',
                      border: `1px solid ${isDragging ? 'var(--accent)' : 'rgba(15,20,30,0.08)'}`,
                      boxShadow: isDragging ? '0 0 0 2px var(--accent-glow)' : 'none',
                      background: `center/cover no-repeat url(${a.url})`,
                      opacity: isDragging ? 0.55 : 1,
                      cursor: dragId ? 'grabbing' : 'pointer',
                      transition: 'transform 160ms ease, box-shadow 120ms ease, opacity 120ms ease',
                    }} title={a.name}>
                    <button onMouseDown={(e) => e.stopPropagation()}
                            onClick={(e) => { e.stopPropagation(); removeAttachment(a.id); }}
                            draggable={false}
                            onDragStart={(e) => e.preventDefault()}
                            style={{
                      position: 'absolute', top: 3, right: 3,
                      width: 18, height: 18, borderRadius: 999,
                      background: 'rgba(14,18,27,0.75)', color: '#fff',
                      border: 0, padding: 0, cursor: 'pointer',
                      display: 'grid', placeItems: 'center',
                    }}>
                      <Icon name="close" size={10}/>
                    </button>
                  </div>
                );
              })}
              <span style={{
                fontSize: 11, color: 'var(--text-faint)',
                alignSelf: 'center', marginLeft: 4,
              }}>{attachments.length}/{MAX_ATTACHMENTS}</span>
            </div>
          )}

          {/* Prompt input row */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <input ref={fileInputRef} type="file" accept="image/*" multiple
                   style={{ display: 'none' }}
                   onChange={(e) => { addAttachments(e.target.files); e.target.value = ''; }}/>
            <button
              onClick={() => fileInputRef.current?.click()}
              disabled={attachments.length >= MAX_ATTACHMENTS}
              title={attachments.length >= MAX_ATTACHMENTS ? `Max ${MAX_ATTACHMENTS} images` : 'Attach images'}
              style={{
                width: 28, height: 28, padding: 0, flexShrink: 0,
                borderRadius: 8,
                background: 'rgba(255,255,255,0.55)',
                border: '1px solid rgba(15,20,30,0.08)',
                color: 'var(--text-2)',
                display: 'grid', placeItems: 'center',
                cursor: attachments.length >= MAX_ATTACHMENTS ? 'not-allowed' : 'pointer',
                opacity: attachments.length >= MAX_ATTACHMENTS ? 0.5 : 1,
              }}>
              <Icon name="plus" size={14}/>
            </button>
            <input
              value={prompt}
              onChange={(e) => setPrompt(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleGenerate(); } }}
              placeholder="Describe the image you want to imagine"
              style={{
                flex: 1, height: 28,
                background: 'transparent', border: 'none', outline: 'none',
                color: 'var(--text)', fontSize: 14, fontFamily: 'inherit',
              }}/>
            {prompt.trim() && (
              <button
                onClick={() => {
                  const saved = imgPrompts.isSaved(prompt, attachments);
                  if (saved) {
                    const currentNames = attachments.map(a => a.name).sort().join('\0');
                    const entry = imgPrompts.prompts.find(p => p.text === prompt.trim() && (p.attachments||[]).map(a=>a.name).sort().join('\0') === currentNames);
                    setSaveDialog({ mode: 'unsave', entry });
                  } else {
                    setSaveDialog({ mode: 'save', name: prompt.trim().slice(0, 60), includeAttachments: attachments.length > 0 });
                  }
                }}
                title={imgPrompts.isSaved(prompt, attachments) ? 'Remove from library' : 'Save prompt'}
                style={{
                  height: 28, padding: '0 10px', flexShrink: 0, gap: 5,
                  borderRadius: 8,
                  background: imgPrompts.isSaved(prompt, attachments) ? 'rgba(99,102,241,0.1)' : 'rgba(255,255,255,0.7)',
                  border: `1px solid ${imgPrompts.isSaved(prompt, attachments) ? 'var(--accent)' : 'rgba(15,20,30,0.12)'}`,
                  color: imgPrompts.isSaved(prompt, attachments) ? 'var(--accent)' : 'var(--text-2)',
                  display: 'inline-flex', alignItems: 'center', cursor: 'pointer',
                  fontSize: 12, fontWeight: 500, fontFamily: 'inherit',
                  boxShadow: '0 1px 2px rgba(15,20,30,0.04)',
                  transition: 'all 140ms ease',
                }}>
                <Icon name="bookmark" size={12}
                      style={{ fill: imgPrompts.isSaved(prompt, attachments) ? 'currentColor' : 'none' }}/>
                {imgPrompts.isSaved(prompt, attachments) ? 'Saved' : 'Save'}
              </button>
            )}
          </div>

          {/* Toolbar row */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            {/* Model */}
            <MenuChip id="model" label={modelLabel} minWidth={220}>
              {AI_IMAGE_MODELS.map(m => (
                <MenuItem key={m.id} active={model === m.id} onClick={() => setModel(m.id)}>
                  <span style={{
                    width: 16, height: 16, borderRadius: 4, flexShrink: 0,
                    background: 'linear-gradient(135deg,#FFE08A,#E0A234)',
                  }}/>
                  <span style={{ display: 'flex', flexDirection: 'column' }}>
                    <span style={{ fontWeight: 500 }}>{m.label}</span>
                    <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{m.desc}</span>
                  </span>
                  {model === m.id && <Icon name="check" size={14} style={{ marginLeft: 'auto', color: 'var(--accent)' }}/>}
                </MenuItem>
              ))}
            </MenuChip>

            {/* Quality */}
            <MenuChip id="quality" icon="sparkles" label={quality} minWidth={120}>
              {AI_IMAGE_QUALITIES.map(q => (
                <MenuItem key={q} active={quality === q} onClick={() => setQuality(q)}>
                  <span style={{ flex: 1 }}>{q}</span>
                  {quality === q && <Icon name="check" size={14} style={{ color: 'var(--accent)' }}/>}
                </MenuItem>
              ))}
            </MenuChip>

            {/* Aspect ratio */}
            <MenuChip
              id="aspect"
              minWidth={160}
              label={
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                  <AspectGlyph {...(AI_IMAGE_ASPECTS.find(a => a.id === aspect) ?? AI_IMAGE_ASPECTS[0])}/>
                  {aspect === 'auto' ? 'Auto' : aspect}
                </span>
              }>
              {AI_IMAGE_ASPECTS.map(a => (
                <MenuItem key={a.id} active={aspect === a.id} onClick={() => setAspect(a.id)}>
                  <AspectGlyph {...a} color={aspect === a.id ? 'var(--accent)' : 'var(--text-2)'}/>
                  <span style={{ flex: 1 }}>{a.id === 'auto' ? 'Auto' : a.id}</span>
                  {aspect === a.id && <Icon name="check" size={14} style={{ color: 'var(--accent)' }}/>}
                </MenuItem>
              ))}
            </MenuChip>

            {/* Image count stepper */}
            <div style={{
              display: 'inline-flex', alignItems: 'center',
              height: 30, borderRadius: 9,
              background: 'rgba(255,255,255,0.55)',
              border: '1px solid rgba(15,20,30,0.08)',
              backdropFilter: 'blur(8px)',
              overflow: 'hidden',
            }}>
              <button
                onClick={() => setCount(c => Math.max(1, c - 1))}
                disabled={count <= 1}
                aria-label="Decrease"
                style={{
                  width: 28, height: 30, padding: 0, border: 0,
                  background: 'transparent',
                  color: count <= 1 ? 'var(--text-faint)' : 'var(--text-2)',
                  cursor: count <= 1 ? 'not-allowed' : 'pointer',
                  display: 'grid', placeItems: 'center',
                }}>
                <Icon name="minus" size={12}/>
              </button>
              <input
                type="number"
                min={1} max={4}
                value={count}
                onChange={(e) => {
                  const v = parseInt(e.target.value, 10);
                  if (Number.isNaN(v)) return;
                  setCount(Math.max(1, Math.min(4, v)));
                }}
                aria-label="Number of images"
                style={{
                  width: 30, height: 30, padding: 0, border: 0,
                  background: 'transparent', textAlign: 'center',
                  fontSize: 12, fontWeight: 500, color: 'var(--text)',
                  fontFamily: 'inherit', outline: 'none',
                  MozAppearance: 'textfield',
                }}
                onWheel={(e) => e.currentTarget.blur()}
              />
              <button
                onClick={() => setCount(c => Math.min(4, c + 1))}
                disabled={count >= 4}
                aria-label="Increase"
                style={{
                  width: 28, height: 30, padding: 0, border: 0,
                  background: 'transparent',
                  color: count >= 4 ? 'var(--text-faint)' : 'var(--text-2)',
                  cursor: count >= 4 ? 'not-allowed' : 'pointer',
                  display: 'grid', placeItems: 'center',
                }}>
                <Icon name="plus" size={12}/>
              </button>
            </div>

            {/* Saved prompts */}
            {imgPrompts.prompts.length > 0 && (
              <MenuChip id="prompts" icon="bookmark" label={`${imgPrompts.prompts.length}`} minWidth={340}>
                <div className="scroll" style={{ maxHeight: 240, overflowY: 'auto' }}>
                  {imgPrompts.prompts.map(p => (
                    <div key={p.id} style={{ display: 'flex', alignItems: 'center', gap: 6, borderRadius: 8, padding: '2px 6px 2px 10px',
                      background: confirmDeleteId === p.id ? 'var(--bg-muted)' : 'transparent' }}
                      onMouseEnter={e => { if (confirmDeleteId !== p.id) e.currentTarget.style.background = 'var(--bg-muted)'; }}
                      onMouseLeave={e => { if (confirmDeleteId !== p.id) e.currentTarget.style.background = 'transparent'; }}>
                      {confirmDeleteId === p.id ? (
                        <>
                          <span style={{ flex: 1, fontSize: 12, color: 'var(--text-2)', padding: '8px 0',
                            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                            Delete "{p.name}"?
                          </span>
                          <button onClick={e => { e.stopPropagation(); imgPrompts.remove(p.id); setConfirmDeleteId(null); }} style={{
                            height: 24, padding: '0 8px', borderRadius: 6, border: 0, flexShrink: 0,
                            background: '#ef4444', color: '#fff', fontSize: 11, fontWeight: 600,
                            cursor: 'pointer', fontFamily: 'inherit',
                          }}>Delete</button>
                          <button onClick={e => { e.stopPropagation(); setConfirmDeleteId(null); }} style={{
                            height: 24, padding: '0 8px', borderRadius: 6, flexShrink: 0,
                            background: 'transparent', border: '1px solid var(--border)',
                            color: 'var(--text-2)', fontSize: 11, fontWeight: 500,
                            cursor: 'pointer', fontFamily: 'inherit',
                          }}>Cancel</button>
                        </>
                      ) : (
                        <>
                          <button onClick={() => applyImgPrompt(p)} style={{
                            flex: 1, background: 'transparent', border: 0, padding: '7px 0',
                            color: 'var(--text)', fontSize: 12, fontFamily: 'inherit',
                            textAlign: 'left', cursor: 'pointer', minWidth: 0,
                          }}>
                            <div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontWeight: 500 }}>
                              {p.name}
                            </div>
                            {p.attachments?.length > 0 && (
                              <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>
                                {p.attachments.length} image{p.attachments.length > 1 ? 's' : ''} saved
                              </div>
                            )}
                          </button>
                          <button onClick={e => { e.stopPropagation(); setConfirmDeleteId(p.id); }} title="Delete" style={{
                            width: 24, height: 24, padding: 0, flexShrink: 0, borderRadius: 6,
                            background: 'transparent', border: 0,
                            color: 'var(--text-faint)', display: 'grid', placeItems: 'center', cursor: 'pointer',
                          }}>
                            <Icon name="close" size={10}/>
                          </button>
                        </>
                      )}
                    </div>
                  ))}
                </div>
              </MenuChip>
            )}

            <div style={{ flex: 1 }}/>

            {/* Generate */}
            <button onClick={handleGenerate} disabled={!prompt.trim() || slots.length > 0} style={{
              height: 36, padding: '0 16px',
              borderRadius: 11,
              background: 'var(--accent)',
              border: 'none', color: 'var(--text-on-dark)',
              fontSize: 13, fontWeight: 600,
              display: 'inline-flex', alignItems: 'center', gap: 8,
              cursor: 'pointer',
              boxShadow: '0 4px 10px -2px var(--accent-shadow), inset 0 1px 0 rgba(255,255,255,0.18)',
            }}>
              <Icon name="sparkles" size={13}/> Generate
            </button>
          </div>
        </div>
      </div>

      {/* Save / unsave prompt dialog */}
      {saveDialog && (
        <div onClick={() => setSaveDialog(null)} style={{
          position: 'fixed', inset: 0, zIndex: 90,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          background: 'rgba(8,12,20,0.4)',
          backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
        }}>
          <div onClick={e => e.stopPropagation()} style={{
            background: 'var(--bg-surface)', borderRadius: 16, padding: 24,
            width: 420, maxWidth: 'calc(100vw - 48px)',
            boxShadow: '0 24px 60px -12px rgba(14,18,27,0.25)',
            border: '1px solid var(--border)',
            display: 'flex', flexDirection: 'column', gap: 16,
          }}>
            {saveDialog.mode === 'unsave' ? (
              <>
                <div style={{ fontWeight: 600, fontSize: 15, color: 'var(--text)' }}>Remove saved prompt</div>
                <div style={{ fontSize: 13, color: 'var(--text-2)', lineHeight: 1.5 }}>
                  Remove <span style={{ fontWeight: 600, color: 'var(--text)' }}>"{saveDialog.entry?.name}"</span> from your library?
                </div>
                <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                  <button onClick={() => setSaveDialog(null)} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: 'var(--bg-muted)', border: '1px solid var(--border)',
                    color: 'var(--text)', fontSize: 13, fontWeight: 500,
                    cursor: 'pointer', fontFamily: 'inherit',
                  }}>Cancel</button>
                  <button onClick={() => { imgPrompts.remove(saveDialog.entry.id); setSaveDialog(null); }} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: '#ef4444', border: 'none',
                    color: '#fff', fontSize: 13, fontWeight: 600,
                    cursor: 'pointer', fontFamily: 'inherit',
                  }}>Remove</button>
                </div>
              </>
            ) : (
              <>
                <div style={{ fontWeight: 600, fontSize: 15, color: 'var(--text)' }}>Save prompt</div>

                <div>
                  <label style={{ fontSize: 12, fontWeight: 500, color: 'var(--text-2)', display: 'block', marginBottom: 6 }}>Name</label>
                  <input
                    autoFocus
                    value={saveDialog.name}
                    onChange={e => setSaveDialog(d => ({ ...d, name: e.target.value }))}
                    onKeyDown={e => { if (e.key === 'Enter') handleImgSave(); if (e.key === 'Escape') setSaveDialog(null); }}
                    style={{
                      width: '100%', boxSizing: 'border-box',
                      padding: '8px 12px', borderRadius: 8,
                      border: '1px solid var(--border)',
                      background: 'var(--bg-muted)',
                      color: 'var(--text)', fontSize: 13, fontFamily: 'inherit', outline: 'none',
                    }}/>
                </div>

                <div style={{
                  padding: '10px 12px', borderRadius: 8, background: 'var(--bg-soft)',
                  fontSize: 12, color: 'var(--text-2)', lineHeight: 1.5,
                  display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical',
                  overflow: 'hidden',
                }}>{prompt}</div>

                {attachments.length > 0 && (
                  <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }}>
                    <input
                      type="checkbox"
                      checked={saveDialog.includeAttachments}
                      onChange={e => setSaveDialog(d => ({ ...d, includeAttachments: e.target.checked }))}
                      style={{ width: 16, height: 16, cursor: 'pointer', accentColor: 'var(--accent)', flexShrink: 0 }}/>
                    <span style={{ fontSize: 13, color: 'var(--text)' }}>
                      Save {attachments.length} reference image{attachments.length > 1 ? 's' : ''}
                    </span>
                  </label>
                )}

                <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                  <button onClick={() => setSaveDialog(null)} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: 'var(--bg-muted)', border: '1px solid var(--border)',
                    color: 'var(--text)', fontSize: 13, fontWeight: 500,
                    cursor: 'pointer', fontFamily: 'inherit',
                  }}>Cancel</button>
                  <button onClick={handleImgSave} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: 'var(--accent)', border: 'none',
                    color: 'var(--text-on-dark)', fontSize: 13, fontWeight: 600,
                    cursor: 'pointer', fontFamily: 'inherit',
                    boxShadow: '0 2px 8px -2px var(--accent-shadow)',
                  }}>Save</button>
                </div>
              </>
            )}
          </div>
        </div>
      )}

      {/* Lightbox */}
      {lightboxItem && (
        <div onClick={() => setLightboxId(null)}
             role="dialog" aria-modal="true"
             style={{
               position: 'fixed', inset: 0, zIndex: 80,
               background: 'rgba(8,12,20,0.78)',
               backdropFilter: 'blur(8px)',
               WebkitBackdropFilter: 'blur(8px)',
               display: 'flex', alignItems: 'center', justifyContent: 'center',
               padding: 32,
               cursor: 'zoom-out',
             }}>
          <img src={lightboxItem.url} alt={lightboxItem.name}
               onClick={(e) => e.stopPropagation()}
               style={{
                 display: 'block',
                 width: 'auto', height: 'auto',
                 maxWidth: 'calc(100vw - 64px)',
                 maxHeight: 'calc(100vh - 64px)',
                 objectFit: 'contain',
                 borderRadius: 12,
                 boxShadow: '0 24px 60px -16px rgba(0,0,0,0.6)',
                 cursor: 'default',
               }}/>
          <button onClick={(e) => { e.stopPropagation(); setLightboxId(null); }}
                  aria-label="Close"
                  style={{
                    position: 'absolute', top: 20, right: 20,
                    width: 36, height: 36, borderRadius: 999,
                    background: 'rgba(255,255,255,0.15)',
                    border: '1px solid rgba(255,255,255,0.2)',
                    color: '#fff',
                    display: 'grid', placeItems: 'center',
                    cursor: 'pointer',
                    backdropFilter: 'blur(6px)',
                  }}>
            <Icon name="close" size={18}/>
          </button>
          {lightboxItem.name && (
            <div style={{
              position: 'absolute', bottom: 20, left: '50%',
              transform: 'translateX(-50%)',
              padding: '6px 12px', borderRadius: 999,
              background: 'rgba(255,255,255,0.12)',
              border: '1px solid rgba(255,255,255,0.18)',
              color: '#fff', fontSize: 12, fontFamily: 'inherit',
              backdropFilter: 'blur(6px)',
              maxWidth: 'calc(100% - 64px)',
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            }}>{lightboxItem.name}</div>
          )}
        </div>
      )}
    </>
  );
};

// ---- Video Transcription ----
const TranscribeV3 = ({ initialId, onTranscriptOpen }) => {
  const items = [
    { id: 1, brand: 'Glossier', title: 'Morning routine — Sarah K.',     dur: '0:38', date: '2h ago', status: 'done',       words: 148 },
    { id: 2, brand: 'Olipop',   title: 'Gut-friendly soda explained',    dur: '1:12', date: '1d ago', status: 'done',       words: 312 },
    { id: 3, brand: 'Hims',     title: 'Hair regrowth before / after',   dur: '0:54', date: '3d ago', status: 'done',       words: 196 },
    { id: 4, brand: 'Magic Spoon', title: 'Cereal that hits different',  dur: '0:29', date: '3d ago', status: 'processing', words: 0   },
    { id: 5, brand: 'Caraway',  title: 'Why we ditched non-stick',       dur: '1:45', date: '5d ago', status: 'done',       words: 384 },
  ];
  const initialIdx = initialId != null
    ? Math.max(0, items.findIndex(it => String(it.id) === String(initialId)))
    : 0;
  const [view, setView] = React.useState(initialId != null ? 'detail' : 'entry');
  const [active, setActive] = React.useState(initialIdx);
  const [urlInput, setUrlInput] = React.useState('');
  const [isDragging, setIsDragging] = React.useState(false);

  const cur = items[active];

  const transcript = [
    { t: '0:00', speaker: 'Sarah', text: "Okay so I've been drinking this every morning for the last 90 days and I have to talk about it." },
    { t: '0:06', speaker: 'Sarah', text: "My energy in the afternoon — gone. The crash. Used to hit me at 2pm like a truck." },
    { t: '0:13', speaker: 'Sarah', text: "Now? Nothing. I'm just… on. And I'm not someone who shills supplements." },
    { t: '0:21', speaker: 'Sarah', text: "It's 75 ingredients. Vitamins, minerals, adaptogens, probiotics — all in one scoop." },
    { t: '0:29', speaker: 'Sarah', text: "Mix it with cold water, drink it on an empty stomach. That's the whole routine." },
    { t: '0:35', speaker: 'Sarah', text: "Link in bio if you want to try it. Use my code for a free travel pack." },
  ];

  const openItem = (i) => {
    setActive(i);
    setView('detail');
    onTranscriptOpen && onTranscriptOpen(items[i].id);
  };

  // ===== Entry view (default landing) =====
  if (view === 'entry') {
    return (
      <>
        <PageHeader
          icon="mic"
          title="Video Transcription"
          subtitle="Auto-transcribe Meta and TikTok video ads"
        />

        <div style={{ flex: 1, overflowY: 'auto' }} className="scroll">
          <div style={{ maxWidth: 920, margin: '0 auto', padding: '32px 24px 48px' }}>

            {/* Hero: Upload (top) + URL (bottom) */}
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16, marginBottom: 36 }}>
              {/* Upload dropzone — large */}
              <label
                onDragOver={(e) => { e.preventDefault(); setIsDragging(true); }}
                onDragLeave={() => setIsDragging(false)}
                onDrop={(e) => { e.preventDefault(); setIsDragging(false); }}
                style={{
                  position: 'relative',
                  display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
                  gap: 12, padding: '56px 32px', minHeight: 280,
                  borderRadius: 16,
                  border: `1.5px dashed ${isDragging ? 'var(--accent)' : 'var(--border)'}`,
                  background: isDragging ? 'var(--accent-soft)' : 'var(--bg-soft)',
                  cursor: 'pointer',
                  transition: 'background 0.15s, border-color 0.15s',
                }}
              >
                <input type="file" accept="video/*,audio/*" hidden/>
                <div style={{
                  width: 56, height: 56, borderRadius: 14,
                  background: 'var(--bg-surface)', border: '1px solid var(--border)',
                  display: 'grid', placeItems: 'center', color: 'var(--text-muted)',
                  marginBottom: 4,
                }}>
                  <Icon name="upload" size={24}/>
                </div>
                <div className="font-display" style={{ fontSize: 18, fontWeight: 600, color: 'var(--text)' }}>
                  Drop a video here
                </div>
                <div style={{ fontSize: 13, color: 'var(--text-faint)', textAlign: 'center', maxWidth: 320, lineHeight: 1.5 }}>
                  or click to browse — MP4, MOV, MP3, WAV up to 500 MB
                </div>
                <div style={{ marginTop: 8 }}>
                  <span className="btn btn-stroke btn-sm" style={{ pointerEvents: 'none' }}>
                    <Icon name="upload" size={13}/> Choose file
                  </span>
                </div>
              </label>

              {/* URL input — compact row below */}
              <div style={{
                display: 'flex', alignItems: 'center', gap: 10,
                padding: 12,
                borderRadius: 14,
                border: '1px solid var(--border)',
                background: 'var(--bg-surface)',
              }}>
                <Icon name="link" size={18} style={{ color: 'var(--text-faint)', flexShrink: 0 }}/>
                <input
                  placeholder="Paste a video URL — Meta Ad Library, TikTok, YouTube, Instagram"
                  value={urlInput}
                  onChange={(e) => setUrlInput(e.target.value)}
                  style={{
                    flex: 1, height: 40,
                    background: 'transparent', border: 0, outline: 0,
                    color: 'var(--text)', fontSize: 14, fontFamily: 'inherit',
                    minWidth: 0,
                  }}
                />
                <button className="btn btn-primary btn-lg" style={{ flexShrink: 0 }}>
                  <Icon name="sparkles" size={14}/> Transcribe
                </button>
              </div>
            </div>

            {/* History list */}
            <div>
              <div style={{
                fontSize: 11, fontWeight: 500, color: 'var(--text-faint)',
                textTransform: 'uppercase', letterSpacing: '0.06em',
                display: 'flex', alignItems: 'center', gap: 10, marginBottom: 12,
                padding: '0 4px',
              }}>
                <span>Recent transcriptions</span>
                <span style={{ fontFamily: 'var(--font-mono)' }}>{items.length}</span>
                <div style={{ flex: 1 }}/>
                <div className="fld" style={{ height: 28, padding: '0 10px', borderRadius: 999, width: 220 }}>
                  <Icon name="search" size={12} style={{ color: 'var(--text-faint)' }}/>
                  <input placeholder="Search history…" style={{ fontSize: 12 }}/>
                </div>
              </div>

              <div style={{
                border: '1px solid var(--border)',
                borderRadius: 12,
                background: 'var(--bg-surface)',
                overflow: 'hidden',
              }}>
                {items.map((it, i) => (
                  <button
                    key={it.id}
                    onClick={() => openItem(i)}
                    onMouseEnter={(e) => { e.currentTarget.style.background = 'var(--bg-soft)'; }}
                    onMouseLeave={(e) => { e.currentTarget.style.background = 'transparent'; }}
                    style={{
                      display: 'flex', alignItems: 'center', gap: 14,
                      padding: '14px 16px', width: '100%',
                      borderBottom: i < items.length - 1 ? '1px solid var(--border-soft)' : 'none',
                      background: 'transparent', border: 0, borderRadius: 0,
                      cursor: 'pointer', textAlign: 'left',
                      transition: 'background 0.1s',
                    }}>
                    <BrandChip name={it.brand} size={32} square/>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
                        <span style={{ fontSize: 11, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: 0.04 }}>{it.brand}</span>
                        <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>·</span>
                        <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{it.date}</span>
                      </div>
                      <div style={{ fontSize: 14, fontWeight: 500, color: 'var(--text)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{it.title}</div>
                    </div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
                      <div style={{ fontSize: 12, fontFamily: 'var(--font-mono)', color: 'var(--text-muted)', minWidth: 36, textAlign: 'right' }}>{it.dur}</div>
                      <div style={{ fontSize: 12, color: 'var(--text-faint)', minWidth: 70, textAlign: 'right' }}>
                        {it.words ? `${it.words} words` : '—'}
                      </div>
                      <div style={{ minWidth: 92, display: 'flex', justifyContent: 'flex-end' }}>
                        {it.status === 'processing' ? (
                          <span style={{ fontSize: 11, color: 'var(--accent)', display: 'inline-flex', alignItems: 'center', gap: 5 }}>
                            <span style={{ width: 5, height: 5, borderRadius: 999, background: 'var(--accent)', animation: 'pulse 1.2s infinite' }}/>
                            processing
                          </span>
                        ) : (
                          <span className="badge badge-green">done</span>
                        )}
                      </div>
                      <Icon name="chevron-right" size={14} style={{ color: 'var(--text-faint)' }}/>
                    </div>
                  </button>
                ))}
              </div>
            </div>

          </div>
        </div>
      </>
    );
  }

  // ===== Detail view (player + transcript) =====
  return (
    <>
      <PageHeader
        icon="mic"
        title="Video Transcription"
        subtitle="Auto-transcribe Meta and TikTok video ads"
      />

      <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>
        {/* Player + transcript */}
        <div style={{ display: 'flex', flexDirection: 'column', overflow: 'hidden', flex: 1 }}>
          {/* Breadcrumb back link */}
          <div style={{ padding: '14px 24px 0' }}>
            <button
              onClick={() => { setView('entry'); onTranscriptOpen && onTranscriptOpen(null); }}
              onMouseEnter={(e) => { e.currentTarget.style.color = 'var(--text)'; }}
              onMouseLeave={(e) => { e.currentTarget.style.color = 'var(--text-muted)'; }}
              style={{
                display: 'inline-flex', alignItems: 'center', gap: 6,
                background: 'transparent', border: 0, padding: '4px 8px 4px 0',
                color: 'var(--text-muted)', fontSize: 13, fontWeight: 500,
                cursor: 'pointer',
                transition: 'color 0.15s',
              }}>
              <Icon name="arrow-left-s" size={16}/> Back to history
            </button>
          </div>
          {/* Header */}
          <div style={{
            padding: '14px 24px 24px', display: 'flex', gap: 20,
            borderBottom: '1px solid var(--border)',
          }}>
            <div style={{
              width: 200, aspectRatio: '9/16', flexShrink: 0,
              borderRadius: 12, position: 'relative', overflow: 'hidden',
              background: 'linear-gradient(135deg, #1a1a2e, #2a2a4a)',
            }}>
              <div style={{ position: 'absolute', inset: 0, background: 'radial-gradient(circle at 30% 40%, rgba(51,92,255,0.4), transparent 60%)' }}/>
              <button style={{
                position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)',
                width: 50, height: 50, borderRadius: 999, background: '#fff',
                display: 'grid', placeItems: 'center', color: 'var(--text)', cursor: 'pointer',
                border: 0,
              }}>
                <Icon name="play" size={18}/>
              </button>
              <div style={{
                position: 'absolute', bottom: 10, left: 10, right: 10,
                fontSize: 11, color: '#fff', fontFamily: 'var(--font-mono)',
                display: 'flex', justifyContent: 'space-between',
              }}>
                <span>0:08</span><span>{cur.dur}</span>
              </div>
            </div>

            <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
              <div style={{ fontSize: 11, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: 0.05, marginBottom: 4 }}>{cur.brand}</div>
              <div className="font-display" style={{ fontWeight: 600, fontSize: 22, color: 'var(--text)', marginBottom: 12 }}>{cur.title}</div>
              <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 16 }}>
                <span className="badge badge-blue">UGC</span>
                <span className="badge badge-neutral">Talking head</span>
                <span className="badge badge-neutral">Morning routine</span>
                <span className="badge badge-neutral">EN · Whisper-large-v3</span>
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 16 }}>
                {[
                  { l: 'Duration',   v: cur.dur },
                  { l: 'Words',      v: cur.words },
                  { l: 'Speakers',   v: 1 },
                  { l: 'Confidence', v: '98%' },
                ].map((s, i) => (
                  <div key={i} style={{
                    padding: 12, borderRadius: 10,
                    background: 'var(--bg-soft)', border: '1px solid var(--border)',
                  }}>
                    <div style={{ fontSize: 11, color: 'var(--text-faint)', textTransform: 'uppercase', letterSpacing: 0.04 }}>{s.l}</div>
                    <div style={{ fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 18, marginTop: 2 }}>{s.v}</div>
                  </div>
                ))}
              </div>
              <div style={{ display: 'flex', gap: 6, marginTop: 'auto' }}>
                <button className="btn btn-stroke btn-sm"><Icon name="copy" size={13}/> Copy text</button>
                <button className="btn btn-stroke btn-sm"><Icon name="download" size={13}/> SRT</button>
                <button className="btn btn-stroke btn-sm"><Icon name="download" size={13}/> VTT</button>
                <button className="btn btn-primary btn-sm"><Icon name="sparkles" size={13}/> Analyze hook</button>
              </div>
            </div>
          </div>

          {/* Transcript */}
          <div style={{ flex: 1, overflowY: 'auto', padding: '20px 24px' }} className="scroll">
            {/* AI summary — above transcript */}
            <div style={{
              padding: 16, borderRadius: 12, marginBottom: 24,
              background: 'var(--accent-soft)',
              border: '1px solid var(--accent-soft)',
              fontSize: 13, lineHeight: 1.6, color: 'var(--text-2)',
            }}>
              <div style={{
                display: 'flex', alignItems: 'center', gap: 6, marginBottom: 8,
                color: 'var(--accent)', fontSize: 11, fontWeight: 600,
                textTransform: 'uppercase', letterSpacing: 0.04,
              }}>
                <Icon name="sparkles" size={12}/> AI summary
              </div>
              Hook lands at 0:00 with a personal-streak claim ("90 days"). The pivotal beat is at 0:13 — pivots from problem (afternoon crash) to outcome ("just on"). Closes with a 75-ingredients credentials list and a code-driven CTA.
            </div>

            <div style={{
              fontSize: 11, fontWeight: 500, color: 'var(--text-faint)',
              textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 12,
              display: 'flex', alignItems: 'center', gap: 10,
            }}>
              Transcript
              <span style={{ fontFamily: 'var(--font-mono)' }}>{transcript.length} segments</span>
              <div style={{ flex: 1 }}/>
              <div className="fld" style={{ height: 28, padding: '0 10px', borderRadius: 999, width: 200 }}>
                <Icon name="search" size={12} style={{ color: 'var(--text-faint)' }}/>
                <input placeholder="Search transcript…" style={{ fontSize: 12 }}/>
              </div>
            </div>
            {transcript.map((line, i) => (
              <div key={i} style={{
                display: 'flex', gap: 14, padding: '12px 0',
                borderBottom: i < transcript.length - 1 ? '1px solid var(--border-soft)' : 'none',
              }}>
                <button style={{
                  flexShrink: 0, fontSize: 11, fontFamily: 'var(--font-mono)',
                  color: 'var(--accent)', fontWeight: 500,
                  padding: '3px 8px', borderRadius: 6,
                  background: 'var(--accent-soft)',
                  alignSelf: 'flex-start',
                }}>{line.t}</button>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 11, color: 'var(--text-muted)', fontWeight: 500, marginBottom: 2 }}>{line.speaker}</div>
                  <div style={{ fontSize: 14, lineHeight: 1.6, color: 'var(--text)' }}>{line.text}</div>
                </div>
                <button className="btn btn-ghost btn-icon" style={{ width: 28, height: 28, alignSelf: 'flex-start' }}>
                  <Icon name="copy" size={13}/>
                </button>
              </div>
            ))}
          </div>
        </div>
      </div>
    </>
  );
};

// ---- Game: Winner or Loser ----
const GameV3 = () => {
  const [pair, setPair] = React.useState(0);
  const [score, setScore] = React.useState({ correct: 0, total: 0, streak: 0 });
  const [reveal, setReveal] = React.useState(null);

  const a = ADS_V3[(pair * 2) % ADS_V3.length];
  const b = ADS_V3[(pair * 2 + 1) % ADS_V3.length];
  const winner = a.estSpend > b.estSpend ? 'left' : 'right';

  const choose = (side) => {
    if (reveal) return;
    setReveal(side);
    const correct = side === winner;
    setScore(s => ({
      correct: s.correct + (correct ? 1 : 0),
      total: s.total + 1,
      streak: correct ? s.streak + 1 : 0,
    }));
    setTimeout(() => { setReveal(null); setPair(p => p + 1); }, 1500);
  };

  const Card = ({ ad, side }) => {
    const isWinner = side === winner;
    const showReveal = reveal === side;
    return (
      <div style={{
        background: 'var(--bg-surface)',
        borderRadius: 'var(--r-xl)',
        border: '1px solid var(--border)',
        boxShadow: 'var(--shadow-card)',
        overflow: 'hidden',
        position: 'relative',
        transition: 'all .35s ease',
        transform: showReveal ? 'scale(1.015)' : 'none',
        outline: showReveal ? `3px solid ${isWinner ? 'var(--success)' : 'var(--danger)'}` : 'none',
        outlineOffset: -1,
      }}>
        <div style={{
          aspectRatio: '4/5',
          background: ad.thumb,
          position: 'relative',
        }}>
          <div style={{
            position: 'absolute', inset: 0,
            background: 'linear-gradient(180deg, rgba(0,0,0,0) 50%, rgba(0,0,0,0.45))',
          }}/>
          <span className="badge" style={{
            position: 'absolute', top: 12, left: 12,
            background: 'rgba(14,18,27,0.7)', color: '#fff', backdropFilter: 'blur(6px)',
          }}>
            <Icon name={ad.type === 'Video' ? 'play' : 'image-ai'} size={10}/>
            {ad.type}
          </span>
          <div style={{
            position: 'absolute', left: 14, bottom: 14, color: '#fff',
            fontFamily: 'var(--font-display)', fontWeight: 600, fontSize: 22,
            letterSpacing: -0.01,
          }}>{ad.brand.split(' ')[0]}</div>

          {showReveal && (
            <div style={{
              position: 'absolute', inset: 0,
              background: isWinner ? 'rgba(16,158,91,0.25)' : 'rgba(220,53,69,0.25)',
              backdropFilter: 'blur(2px)',
              display: 'grid', placeItems: 'center',
            }}>
              <div style={{
                padding: '12px 22px', borderRadius: 999,
                background: '#fff',
                fontSize: 15, fontWeight: 700,
                color: isWinner ? 'var(--success)' : 'var(--danger)',
                boxShadow: '0 8px 24px rgba(14,18,27,0.20)',
                display: 'flex', alignItems: 'center', gap: 8,
              }}>
                <Icon name={isWinner ? 'thumbs-up' : 'flame'} size={18}/>
                {isWinner ? 'WINNER' : 'LOSER'}
              </div>
            </div>
          )}
        </div>
        <div style={{ padding: 16 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
            <BrandChip name={ad.brand} size={22} square/>
            <span style={{ fontSize: 13, fontWeight: 500 }}>{ad.brand}</span>
            <Icon name="check-circle" size={12} style={{ color: 'var(--accent)' }}/>
          </div>
          <div style={{
            fontSize: 13, color: 'var(--text-2)', lineHeight: 1.5,
            display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical',
            overflow: 'hidden', minHeight: 38,
          }}>{ad.title}</div>
          {showReveal && (
            <div style={{
              marginTop: 10, paddingTop: 10, borderTop: '1px solid var(--border-soft)',
              display: 'flex', justifyContent: 'space-between',
              fontSize: 12, color: 'var(--text-muted)',
            }}>
              <span>Spend: <b style={{ fontFamily: 'var(--font-mono)', color: 'var(--text)' }}>€{(ad.estSpend/1000).toFixed(1)}k</b></span>
              <span>Reach: <b style={{ fontFamily: 'var(--font-mono)', color: 'var(--text)' }}>{(ad.reach/1000).toFixed(0)}k</b></span>
              <span>{ad.daysActive}d active</span>
            </div>
          )}
        </div>
      </div>
    );
  };

  return (
    <>
      <PageHeader
        icon="gamepad"
        title="Winner or Loser"
        subtitle="Train your eye — pick the ad that actually scaled"
        right={
          <div style={{
            padding: '6px 14px', borderRadius: 999,
            background: 'var(--bg-soft)',
            display: 'flex', alignItems: 'center', gap: 14, height: 36,
          }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <Icon name="flame" size={14} style={{ color: '#F59E0B' }}/>
              <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 600 }}>{score.streak}</span>
              <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>streak</span>
            </div>
            <span style={{ width: 1, height: 16, background: 'var(--border)' }}/>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span style={{ fontFamily: 'var(--font-mono)', fontWeight: 600 }}>{score.correct}/{score.total}</span>
              <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>correct</span>
            </div>
          </div>
        }
      />

      <div style={{
        flex: 1, padding: '32px 24px', overflow: 'auto',
        display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 24,
      }} className="scroll">
        <div style={{ maxWidth: 600, textAlign: 'center', color: 'var(--text-muted)', fontSize: 14, lineHeight: 1.55 }}>
          Two creatives, same category. Pick the one that <b style={{ color: 'var(--text)' }}>actually scaled</b>.
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20, width: '100%', maxWidth: 880 }}>
          <Card ad={a} side="left"/>
          <Card ad={b} side="right"/>
        </div>

        <div style={{ display: 'flex', gap: 14 }}>
          <button onClick={() => choose('left')} className="btn btn-stroke btn-lg" style={{ height: 48, padding: '0 24px', borderRadius: 999 }}>
            <Icon name="arrow-left-s" size={18}/> Left wins
          </button>
          <button onClick={() => choose('right')} className="btn btn-night btn-lg" style={{ height: 48, padding: '0 24px', borderRadius: 999 }}>
            Right wins <Icon name="arrow-right-s" size={18}/>
          </button>
        </div>
      </div>
    </>
  );
};

// ---- Reddit Extractor (modal-style tool) ----
const RedditModal = ({ open, onClose }) => {
  const [url, setUrl] = React.useState('reddit.com/r/Skincare');
  const [running, setRunning] = React.useState(false);
  if (!open) return null;

  const quotes = [
    { sub: 'r/Skincare',      score: 1247, text: 'My skin is super dry but breaks out the moment I use anything heavy. Why is everything either greasy or stripping?' },
    { sub: 'r/SkincareAddiction', score: 893, text: 'I\'ve spent $400 trying to fix hormonal acne. Nothing has worked. At this point I\'d pay anything that actually delivers.' },
    { sub: 'r/30PlusSkinCare',score: 654,  text: 'I just want a routine that\'s under 5 steps. I do not have time for layering 8 serums every morning.' },
    { sub: 'r/Skincare',      score: 421,  text: 'Tretinoin destroyed my barrier. I need a recovery moisturizer that won\'t clog my pores.' },
  ];

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 150,
      background: 'rgba(14,18,27,0.50)', backdropFilter: 'blur(6px)',
      display: 'grid', placeItems: 'center',
    }}>
      <div onClick={(e) => e.stopPropagation()} className="card" style={{
        width: 720, maxWidth: '92vw', maxHeight: '85vh',
        display: 'flex', flexDirection: 'column',
        overflow: 'hidden',
      }}>
        <div style={{
          padding: '18px 22px',
          display: 'flex', alignItems: 'center', gap: 12,
          borderBottom: '1px solid var(--border)',
        }}>
          <div style={{
            width: 36, height: 36, borderRadius: 10,
            background: 'linear-gradient(135deg, #FB923C, #EA580C)',
            display: 'grid', placeItems: 'center', color: '#fff',
          }}>
            <Icon name="flame" size={18}/>
          </div>
          <div style={{ flex: 1 }}>
            <div className="font-display" style={{ fontWeight: 600, fontSize: 16 }}>Reddit Extractor</div>
            <div style={{ fontSize: 12, color: 'var(--text-faint)' }}>Mine pain points, language and quotes from any subreddit</div>
          </div>
          <button onClick={onClose} className="btn btn-ghost btn-icon"><Icon name="close" size={16}/></button>
        </div>

        <div style={{ padding: 22, display: 'flex', flexDirection: 'column', gap: 16, overflowY: 'auto' }} className="scroll">
          <div style={{ display: 'flex', gap: 8 }}>
            <div className="fld" style={{ flex: 1 }}>
              <Icon name="link" size={14} style={{ color: 'var(--text-faint)' }}/>
              <input value={url} onChange={(e) => setUrl(e.target.value)}
                     placeholder="reddit.com/r/skincare or full thread URL"/>
            </div>
            <button className="btn btn-primary" onClick={() => { setRunning(true); setTimeout(() => setRunning(false), 1200); }}>
              <Icon name="sparkles" size={14}/> {running ? 'Mining…' : 'Extract'}
            </button>
          </div>

          <div style={{ display: 'flex', gap: 8 }}>
            {['Pain points', 'Objections', 'Praise', 'Questions', 'Slang & vocabulary'].map((t, i) => (
              <button key={t} className="chip" style={{
                height: 28, fontSize: 12,
                background: i === 0 ? 'var(--accent-soft)' : 'var(--bg-surface)',
                borderColor: i === 0 ? 'var(--accent-soft)' : 'var(--border)',
                color: i === 0 ? 'var(--accent)' : 'var(--text)',
              }}>{t}</button>
            ))}
          </div>

          <div style={{
            fontSize: 11, fontWeight: 500, color: 'var(--text-faint)',
            textTransform: 'uppercase', letterSpacing: 0.04, marginTop: 4,
          }}>Top 4 pain-point quotes</div>

          {quotes.map((q, i) => (
            <div key={i} className="card" style={{
              padding: 16, border: '1px solid var(--border)', boxShadow: 'none',
            }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8 }}>
                <span style={{
                  fontSize: 11, fontFamily: 'var(--font-mono)',
                  padding: '2px 6px', borderRadius: 4,
                  background: 'var(--bg-soft)', color: 'var(--text-2)',
                }}>{q.sub}</span>
                <span style={{ fontSize: 11, color: 'var(--text-faint)', display: 'flex', alignItems: 'center', gap: 4 }}>
                  <Icon name="thumbs-up" size={11}/> {q.score}
                </span>
                <div style={{ flex: 1 }}/>
                <button className="btn btn-ghost btn-xs">
                  <Icon name="copy" size={11}/> Copy
                </button>
              </div>
              <div style={{ fontSize: 13, lineHeight: 1.55, color: 'var(--text)', fontStyle: 'italic' }}>
                "{q.text}"
              </div>
            </div>
          ))}

          <div style={{
            padding: 16, borderRadius: 12,
            background: 'var(--accent-soft)',
            border: '1px solid var(--accent-soft)',
            fontSize: 13, lineHeight: 1.6, color: 'var(--text-2)',
          }}>
            <div style={{
              display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6,
              color: 'var(--accent)', fontSize: 11, fontWeight: 600,
              textTransform: 'uppercase', letterSpacing: 0.04,
            }}>
              <Icon name="sparkles" size={12}/> Hook angles
            </div>
            Three angles for ad copy emerge: 1) "tired of choosing between greasy or stripping?" — addresses the #1 frustration; 2) the under-5-step routine — speaks to time-poor 30+ buyers; 3) post-tret recovery — a niche but high-LTV cohort.
          </div>
        </div>
      </div>
    </div>
  );
};

// ---- AI Video Generation ----
const AI_VIDEO_MODELS = [
  { id: 'seedance-2', label: 'Seedance 2.0', desc: 'Highest quality · cinematic' },
  { id: 'kling-3',    label: 'Kling 3.0',    desc: 'Fast, realistic motion' },
  { id: 'grok',       label: 'Grok',         desc: 'Experimental · creative' },
];
const AI_VIDEO_ASPECTS = [
  { id: 'auto',  w: 18, h: 14, dashed: true },
  { id: '16:9',  w: 18, h: 10 },
  { id: '4:3',   w: 16, h: 12 },
  { id: '1:1',   w: 14, h: 14 },
  { id: '3:4',   w: 12, h: 16 },
  { id: '9:16',  w: 10, h: 18 },
];
const AI_VIDEO_DURATION_MIN = 1;
const AI_VIDEO_DURATION_MAX = 15;

const AIVideoV3 = () => {
  const [prompt, setPrompt] = React.useState('');
  const [aspect, setAspect] = React.useState('16:9');
  const [model, setModel]   = React.useState('seedance-2');
  const [duration, setDuration] = React.useState(5);
  const [tab, setTab]       = React.useState('history');
  const [attachments, setAttachments] = React.useState([]);
  const [openMenu, setOpenMenu] = React.useState(null);
  const [dragId, setDragId] = React.useState(null);
  const [lightboxId, setLightboxId] = React.useState(null);
  const [saveDialog, setSaveDialog] = React.useState(null); // null | { name, includeAttachments }
  const [confirmDeleteId, setConfirmDeleteId] = React.useState(null);
  const [selectedFolder, setSelectedFolder] = React.useState(null);
  const fileInputRef = React.useRef(null);
  const vidPrompts = usePromptLibrary('1r-vid-prompts');
  const aiItems = useAIItems();

  React.useEffect(() => { if (openMenu !== 'prompts') setConfirmDeleteId(null); }, [openMenu]);

  const blobToDataUrl = (url) =>
    fetch(url).then(r => r.blob()).then(b => new Promise((res, rej) => {
      const fr = new FileReader(); fr.onload = () => res(fr.result); fr.onerror = rej; fr.readAsDataURL(b);
    }));

  const handleVidSave = async () => {
    let savedAttachments = [];
    if (saveDialog.includeAttachments && attachments.length > 0) {
      const results = await Promise.allSettled(
        attachments
          .filter(a => !a.url.startsWith('data:video')) // skip large video blobs
          .map(a => blobToDataUrl(a.url).then(dataUrl => ({ name: a.name, dataUrl })))
      );
      savedAttachments = results.filter(r => r.status === 'fulfilled').map(r => r.value);
    }
    vidPrompts.save({ text: prompt, name: saveDialog.name, attachments: savedAttachments });
    setSaveDialog(null);
  };

  const applyVidPrompt = (p) => {
    setPrompt(p.text);
    if (p.attachments?.length > 0) {
      setAttachments(p.attachments.map(a => ({
        id: `r-${Date.now()}-${Math.random().toString(36).slice(2,5)}`,
        url: a.dataUrl,
        name: a.name,
      })));
    }
    setOpenMenu(null);
  };

  React.useEffect(() => {
    if (!lightboxId) return;
    const onKey = (e) => { if (e.key === 'Escape') setLightboxId(null); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [lightboxId]);

  const lightboxItem = lightboxId ? attachments.find(a => a.id === lightboxId) : null;
  const modelLabel = AI_VIDEO_MODELS.find(m => m.id === model)?.label ?? '';

  const addAttachments = (files) => {
    const slots = MAX_ATTACHMENTS - attachments.length;
    const accepted = Array.from(files)
      .filter(f => f.type.startsWith('image/') || f.type.startsWith('video/'))
      .slice(0, slots)
      .map(f => ({
        id: `${f.name}-${f.lastModified}-${Math.random().toString(36).slice(2,7)}`,
        url: URL.createObjectURL(f),
        name: f.name,
      }));
    if (accepted.length) setAttachments(a => [...a, ...accepted]);
  };
  const removeAttachment = (id) => setAttachments(a => {
    const target = a.find(x => x.id === id);
    if (target) URL.revokeObjectURL(target.url);
    return a.filter(x => x.id !== id);
  });
  const reorderAttachments = (sourceId, targetId) => {
    if (!sourceId || sourceId === targetId) return;
    setAttachments(a => {
      const from = a.findIndex(x => x.id === sourceId);
      const to   = a.findIndex(x => x.id === targetId);
      if (from < 0 || to < 0) return a;
      const next = a.slice();
      const [moved] = next.splice(from, 1);
      next.splice(to, 0, moved);
      return next;
    });
  };

  React.useEffect(() => () => attachments.forEach(a => URL.revokeObjectURL(a.url)), []);

  const MenuChip = ({ id, icon, label, children, minWidth = 180 }) => {
    const open = openMenu === id;
    return (
      <div style={{ position: 'relative' }}>
        <button onClick={() => setOpenMenu(open ? null : id)} className="chip" style={{
          height: 30, padding: '0 10px', gap: 6, fontSize: 12, fontWeight: 500,
          borderRadius: 9,
          background: open ? 'rgba(255,255,255,0.85)' : 'rgba(255,255,255,0.55)',
          border: `1px solid ${open ? 'rgba(15,20,30,0.14)' : 'rgba(15,20,30,0.08)'}`,
          color: 'var(--text)',
          backdropFilter: 'blur(8px)',
        }}>
          {icon && <Icon name={icon} size={12} style={{ color: 'var(--text-2)' }}/>}
          {label}
          <Icon name="arrow-up-s" size={12} style={{ color: 'var(--text-faint)' }}/>
        </button>
        {open && (
          <>
            <div onClick={() => setOpenMenu(null)} style={{ position: 'fixed', inset: 0, zIndex: 60 }}/>
            <div role="menu" style={{
              position: 'absolute', bottom: 'calc(100% + 6px)', left: 0,
              minWidth, zIndex: 61,
              background: 'var(--bg-surface)',
              border: '1px solid var(--border)',
              borderRadius: 12,
              boxShadow: '0 12px 32px rgba(14,18,27,0.12)',
              padding: 6,
              display: 'flex', flexDirection: 'column', gap: 2,
            }}>
              {children}
            </div>
          </>
        )}
      </div>
    );
  };

  const MenuItem = ({ active, onClick, children }) => (
    <button onClick={() => { onClick(); setOpenMenu(null); }} style={{
      display: 'flex', alignItems: 'center', gap: 10,
      width: '100%', padding: '8px 10px',
      background: active ? 'var(--bg-muted)' : 'transparent',
      border: 0, borderRadius: 8,
      color: 'var(--text)', fontSize: 13, textAlign: 'left',
      cursor: 'pointer', fontFamily: 'inherit',
    }}
    onMouseEnter={(e) => e.currentTarget.style.background = 'var(--bg-muted)'}
    onMouseLeave={(e) => e.currentTarget.style.background = active ? 'var(--bg-muted)' : 'transparent'}>
      {children}
    </button>
  );

  return (
    <>
      <PageHeader
        icon="video"
        title="AI Video Generation"
        subtitle="Generate video ads, product demos and creative content"
      />

      <div style={{
        flex: 1, display: 'flex', flexDirection: 'column', position: 'relative', overflow: 'hidden',
        background: 'var(--bg-soft)',
      }}>
        <div style={{ padding: '10px 16px', flexShrink: 0, borderBottom: '1px solid var(--border)', background: 'var(--bg-soft)' }}>
          <FolderChipsBar
            selectedFolder={selectedFolder}
            onSelect={setSelectedFolder}
            aiItems={aiItems}
            itemType="video"
          />
        </div>

        {/* Video grid */}
        {(() => {
          const vids = aiItems.items.filter(i => i.type === 'video' && (selectedFolder === null || i.folderId === selectedFolder));
          return (
            <div className="scroll" style={{
              flex: 1, overflowY: 'auto',
              padding: '16px 16px 120px',
            }}>
              {vids.length > 0 ? (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8 }}>
                  {vids.map(item => (
                    <div key={item.id} style={{
                      aspectRatio: '16/9', borderRadius: 10, overflow: 'hidden',
                      position: 'relative',
                      background: AD_THUMBS[item.thumbIndex % AD_THUMBS.length],
                      cursor: 'pointer',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                    }}>
                      <div style={{
                        width: 36, height: 36, borderRadius: 999,
                        background: 'rgba(0,0,0,0.38)',
                        display: 'flex', alignItems: 'center', justifyContent: 'center',
                        backdropFilter: 'blur(4px)',
                      }}>
                        <Icon name="play" size={16} style={{ color: '#fff', marginLeft: 2 }}/>
                      </div>
                      {item.prompt && (
                        <div style={{
                          position: 'absolute', bottom: 0, left: 0, right: 0,
                          padding: '24px 8px 8px',
                          background: 'linear-gradient(transparent, rgba(10,12,20,0.72))',
                          color: '#fff', fontSize: 11, lineHeight: 1.4,
                          overflow: 'hidden', textOverflow: 'ellipsis',
                          display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical',
                          opacity: 0, transition: 'opacity 160ms',
                        }}
                        onMouseEnter={e => e.currentTarget.style.opacity = 1}
                        onMouseLeave={e => e.currentTarget.style.opacity = 0}>
                          {item.prompt}
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              ) : selectedFolder ? (
                <div style={{
                  display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
                  height: '60%', gap: 10, color: 'var(--text-faint)',
                }}>
                  <Icon name="video" size={32}/>
                  <span style={{ fontSize: 14, color: 'var(--text-2)' }}>No videos in this folder yet</span>
                  <span style={{ fontSize: 12 }}>Generate something and it will appear here</span>
                </div>
              ) : (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 8 }}>
                  {Array.from({ length: 8 }).map((_, i) => (
                    <div key={i} style={{
                      aspectRatio: '16/9', borderRadius: 10, overflow: 'hidden',
                      position: 'relative',
                      background: AD_THUMBS[i % AD_THUMBS.length],
                      cursor: 'pointer',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                    }}>
                      <div style={{
                        width: 36, height: 36, borderRadius: 999,
                        background: 'rgba(0,0,0,0.38)',
                        display: 'flex', alignItems: 'center', justifyContent: 'center',
                        backdropFilter: 'blur(4px)',
                      }}>
                        <Icon name="play" size={16} style={{ color: '#fff', marginLeft: 2 }}/>
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </div>
          );
        })()}

        {/* Floating prompt bar */}
        <div style={{
          position: 'absolute', left: '50%', bottom: 20,
          transform: 'translateX(-50%)',
          width: 'min(880px, calc(100% - 48px))',
          background: 'rgba(255,255,255,0.86)',
          color: 'var(--text)',
          borderRadius: 18,
          padding: '12px 12px 12px 16px',
          display: 'flex', flexDirection: 'column', gap: 10,
          backdropFilter: 'blur(24px) saturate(180%)',
          WebkitBackdropFilter: 'blur(24px) saturate(180%)',
          boxShadow: '0 24px 48px -16px rgba(15,20,30,0.18), 0 4px 14px -4px rgba(15,20,30,0.08), inset 0 1px 0 rgba(255,255,255,0.9)',
          border: '1px solid rgba(255,255,255,0.8)',
          zIndex: 3,
        }}>
          {/* Attachments strip */}
          {attachments.length > 0 && (
            <div style={{
              display: 'flex', gap: 6, flexWrap: 'wrap',
              paddingBottom: 4,
            }}>
              {attachments.map(a => {
                const isDragging = dragId === a.id;
                return (
                  <div key={a.id}
                    draggable
                    role="button"
                    tabIndex={0}
                    onClick={() => { if (!dragId) setLightboxId(a.id); }}
                    onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); setLightboxId(a.id); } }}
                    onDragStart={(e) => {
                      setDragId(a.id);
                      e.dataTransfer.effectAllowed = 'move';
                      try { e.dataTransfer.setData('text/plain', a.id); } catch {}
                    }}
                    onDragEnter={() => {
                      if (dragId && dragId !== a.id) reorderAttachments(dragId, a.id);
                    }}
                    onDragOver={(e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }}
                    onDrop={(e) => { e.preventDefault(); setDragId(null); }}
                    onDragEnd={() => setDragId(null)}
                    style={{
                      position: 'relative', width: 56, height: 56,
                      borderRadius: 10, overflow: 'hidden',
                      border: `1px solid ${isDragging ? 'var(--accent)' : 'rgba(15,20,30,0.08)'}`,
                      boxShadow: isDragging ? '0 0 0 2px var(--accent-glow)' : 'none',
                      background: `center/cover no-repeat url(${a.url})`,
                      opacity: isDragging ? 0.55 : 1,
                      cursor: dragId ? 'grabbing' : 'pointer',
                      transition: 'transform 160ms ease, box-shadow 120ms ease, opacity 120ms ease',
                    }} title={a.name}>
                    <button onMouseDown={(e) => e.stopPropagation()}
                            onClick={(e) => { e.stopPropagation(); removeAttachment(a.id); }}
                            draggable={false}
                            onDragStart={(e) => e.preventDefault()}
                            style={{
                      position: 'absolute', top: 3, right: 3,
                      width: 18, height: 18, borderRadius: 999,
                      background: 'rgba(14,18,27,0.75)', color: '#fff',
                      border: 0, padding: 0, cursor: 'pointer',
                      display: 'grid', placeItems: 'center',
                    }}>
                      <Icon name="close" size={10}/>
                    </button>
                  </div>
                );
              })}
              <span style={{
                fontSize: 11, color: 'var(--text-faint)',
                alignSelf: 'center', marginLeft: 4,
              }}>{attachments.length}/{MAX_ATTACHMENTS}</span>
            </div>
          )}

          {/* Prompt input row */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <input ref={fileInputRef} type="file" accept="image/*,video/*" multiple
                   style={{ display: 'none' }}
                   onChange={(e) => { addAttachments(e.target.files); e.target.value = ''; }}/>
            <button
              onClick={() => fileInputRef.current?.click()}
              disabled={attachments.length >= MAX_ATTACHMENTS}
              title={attachments.length >= MAX_ATTACHMENTS ? `Max ${MAX_ATTACHMENTS} files` : 'Attach reference image or video'}
              style={{
                width: 28, height: 28, padding: 0, flexShrink: 0,
                borderRadius: 8,
                background: 'rgba(255,255,255,0.55)',
                border: '1px solid rgba(15,20,30,0.08)',
                color: 'var(--text-2)',
                display: 'grid', placeItems: 'center',
                cursor: attachments.length >= MAX_ATTACHMENTS ? 'not-allowed' : 'pointer',
                opacity: attachments.length >= MAX_ATTACHMENTS ? 0.5 : 1,
              }}>
              <Icon name="plus" size={14}/>
            </button>
            <input
              value={prompt}
              onChange={(e) => setPrompt(e.target.value)}
              placeholder="Describe the video you want to create"
              style={{
                flex: 1, height: 28,
                background: 'transparent', border: 'none', outline: 'none',
                color: 'var(--text)', fontSize: 14, fontFamily: 'inherit',
              }}/>
            {prompt.trim() && (
              <button
                onClick={() => {
                  const saved = vidPrompts.isSaved(prompt, attachments);
                  if (saved) {
                    const currentNames = attachments.map(a => a.name).sort().join('\0');
                    const entry = vidPrompts.prompts.find(p => p.text === prompt.trim() && (p.attachments||[]).map(a=>a.name).sort().join('\0') === currentNames);
                    setSaveDialog({ mode: 'unsave', entry });
                  } else {
                    setSaveDialog({ mode: 'save', name: prompt.trim().slice(0, 60), includeAttachments: attachments.length > 0 });
                  }
                }}
                title={vidPrompts.isSaved(prompt, attachments) ? 'Remove from library' : 'Save prompt'}
                style={{
                  height: 28, padding: '0 10px', flexShrink: 0, gap: 5,
                  borderRadius: 8,
                  background: vidPrompts.isSaved(prompt, attachments) ? 'rgba(99,102,241,0.1)' : 'rgba(255,255,255,0.7)',
                  border: `1px solid ${vidPrompts.isSaved(prompt, attachments) ? 'var(--accent)' : 'rgba(15,20,30,0.12)'}`,
                  color: vidPrompts.isSaved(prompt, attachments) ? 'var(--accent)' : 'var(--text-2)',
                  display: 'inline-flex', alignItems: 'center', cursor: 'pointer',
                  fontSize: 12, fontWeight: 500, fontFamily: 'inherit',
                  boxShadow: '0 1px 2px rgba(15,20,30,0.04)',
                  transition: 'all 140ms ease',
                }}>
                <Icon name="bookmark" size={12}
                      style={{ fill: vidPrompts.isSaved(prompt, attachments) ? 'currentColor' : 'none' }}/>
                {vidPrompts.isSaved(prompt, attachments) ? 'Saved' : 'Save'}
              </button>
            )}
          </div>

          {/* Toolbar row */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            {/* Model */}
            <MenuChip id="model" label={modelLabel} minWidth={230}>
              {AI_VIDEO_MODELS.map(m => (
                <MenuItem key={m.id} active={model === m.id} onClick={() => setModel(m.id)}>
                  <span style={{
                    width: 16, height: 16, borderRadius: 4, flexShrink: 0,
                    background: 'linear-gradient(135deg,#A78BFA,#6D28D9)',
                  }}/>
                  <span style={{ display: 'flex', flexDirection: 'column' }}>
                    <span style={{ fontWeight: 500 }}>{m.label}</span>
                    <span style={{ fontSize: 11, color: 'var(--text-faint)' }}>{m.desc}</span>
                  </span>
                  {model === m.id && <Icon name="check" size={14} style={{ marginLeft: 'auto', color: 'var(--accent)' }}/>}
                </MenuItem>
              ))}
            </MenuChip>

            {/* Aspect ratio */}
            <MenuChip
              id="aspect"
              minWidth={160}
              label={
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                  <AspectGlyph {...(AI_VIDEO_ASPECTS.find(a => a.id === aspect) ?? AI_VIDEO_ASPECTS[0])}/>
                  {aspect === 'auto' ? 'Auto' : aspect}
                </span>
              }>
              {AI_VIDEO_ASPECTS.map(a => (
                <MenuItem key={a.id} active={aspect === a.id} onClick={() => setAspect(a.id)}>
                  <AspectGlyph {...a} color={aspect === a.id ? 'var(--accent)' : 'var(--text-2)'}/>
                  <span style={{ flex: 1 }}>{a.id === 'auto' ? 'Auto' : a.id}</span>
                  {aspect === a.id && <Icon name="check" size={14} style={{ color: 'var(--accent)' }}/>}
                </MenuItem>
              ))}
            </MenuChip>

            {/* Duration stepper */}
            <div style={{
              display: 'inline-flex', alignItems: 'center',
              height: 30, borderRadius: 9,
              background: 'rgba(255,255,255,0.55)',
              border: '1px solid rgba(15,20,30,0.08)',
              backdropFilter: 'blur(8px)',
              overflow: 'hidden',
            }}>
              <button
                onClick={() => setDuration(d => Math.max(AI_VIDEO_DURATION_MIN, d - 1))}
                disabled={duration <= AI_VIDEO_DURATION_MIN}
                aria-label="Decrease duration"
                style={{
                  width: 28, height: 30, padding: 0, border: 0,
                  background: 'transparent',
                  color: duration <= AI_VIDEO_DURATION_MIN ? 'var(--text-faint)' : 'var(--text-2)',
                  cursor: duration <= AI_VIDEO_DURATION_MIN ? 'not-allowed' : 'pointer',
                  display: 'grid', placeItems: 'center',
                }}>
                <Icon name="minus" size={12}/>
              </button>
              <span style={{
                padding: '0 4px', minWidth: 46, textAlign: 'center',
                fontSize: 12, fontWeight: 500, color: 'var(--text)',
                userSelect: 'none',
              }}>{duration}s</span>
              <button
                onClick={() => setDuration(d => Math.min(AI_VIDEO_DURATION_MAX, d + 1))}
                disabled={duration >= AI_VIDEO_DURATION_MAX}
                aria-label="Increase duration"
                style={{
                  width: 28, height: 30, padding: 0, border: 0,
                  background: 'transparent',
                  color: duration >= AI_VIDEO_DURATION_MAX ? 'var(--text-faint)' : 'var(--text-2)',
                  cursor: duration >= AI_VIDEO_DURATION_MAX ? 'not-allowed' : 'pointer',
                  display: 'grid', placeItems: 'center',
                }}>
                <Icon name="plus" size={12}/>
              </button>
            </div>

            {/* Saved prompts */}
            {vidPrompts.prompts.length > 0 && (
              <MenuChip id="prompts" icon="bookmark" label={`${vidPrompts.prompts.length}`} minWidth={340}>
                <div className="scroll" style={{ maxHeight: 240, overflowY: 'auto' }}>
                  {vidPrompts.prompts.map(p => (
                    <div key={p.id} style={{ display: 'flex', alignItems: 'center', gap: 6, borderRadius: 8, padding: '2px 6px 2px 10px',
                      background: confirmDeleteId === p.id ? 'var(--bg-muted)' : 'transparent' }}
                      onMouseEnter={e => { if (confirmDeleteId !== p.id) e.currentTarget.style.background = 'var(--bg-muted)'; }}
                      onMouseLeave={e => { if (confirmDeleteId !== p.id) e.currentTarget.style.background = 'transparent'; }}>
                      {confirmDeleteId === p.id ? (
                        <>
                          <span style={{ flex: 1, fontSize: 12, color: 'var(--text-2)', padding: '8px 0',
                            overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                            Delete "{p.name}"?
                          </span>
                          <button onClick={e => { e.stopPropagation(); vidPrompts.remove(p.id); setConfirmDeleteId(null); }} style={{
                            height: 24, padding: '0 8px', borderRadius: 6, border: 0, flexShrink: 0,
                            background: '#ef4444', color: '#fff', fontSize: 11, fontWeight: 600,
                            cursor: 'pointer', fontFamily: 'inherit',
                          }}>Delete</button>
                          <button onClick={e => { e.stopPropagation(); setConfirmDeleteId(null); }} style={{
                            height: 24, padding: '0 8px', borderRadius: 6, flexShrink: 0,
                            background: 'transparent', border: '1px solid var(--border)',
                            color: 'var(--text-2)', fontSize: 11, fontWeight: 500,
                            cursor: 'pointer', fontFamily: 'inherit',
                          }}>Cancel</button>
                        </>
                      ) : (
                        <>
                          <button onClick={() => applyVidPrompt(p)} style={{
                            flex: 1, background: 'transparent', border: 0, padding: '7px 0',
                            color: 'var(--text)', fontSize: 12, fontFamily: 'inherit',
                            textAlign: 'left', cursor: 'pointer', minWidth: 0,
                          }}>
                            <div style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontWeight: 500 }}>
                              {p.name}
                            </div>
                            {p.attachments?.length > 0 && (
                              <div style={{ fontSize: 11, color: 'var(--text-faint)', marginTop: 1 }}>
                                {p.attachments.length} image{p.attachments.length > 1 ? 's' : ''} saved
                              </div>
                            )}
                          </button>
                          <button onClick={e => { e.stopPropagation(); setConfirmDeleteId(p.id); }} title="Delete" style={{
                            width: 24, height: 24, padding: 0, flexShrink: 0, borderRadius: 6,
                            background: 'transparent', border: 0,
                            color: 'var(--text-faint)', display: 'grid', placeItems: 'center', cursor: 'pointer',
                          }}>
                            <Icon name="close" size={10}/>
                          </button>
                        </>
                      )}
                    </div>
                  ))}
                </div>
              </MenuChip>
            )}

            <div style={{ flex: 1 }}/>

            {/* Generate */}
            <button onClick={() => {
              aiItems.add({
                id: `ai-${Date.now()}-${Math.random().toString(36).slice(2,5)}`,
                type: 'video',
                folderId: selectedFolder,
                prompt: prompt.trim(),
                aspect, model, duration,
                createdAt: Date.now(),
                thumbIndex: Math.floor(Math.random() * AD_THUMBS.length),
              });
            }} style={{
              height: 36, padding: '0 16px',
              borderRadius: 11,
              background: 'var(--accent)',
              border: 'none', color: 'var(--text-on-dark)',
              fontSize: 13, fontWeight: 600,
              display: 'inline-flex', alignItems: 'center', gap: 8,
              cursor: 'pointer',
              boxShadow: '0 4px 10px -2px var(--accent-shadow), inset 0 1px 0 rgba(255,255,255,0.18)',
            }}>
              <Icon name="sparkles" size={13}/> Generate
            </button>
          </div>
        </div>
      </div>

      {/* Save / unsave prompt dialog */}
      {saveDialog && (
        <div onClick={() => setSaveDialog(null)} style={{
          position: 'fixed', inset: 0, zIndex: 90,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          background: 'rgba(8,12,20,0.4)',
          backdropFilter: 'blur(4px)', WebkitBackdropFilter: 'blur(4px)',
        }}>
          <div onClick={e => e.stopPropagation()} style={{
            background: 'var(--bg-surface)', borderRadius: 16, padding: 24,
            width: 420, maxWidth: 'calc(100vw - 48px)',
            boxShadow: '0 24px 60px -12px rgba(14,18,27,0.25)',
            border: '1px solid var(--border)',
            display: 'flex', flexDirection: 'column', gap: 16,
          }}>
            {saveDialog.mode === 'unsave' ? (
              <>
                <div style={{ fontWeight: 600, fontSize: 15, color: 'var(--text)' }}>Remove saved prompt</div>
                <div style={{ fontSize: 13, color: 'var(--text-2)', lineHeight: 1.5 }}>
                  Remove <span style={{ fontWeight: 600, color: 'var(--text)' }}>"{saveDialog.entry?.name}"</span> from your library?
                </div>
                <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                  <button onClick={() => setSaveDialog(null)} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: 'var(--bg-muted)', border: '1px solid var(--border)',
                    color: 'var(--text)', fontSize: 13, fontWeight: 500,
                    cursor: 'pointer', fontFamily: 'inherit',
                  }}>Cancel</button>
                  <button onClick={() => { vidPrompts.remove(saveDialog.entry.id); setSaveDialog(null); }} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: '#ef4444', border: 'none',
                    color: '#fff', fontSize: 13, fontWeight: 600,
                    cursor: 'pointer', fontFamily: 'inherit',
                  }}>Remove</button>
                </div>
              </>
            ) : (
              <>
                <div style={{ fontWeight: 600, fontSize: 15, color: 'var(--text)' }}>Save prompt</div>

                <div>
                  <label style={{ fontSize: 12, fontWeight: 500, color: 'var(--text-2)', display: 'block', marginBottom: 6 }}>Name</label>
                  <input
                    autoFocus
                    value={saveDialog.name}
                    onChange={e => setSaveDialog(d => ({ ...d, name: e.target.value }))}
                    onKeyDown={e => { if (e.key === 'Enter') handleVidSave(); if (e.key === 'Escape') setSaveDialog(null); }}
                    style={{
                      width: '100%', boxSizing: 'border-box',
                      padding: '8px 12px', borderRadius: 8,
                      border: '1px solid var(--border)',
                      background: 'var(--bg-muted)',
                      color: 'var(--text)', fontSize: 13, fontFamily: 'inherit', outline: 'none',
                    }}/>
                </div>

                <div style={{
                  padding: '10px 12px', borderRadius: 8, background: 'var(--bg-soft)',
                  fontSize: 12, color: 'var(--text-2)', lineHeight: 1.5,
                  display: '-webkit-box', WebkitLineClamp: 3, WebkitBoxOrient: 'vertical',
                  overflow: 'hidden',
                }}>{prompt}</div>

                {attachments.length > 0 && (
                  <label style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }}>
                    <input
                      type="checkbox"
                      checked={saveDialog.includeAttachments}
                      onChange={e => setSaveDialog(d => ({ ...d, includeAttachments: e.target.checked }))}
                      style={{ width: 16, height: 16, cursor: 'pointer', accentColor: 'var(--accent)', flexShrink: 0 }}/>
                    <span style={{ fontSize: 13, color: 'var(--text)' }}>
                      Save {attachments.length} reference file{attachments.length > 1 ? 's' : ''} (images only)
                    </span>
                  </label>
                )}

                <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
                  <button onClick={() => setSaveDialog(null)} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: 'var(--bg-muted)', border: '1px solid var(--border)',
                    color: 'var(--text)', fontSize: 13, fontWeight: 500,
                    cursor: 'pointer', fontFamily: 'inherit',
                  }}>Cancel</button>
                  <button onClick={handleVidSave} style={{
                    height: 34, padding: '0 16px', borderRadius: 9,
                    background: 'var(--accent)', border: 'none',
                    color: 'var(--text-on-dark)', fontSize: 13, fontWeight: 600,
                    cursor: 'pointer', fontFamily: 'inherit',
                    boxShadow: '0 2px 8px -2px var(--accent-shadow)',
                  }}>Save</button>
                </div>
              </>
            )}
          </div>
        </div>
      )}

      {/* Lightbox */}
      {lightboxItem && (
        <div onClick={() => setLightboxId(null)}
             role="dialog" aria-modal="true"
             style={{
               position: 'fixed', inset: 0, zIndex: 80,
               background: 'rgba(8,12,20,0.78)',
               backdropFilter: 'blur(8px)',
               WebkitBackdropFilter: 'blur(8px)',
               display: 'flex', alignItems: 'center', justifyContent: 'center',
               padding: 32,
               cursor: 'zoom-out',
             }}>
          <img src={lightboxItem.url} alt={lightboxItem.name}
               onClick={(e) => e.stopPropagation()}
               style={{
                 display: 'block',
                 width: 'auto', height: 'auto',
                 maxWidth: 'calc(100vw - 64px)',
                 maxHeight: 'calc(100vh - 64px)',
                 objectFit: 'contain',
                 borderRadius: 12,
                 boxShadow: '0 24px 60px -16px rgba(0,0,0,0.6)',
                 cursor: 'default',
               }}/>
          <button onClick={(e) => { e.stopPropagation(); setLightboxId(null); }}
                  aria-label="Close"
                  style={{
                    position: 'absolute', top: 20, right: 20,
                    width: 36, height: 36, borderRadius: 999,
                    background: 'rgba(255,255,255,0.15)',
                    border: '1px solid rgba(255,255,255,0.2)',
                    color: '#fff',
                    display: 'grid', placeItems: 'center',
                    cursor: 'pointer',
                    backdropFilter: 'blur(6px)',
                  }}>
            <Icon name="close" size={18}/>
          </button>
          {lightboxItem.name && (
            <div style={{
              position: 'absolute', bottom: 20, left: '50%',
              transform: 'translateX(-50%)',
              padding: '6px 12px', borderRadius: 999,
              background: 'rgba(255,255,255,0.12)',
              border: '1px solid rgba(255,255,255,0.18)',
              color: '#fff', fontSize: 12, fontFamily: 'inherit',
              backdropFilter: 'blur(6px)',
              maxWidth: 'calc(100% - 64px)',
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            }}>{lightboxItem.name}</div>
          )}
        </div>
      )}
    </>
  );
};

Object.assign(window, { AIChatV3, AIImageV3, AIVideoV3, TranscribeV3, GameV3, RedditModal });
