// landing.jsx — warmer, more playful travel journal with upload affordances

const displayAuthor = (story) => story.authorEn || story.author;
const displayAuthorSubline = (story) => story.authorEn ? story.author : '';
const DRIVE_PHOTOS_CACHE_KEY = 'es-drive-photos-cache-v1';
const DRIVE_PHOTOS_REFRESH_MS = 15000;

function useDrivePhotos() {
  const [photos, setPhotos] = React.useState(() => {
    try {
      const cached = JSON.parse(localStorage.getItem(DRIVE_PHOTOS_CACHE_KEY) || '[]');
      return Array.isArray(cached) ? cached : [];
    } catch {
      return [];
    }
  });
  const [syncState, setSyncState] = React.useState({ loading: true, error: '' });

  const refresh = React.useCallback(async () => {
    try {
      const response = await fetch(`/api/drive-photos?t=${Date.now()}`, { cache: 'no-store' });
      if (!response.ok) throw new Error('Unable to sync photos from Google Drive.');
      const payload = await response.json();
      if (!payload?.ok || !Array.isArray(payload.photos)) throw new Error(payload?.error || 'Unable to sync photos from Google Drive.');
      setPhotos(payload.photos);
      try { localStorage.setItem(DRIVE_PHOTOS_CACHE_KEY, JSON.stringify(payload.photos)); } catch {}
      setSyncState({ loading: false, error: '', refreshedAt: payload.refreshedAt || new Date().toISOString() });
    } catch (error) {
      setSyncState({
        loading: false,
        error: error instanceof Error ? error.message : 'Unable to sync photos from Google Drive.',
      });
    }
  }, []);

  React.useEffect(() => {
    refresh();
    const timer = window.setInterval(refresh, DRIVE_PHOTOS_REFRESH_MS);
    const onFocus = () => refresh();
    const onVisible = () => { if (document.visibilityState === 'visible') refresh(); };
    const onOnline = () => refresh();
    const onManualRefresh = () => refresh();
    window.addEventListener('focus', onFocus);
    window.addEventListener('online', onOnline);
    window.addEventListener('es-drive-photos-refresh', onManualRefresh);
    document.addEventListener('visibilitychange', onVisible);
    return () => {
      window.clearInterval(timer);
      window.removeEventListener('focus', onFocus);
      window.removeEventListener('online', onOnline);
      window.removeEventListener('es-drive-photos-refresh', onManualRefresh);
      document.removeEventListener('visibilitychange', onVisible);
    };
  }, [refresh]);

  return { photos, syncState, refresh };
}

const Hero = ({ onWriteLetter, storyCount, syncState }) => (
  <div style={{ position: 'relative', padding: '28px 24px 8px' }}>
    {/* Floating confetti dots */}
    <div style={{ position: 'absolute', top: 30, right: 24, display: 'flex', gap: 5 }}>
      <span style={{ width: 8, height: 8, borderRadius: 4, background: 'var(--sun)' }}/>
      <span style={{ width: 8, height: 8, borderRadius: 4, background: 'var(--mint)' }}/>
      <span style={{ width: 8, height: 8, borderRadius: 4, background: 'var(--coral)' }}/>
    </div>

    <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 24 }}>
      <div style={{ width: 28, height: 1, background: 'var(--ink)' }} />
      <span className="kicker">Issue 01 · Spring '26</span>
    </div>

    <div style={{ marginTop: 10 }}>
      <div className="display" style={{ fontSize: 52, fontWeight: 300, lineHeight: 1.0, color: 'var(--ink)', letterSpacing: '-0.035em' }}>
        Thank you,
      </div>
      <div style={{ position: 'relative', marginTop: 2 }}>
        <div className="display" style={{ fontSize: 54, fontWeight: 700, lineHeight: 1.0, color: 'var(--coral)', letterSpacing: '-0.035em', fontStyle: 'italic' }}>
          Ed & Sharon
        </div>
        {/* squiggly underline */}
        <svg width="180" height="10" viewBox="0 0 180 10" style={{ position: 'absolute', bottom: -6, left: 2 }}>
          <path d="M2 6 Q 20 0 38 6 T 74 6 T 110 6 T 146 6 T 178 6"
                fill="none" stroke="var(--sun)" strokeWidth="3" strokeLinecap="round"/>
        </svg>
      </div>
      <div className="body-text" style={{ fontSize: 15, color: 'var(--ink-soft)', marginTop: 18, lineHeight: 1.55, fontStyle: 'italic' }}>
        We thank God for bringing you into our midst.
      </div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 14 }}>
        <span className="chip-pop" style={{ background: 'rgba(111,195,168,0.22)', boxShadow: 'none', transform: 'none' }}>
          Peniel Church in Taiwan
        </span>
      </div>
    </div>

    {/* Figures stage — real clay illustration */}
    <div style={{ position: 'relative', height: 310, marginTop: 10 }}>
      {/* Soft sun backdrop */}
      <div style={{
        position: 'absolute', top: 18, left: '50%', transform: 'translateX(-50%)',
        width: 270, height: 210, borderRadius: '50%',
        background: 'radial-gradient(ellipse at 45% 35%, #FFF2CC 0%, #FCE8A9 45%, rgba(242,201,76,0) 72%)',
      }} />
      {/* Scalloped sun rays */}
      <svg width="260" height="200" viewBox="0 0 260 200" style={{ position: 'absolute', top: 22, left: '50%', transform: 'translateX(-50%)', opacity: 0.35 }}>
        {[...Array(14)].map((_, i) => {
          const a = (i / 14) * Math.PI * 2 - Math.PI / 2;
          const r1 = 92, r2 = 108;
          const x1 = 130 + Math.cos(a) * r1;
          const y1 = 100 + Math.sin(a) * r1 * 0.8;
          const x2 = 130 + Math.cos(a) * r2;
          const y2 = 100 + Math.sin(a) * r2 * 0.8;
          return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--sun)" strokeWidth="2.5" strokeLinecap="round"/>;
        })}
      </svg>

      {/* sparkles */}
      <svg width="14" height="14" viewBox="0 0 14 14" style={{ position: 'absolute', top: 36, left: 34 }}>
        <path d="M7 0 L8 6 L14 7 L8 8 L7 14 L6 8 L0 7 L6 6 Z" fill="var(--sun)"/>
      </svg>
      <svg width="10" height="10" viewBox="0 0 14 14" style={{ position: 'absolute', top: 92, right: 34 }}>
        <path d="M7 0 L8 6 L14 7 L8 8 L7 14 L6 8 L0 7 L6 6 Z" fill="var(--mint)"/>
      </svg>
      <svg width="12" height="12" viewBox="0 0 14 14" style={{ position: 'absolute', bottom: 52, left: 22 }}>
        <path d="M7 0 L8 6 L14 7 L8 8 L7 14 L6 8 L0 7 L6 6 Z" fill="var(--coral)"/>
      </svg>
      <svg width="8" height="8" viewBox="0 0 14 14" style={{ position: 'absolute', top: 60, right: 90 }}>
        <path d="M7 0 L8 6 L14 7 L8 8 L7 14 L6 8 L0 7 L6 6 Z" fill="var(--plum)"/>
      </svg>

      {/* Ground shadow */}
      <div style={{
        position: 'absolute', bottom: 14, left: '50%', transform: 'translateX(-50%)',
        width: 240, height: 22,
        background: 'radial-gradient(ellipse at center, rgba(31,26,19,0.3) 0%, transparent 70%)',
        filter: 'blur(3px)',
      }} />

      {/* The photo */}
      <div style={{
        position: 'absolute', bottom: 8, left: '50%', transform: 'translateX(-50%)',
        width: 320, height: 300,
      }}>
        <div className="float-slow" style={{ width: '100%', height: '100%', display: 'flex', alignItems: 'flex-end', justifyContent: 'center' }}>
          <img src="assets/ed-sharon-clay.png" alt="Ed & Sharon" style={{
            width: '100%', height: '100%', objectFit: 'contain', objectPosition: 'center bottom',
            filter: 'drop-shadow(0 14px 18px rgba(31,26,19,0.25))',
          }}/>
        </div>
      </div>

    </div>

    {/* Trip stats */}
    <div style={{
      display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
      marginTop: 14, borderTop: '1.5px solid rgba(31,26,19,0.15)', borderBottom: '1.5px solid rgba(31,26,19,0.15)',
      padding: '16px 0',
    }}>
        {[
          { n: '21', l: 'days', s: 'in Taiwan', c: 'var(--coral)' },
          { n: '02', l: 'cities', s: 'Banqiao · Tamsui', c: 'var(--mint)' },
          { n: String(storyCount).padStart(2, '0'), l: 'letters', s: 'messages from church members', c: 'var(--sun)' },
        ].map((s, i) => (
        <div key={s.l} style={{
          textAlign: 'center',
          borderLeft: i > 0 ? '1px solid rgba(31,26,19,0.12)' : 'none',
          padding: '0 6px',
        }}>
          <div className="display" style={{ fontSize: 32, color: s.c, lineHeight: 1, fontWeight: 700, fontStyle: 'italic' }}>{s.n}</div>
          <div className="kicker" style={{ marginTop: 6 }}>{s.l}</div>
          <div style={{ fontSize: 10, color: 'var(--ink-dim)', marginTop: 4, fontStyle: 'italic' }}>{s.s}</div>
        </div>
      ))}
    </div>

  </div>
);

const downloadPhotoFile = async (photo, index) => {
  const fallbackName = `photo-${String(index + 1).padStart(2, '0')}`;
  const src = photo.src || '';
  const fileName = photo.name || photo.filename || `${fallbackName}.jpg`;

  if (src.startsWith('data:')) {
    const link = document.createElement('a');
    link.href = src;
    link.download = fileName;
    link.click();
    return;
  }

  const link = document.createElement('a');
  link.href = photo.downloadUrl || src;
  link.download = fileName;
  link.target = '_blank';
  link.rel = 'noopener';
  link.click();
};

const PhotoGallery = ({ userPhotos, onAddPhoto, onRemovePhoto, photoAdmin }) => {
  const { photos: drivePhotos, syncState: driveSyncState } = useDrivePhotos();
  const [activePhotoIndex, setActivePhotoIndex] = React.useState(null);
  const [showAdminPanel, setShowAdminPanel] = React.useState(false);
  const [showAdminPrompt, setShowAdminPrompt] = React.useState(false);
  const [adminPassword, setAdminPassword] = React.useState('');
  const [adminError, setAdminError] = React.useState('');
  const [downloadBusy, setDownloadBusy] = React.useState(false);
  const swipeStartX = React.useRef(null);

  const visibleDrivePhotos = drivePhotos.filter((photo) => !photoAdmin.hiddenPhotoIds.includes(photo.id));
  const hero = visibleDrivePhotos[0] || null;
  const gridPhotos = [...visibleDrivePhotos.slice(1), ...userPhotos.map(p => ({ ...p, user: true }))];
  const allVisiblePhotos = [...visibleDrivePhotos, ...userPhotos.map(p => ({ ...p, user: true }))];
  const totalPhotos = allVisiblePhotos.length;
  const activePhoto = activePhotoIndex === null ? null : allVisiblePhotos[activePhotoIndex] || null;

  const openPhoto = (photo) => {
    const nextIndex = allVisiblePhotos.findIndex((item) => item.id === photo.id);
    if (nextIndex >= 0) setActivePhotoIndex(nextIndex);
  };

  const closePhoto = () => setActivePhotoIndex(null);
  const showPrevPhoto = () => setActivePhotoIndex((index) => {
    if (index === null || !allVisiblePhotos.length) return index;
    return (index - 1 + allVisiblePhotos.length) % allVisiblePhotos.length;
  });
  const showNextPhoto = () => setActivePhotoIndex((index) => {
    if (index === null || !allVisiblePhotos.length) return index;
    return (index + 1) % allVisiblePhotos.length;
  });

  const submitAdminPassword = () => {
    if (photoAdmin.login(adminPassword)) {
      setAdminPassword('');
      setAdminError('');
      setShowAdminPrompt(false);
      setShowAdminPanel(true);
      return;
    }
    setAdminError('Password incorrect.');
  };

  const removePhoto = (photo) => {
    if (photo.user) onRemovePhoto(photo.id);
    else photoAdmin.hidePhoto(photo.id);
    if (activePhoto?.id === photo.id) closePhoto();
  };

  const downloadAllPhotos = async () => {
    setDownloadBusy(true);
    try {
      for (let i = 0; i < allVisiblePhotos.length; i += 1) {
        await downloadPhotoFile(allVisiblePhotos[i], i);
        await new Promise((resolve) => window.setTimeout(resolve, 180));
      }
    } finally {
      setDownloadBusy(false);
    }
  };

  const renderMeta = (photo, size = 'small') => {
    if (!photo.caption && !photo.date) return null;
    const captionStyle = size === 'hero'
      ? { fontSize: 19, color: 'var(--ink)' }
      : { fontSize: 14, color: 'var(--ink)', lineHeight: 1.1 };
    const dateStyle = size === 'hero'
      ? { fontSize: 9, color: 'var(--ink-dim)', letterSpacing: '0.15em' }
      : { fontSize: 8, color: 'var(--ink-dim)', letterSpacing: '0.12em' };

    return (
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginTop: 8, padding: '0 2px', gap: 12 }}>
        <div className="hand" style={captionStyle}>{photo.caption || ''}</div>
        <div className="mono" style={dateStyle}>{photo.date || ''}</div>
      </div>
    );
  };

  React.useEffect(() => {
    if (activePhotoIndex === null) return undefined;
    const onKeyDown = (event) => {
      if (event.key === 'Escape') closePhoto();
      if (event.key === 'ArrowLeft') showPrevPhoto();
      if (event.key === 'ArrowRight') showNextPhoto();
    };
    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, [activePhotoIndex, allVisiblePhotos.length]);

  React.useEffect(() => {
    if (activePhotoIndex !== null && activePhotoIndex >= allVisiblePhotos.length) {
      setActivePhotoIndex(allVisiblePhotos.length ? allVisiblePhotos.length - 1 : null);
    }
  }, [activePhotoIndex, allVisiblePhotos.length]);

  return (
    <div style={{ padding: '30px 24px 16px', position: 'relative' }}>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', marginBottom: 4 }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 4 }}>
            <div style={{ width: 28, height: 1, background: 'var(--ink)' }} />
            <span className="kicker">the photo roll</span>
          </div>
          <div className="display" style={{ fontSize: 28, color: 'var(--ink)', fontWeight: 500, marginTop: 8, lineHeight: 1.1 }}>
            Three weeks <em style={{ color: 'var(--coral)', fontStyle: 'italic', fontWeight: 400 }}>in frames</em>.
          </div>
        </div>
        <span className="chip-pop">{totalPhotos} pics</span>
      </div>
      <div className="body-text" style={{ fontSize: 12, color: 'var(--ink-dim)', marginTop: 6, lineHeight: 1.5 }}>
        Little moments from this season together.
        {driveSyncState?.error ? ` ${driveSyncState.error}` : ''}
      </div>

      {/* Wide hero photo */}
      {hero && (
        <div style={{ marginTop: 18, position: 'relative' }}>
          <div className="tape tape-sun" style={{ top: -10, left: '50%', marginLeft: -30, transform: 'rotate(-3deg)', zIndex: 2 }} />
          <div className="photo-tile" style={{ transform: `rotate(${hero.rot}deg)`, cursor: 'zoom-in' }} onClick={() => openPhoto(hero)}>
            {photoAdmin.isAdmin && (
              <button
                onClick={(e) => { e.stopPropagation(); removePhoto(hero); }}
                style={{
                  position: 'absolute', top: 6, right: 6, zIndex: 3,
                  width: 26, height: 26, borderRadius: 13, border: 'none',
                  background: 'rgba(31,26,19,0.75)', color: 'var(--paper)', cursor: 'pointer',
                  fontSize: 13, display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}
                title="Delete photo"
              >×</button>
            )}
            <div style={{ width: '100%', aspectRatio: '4 / 3', overflow: 'hidden', background: '#E2D6B8', borderRadius: 2 }}>
              <img src={hero.src} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', filter: 'saturate(1.02) contrast(1.02)' }} />
            </div>
            {renderMeta(hero, 'hero')}
          </div>
        </div>
      )}

      {/* Grid */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 14, marginTop: 20 }}>
        {gridPhotos.map((p, i) => (
          <div key={p.id || i} className="photo-tile"
               style={{ transform: `rotate(${p.rot}deg)`, marginTop: i % 2 === 1 ? 10 : 0, position: 'relative', cursor: p.src ? 'zoom-in' : 'default' }}
               onClick={() => p.src && openPhoto(p)}>
            {photoAdmin.isAdmin && (
              <button
                onClick={(e) => { e.stopPropagation(); removePhoto(p); }}
                style={{
                  position: 'absolute', top: 4, right: 4, zIndex: 3,
                  width: 22, height: 22, borderRadius: 11,
                  border: 'none', background: 'rgba(31,26,19,0.75)',
                  color: 'var(--paper)', cursor: 'pointer',
                  fontSize: 12, lineHeight: 1,
                  display: 'flex', alignItems: 'center', justifyContent: 'center',
                }}
                title="Delete photo">×</button>
            )}
            <div style={{
              width: '100%', aspectRatio: '1 / 1', overflow: 'hidden', borderRadius: 2,
              background: p.palette ? `repeating-linear-gradient(135deg, ${p.palette[0]} 0 10px, ${p.palette[1]} 10px 20px)` : '#E2D6B8',
              position: 'relative',
            }}>
              {p.src
                ? <img src={p.src} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover', filter: 'saturate(1.02) contrast(1.02)' }} />
                : (
                  <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                    <div className="mono" style={{ fontSize: 8, letterSpacing: '0.2em', color: 'var(--ink-soft)', background: 'rgba(255,253,247,0.85)', padding: '4px 8px', borderRadius: 4 }}>
                      IMG · PLACEHOLDER
                    </div>
                  </div>
                )
              }
              {p.user && (
                <div style={{
                  position: 'absolute', top: 6, left: 6,
                  background: 'var(--sun)', padding: '2px 7px', borderRadius: 999,
                  fontFamily: 'JetBrains Mono, monospace', fontSize: 8,
                  fontWeight: 700, letterSpacing: '0.1em', color: 'var(--ink)',
                }}>NEW</div>
              )}
            </div>
            {renderMeta(p)}
          </div>
        ))}

        {/* Upload tile — always last */}
        <div className="upload-tile" onClick={onAddPhoto}
             style={{ marginTop: gridPhotos.length % 2 === 1 ? 10 : 0 }}>
          <svg width="36" height="36" viewBox="0 0 40 40" fill="none">
            <circle cx="20" cy="20" r="17" stroke="currentColor" strokeWidth="2"/>
            <path d="M20 13v14M13 20h14" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
          </svg>
          <div style={{ fontSize: 12, fontWeight: 600 }}>Add a photo</div>
          <div className="mono" style={{ fontSize: 8, letterSpacing: '0.15em', color: 'var(--ink-dim)' }}>FROM THE TRIP</div>
        </div>
      </div>

      {photoAdmin.isAdmin && showAdminPanel && (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'center', marginTop: 18 }}>
          <span className="chip-pop" style={{ background: 'var(--mint)', boxShadow: 'none', transform: 'none' }}>
            admin unlocked
          </span>
          <button className="btn btn-ghost" onClick={downloadAllPhotos} disabled={downloadBusy}>
            {downloadBusy ? 'Downloading…' : 'Batch download'}
          </button>
          <button className="btn btn-ghost" onClick={photoAdmin.restorePhotos}>
            Restore deleted
          </button>
          <button className="btn btn-ghost" onClick={() => { photoAdmin.logout(); setShowAdminPanel(false); }}>
            Lock
          </button>
        </div>
      )}

      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 16 }}>
        <button
          onClick={() => {
            if (photoAdmin.isAdmin) setShowAdminPanel((open) => !open);
            else {
              setAdminError('');
              setShowAdminPrompt(true);
            }
          }}
          style={{
            width: 34,
            height: 34,
            borderRadius: 17,
            border: '1px solid rgba(31,26,19,0.16)',
            background: 'rgba(255,253,247,0.9)',
            color: 'var(--ink-soft)',
            cursor: 'pointer',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            boxShadow: '0 4px 12px rgba(31,26,19,0.08)',
          }}
          aria-label="Open admin tools"
          title="Admin tools"
        >
          <span style={{ fontSize: 15, lineHeight: 1 }}>✎</span>
        </button>
      </div>

      {activePhoto && (
        <div
          onClick={closePhoto}
          style={{
            position: 'fixed',
            inset: 0,
            zIndex: 350,
            background: 'rgba(20,16,10,0.78)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            padding: 20,
          }}
        >
          <button
            onClick={closePhoto}
            style={{
              position: 'absolute',
              top: 18,
              right: 18,
              width: 38,
              height: 38,
              borderRadius: 19,
              border: 'none',
              background: 'rgba(255,253,247,0.15)',
              color: 'var(--paper)',
              fontSize: 20,
              cursor: 'pointer',
            }}
            aria-label="Close photo"
          >
            ×
          </button>
          {allVisiblePhotos.length > 1 && (
            <>
              <button
                onClick={(e) => { e.stopPropagation(); showPrevPhoto(); }}
                style={{
                  position: 'absolute',
                  left: 16,
                  top: '50%',
                  transform: 'translateY(-50%)',
                  width: 42,
                  height: 42,
                  borderRadius: 21,
                  border: 'none',
                  background: 'rgba(255,253,247,0.16)',
                  color: 'var(--paper)',
                  fontSize: 22,
                  cursor: 'pointer',
                }}
                aria-label="Previous photo"
              >
                ‹
              </button>
              <button
                onClick={(e) => { e.stopPropagation(); showNextPhoto(); }}
                style={{
                  position: 'absolute',
                  right: 16,
                  top: '50%',
                  transform: 'translateY(-50%)',
                  width: 42,
                  height: 42,
                  borderRadius: 21,
                  border: 'none',
                  background: 'rgba(255,253,247,0.16)',
                  color: 'var(--paper)',
                  fontSize: 22,
                  cursor: 'pointer',
                }}
                aria-label="Next photo"
              >
                ›
              </button>
            </>
          )}
          <div
            onClick={(e) => e.stopPropagation()}
            style={{
              maxWidth: 'min(92vw, 760px)',
              maxHeight: '88vh',
              width: '100%',
            }}
            onTouchStart={(event) => {
              swipeStartX.current = event.changedTouches[0]?.clientX ?? null;
            }}
            onTouchEnd={(event) => {
              const endX = event.changedTouches[0]?.clientX ?? null;
              const startX = swipeStartX.current;
              swipeStartX.current = null;
              if (startX === null || endX === null) return;
              const deltaX = endX - startX;
              if (Math.abs(deltaX) < 40) return;
              if (deltaX > 0) showPrevPhoto();
              else showNextPhoto();
            }}
          >
            <img
              src={activePhoto.src}
              alt={activePhoto.caption || 'Trip photo'}
              style={{
                width: '100%',
                maxHeight: '78vh',
                objectFit: 'contain',
                display: 'block',
                borderRadius: 18,
                boxShadow: '0 20px 50px rgba(0,0,0,0.35)',
                background: 'rgba(255,253,247,0.08)',
              }}
            />
            {allVisiblePhotos.length > 1 && (
              <div className="mono" style={{ padding: '10px 6px 0', color: 'rgba(255,253,247,0.7)', fontSize: 9, letterSpacing: '0.16em' }}>
                SWIPE OR USE ARROWS
              </div>
            )}
            {(activePhoto.caption || activePhoto.date) && (
              <div style={{ padding: '12px 6px 0', color: 'var(--paper)' }}>
                {activePhoto.caption && (
                  <div className="hand" style={{ fontSize: 20, lineHeight: 1.2 }}>
                    {activePhoto.caption}
                  </div>
                )}
                {activePhoto.date && (
                  <div className="mono" style={{ fontSize: 10, letterSpacing: '0.16em', opacity: 0.8, marginTop: 6 }}>
                    {activePhoto.date}
                  </div>
                )}
              </div>
            )}
          </div>
        </div>
      )}

      {showAdminPrompt && !photoAdmin.isAdmin && (
        <div
          onClick={() => setShowAdminPrompt(false)}
          style={{
            position: 'fixed',
            inset: 0,
            zIndex: 360,
            background: 'rgba(20,16,10,0.54)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            padding: 20,
          }}
        >
          <div
            onClick={(e) => e.stopPropagation()}
            style={{
              width: 'min(92vw, 360px)',
              background: 'var(--card)',
              borderRadius: 18,
              padding: '18px 18px 20px',
              boxShadow: '0 18px 40px rgba(0,0,0,0.2)',
            }}
          >
            <div className="display" style={{ fontSize: 24, color: 'var(--ink)', fontWeight: 600 }}>
              Admin access
            </div>
            <div style={{ fontSize: 13, color: 'var(--ink-soft)', marginTop: 8, lineHeight: 1.5 }}>
              Enter the password to edit photos, delete items, and batch download the gallery.
            </div>
            <input
              className="input"
              type="password"
              placeholder="Password"
              value={adminPassword}
              onChange={(e) => setAdminPassword(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === 'Enter') submitAdminPassword();
              }}
              style={{ marginTop: 14 }}
              autoFocus
            />
            {adminError && (
              <div style={{ fontSize: 12, color: 'var(--coral-deep)', marginTop: 8 }}>{adminError}</div>
            )}
            <div style={{ display: 'flex', gap: 10, marginTop: 16 }}>
              <button className="btn btn-ghost" onClick={() => setShowAdminPrompt(false)} style={{ flex: 1, justifyContent: 'center' }}>
                Cancel
              </button>
              <button className="btn btn-coral" onClick={submitAdminPassword} style={{ flex: 1, justifyContent: 'center' }}>
                Unlock
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

const Overview = ({ onPick, allStories, onWriteLetter, onRemoveLetter, syncState }) => (
  <div style={{ padding: '30px 0 120px' }}>
    <div style={{ padding: '0 24px' }}>
      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between' }}>
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 4 }}>
            <div style={{ width: 28, height: 1, background: 'var(--ink)' }} />
            <span className="kicker">the letters</span>
          </div>
          <div className="display" style={{ fontSize: 28, color: 'var(--ink)', fontWeight: 500, marginTop: 8, lineHeight: 1.1 }}>
            <em style={{ color: 'var(--coral)', fontStyle: 'italic', fontWeight: 400 }}>{allStories.length}</em> voices.
          </div>
        </div>
        <span className="chip-pop" style={{ background: 'var(--mint)', boxShadow: '0 2px 6px rgba(111,195,168,0.4)' }}>
          tap to open
        </span>
      </div>
      <div className="body-text" style={{ fontSize: 14, color: 'var(--ink-soft)', marginTop: 10, fontStyle: 'italic' }}>
        Tap a name to read their letter.
      </div>
      <div className="body-text" style={{ fontSize: 12, color: 'var(--ink-dim)', marginTop: 8, lineHeight: 1.5 }}>
        The notes below are words of gratitude and feedback from brothers and sisters in the church, thanking you both for your love, service, and wholehearted investment.
        {syncState?.error ? ` ${syncState.error}` : ''}
      </div>
    </div>

    <div style={{ padding: '22px 20px 0', display: 'flex', flexDirection: 'column', gap: 16 }}>
      {allStories.map((s, i) => {
        const initials = displayAuthor(s).split(/\s+/).map(w => w[0]).slice(0, 2).join('').toUpperCase();
        const rot = ((i * 37) % 7) - 3;
        const stampColors = ['var(--coral)', 'var(--ink)', 'var(--mint)', 'var(--sky)', 'var(--plum)'];
        const stampColor = s.user ? 'var(--mint)' : stampColors[i % stampColors.length];
        const preview = (s.body[0] || '').slice(0, 58);
        return (
          <div
            key={s.id}
            onClick={() => onPick(i)}
            style={{
              position: 'relative',
              background: 'var(--card)',
              border: '1.5px solid rgba(31,26,19,0.14)',
              borderRadius: 10,
              padding: '14px 14px 16px 14px',
              boxShadow: '0 1px 0 rgba(31,26,19,0.04), 0 8px 18px rgba(31,26,19,0.09), 0 2px 4px rgba(31,26,19,0.05)',
              transform: `rotate(${rot}deg)`,
              cursor: 'pointer',
              transition: 'transform 220ms cubic-bezier(0.3, 1.4, 0.5, 1), box-shadow 220ms',
              overflow: 'hidden',
            }}
            onMouseEnter={e => { e.currentTarget.style.transform = 'rotate(0deg) translateY(-3px)'; e.currentTarget.style.boxShadow = '0 14px 26px rgba(31,26,19,0.14)'; }}
            onMouseLeave={e => { e.currentTarget.style.transform = `rotate(${rot}deg)`; e.currentTarget.style.boxShadow = '0 1px 0 rgba(31,26,19,0.04), 0 8px 18px rgba(31,26,19,0.09), 0 2px 4px rgba(31,26,19,0.05)'; }}
          >
            {/* airmail border */}
            <div style={{
              position: 'absolute', top: 0, left: 0, right: 0, height: 5,
              background: 'repeating-linear-gradient(-45deg, var(--coral) 0 6px, transparent 6px 10px, var(--ink) 10px 16px, transparent 16px 20px)',
              opacity: 0.55,
            }} />
            <div style={{
              position: 'absolute', bottom: 0, left: 0, right: 0, height: 5,
              background: 'repeating-linear-gradient(-45deg, var(--coral) 0 6px, transparent 6px 10px, var(--ink) 10px 16px, transparent 16px 20px)',
              opacity: 0.55,
            }} />

            {/* "new" badge for user-written letters */}
            {s.user && (
              <div style={{
                position: 'absolute', top: 10, left: 10, zIndex: 4,
                background: 'var(--sun)', color: 'var(--ink)',
                padding: '2px 8px', borderRadius: 999,
                fontFamily: 'DM Sans', fontSize: 9, fontWeight: 700,
                letterSpacing: '0.08em',
                transform: 'rotate(-4deg)',
                boxShadow: '0 2px 4px rgba(242,201,76,0.4)',
              }}>NEW ✦</div>
            )}

            <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginTop: 6 }}>
              <div style={{ flex: 1, minWidth: 0, paddingLeft: s.user ? 46 : 0 }}>
                <div className="mono" style={{ fontSize: 8, letterSpacing: '0.24em', color: 'var(--ink-dim)' }}>TO</div>
                <div className="display" style={{ fontSize: 22, color: 'var(--ink)', fontWeight: 500, lineHeight: 1.1, marginTop: 2, fontStyle: 'italic' }}>
                  Ed & Sharon
                </div>

                <div className="mono" style={{ fontSize: 8, letterSpacing: '0.24em', color: 'var(--ink-dim)', marginTop: 10 }}>FROM</div>
                <div className="display" style={{ fontSize: 17, color: 'var(--ink)', fontWeight: 500, lineHeight: 1.1, marginTop: 2 }}>
                  {displayAuthor(s)}
                </div>
                {displayAuthorSubline(s) && (
                  <div style={{ fontSize: 11, color: 'var(--ink-dim)', marginTop: 3, fontStyle: 'italic' }}>
                    {displayAuthorSubline(s)}
                  </div>
                )}
                <div style={{ fontSize: 10.5, color: 'var(--ink-soft)', marginTop: 3 }}>
                  {s.role} <span style={{ color: 'var(--ink-dim)' }}>·</span> <span style={{ fontStyle: 'italic', color: 'var(--ink-dim)' }}>{s.group}</span>
                </div>
              </div>

              {/* postage stamp */}
              <div style={{ position: 'relative', flexShrink: 0, width: 56 }}>
                <div style={{
                  background: stampColor,
                  color: 'var(--paper)',
                  padding: '8px 4px 6px',
                  textAlign: 'center',
                  transform: `rotate(${rot * -1.5 + 2}deg)`,
                  boxShadow: '0 2px 4px rgba(31,26,19,0.15)',
                  WebkitMaskImage: 'radial-gradient(circle at 3px 3px, transparent 2px, black 2.5px)',
                  WebkitMaskSize: '6px 6px',
                  WebkitMaskPosition: '-3px -3px',
                  maskImage: 'radial-gradient(circle at 3px 3px, transparent 2px, black 2.5px)',
                  maskSize: '6px 6px',
                  maskPosition: '-3px -3px',
                }}>
                  <div className="mono" style={{ fontSize: 7, letterSpacing: '0.15em', opacity: 0.75 }}>PENIEL</div>
                  <div className="display" style={{ fontSize: 16, fontWeight: 700, lineHeight: 1, margin: '3px 0', fontStyle: 'italic' }}>
                    {initials}
                  </div>
                  <div className="mono" style={{ fontSize: 7, letterSpacing: '0.15em', opacity: 0.75 }}>№ {String(i + 1).padStart(2, '0')}</div>
                </div>
                <svg width="66" height="66" viewBox="0 0 66 66" style={{
                  position: 'absolute', top: -6, right: -8,
                  opacity: 0.32, pointerEvents: 'none',
                  transform: `rotate(${rot * 4 - 8}deg)`,
                }}>
                  <circle cx="33" cy="33" r="28" fill="none" stroke="var(--ink)" strokeWidth="1.2"/>
                  <circle cx="33" cy="33" r="22" fill="none" stroke="var(--ink)" strokeWidth="1"/>
                  <text x="33" y="24" textAnchor="middle" fill="var(--ink)" fontFamily="JetBrains Mono, monospace" fontSize="5.5" letterSpacing="0.5">TAIWAN</text>
                  <text x="33" y="37" textAnchor="middle" fill="var(--ink)" fontFamily="JetBrains Mono, monospace" fontSize="6" fontWeight="700" letterSpacing="0.3">APR 2026</text>
                  <text x="33" y="48" textAnchor="middle" fill="var(--ink)" fontFamily="JetBrains Mono, monospace" fontSize="5.5" letterSpacing="0.5">BANQIAO</text>
                </svg>
              </div>
            </div>

            <div style={{
              marginTop: 14, paddingTop: 10,
              borderTop: '1px dashed rgba(31,26,19,0.18)',
              display: 'flex', alignItems: 'center', gap: 10,
            }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="hand" style={{
                  fontSize: 17, color: 'var(--ink-soft)', lineHeight: 1.25,
                  fontStyle: 'italic',
                  whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                }}>
                  “{preview}{preview.length >= 58 ? '…' : ''}”
                </div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 4, flexShrink: 0 }}>
                <span className="mono" style={{ fontSize: 8, letterSpacing: '0.18em', color: 'var(--ink-dim)' }}>
                  OPEN
                </span>
                <svg width="12" height="12" viewBox="0 0 24 24" style={{ color: 'var(--coral)' }}>
                  <path d="M9 6l6 6-6 6" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
                </svg>
              </div>
            </div>

            {s.user && (
              <button
                onClick={(e) => { e.stopPropagation(); onRemoveLetter(s.id); }}
                style={{
                  position: 'absolute', bottom: 10, right: 10,
                  width: 24, height: 24, borderRadius: 12,
                  border: 'none', background: 'rgba(31,26,19,0.12)',
                  color: 'var(--ink-soft)', cursor: 'pointer',
                  fontSize: 14, lineHeight: 1,
                  display: 'none', alignItems: 'center', justifyContent: 'center',
                }}
                className="letter-del-btn"
                title="Remove">×</button>
            )}
          </div>
        );
      })}

      {/* Write-a-letter tile */}
      <div
        onClick={onWriteLetter}
        style={{
          border: '2px dashed rgba(232,90,62,0.45)',
          background: 'rgba(232,90,62,0.04)',
          borderRadius: 12,
          padding: '22px 20px',
          display: 'flex', alignItems: 'center', gap: 14,
          cursor: 'pointer',
          transition: 'all 220ms',
        }}
        onMouseEnter={e => { e.currentTarget.style.background = 'rgba(232,90,62,0.09)'; e.currentTarget.style.transform = 'translateY(-2px)'; }}
        onMouseLeave={e => { e.currentTarget.style.background = 'rgba(232,90,62,0.04)'; e.currentTarget.style.transform = 'none'; }}
      >
        <div style={{
          width: 48, height: 48, borderRadius: 24,
          background: 'var(--coral)', color: 'var(--paper)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontSize: 22, flexShrink: 0,
          boxShadow: '0 4px 10px rgba(232,90,62,0.35)',
        }}>✎</div>
        <div style={{ flex: 1 }}>
          <div className="display" style={{ fontSize: 18, color: 'var(--coral)', fontWeight: 600, fontStyle: 'italic', lineHeight: 1.1 }}>
            Write your own letter
          </div>
          <div style={{ fontSize: 12, color: 'var(--ink-soft)', marginTop: 4 }}>
            Add your thanks to the collection →
          </div>
        </div>
      </div>
    </div>

    {/* Colophon */}
    <div style={{ padding: '36px 24px 0', textAlign: 'center' }}>
      <div style={{ display: 'flex', justifyContent: 'center', gap: 6, marginBottom: 10 }}>
        <span style={{ width: 5, height: 5, borderRadius: 3, background: 'var(--coral)' }}/>
        <span style={{ width: 5, height: 5, borderRadius: 3, background: 'var(--sun)' }}/>
        <span style={{ width: 5, height: 5, borderRadius: 3, background: 'var(--mint)' }}/>
      </div>
      <div className="kicker" style={{ color: 'var(--ink-dim)' }}>— with love —</div>
      <div className="display" style={{ fontSize: 20, color: 'var(--ink)', fontStyle: 'italic', marginTop: 8, fontWeight: 500 }}>
        Peniel Church
      </div>
      <div className="mono" style={{ fontSize: 9, letterSpacing: '0.2em', color: 'var(--ink-dim)', marginTop: 4 }}>
        BANQIAO · TAMSUI
      </div>
    </div>
  </div>
);

Object.assign(window, { Hero, PhotoGallery, Overview });
