const { useState, useEffect, useRef } = React;

// Design System — BUBA "Enchanted Storybook" (DESIGN.md 기반)
const COLORS = {
  // Primary Brand
  primary: '#B39DDB',       // Lavender Dream — 메인 브랜드
  primaryDark: '#7E57C2',   // Deep Storybook — 호버/프레스
  dark: '#311B57',          // Royal Purple — 가장 어두운 보라
  // Warm Neutrals (양피지 스케일)
  lightBackground: '#FBF8FF', // Parchment White — 페이지 배경
  warmCream: '#F3E5F5',     // Cream Lavender — 대체 섹션 배경
  warmLight: '#EDE7F6',     // Soft Lilac — 서브 섹션 배경
  // Text
  text: '#37274A',          // Story Brown — 주요 텍스트
  subtitle: '#9575CD',      // Muted Lavender — 부제목 (큰 텍스트용)
  warmGray: '#7B6B8A',      // Warm Gray — 본문 보조 텍스트
  placeholder: '#B0A3BF',   // Light Gray — 플레이스홀더
  // Borders & Surfaces
  border: '#D1C4E9',        // Lavender Border
  white: '#FFFFFF',         // Cloud White — 카드 표면
  disabled: '#D1C4E9',      // Disabled 배경
  // Accents (동화 테마)
  magicGold: '#FFD166',     // Magic Gold — 별점, 프리미엄, 마법
  fairyCoral: '#FF8A80',    // Fairy Coral — 하트, 좋아요
  forestSage: '#81C784',    // Forest Sage — 성공, 자연 카테고리
  skyBlue: '#64B5F6',       // Sky Blue — 정보, 하늘 카테고리
  sunsetOrange: '#FFB74D',  // Sunset Orange — 경고, 모험 카테고리
  rosePink: '#F48FB1',      // Rose Pink — 공주 카테고리
  magicPurple: '#CE93D8',   // Magic Purple — 판타지 카테고리
  // Semantic
  success: '#81C784',       // Forest Sage
  warning: '#FFB74D',       // Sunset Orange
  error: '#EF5350',
  // Admin (별도 팔레트)
  adminNavy: '#1A1A2E',
  adminBlue: '#7C4DFF',
  adminLight: '#F8F7FC',
  lightGray: '#F5F3FA',
};

// Shadow System — 따뜻한 보라-갈색 기반 (cold black 금지)
const SHADOWS = {
  card: '0 4px 16px rgba(55,39,74,0.08), 0 2px 6px rgba(55,39,74,0.05)',
  elevated: '0 8px 32px rgba(55,39,74,0.12), 0 4px 12px rgba(55,39,74,0.06)',
  floating: '0 16px 48px rgba(55,39,74,0.16), 0 4px 16px rgba(55,39,74,0.08)',
  magicGlow: '0 4px 24px rgba(179,157,219,0.35)',
  goldGlow: '0 4px 20px rgba(255,209,102,0.30)',
  focusRing: '0 0 0 4px rgba(179,157,219,0.30)',
};

// Gradient System
const GRADIENTS = {
  cta: `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)`,
  hero: 'linear-gradient(135deg, #F3E5F5 0%, #EDE7F6 40%, #FBF8FF 100%)',
  magic: `linear-gradient(135deg, #B39DDB 0%, #CE93D8 50%, #F48FB1 100%)`,
  gold: 'linear-gradient(135deg, #FFD166, #FFB74D)',
  dark: `linear-gradient(145deg, ${COLORS.dark}, #37274A)`,
  progressFill: 'linear-gradient(90deg, #B39DDB, #CE93D8, #F48FB1)',
};

// Toast Notification System
const ToastContext = React.createContext();
const ToastProvider = ({ children }) => {
  const [toasts, setToasts] = useState([]);
  const addToast = (message, type = 'info', duration = 3000) => {
    const id = Date.now();
    setToasts(prev => [...prev, { id, message, type }]);
    setTimeout(() => setToasts(prev => prev.filter(t => t.id !== id)), duration);
  };
  return (
    <ToastContext.Provider value={addToast}>
      {children}
      <div style={{ position: 'fixed', top: '20px', right: '20px', zIndex: 10000, display: 'flex', flexDirection: 'column', gap: '10px' }}>
        {toasts.map(t => (
          <div key={t.id} style={{
            padding: '14px 24px',
            borderRadius: '16px',
            background: t.type === 'error' ? '#FFEBEE' : t.type === 'success' ? '#E8F5E9' : COLORS.warmLight,
            color: t.type === 'error' ? '#C62828' : t.type === 'success' ? '#2E7D32' : COLORS.text,
            boxShadow: '0 4px 20px rgba(55,39,74,0.15)',
            fontSize: '14px',
            fontWeight: '500',
            animation: 'toastIn 0.3s ease-out',
            maxWidth: '350px',
          }}>
            {t.type === 'error' ? '❌ ' : t.type === 'success' ? '✅ ' : 'ℹ️ '}{t.message}
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
};

// API Helper
const useApi = (token) => {
  return async (url, options = {}) => {
    const headers = { 'Content-Type': 'application/json' };
    if (token) headers['Authorization'] = `Bearer ${token}`;
    const res = await fetch(`/api${url}`, {
      ...options,
      headers: { ...headers, ...options.headers },
    });
    const data = await res.json();
    if (!res.ok) throw new Error(data.error || '오류가 발생했습니다');
    return data;
  };
};

// ===== 수채화 배경 SVG 컴포넌트 =====
const WatercolorLandingBg = () => (
  <svg viewBox="0 0 1440 900" preserveAspectRatio="xMidYMax slice" style={{ position:"absolute", bottom:0, left:0, width:"100%", height:"100%", pointerEvents:"none", opacity:0.45 }}>
    <defs>
      <linearGradient id="wc-sky" x1="0" y1="0" x2="0" y2="1">
        <stop offset="0%" stopColor="#F3E5F5" stopOpacity="0"/>
        <stop offset="100%" stopColor="#EDE7F6" stopOpacity="0.3"/>
      </linearGradient>
      <filter id="wc-blur1"><feGaussianBlur stdDeviation="8"/></filter>
      <filter id="wc-blur2"><feGaussianBlur stdDeviation="4"/></filter>
      <filter id="wc-blur3"><feGaussianBlur stdDeviation="12"/></filter>
      <filter id="wc-glow"><feGaussianBlur stdDeviation="3"/></filter>
    </defs>
    <rect width="1440" height="900" fill="url(#wc-sky)"/>
    {/* 달 */}
    <circle cx="1100" cy="180" r="50" fill="#FFF9C4" opacity="0.2" filter="url(#wc-blur3)"/>
    <circle cx="1100" cy="180" r="30" fill="#FFFDE7" opacity="0.15" filter="url(#wc-blur1)"/>
    {/* 별들 */}
    {[[150,120],[320,80],[500,150],[680,60],[850,130],[1000,90],[1200,110],[1350,70],[200,200],[600,190],[900,170],[1280,160]].map(([x,y],i)=>(
      <circle key={`star-${i}`} cx={x} cy={y} r={1.5+i%3} fill="#FFF9C4" opacity={0.15+i%4*0.05} filter="url(#wc-glow)"/>
    ))}
    {/* 부드러운 언덕 (라벤더) */}
    <path d="M0 600 Q200 520 400 560 Q600 500 800 550 Q1000 510 1200 540 Q1350 520 1440 560 L1440 900 L0 900Z" fill="#E1BEE7" opacity="0.15" filter="url(#wc-blur2)"/>
    <path d="M0 650 Q300 600 600 640 Q900 590 1100 620 Q1300 600 1440 640 L1440 900 L0 900Z" fill="#D1C4E9" opacity="0.12" filter="url(#wc-blur2)"/>
    {/* 펼쳐진 책 모양 */}
    <g transform="translate(720,700)" opacity="0.12">
      <path d="M-80 0 Q-40 -30 0 -20 Q40 -30 80 0 L80 50 Q40 30 0 40 Q-40 30 -80 50Z" fill="#B39DDB" filter="url(#wc-blur1)"/>
      <line x1="0" y1="-20" x2="0" y2="40" stroke="#9575CD" strokeWidth="1" opacity="0.3"/>
    </g>
    {/* 작은 별 반짝임들 (스토리북 분위기) */}
    {[[100,500,"#CE93D8"],[250,450,"#B39DDB"],[400,520,"#E1BEE7"],[550,470,"#D1C4E9"],[700,510,"#CE93D8"],[850,460,"#B39DDB"],[1000,500,"#E1BEE7"],[1150,470,"#D1C4E9"],[1300,510,"#CE93D8"]].map(([x,y,c],i)=>(
      <g key={`sparkle-${i}`} opacity={0.2+i%3*0.08}>
        <circle cx={x} cy={y} r={2} fill={c}/>
        <line x1={x-4} y1={y} x2={x+4} y2={y} stroke={c} strokeWidth="0.5" opacity="0.6"/>
        <line x1={x} y1={y-4} x2={x} y2={y+4} stroke={c} strokeWidth="0.5" opacity="0.6"/>
      </g>
    ))}
    {/* 부드러운 라벤더 번짐 */}
    <circle cx="200" cy="750" r="100" fill="#E1BEE7" opacity="0.06" filter="url(#wc-blur3)"/>
    <circle cx="900" cy="780" r="120" fill="#D1C4E9" opacity="0.05" filter="url(#wc-blur3)"/>
    <circle cx="600" cy="820" r="80" fill="#F3E5F5" opacity="0.08" filter="url(#wc-blur3)"/>
  </svg>
);

const WatercolorBlob = ({ color, size = 200, x = 0, y = 0, opacity = 0.15 }) => (
  <svg width={size} height={size} viewBox="0 0 200 200"
    style={{ position: "absolute", left: x, top: y, opacity, pointerEvents: "none", filter: "blur(2px)" }}>
    <defs>
      <filter id={`wc-${color.replace("#","")}`}>
        <feTurbulence type="fractalNoise" baseFrequency="0.03" numOctaves="4" seed={42}/>
        <feDisplacementMap in="SourceGraphic" scale="30"/>
      </filter>
    </defs>
    <ellipse cx="100" cy="100" rx="85" ry="75" fill={color} filter={`url(#wc-${color.replace("#","")})`}/>
  </svg>
);

// ============ Home C 공용 컴포넌트 (아이콘 · 로고 · 스펙 · 푸터) ============
const Ico = {
  Sparkle: ({size=16, color='#FFD166'}) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none"><path d="M12 2l2.39 6.96L22 11l-6.61 2.39L12 22l-3.39-6.61L2 13l7.61-2.04L12 2z" fill={color}/></svg>),
  Star: ({size=16, filled=true}) => (<svg width={size} height={size} viewBox="0 0 24 24" fill={filled ? '#FFD166' : '#D1C4E9'}><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>),
  Book: ({size=20, color='currentColor'}) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 19.5A2.5 2.5 0 016.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z"/></svg>),
  Camera: ({size=20}) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>),
  Chat: ({size=20}) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>),
  Wand: ({size=20}) => (<svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M15 4V2m0 14v-2m7-5h-2M4 9H2m17.24-6.24l-1.42 1.42M6.76 16.24l-1.42 1.42m0-12.48l1.42 1.42m12.48 12.48l-1.42-1.42"/><circle cx="12" cy="12" r="3"/></svg>),
};

const BubaLogo = ({size=36}) => (
  <div style={{display:'flex', alignItems:'center', gap:10}}>
    <div style={{width:size, height:size, borderRadius:'50%', background:'linear-gradient(135deg, #B39DDB, #7E57C2)', display:'flex', alignItems:'center', justifyContent:'center', boxShadow:'0 4px 16px rgba(179,157,219,0.4)', position:'relative'}}>
      <svg width={size*0.55} height={size*0.55} viewBox="0 0 24 24" fill="#fff"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
      <div style={{position:'absolute', top:-2, right:-2}}><Ico.Sparkle size={12}/></div>
    </div>
    <div>
      <div style={{fontFamily:"'Jua','Gaegu','Nunito',sans-serif", fontSize:20, color:'#311B57', lineHeight:1}}>부바</div>
      <div style={{fontSize:9, color:'#9575CD', letterSpacing:2, marginTop:2}}>BUBA</div>
    </div>
  </div>
);

const BookSpecs = ({variant='light'}) => {
  const dark = variant === 'dark';
  const fg = dark ? '#fff' : '#37274A';
  const sub = dark ? 'rgba(255,255,255,0.7)' : '#7B6B8A';
  const panel = dark ? 'rgba(255,255,255,0.05)' : 'rgba(255,255,255,0.7)';
  const border = dark ? 'rgba(255,255,255,0.12)' : 'rgba(209,196,233,0.55)';
  return (
    <section style={{padding:'80px 48px', background: dark?'#2A1847':'#F6F1E8', position:'relative'}}>
      <div style={{maxWidth:1280, margin:'0 auto'}}>
        <div style={{fontFamily:"'Jua',sans-serif", fontSize:13, color:'#C5A572', letterSpacing:4, marginBottom:10, textTransform:'uppercase'}}>E-Book Viewer Format</div>
        <h2 style={{fontFamily:"'Jua',sans-serif", fontSize:44, color:fg, margin:'0 0 14px', lineHeight:1.15}}>전자 동화책 뷰어 · 400 x 200 규격</h2>
        <p style={{fontSize:16, color:sub, maxWidth:640, lineHeight:1.7, margin:'0 0 48px'}}>부바의 동화는 <strong style={{color:fg}}>펼침 기준 400 x 200 (2:1)</strong> 와이드 뷰어로 재생되는 전자책입니다.</p>
        <div style={{display:'grid', gridTemplateColumns:'1.1fr 1fr', gap:48, alignItems:'center'}} className="responsive-grid">
          <div style={{background:panel, border:`1px solid ${border}`, borderRadius:24, padding:40, minHeight:360}}>
            <div style={{display:'flex', alignItems:'center', justifyContent:'center', gap:10, marginBottom:14, color:sub, fontSize:12, letterSpacing:2}}>
              <div style={{flex:1, height:1, background:border}}/><span style={{fontFamily:'monospace', fontWeight:700, color:fg}}>400 · 뷰어 펼침 (2:1)</span><div style={{flex:1, height:1, background:border}}/>
            </div>
            <div style={{display:'flex', aspectRatio:'2/1', borderRadius:6, overflow:'hidden', boxShadow:'0 20px 60px rgba(49,27,87,0.25)'}}>
              <div style={{flex:1, background:'linear-gradient(135deg, #F6F1E8, #E8DCC4)', padding:20, borderRight:'1px solid rgba(49,27,87,0.15)', display:'flex', alignItems:'center', justifyContent:'center', color:'#9B8866', fontSize:10}}>삽화</div>
              <div style={{flex:1, background:'linear-gradient(135deg, #FFF9EC, #F6EFD9)', padding:20, display:'flex', alignItems:'center', justifyContent:'center', color:'#9B8866', fontSize:10}}>본문</div>
            </div>
          </div>
          <dl style={{margin:0}}>
            {[{t:'뷰어 판형', v:'펼침 400x200 (2:1) · 페이지 200x200 정사각'},{t:'분량', v:'표지 + 본문 12p'},{t:'해상도', v:'2048x1024 기본 / 레티나 4K 대응'},{t:'지원 기기', v:'PC · 태블릿 · 모바일 스와이프'},{t:'읽기 기능', v:'AI 내레이션(TTS) · 배경음 · 자동 넘김'},{t:'공유', v:'링크 공유 · PDF 다운로드 · 앨범 저장'}].map(s=>(
              <div key={s.t} style={{display:'grid', gridTemplateColumns:'110px 1fr', gap:20, padding:'16px 0', borderBottom:`1px solid ${border}`}}>
                <dt style={{fontSize:13, color:sub, fontWeight:600, letterSpacing:1}}>{s.t}</dt>
                <dd style={{margin:0, fontSize:15, color:fg, lineHeight:1.5, fontWeight:500}}>{s.v}</dd>
              </div>
            ))}
          </dl>
        </div>
      </div>
    </section>
  );
};

const SiteFooter = ({variant='dark'}) => {
  const dark = variant === 'dark';
  const bg = dark ? '#1E1230' : '#F0EAE0';
  const fg = dark ? '#fff' : '#37274A';
  const sub = dark ? 'rgba(255,255,255,0.7)' : '#5B4A70';
  const muted = dark ? 'rgba(255,255,255,0.45)' : '#9B8AAD';
  const border = dark ? 'rgba(255,255,255,0.12)' : 'rgba(49,27,87,0.12)';
  const hover = dark ? 'rgba(255,255,255,0.08)' : 'rgba(49,27,87,0.06)';
  const socials = [
    {k:'instagram', label:'인스타그램 @buba.kr', href:'https://instagram.com/buba.kr',
      svg:<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor"/></svg>},
    {k:'youtube', label:'유튜브 @buba', href:'https://youtube.com/@buba',
      svg:<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinejoin="round"><rect x="2.5" y="6" width="19" height="12" rx="3"/><path d="M10.5 9.5 L 15 12 L 10.5 14.5 Z" fill="currentColor" stroke="none"/></svg>},
    {k:'kakao', label:'카카오톡 채널 @부바', href:'https://pf.kakao.com/_buba',
      svg:<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 4c-4.97 0-9 3.13-9 7 0 2.3 1.45 4.32 3.68 5.6L5.8 20l3.5-2.2c.87.18 1.77.27 2.7.27 4.97 0 9-3.13 9-7s-4.03-7-9-7Z"/></svg>},
  ];
  return (
    <footer role="contentinfo" style={{background:bg, color:fg, padding:'56px 48px 28px', fontSize:13, lineHeight:1.6}}>
      <div style={{maxWidth:1200, margin:'0 auto'}}>
        {/* 상단: 로고 + 카톡 상담 CTA + 소셜 */}
        <div style={{display:'flex', flexWrap:'wrap', gap:32, alignItems:'flex-start', justifyContent:'space-between', paddingBottom:32, borderBottom:`1px solid ${border}`}}>
          <div style={{maxWidth:420}}>
            <BubaLogo/>
            <p style={{color:sub, marginTop:14, fontSize:13, lineHeight:1.7}}>AI × 전문가 일러스트레이터가 함께 만드는,<br/>아이가 주인공인 맞춤 전자 동화책.</p>
          </div>
          <a href="https://pf.kakao.com/_buba/chat" target="_blank" rel="noopener noreferrer"
             style={{display:'inline-flex', alignItems:'center', gap:10, background:'#FEE500', color:'#3C1E1E', textDecoration:'none', padding:'14px 22px', borderRadius:12, fontWeight:700, fontSize:14, boxShadow: dark ? '0 4px 16px rgba(0,0,0,0.3)' : '0 4px 12px rgba(49,27,87,0.15)'}}>
            <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="#3C1E1E" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 4c-4.97 0-9 3.13-9 7 0 2.3 1.45 4.32 3.68 5.6L5.8 20l3.5-2.2c.87.18 1.77.27 2.7.27 4.97 0 9-3.13 9-7s-4.03-7-9-7Z"/></svg>
            카카오톡 고객상담 →
          </a>
          <nav style={{display:'flex', gap:10}}>
            {socials.map(s => (
              <a key={s.k} href={s.href} target="_blank" rel="noopener noreferrer" aria-label={s.label}
                 style={{width:44, height:44, borderRadius:12, background:hover, display:'inline-flex', alignItems:'center', justifyContent:'center', color:fg, textDecoration:'none'}}
                 onMouseEnter={e=>e.currentTarget.style.background=dark?'rgba(255,255,255,0.16)':'rgba(49,27,87,0.12)'}
                 onMouseLeave={e=>e.currentTarget.style.background=hover}>
                {s.svg}
              </a>
            ))}
          </nav>
        </div>

        {/* 약관 · 정책 */}
        <nav style={{display:'flex', flexWrap:'wrap', gap:'10px 28px', padding:'22px 0', borderBottom:`1px solid ${border}`, alignItems:'center'}}>
          <a href="/terms" style={{color:fg, fontSize:13, textDecoration:'none', fontWeight:700}}>이용약관</a>
          <a href="/privacy" style={{color:fg, fontSize:13, textDecoration:'none', fontWeight:700}}><span style={{textDecoration:'underline', textUnderlineOffset:3}}>개인정보처리방침</span></a>
          <a href="/youth" style={{color:sub, fontSize:13, textDecoration:'none'}}>청소년보호정책</a>
          <a href="/delivery" style={{color:sub, fontSize:13, textDecoration:'none'}}>배송·교환·환불</a>
          <a href="/photo-consent" style={{color:sub, fontSize:13, textDecoration:'none'}}>사진 이용 동의</a>
        </nav>

        {/* 사업자 정보 */}
        <address style={{fontStyle:'normal', display:'grid', gridTemplateColumns:'repeat(auto-fit, minmax(260px, 1fr))', gap:'10px 32px', padding:'24px 0', color:sub, fontSize:12, lineHeight:1.8}}>
          <div><strong style={{color:fg, fontWeight:600, marginRight:8}}>상호</strong>(주)부바스튜디오<span style={{margin:'0 10px', color:border}}>|</span><strong style={{color:fg, fontWeight:600, marginRight:8}}>대표</strong>김부바</div>
          <div><strong style={{color:fg, fontWeight:600, marginRight:8}}>사업자등록번호</strong><span>123-45-67890</span><a href="https://www.ftc.go.kr/bizCommPop.do?wrkr_no=1234567890" target="_blank" rel="noopener noreferrer" style={{color:sub, marginLeft:8, fontSize:11, textDecoration:'underline'}}>[사업자정보확인]</a></div>
          <div><strong style={{color:fg, fontWeight:600, marginRight:8}}>통신판매업신고</strong>제 2024-서울강남-12345호</div>
          <div><strong style={{color:fg, fontWeight:600, marginRight:8}}>이메일</strong><a href="mailto:hello@buba.kr" style={{color:sub}}>hello@buba.kr</a></div>
          <div style={{gridColumn:'1 / -1'}}><strong style={{color:fg, fontWeight:600, marginRight:8}}>주소</strong>서울특별시 강남구 테헤란로 123, 8층 (역삼동)<span style={{margin:'0 10px', color:border}}>|</span><strong style={{color:fg, fontWeight:600, marginRight:8}}>개인정보보호책임자</strong>이보바 (<a href="mailto:privacy@buba.kr" style={{color:sub}}>privacy@buba.kr</a>)</div>
        </address>

        {/* 저작권 + 인증 배지 */}
        <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', flexWrap:'wrap', gap:16, paddingTop:20, borderTop:`1px solid ${border}`}}>
          <small style={{color:muted, fontSize:11}}>© 2026 BUBA Studio, Inc. All rights reserved.</small>
          <div style={{display:'flex', gap:8, alignItems:'center'}}>
            {['KC 안전확인','ISMS','에스크로','토스페이먼츠'].map(b => (
              <span key={b} style={{padding:'5px 10px', borderRadius:6, border:`1px solid ${border}`, fontSize:10, letterSpacing:0.5, color:muted, fontWeight:600}}>{b}</span>
            ))}
          </div>
        </div>
      </div>
    </footer>
  );
};

// ============ Landing Page Component (Home C · 스크롤 내러티브) ============
// 이미지 플레이스홀더 — 관리자가 이미지 업로드 전 표시
const ImgOrPlaceholder = ({src, alt='', style={}, gradient='linear-gradient(135deg, #B39DDB, #7E57C2)', label}) => {
  const [broken, setBroken] = useState(false);
  if (!src || broken) {
    return <div style={{...style, background:gradient, display:'flex', alignItems:'center', justifyContent:'center', color:'rgba(255,255,255,0.6)', fontSize:13, fontWeight:600, textAlign:'center', padding:16}}>{label || '관리자 페이지에서 이미지를 등록하세요'}</div>;
  }
  return <img src={src} alt={alt} style={style} onError={() => setBroken(true)} />;
};

// 이미지 로드 실패 시 큰 emoji로 폴백하는 컴포넌트 (템플릿 카드용)
const EmojiFallbackImg = ({ src, emoji = '📖', emojiSize = 56, style = {}, bgColor }) => {
  const [broken, setBroken] = useState(false);
  if (!src || broken) {
    return (
      <div style={{ ...style, ...(bgColor ? { background: bgColor } : {}), display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <span style={{ fontSize: `${emojiSize}px` }}>{emoji}</span>
      </div>
    );
  }
  return (
    <img
      src={src}
      alt=""
      onError={() => setBroken(true)}
      draggable={false}
      onDragStart={(e) => e.preventDefault()}
      onContextMenu={(e) => e.preventDefault()}
      style={{ ...style, objectFit: 'cover', WebkitUserDrag: 'none', userSelect: 'none' }}
    />
  );
};

// 랜딩 Chapter 2 스토리 카드 — admin 슬롯 이미지 우선, 없거나 깨지면 stories.js cover, 그것도 없으면 gradient+emoji 폴백
const StoryCard = ({ s, slotImg }) => {
  const [broken, setBroken] = useState(false);
  const src = !broken ? (slotImg || s.cover) : null;
  if (src) {
    return (
      <div style={{borderRadius:8, overflow:'hidden', boxShadow:'0 2px 8px rgba(55,39,74,0.08)', border:'1px solid #E8DEF8', background:'#fff'}}>
        <img
          src={src}
          alt={s.title}
          onError={() => setBroken(true)}
          draggable={false}
          onDragStart={(e) => e.preventDefault()}
          onContextMenu={(e) => e.preventDefault()}
          style={{width:'100%', aspectRatio:'2/1', objectFit:'cover', display:'block', WebkitUserDrag:'none', userSelect:'none'}}
        />
        <div style={{padding:'12px 14px'}}>
          <div style={{fontSize:10, padding:'3px 8px', marginBottom:6, display:'inline-block', borderRadius:9999, background:'rgba(179,157,219,0.12)', color:'#7E57C2', fontWeight:600}}>{s.tag}</div>
          <div style={{fontFamily:"'Jua',sans-serif", fontSize:14, color:'#311B57'}}>{s.title}</div>
        </div>
      </div>
    );
  }
  return (
    <div style={{borderRadius:8, boxShadow:'0 2px 8px rgba(55,39,74,0.08)', background:`linear-gradient(135deg, ${s.color}, ${s.color}cc)`, color:'#fff', padding:18, display:'flex', flexDirection:'column', justifyContent:'space-between', minHeight:150}}>
      <div style={{display:'flex', alignItems:'center', justifyContent:'space-between'}}>
        <div style={{fontSize:28}}>{s.emoji}</div>
        <div style={{fontSize:10, padding:'3px 8px', borderRadius:9999, background:'rgba(255,255,255,0.25)', color:'#fff', fontWeight:600}}>{s.tag}</div>
      </div>
      <div style={{fontFamily:"'Jua',sans-serif", fontSize:16}}>{s.title}</div>
    </div>
  );
};

const LandingPage = ({ onNavigate, user, token, onLogout }) => {
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
  const [uploadedPhoto, setUploadedPhoto] = useState(null);
  const [convertedPhoto, setConvertedPhoto] = useState(null);
  const [converting, setConverting] = useState(false);
  const [storyTemplates, setStoryTemplates] = useState([]);
  const [landingImages, setLandingImages] = useState({});
  const fileInputRef = useRef(null);

  useEffect(() => {
    fetch('/api/templates').then(r => r.json()).then(data => {
      const list = Array.isArray(data) ? data : (data.templates || []);
      setStoryTemplates(list);
    }).catch(() => {});
    // 관리자가 업로드한 랜딩 이미지 로드
    fetch('/api/admin/landing-images-public').then(r => r.json()).then(data => {
      setLandingImages(data);
    }).catch(() => {});
  }, []);

  const handlePhotoUpload = (file) => {
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (e) => setUploadedPhoto(e.target.result);
    reader.readAsDataURL(file);
  };

  const handleConvertFace = async () => {
    if (!uploadedPhoto) return;
    setConverting(true);
    try {
      const res = await fetch('/api/trial/face-convert', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ imageData: uploadedPhoto }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || '변환 실패');
      setConvertedPhoto('data:image/jpeg;base64,' + data.image);
    } catch (err) {
      alert('사진 변환에 실패했습니다: ' + err.message);
    } finally {
      setConverting(false);
    }
  };

  // 네비게이션
  const TopNav = () => (
    <nav style={{display:'flex', alignItems:'center', justifyContent:'space-between', padding:'18px 32px', position:'sticky', top:0, zIndex:100, background:'rgba(255,255,255,0.9)', backdropFilter:'blur(14px)', borderBottom:'1px solid #E8DEF8'}}>
      <div style={{cursor:'pointer'}} onClick={() => onNavigate('landing')}><BubaLogo/></div>
      <div className="hide-mobile" style={{display:'flex', gap:6, alignItems:'center'}}>
        {token && user ? (<>
          <span style={{fontSize:14, color:'#37274A', fontWeight:600, marginRight:4}}>{user.name || user.email}님</span>
          <button onClick={() => onNavigate('mypage')} style={{background:'transparent', border:'1.5px solid #B39DDB', color:'#7E57C2', padding:'8px 16px', borderRadius:20, cursor:'pointer', fontWeight:600, fontSize:14}}>마이페이지</button>
          <button onClick={() => onNavigate('templates')} style={{background:'#7E57C2', color:'#fff', padding:'8px 16px', borderRadius:20, border:'none', cursor:'pointer', fontWeight:700, fontSize:14, display:'flex', alignItems:'center', gap:6}}><Ico.Wand size={14}/> 동화 만들기</button>
          <button onClick={onLogout} style={{background:'transparent', border:'1.5px solid #B39DDB', color:'#7E57C2', padding:'8px 16px', borderRadius:20, cursor:'pointer', fontWeight:600, fontSize:14}}>로그아웃</button>
        </>) : (<>
          <button onClick={() => onNavigate('login')} style={{background:'transparent', border:'1.5px solid #B39DDB', color:'#7E57C2', padding:'8px 16px', borderRadius:20, cursor:'pointer', fontWeight:600, fontSize:14}}>로그인</button>
          <button onClick={() => onNavigate('register')} style={{background:'#7E57C2', color:'#fff', padding:'8px 16px', borderRadius:20, border:'none', cursor:'pointer', fontWeight:700, fontSize:14, display:'flex', alignItems:'center', gap:6}}><Ico.Wand size={14}/> 무료 시작하기</button>
        </>)}
      </div>
      <button className="show-mobile-only" onClick={() => setMobileMenuOpen(!mobileMenuOpen)} style={{display:'none', background:'none', border:'none', cursor:'pointer', padding:8, fontSize:24, color:'#311B57'}}>{mobileMenuOpen ? '✕' : '☰'}</button>
    </nav>
  );

  return (
    <div style={{minHeight:'100vh', background:'#FBF8FF', color:'#37274A', overflow:'hidden'}}>
      <TopNav/>
      {mobileMenuOpen && (
        <div style={{position:'fixed', top:72, left:0, right:0, background:'rgba(255,255,255,0.97)', backdropFilter:'blur(10px)', padding:20, zIndex:99, borderBottom:'1px solid #D1C4E9', display:'flex', flexDirection:'column', gap:12}}>
          {token && user ? (<>
            <span style={{color:'#37274A', fontWeight:600, fontSize:14, padding:'8px 0'}}>{user.name || user.email}님</span>
            <button onClick={()=>{onNavigate('mypage'); setMobileMenuOpen(false);}} style={{padding:'8px 16px', borderRadius:20, border:'1.5px solid #B39DDB', background:'transparent', color:'#7E57C2', cursor:'pointer', fontWeight:600}}>마이페이지</button>
            <button onClick={()=>{onNavigate('templates'); setMobileMenuOpen(false);}} style={{padding:'8px 16px', borderRadius:20, background:'#7E57C2', color:'#fff', border:'none', cursor:'pointer', fontWeight:700}}>동화 만들기</button>
            <button onClick={()=>{onLogout(); setMobileMenuOpen(false);}} style={{padding:'8px 16px', borderRadius:20, border:'1.5px solid #B39DDB', background:'transparent', color:'#7E57C2', cursor:'pointer', fontWeight:600}}>로그아웃</button>
          </>) : (<>
            <button onClick={()=>{onNavigate('login'); setMobileMenuOpen(false);}} style={{padding:'8px 16px', borderRadius:20, border:'1.5px solid #B39DDB', background:'transparent', color:'#7E57C2', cursor:'pointer', fontWeight:600}}>로그인</button>
            <button onClick={()=>{onNavigate('register'); setMobileMenuOpen(false);}} style={{padding:'8px 16px', borderRadius:20, background:'#7E57C2', color:'#fff', border:'none', cursor:'pointer', fontWeight:700}}>무료 시작하기</button>
          </>)}
        </div>
      )}

      {/* HERO */}
      <section style={{position:'relative', height:'min(720px, 85vh)', minHeight:560, overflow:'hidden'}}>
        <ImgOrPlaceholder src={landingImages.hero} alt="" style={{position:'absolute', inset:0, width:'100%', height:'100%', objectFit:'cover'}} gradient="linear-gradient(135deg, rgba(179,157,219,0.5), rgba(126,87,194,0.7)), linear-gradient(180deg, #F3EBFF 0%, #D1C4E9 100%)" label="히어로 배경 이미지"/>
        <div style={{position:'absolute', inset:0, background:'linear-gradient(180deg, rgba(251,248,255,0.2) 0%, rgba(49,27,87,0.5) 60%, rgba(30,15,56,0.88) 100%)'}}/>
        <div style={{position:'absolute', inset:0, display:'flex', alignItems:'flex-end', justifyContent:'center', paddingBottom:'8vh'}}>
          <div style={{textAlign:'center', color:'#fff', maxWidth:820, padding:'0 32px'}}>
            <div style={{fontFamily:"'Jua','Noto Sans KR',sans-serif", fontSize:20, color:'#FFD166', marginBottom:16, letterSpacing:2}}>✦ 옛날 옛날에 ✦</div>
            <h1 style={{fontSize:'clamp(40px, 6vw, 72px)', lineHeight:1.05, marginBottom:20, textShadow:'0 2px 8px rgba(0,0,0,0.2)', fontFamily:"'Jua','Noto Sans KR',sans-serif"}}>사진 한 장이,<br/>우리 아이의 동화가 돼요.</h1>
            <p style={{fontSize:17, opacity:0.92, lineHeight:1.6, maxWidth:640, margin:'0 auto 32px'}}>AI가 아이의 얼굴로 수채화 주인공을 그려내고,<br/><b style={{color:'#FFD166'}}>전문 일러스트레이터가 모든 장면을 최종 검수</b>합니다.</p>
            <div style={{display:'flex', gap:14, justifyContent:'center', flexWrap:'wrap'}}>
              <button onClick={() => onNavigate(token ? 'templates' : 'register')} style={{background:'#FFD166', color:'#1E1230', padding:'8px 16px', fontSize:16, borderRadius:20, border:'none', cursor:'pointer', fontWeight:700, display:'flex', alignItems:'center', gap:8}}><Ico.Wand size={18}/> 지금 시작하기</button>
              <button onClick={() => document.getElementById('story-showcase')?.scrollIntoView({behavior:'smooth', block:'start'})} style={{background:'transparent', color:'#fff', border:'1.5px solid rgba(255,255,255,0.4)', padding:'8px 16px', borderRadius:20, cursor:'pointer', fontWeight:600, display:'flex', alignItems:'center', gap:8}}><Ico.Book size={18}/> 샘플 보기</button>
            </div>
          </div>
        </div>
      </section>

      {/* CHAPTER 1: 사진 업로드 */}
      <section style={{padding:'clamp(80px, 12vw, 120px) 32px', background:'#FAF6FF', borderLeft:'3px solid #D1C4E9'}}>
        <div style={{maxWidth:1200, margin:'0 auto', display:'grid', gridTemplateColumns:'1fr 1fr', gap:64, alignItems:'center'}} className="responsive-grid">
          <div>
            <div style={{fontFamily:"'Jua','Noto Sans KR',sans-serif", fontSize:18, color:'#9575CD', marginBottom:8}}>— Chapter 1 —</div>
            <div style={{fontFamily:"'Jua',sans-serif", fontSize:88, color:'#EDE7F6', lineHeight:0.9, marginBottom:-30, userSelect:'none'}}>01</div>
            <h2 style={{fontSize:'clamp(32px, 4vw, 42px)', color:'#311B57', marginBottom:20, fontFamily:"'Jua','Noto Sans KR',sans-serif"}}>사진 한 장, 그걸로<br/>충분해요.</h2>
            <p style={{fontSize:17, color:'#8A7FA8', lineHeight:1.6, marginBottom:28}}>아이의 정면 얼굴 사진 한 장이면 돼요. 정돈된 스튜디오 사진이 아니어도, 일상에서 찍은 환한 웃음 사진이면 충분합니다. AI는 얼굴의 특징만 부드럽게 학습해, 수채화 속 주인공으로 그려냅니다.</p>
            <div style={{display:'flex', gap:16, padding:'14px 16px', background:'#EDE7F6', borderRadius:12, fontSize:14, color:'#37274A', alignItems:'flex-start'}}><Ico.Sparkle size={20}/><div>업로드한 원본 사진은 48시간 후 자동 삭제됩니다. 개인정보는 안전하게 보호돼요.</div></div>
            {/* 무료 체험 */}
            <div style={{marginTop:24, padding:'24px', background:'#fff', borderRadius:12, border:'2px dashed #B39DDB', boxShadow:'0 4px 24px rgba(0,0,0,0.08)'}}>
              <div style={{display:'flex', alignItems:'center', gap:10, marginBottom:16}}>
                <span style={{fontSize:12, fontWeight:700, padding:'3px 10px', borderRadius:12, background:'#FFF4CC', color:'#B8860B'}}>FREE TRIAL</span>
                <div style={{fontSize:14, color:'#8A7FA8'}}>지금 바로 변환을 체험해보세요</div>
              </div>
              <div style={{display:'grid', gridTemplateColumns: uploadedPhoto ? '1fr 1fr' : '1fr', gap:16}}>
                <div onClick={() => fileInputRef.current?.click()} onDragOver={(e)=>e.preventDefault()} onDrop={(e)=>{e.preventDefault(); const f=e.dataTransfer.files[0]; if(f) handlePhotoUpload(f);}} style={{border:'2px dashed #B39DDB', borderRadius:10, padding:24, textAlign:'center', cursor:'pointer', background:'#FBF8FF', minHeight:160, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center'}}>
                  {uploadedPhoto ? <img src={uploadedPhoto} alt="업로드한 사진" style={{maxWidth:'100%', maxHeight:160, borderRadius:8}}/> : <><Ico.Camera size={32}/><p style={{fontSize:14, fontWeight:600, color:'#37274A', marginTop:8}}>사진 선택 또는 드래그</p></>}
                  <input ref={fileInputRef} type="file" accept="image/*" style={{display:'none'}} onChange={(e) => handlePhotoUpload(e.target.files?.[0])}/>
                </div>
                {uploadedPhoto && <div style={{display:'flex', flexDirection:'column', gap:12, justifyContent:'center'}}>
                  {convertedPhoto ? <><img src={convertedPhoto} alt="변환된 일러스트" style={{width:'100%', borderRadius:8}}/><button onClick={() => onNavigate(token ? 'templates' : 'register')} style={{background:'#7E57C2', color:'#fff', padding:'8px 16px', borderRadius:20, border:'none', cursor:'pointer', fontWeight:700}}>{token ? '동화 만들기' : '가입하고 동화 만들기'}</button></> : <button onClick={handleConvertFace} disabled={converting} style={{background:'#7E57C2', color:'#fff', padding:'8px 16px', borderRadius:20, border:'none', cursor:'pointer', fontWeight:700, opacity:converting?0.6:1}}>{converting ? '변환 중...' : 'AI로 변환하기'}</button>}
                </div>}
              </div>
            </div>
          </div>
          <div style={{position:'relative', minHeight:520}} className="hide-mobile">
            <div style={{position:'absolute', top:40, left:0, width:280, height:360, borderRadius:16, background:'#fff', padding:16, boxShadow:'0 16px 40px rgba(55,39,74,0.15)', transform:'rotate(-4deg)'}}>
              <div style={{width:'100%', height:'90%', borderRadius:10, background:'repeating-linear-gradient(45deg, #EDE7F6, #EDE7F6 8px, #F3E5F5 8px, #F3E5F5 16px)', display:'flex', alignItems:'center', justifyContent:'center', flexDirection:'column', gap:12, color:'#9575CD'}}><Ico.Camera size={48}/><div style={{fontFamily:'monospace', fontSize:11}}>[아이의 얼굴 사진]</div></div>
            </div>
            <div style={{position:'absolute', top:60, right:0, width:360, height:180, borderRadius:10, overflow:'hidden', boxShadow:'0 16px 40px rgba(55,39,74,0.2)', transform:'rotate(4deg)'}}><ImgOrPlaceholder src={landingImages.ch1_illustration} alt="수채화 일러스트 샘플" style={{width:'100%', height:'100%', objectFit:'cover'}} label="일러스트 샘플"/></div>
          </div>
        </div>
      </section>

      {/* CHAPTER 2: 스토리 선택 */}
      <section id="story-showcase" style={{padding:'clamp(80px, 12vw, 120px) 32px', background:'#F3EBFF', borderLeft:'3px solid #B39DDB', overflow:'hidden'}}>
        <div style={{maxWidth:1240, margin:'0 auto', display:'grid', gridTemplateColumns:'1.1fr 1fr', gap:56, alignItems:'center'}} className="responsive-grid">
          <div style={{display:'grid', gridTemplateColumns:'repeat(2, 1fr)', gap:20}} className="hide-mobile">
            {(window.BUBA_STORIES?.boy || []).slice(0,3).map((s, i)=>(
              <StoryCard key={s.id} s={s} slotImg={landingImages[`story_boy${i+1}`]}/>
            ))}
            {(window.BUBA_STORIES?.girl || []).slice(0,3).map((s, i)=>(
              <StoryCard key={s.id} s={s} slotImg={landingImages[`story_girl${i+1}`]}/>
            ))}
          </div>
          <div>
            <div style={{fontFamily:"'Jua','Noto Sans KR',sans-serif", fontSize:18, color:'#7E57C2', marginBottom:8}}>— Chapter 2 —</div>
            <div style={{fontFamily:"'Jua',sans-serif", fontSize:88, color:'rgba(179,157,219,0.3)', lineHeight:0.9, marginBottom:-30}}>02</div>
            <h2 style={{fontSize:'clamp(32px, 4vw, 42px)', color:'#311B57', marginBottom:20, fontFamily:"'Jua',sans-serif"}}>우리 아이에게<br/>어울리는 이야기를 고르세요.</h2>
            <p style={{fontSize:17, color:'#7B6B8A', lineHeight:1.8, marginBottom:24}}>남자아이 주인공 <b style={{color:'#7E57C2'}}>부키 12편</b>, 여자아이 주인공 <b style={{color:'#7E57C2'}}>바바 10편</b>. 판타지, 모험, 전래동화, 우주 과학까지 — 연령과 취향에 맞춰 고를 수 있어요.</p>
            <div style={{display:'flex', flexWrap:'wrap', gap:8, marginBottom:28}}>
              {(window.BUBA_TAGS || []).slice(1,7).map(t=><span key={t} style={{display:'inline-flex', padding:'6px 14px', borderRadius:9999, background:'#fff', border:'1px solid #D1C4E9', fontSize:12, fontWeight:600, color:'#7E57C2'}}>{t}</span>)}
            </div>
            <button onClick={() => onNavigate(token ? 'templates' : 'register')} style={{background:'#7E57C2', color:'#fff', padding:'8px 16px', borderRadius:20, border:'none', cursor:'pointer', fontWeight:700, display:'flex', alignItems:'center', gap:8}}><Ico.Book size={16}/> 22편 전체 둘러보기</button>
          </div>
        </div>
      </section>

      {/* CHAPTER 3: 전문가 검수 */}
      <section style={{padding:'clamp(80px, 12vw, 120px) 32px', background:'#2D1C47', color:'#fff', borderLeft:'3px solid #FFD166', overflow:'hidden'}}>
        <div style={{maxWidth:1200, margin:'0 auto', display:'grid', gridTemplateColumns:'1fr 1fr', gap:64, alignItems:'center'}} className="responsive-grid">
          <div>
            <div style={{fontFamily:"'Jua','Noto Sans KR',sans-serif", fontSize:18, color:'#FFD166', marginBottom:8}}>— Chapter 3 —</div>
            <div style={{fontFamily:"'Jua',sans-serif", fontSize:88, color:'rgba(255,255,255,0.1)', lineHeight:0.9, marginBottom:-30}}>03</div>
            <h2 style={{fontSize:'clamp(32px, 4vw, 42px)', marginBottom:20, lineHeight:1.2, fontFamily:"'Jua',sans-serif"}}>AI가 아닌,<br/><span style={{color:'#FFD166'}}>사람의 손</span>으로 완성합니다.</h2>
            <p style={{fontSize:17, opacity:0.85, lineHeight:1.8, marginBottom:28}}>AI가 만든 초안을 전문 일러스트레이터가 한 장 한 장 검수하고 다듬습니다. 어색한 표정, 구도, 색감 불일치 — 모두 사람이 봅니다. 그래서 <b style={{color:'#FFD166'}}>부바 동화책은 3~5일이 걸립니다.</b></p>
            <div style={{display:'grid', gridTemplateColumns:'repeat(2, 1fr)', gap:16}}>
              {[{n:'03', t:'장인의 수정', d:'표정·구도·색감 수작업 보정'},{n:'04', t:'이중 승인', d:'내부 검수 → 부모님 최종 확인'}].map((s,i)=>(
                <div key={i} style={{padding:20, background:'rgba(255,255,255,0.08)', borderRadius:14, border:'1px solid rgba(255,255,255,0.1)'}}>
                  <div style={{fontFamily:"'Jua',sans-serif", fontSize:22, color:'#FFD166', marginBottom:6}}>Step {s.n}</div>
                  <div style={{fontWeight:700, marginBottom:4}}>{s.t}</div>
                  <div style={{fontSize:13, opacity:0.7}}>{s.d}</div>
                </div>
              ))}
            </div>
          </div>
          <div style={{position:'relative', height:540}} className="hide-mobile">
            <div style={{position:'absolute', top:0, left:0, right:40, background:'#fff', borderRadius:16, padding:24, color:'#37274A', boxShadow:'0 16px 48px rgba(0,0,0,0.3)'}}>
              <div style={{display:'flex', alignItems:'center', gap:10, marginBottom:14}}>
                <div style={{width:32, height:32, borderRadius:'50%', background:'#B39DDB', display:'flex', alignItems:'center', justifyContent:'center', color:'#fff'}}><Ico.Wand size={16}/></div>
                <div style={{fontSize:13, fontWeight:600}}>디자이너 수정 중</div>
                <div style={{marginLeft:'auto', fontSize:11, color:'#9575CD'}}>3/5 단계</div>
              </div>
              <div style={{height:6, background:'#EDE7F6', borderRadius:3, overflow:'hidden', marginBottom:16}}><div style={{width:'60%', height:'100%', background:'linear-gradient(90deg, #B39DDB, #F48FB1)'}}/></div>
              <div style={{display:'flex', gap:8, marginBottom:16}}>
                {[{slot:'ch3_preview1',l:'미리보기 1'},{slot:'ch3_preview2',l:'미리보기 2'},{slot:'ch3_preview3',l:'미리보기 3'}].map(p=><div key={p.slot} style={{flex:1, aspectRatio:'2/1', borderRadius:10, overflow:'hidden'}}><ImgOrPlaceholder src={landingImages[p.slot]} alt="" style={{width:'100%', height:'100%', objectFit:'cover'}} gradient="linear-gradient(135deg, #9575CD, #B39DDB)" label={p.l}/></div>)}
              </div>
              <div style={{fontSize:12, color:'#7B6B8A'}}>✓ 얼굴 일관성 확인 · ✓ 배경 색감 조정 · ⏳ 최종 검수 대기</div>
            </div>
            <div style={{position:'absolute', bottom:0, right:0, width:320, background:'#FEE500', borderRadius:16, padding:'16px 20px', boxShadow:'0 12px 32px rgba(0,0,0,0.25)', transform:'rotate(3deg)'}}>
              <div style={{display:'flex', alignItems:'center', gap:8, marginBottom:8}}><Ico.Chat size={18}/><div style={{fontSize:13, fontWeight:700, color:'#3C1E1E'}}>카카오톡 알림</div></div>
              <div style={{fontSize:14, color:'#3C1E1E', lineHeight:1.5}}><b>[부바]</b> 지우의 동화책이 완성됐어요!<br/><span style={{fontSize:12, opacity:0.8}}>지금 바로 읽어보세요 →</span></div>
            </div>
          </div>
        </div>
      </section>

      {/* FINAL: 평생 소장 */}
      <section style={{padding:'clamp(80px, 12vw, 120px) 32px', background:'#FBF8FF'}}>
        <div style={{maxWidth:1200, margin:'0 auto', textAlign:'center'}}>
          <div style={{fontFamily:"'Jua','Noto Sans KR',sans-serif", fontSize:18, color:'#9575CD', marginBottom:8}}>— Final Chapter —</div>
          <h2 style={{fontSize:'clamp(32px, 4vw, 48px)', color:'#311B57', marginBottom:20, lineHeight:1.2, fontFamily:"'Jua',sans-serif"}}>그리고, 아이는<br/><span style={{backgroundImage:'linear-gradient(transparent 65%, rgba(255,209,102,0.45) 65%)', padding:'0 3px'}}>평생 간직할 이야기</span>를 얻습니다.</h2>
          <p style={{fontSize:17, color:'#7B6B8A', maxWidth:640, margin:'0 auto 56px', lineHeight:1.8}}>전자책은 마이페이지에서 언제든 다시 열람할 수 있고, 카톡 링크로 할머니·할아버지에게도 쉽게 공유할 수 있어요.</p>
          <div style={{maxWidth:960, margin:'0 auto', background:'#1E0F38', borderRadius:20, padding:24, boxShadow:'0 24px 64px rgba(55,39,74,0.25)'}}>
            <div style={{display:'flex', alignItems:'center', gap:8, marginBottom:16}}>
              {['#FF8A80','#FFD166','#81C784'].map((c,i)=><div key={i} style={{width:12, height:12, borderRadius:'50%', background:c}}/>)}
              <div style={{marginLeft:12, fontSize:12, color:'rgba(255,255,255,0.5)'}}>buba.co.kr/reader/yr-dongwha</div>
            </div>
            <div style={{borderRadius:12, overflow:'hidden'}}><div style={{position:'relative', aspectRatio:'2/1'}}><ImgOrPlaceholder src={landingImages.viewer_sample} alt="동화책 뷰어 샘플" style={{width:'100%', height:'100%', objectFit:'cover', display:'block'}} gradient="linear-gradient(135deg, #7E57C2, #311B57)" label="뷰어 샘플 이미지"/></div></div>
          </div>
        </div>
      </section>

      {/* CTA */}
      <section style={{padding:'clamp(80px, 10vw, 100px) 32px', background:'#311B57', color:'#fff', textAlign:'center'}}>
        <div style={{maxWidth:680, margin:'0 auto'}}>
          <h2 style={{fontSize:'clamp(32px, 5vw, 52px)', marginBottom:18, lineHeight:1.2, fontFamily:"'Jua','Noto Sans KR',sans-serif"}}>오늘 이야기의 주인공,<br/>우리 아이입니다.</h2>
          <button onClick={() => onNavigate(token ? 'templates' : 'register')} style={{background:'#FFD166', color:'#1E1230', padding:'8px 16px', fontSize:17, borderRadius:20, border:'none', cursor:'pointer', fontWeight:700, marginTop:24, display:'inline-flex', alignItems:'center', gap:8}}><Ico.Wand size={20}/> {token ? '지금 시작하기' : '무료로 시작하기'}</button>
        </div>
      </section>

      <BookSpecs variant="dark"/>
      <SiteFooter variant="light"/>
    </div>
  );
};

// Auth Page Component
const AuthPage = ({ isRegister, onNavigate, onLoginSuccess }) => {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
    passwordConfirm: '',
    phone: '',
    address: '',
    addressDetail: '',
    zonecode: '',
  });
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const [showAddressModal, setShowAddressModal] = useState(false);
  const api = useApi(null);

  // 카카오 주소 검색 (Daum Postcode API)
  const openAddressSearch = () => {
    setShowAddressModal(true);
    // 다음 렌더 사이클에서 iframe 생성
    setTimeout(() => {
      const container = document.getElementById('daum-postcode-container');
      if (!container) return;
      container.innerHTML = '';
      new daum.Postcode({
        oncomplete: (data) => {
          const fullAddr = data.roadAddress || data.jibunAddress;
          setFormData(prev => ({
            ...prev,
            address: fullAddr,
            zonecode: data.zonecode,
          }));
          setShowAddressModal(false);
        },
        onclose: () => setShowAddressModal(false),
        width: '100%',
        height: '100%',
      }).embed(container);
    }, 100);
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError('');
    setLoading(true);

    try {
      if (isRegister) {
        if (formData.password !== formData.passwordConfirm) {
          throw new Error('비밀번호가 일치하지 않습니다');
        }
        const response = await api('/auth/register', {
          method: 'POST',
          body: JSON.stringify({
            email: formData.email,
            password: formData.password,
            passwordConfirm: formData.passwordConfirm,
            name: formData.name,
            phone: formData.phone,
            address: formData.address,
            addressDetail: formData.addressDetail,
          }),
        });
        localStorage.setItem('token', response.token);
        onLoginSuccess(response.user, response.token);
      } else {
        const response = await api('/auth/login', {
          method: 'POST',
          body: JSON.stringify({
            email: formData.email,
            password: formData.password,
          }),
        });
        localStorage.setItem('token', response.token);
        onLoginSuccess(response.user, response.token);
      }
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div style={{
      minHeight: '100vh',
      background: `linear-gradient(135deg, ${COLORS.warmCream} 0%, ${COLORS.warmLight} 100%)`,
      display: 'flex',
      flexDirection: 'column',
    }}>
      {/* Header */}
      <header style={{
        padding: '20px 40px',
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
        background: 'rgba(255, 255, 255, 0.7)',
        backdropFilter: 'blur(10px)',
        borderBottom: `1px solid ${COLORS.border}`,
      }}>
        <button
          onClick={() => onNavigate('landing')}
          style={{ background: 'none', border: 'none', cursor: 'pointer', padding: 0 }}
        >
          <img src="/bubalog.jpg" alt="BUBA" style={{ height: '36px', objectFit: 'contain' }} />
        </button>
      </header>

      {/* Auth Card */}
      <div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '40px 20px' }}>
        <div style={{
          background: COLORS.white,
          borderRadius: '20px',
          padding: '50px',
          boxShadow: '0 10px 40px rgba(55,39,74,0.15)',
          maxWidth: '450px',
          width: '100%',
          backdropFilter: 'blur(10px)',
          border: `1px solid ${COLORS.border}`,
        }}>
          <h1 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '10px', textAlign: 'center' }}>
            {isRegister ? '회원가입' : '로그인'}
          </h1>
          <p style={{ textAlign: 'center', color: COLORS.subtitle, marginBottom: '30px' }}>
            {isRegister ? '새로운 계정을 만들어보세요' : '계정에 로그인하세요'}
          </p>

          <form onSubmit={handleSubmit} style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
            {isRegister && (
              <input
                type="text"
                placeholder="아이 이름"
                value={formData.name}
                onChange={(e) => setFormData({ ...formData, name: e.target.value })}
                className="input-focus"
                style={{
                  padding: '14px',
                  borderRadius: '10px',
                  border: `1px solid ${COLORS.border}`,
                  fontSize: '14px',
                  outline: 'none',
                }}
                required
              />
            )}

            <input
              type="email"
              placeholder="이메일"
              value={formData.email}
              onChange={(e) => setFormData({ ...formData, email: e.target.value })}
              className="input-focus"
              style={{
                padding: '14px',
                borderRadius: '10px',
                border: `1px solid ${COLORS.border}`,
                fontSize: '14px',
                outline: 'none',
              }}
              required
            />

            <input
              type="password"
              placeholder="비밀번호"
              value={formData.password}
              onChange={(e) => setFormData({ ...formData, password: e.target.value })}
              className="input-focus"
              style={{
                padding: '14px',
                borderRadius: '10px',
                border: `1px solid ${COLORS.border}`,
                fontSize: '14px',
                outline: 'none',
              }}
              required
            />

            {isRegister && (
              <>
                <input
                  type="password"
                  placeholder="비밀번호 확인"
                  value={formData.passwordConfirm}
                  onChange={(e) => setFormData({ ...formData, passwordConfirm: e.target.value })}
                  className="input-focus"
                  style={{
                    padding: '14px',
                    borderRadius: '10px',
                    border: `1px solid ${COLORS.border}`,
                    fontSize: '14px',
                    outline: 'none',
                  }}
                  required
                />

                <input
                  type="tel"
                  placeholder="휴대폰 번호"
                  value={formData.phone}
                  onChange={(e) => setFormData({ ...formData, phone: e.target.value })}
                  className="input-focus"
                  style={{
                    padding: '14px',
                    borderRadius: '10px',
                    border: `1px solid ${COLORS.border}`,
                    fontSize: '14px',
                    outline: 'none',
                  }}
                />

                {/* 주소 검색 */}
                <div style={{ display: 'flex', gap: '8px' }}>
                  <input
                    type="text"
                    placeholder="주소 검색을 클릭하세요"
                    value={formData.address}
                    readOnly
                    onClick={openAddressSearch}
                    style={{
                      flex: 1,
                      padding: '14px',
                      borderRadius: '10px',
                      border: `1px solid ${COLORS.border}`,
                      fontSize: '14px',
                      outline: 'none',
                      background: COLORS.lightBackground,
                      cursor: 'pointer',
                      color: formData.address ? COLORS.text : COLORS.placeholder,
                    }}
                  />
                  <button
                    type="button"
                    onClick={openAddressSearch}
                    style={{
                      padding: '14px 20px',
                      borderRadius: '10px',
                      border: 'none',
                      background: GRADIENTS.cta,
                      color: COLORS.white,
                      fontSize: '13px',
                      fontWeight: '600',
                      cursor: 'pointer',
                      whiteSpace: 'nowrap',
                      boxShadow: SHADOWS.magicGlow,
                    }}
                  >
                    주소 검색
                  </button>
                </div>
                {formData.zonecode && (
                  <div style={{ fontSize: '12px', color: COLORS.warmGray, marginTop: '-12px' }}>
                    우편번호: {formData.zonecode}
                  </div>
                )}
                <input
                  type="text"
                  placeholder="상세주소 (동/호수)"
                  value={formData.addressDetail}
                  onChange={(e) => setFormData({ ...formData, addressDetail: e.target.value })}
                  className="input-focus"
                  style={{
                    padding: '14px',
                    borderRadius: '10px',
                    border: `1px solid ${COLORS.border}`,
                    fontSize: '14px',
                    outline: 'none',
                  }}
                />

                <label style={{ display: 'flex', alignItems: 'center', gap: '10px', color: COLORS.subtitle, fontSize: '14px' }}>
                  <input type="checkbox" required />
                  이용약관에 동의합니다
                </label>
              </>
            )}

            {error && (
              <div style={{
                background: '#FFEBEE',
                color: COLORS.error,
                padding: '12px',
                borderRadius: '8px',
                fontSize: '14px',
              }}>
                {error}
              </div>
            )}

            <button
              type="submit"
              disabled={loading}
              className="btn-hover"
              style={{
                background: COLORS.primary,
                color: COLORS.white,
                padding: '14px',
                borderRadius: '25px',
                border: 'none',
                fontSize: '16px',
                fontWeight: 'bold',
                cursor: loading ? 'not-allowed' : 'pointer',
                opacity: loading ? 0.6 : 1,
                marginTop: '10px',
              }}
            >
              {loading ? '처리 중...' : isRegister ? '회원가입' : '로그인'}
            </button>
          </form>

          {/* 소셜 로그인 구분선 */}
          <div style={{ display: 'flex', alignItems: 'center', margin: '24px 0', gap: '12px' }}>
            <div style={{ flex: 1, height: '1px', background: COLORS.border }} />
            <span style={{ color: COLORS.subtitle, fontSize: '13px', whiteSpace: 'nowrap' }}>또는</span>
            <div style={{ flex: 1, height: '1px', background: COLORS.border }} />
          </div>

          {/* Google 로그인 버튼 */}
          <button
            onClick={() => {
              if (!window.google?.accounts?.id) {
                setError('Google 로그인을 불러오는 중입니다. 잠시 후 다시 시도해주세요.');
                return;
              }
              window.google.accounts.id.initialize({
                client_id: 'YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com',
                callback: async (response) => {
                  try {
                    setLoading(true);
                    setError('');
                    const res = await fetch('/api/auth/google', {
                      method: 'POST',
                      headers: { 'Content-Type': 'application/json' },
                      body: JSON.stringify({ credential: response.credential }),
                    });
                    const data = await res.json();
                    if (!res.ok) throw new Error(data.error || 'Google 로그인 실패');
                    localStorage.setItem('token', data.token);
                    onLoginSuccess(data.user, data.token);
                  } catch (err) {
                    setError(err.message);
                  } finally {
                    setLoading(false);
                  }
                },
              });
              window.google.accounts.id.prompt();
            }}
            className="btn-hover"
            style={{
              width: '100%',
              padding: '12px',
              borderRadius: '25px',
              border: `1px solid ${COLORS.border}`,
              background: COLORS.white,
              color: COLORS.text,
              fontSize: '15px',
              fontWeight: '500',
              cursor: 'pointer',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              gap: '10px',
            }}
          >
            <svg width="18" height="18" viewBox="0 0 24 24">
              <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"/>
              <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
              <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
              <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
            </svg>
            Google로 {isRegister ? '가입하기' : '로그인'}
          </button>

          <p style={{ textAlign: 'center', marginTop: '20px', color: COLORS.subtitle, fontSize: '14px' }}>
            {isRegister ? '이미 계정이 있으신가요?' : '계정이 없으신가요?'}{' '}
            <button
              onClick={() => onNavigate(isRegister ? 'login' : 'register')}
              style={{
                color: COLORS.primary,
                background: 'none',
                border: 'none',
                cursor: 'pointer',
                fontWeight: 'bold',
                textDecoration: 'underline',
              }}
            >
              {isRegister ? '로그인' : '회원가입'}
            </button>
          </p>
        </div>
      </div>

      <SiteFooter variant="light"/>

      {/* 주소 검색 모달 (Daum Postcode API) */}
      {showAddressModal && (
        <div
          onClick={() => setShowAddressModal(false)}
          style={{
            position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
            background: 'rgba(0, 0, 0, 0.5)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            zIndex: 10000,
            animation: 'fadeIn 0.2s ease-out',
          }}
        >
          <div
            onClick={(e) => e.stopPropagation()}
            style={{
              background: COLORS.white,
              borderRadius: '20px',
              width: '90%',
              maxWidth: '500px',
              height: '500px',
              overflow: 'hidden',
              boxShadow: SHADOWS.floating,
              display: 'flex',
              flexDirection: 'column',
            }}
          >
            <div style={{
              padding: '16px 20px',
              borderBottom: `1px solid rgba(209,196,233,0.3)`,
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
            }}>
              <h3 style={{ fontSize: '16px', fontWeight: '700', color: COLORS.dark }}>주소 검색</h3>
              <button
                onClick={() => setShowAddressModal(false)}
                style={{
                  background: 'none', border: 'none', cursor: 'pointer',
                  fontSize: '22px', color: COLORS.warmGray, padding: '4px',
                }}
              >
                ✕
              </button>
            </div>
            <div id="daum-postcode-container" style={{ flex: 1 }} />
          </div>
        </div>
      )}
    </div>
  );
};

// My Page Component
const MyPage = ({ onNavigate, token, user }) => {
  const [books, setBooks] = useState([]);
  const [loading, setLoading] = useState(true);
  const api = useApi(token);

  useEffect(() => {
    const fetchBooks = async () => {
      try {
        const res = await api('/books');
        setBooks(res.books || []);
      } catch (err) {
        console.error('내 동화책 로드 실패:', err);
      } finally {
        setLoading(false);
      }
    };
    fetchBooks();
  }, []);

  const getStatusInfo = (status) => {
    const map = {
      processing: { label: '생성 중', color: '#FF9800', bg: '#FFF3E0', icon: '⏳' },
      page1_ready: { label: '1페이지 완성', color: '#2196F3', bg: '#E3F2FD', icon: '📄' },
      generating_all: { label: '전체 생성 중', color: '#FF9800', bg: '#FFF3E0', icon: '⏳' },
      paid: { label: '결제 완료', color: '#2196F3', bg: '#E3F2FD', icon: '💳' },
      completed: { label: '완성', color: '#4CAF50', bg: '#E8F5E9', icon: '✅' },
      approved: { label: '검수 완료', color: '#4CAF50', bg: '#E8F5E9', icon: '🎉' },
      review_pending: { label: '검수 대기', color: '#9C27B0', bg: '#F3E5F5', icon: '🔍' },
      revision_needed: { label: '수정 필요', color: '#F44336', bg: '#FFEBEE', icon: '✏️' },
    };
    return map[status] || { label: status || '알 수 없음', color: COLORS.subtitle, bg: COLORS.lightGray, icon: '📖' };
  };

  return (
    <div style={{ minHeight: '100vh', background: '#FBF8FF' }}>
      {/* Header */}
      <header style={{
        padding: '16px 24px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        background: 'rgba(255,255,255,0.9)', backdropFilter: 'blur(10px)', borderBottom: `1px solid ${COLORS.border}`,
        position: 'sticky', top: 0, zIndex: 100,
      }}>
        <div style={{ cursor: 'pointer' }} onClick={() => onNavigate('landing')}>
          <img src="/bubalog.jpg" alt="BUBA" style={{ height: '36px', objectFit: 'contain' }} />
        </div>
        <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
          <span style={{ color: COLORS.text, fontWeight: '600', fontSize: '14px' }}>{user?.name || user?.email}님</span>
          <button onClick={() => onNavigate('templates')} className="btn-hover" style={{ background: COLORS.primary, color: COLORS.white, padding: '10px 24px', borderRadius: '25px', border: 'none', cursor: 'pointer', fontWeight: '600', fontSize: '14px' }}>
            새 동화책 만들기
          </button>
        </div>
      </header>

      <div style={{ maxWidth: '900px', margin: '0 auto', padding: '40px 20px' }}>
        {/* Profile section */}
        <div style={{ background: 'white', borderRadius: '20px', padding: '32px', marginBottom: '30px', boxShadow: '0 4px 15px rgba(55,39,74,0.08)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: '20px' }}>
            <div style={{
              width: '64px', height: '64px', borderRadius: '50%',
              background: `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)`,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              color: 'white', fontSize: '24px', fontWeight: 'bold',
            }}>
              {(user?.name || '?')[0]}
            </div>
            <div>
              <h1 style={{ fontSize: '22px', fontWeight: 'bold', color: COLORS.dark }}>{user?.name || '사용자'}님</h1>
              <p style={{ fontSize: '14px', color: COLORS.subtitle, marginTop: '2px' }}>{user?.email}</p>
            </div>
            <div style={{ marginLeft: 'auto' }}>
              <span style={{
                padding: '6px 16px', borderRadius: '20px', fontSize: '13px', fontWeight: '600',
                background: user?.plan === 'premium' ? '#F3E5F5' : '#E3F2FD',
                color: user?.plan === 'premium' ? COLORS.primaryDark : '#1565C0',
              }}>
                {user?.plan === 'premium' ? '프리미엄' : '무료'}
              </span>
            </div>
          </div>
        </div>

        {/* Books section */}
        <h2 style={{ fontSize: '20px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '20px' }}>
          내 동화책 ({books.length})
        </h2>

        {loading ? (
          <div style={{ textAlign: 'center', padding: '60px', color: COLORS.subtitle }}>로딩 중...</div>
        ) : books.length === 0 ? (
          <div style={{
            background: 'white', borderRadius: '20px', padding: '60px 30px',
            textAlign: 'center', boxShadow: '0 4px 15px rgba(55,39,74,0.08)',
          }}>
            <div style={{ fontSize: '48px', marginBottom: '16px' }}>📚</div>
            <h3 style={{ fontSize: '18px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '8px' }}>
              아직 만든 동화책이 없어요
            </h3>
            <p style={{ color: COLORS.subtitle, marginBottom: '24px' }}>
              우리 아이만의 특별한 동화책을 만들어보세요!
            </p>
            <button
              onClick={() => onNavigate('templates')}
              className="btn-hover"
              style={{
                background: `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)`,
                color: COLORS.white, padding: '14px 32px', borderRadius: '25px',
                border: 'none', cursor: 'pointer', fontWeight: 'bold', fontSize: '16px',
                boxShadow: '0 6px 20px rgba(179,157,219,0.3)',
              }}
            >
              동화책 만들기
            </button>
          </div>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
            {books.map((book) => {
              const statusInfo = getStatusInfo(book.status);
              const isGenerating = book.status === 'processing' || book.status === 'generating_all';
              return (
                <div
                  key={book.id}
                  onClick={() => {
                    if (book.status !== 'processing') {
                      onNavigate('preview', { bookId: book.id });
                    }
                  }}
                  style={{
                    background: 'white', borderRadius: '16px', padding: '20px',
                    boxShadow: '0 4px 15px rgba(55,39,74,0.08)',
                    cursor: book.status === 'processing' ? 'default' : 'pointer',
                    display: 'flex', alignItems: 'center', gap: '16px',
                    transition: 'transform 0.2s ease, box-shadow 0.2s ease',
                    border: isGenerating ? `2px solid ${COLORS.warning}` : '2px solid transparent',
                  }}
                  onMouseEnter={(e) => { if (book.status !== 'processing') { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = '0 8px 25px rgba(55,39,74,0.12)'; }}}
                  onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)'; e.currentTarget.style.boxShadow = '0 4px 15px rgba(55,39,74,0.08)'; }}
                >
                  {/* Book thumbnail */}
                  <div style={{
                    width: '72px', height: '90px', borderRadius: '10px', flexShrink: 0, overflow: 'hidden',
                    background: COLORS.warmCream, display: 'flex', alignItems: 'center', justifyContent: 'center',
                  }}>
                    {book.generated_face_url ? (
                      <img src={book.generated_face_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                    ) : (
                      <span style={{ fontSize: '32px' }}>{book.template_emoji || '📖'}</span>
                    )}
                  </div>

                  {/* Book info */}
                  <div style={{ flex: 1 }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
                      <h3 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark }}>
                        {book.character_name}의 모험
                      </h3>
                      <span style={{
                        padding: '2px 10px', borderRadius: '10px', fontSize: '11px', fontWeight: '600',
                        background: statusInfo.bg, color: statusInfo.color,
                      }}>
                        {statusInfo.icon} {statusInfo.label}
                      </span>
                    </div>
                    <p style={{ fontSize: '13px', color: COLORS.subtitle }}>
                      {book.template_title || '동화책'} · {book.pages_generated}/{book.total_pages}페이지
                    </p>
                    <p style={{ fontSize: '12px', color: COLORS.subtitle, marginTop: '2px' }}>
                      {new Date(book.created_at).toLocaleDateString('ko-KR')}
                    </p>

                    {/* Generating notification */}
                    {isGenerating && (
                      <div style={{
                        marginTop: '8px', padding: '10px 14px', borderRadius: '10px',
                        background: '#FFF8E1', border: '1px solid #FFE082',
                        display: 'flex', alignItems: 'center', gap: '8px',
                      }}>
                        <span style={{ fontSize: '16px', animation: 'gentleFloat 2s ease-in-out infinite' }}>⏳</span>
                        <div>
                          <p style={{ fontSize: '13px', fontWeight: '600', color: '#E65100' }}>
                            동화가 생성중이에요
                          </p>
                          <p style={{ fontSize: '12px', color: '#BF360C' }}>
                            완료되면 알림 보내드릴게요!
                          </p>
                        </div>
                      </div>
                    )}
                  </div>

                  {/* Arrow */}
                  {!isGenerating && (
                    <span style={{ color: COLORS.subtitle, fontSize: '20px', flexShrink: 0 }}>&gt;</span>
                  )}
                </div>
              );
            })}
          </div>
        )}
      </div>

      <SiteFooter variant="light"/>
    </div>
  );
};

// Templates Page Component
const TemplatesPage = ({ onNavigate, token, user }) => {
  const [templates, setTemplates] = useState([]);
  const [loading, setLoading] = useState(true);
  const [genderFilter, setGenderFilter] = useState('all');
  const [detailTemplate, setDetailTemplate] = useState(null);
  const [previewIdx, setPreviewIdx] = useState(0);
  const api = useApi(token);

  useEffect(() => {
    const fetchTemplates = async () => {
      try {
        const response = await api('/templates');
        const list = response.templates || (Array.isArray(response) ? response : []);
        setTemplates(list);
      } catch (err) {
        console.warn('템플릿 로드 실패:', err.message);
      } finally {
        setLoading(false);
      }
    };
    fetchTemplates();
  }, []);

  const filtered = templates.filter(t => genderFilter === 'all' || t.target_gender === genderFilter || t.target_gender === 'both');

  if (loading) {
    return (
      <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <p style={{ fontSize: '18px', color: COLORS.subtitle }}>로딩 중...</p>
      </div>
    );
  }

  return (
    <div style={{ minHeight: '100vh', background: '#FBF8FF' }}>
      {/* Header */}
      <header style={{
        padding: '16px 24px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        background: 'rgba(255,255,255,0.9)', backdropFilter: 'blur(10px)', borderBottom: `1px solid ${COLORS.border}`,
        position: 'sticky', top: 0, zIndex: 100,
      }}>
        <div style={{ cursor: 'pointer' }} onClick={() => onNavigate('landing')}>
          <img src="/bubalog.jpg" alt="BUBA" style={{ height: '36px', objectFit: 'contain' }} />
        </div>
        <div style={{ display: 'flex', gap: '12px', alignItems: 'center' }}>
          <button onClick={() => onNavigate('mypage')} style={{ background: 'transparent', border: `2px solid ${COLORS.primary}`, color: COLORS.primary, padding: '10px 20px', borderRadius: '25px', cursor: 'pointer', fontWeight: '600', fontSize: '14px' }}>마이페이지</button>
        </div>
      </header>

      <div style={{ maxWidth: '1100px', margin: '0 auto', padding: '40px 20px' }}>
        <div style={{ textAlign: 'center', marginBottom: '36px' }}>
          <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '8px' }}>
            어떤 동화를 만들어볼까요?
          </h1>
          <p style={{ fontSize: '16px', color: COLORS.subtitle }}>우리 아이가 주인공이 되는 특별한 이야기를 골라보세요</p>
        </div>

        {/* Gender Filter */}
        <div style={{ display: 'flex', gap: '12px', justifyContent: 'center', marginBottom: '32px' }}>
          {[
            { id: 'all', label: '전체', icon: '📚' },
            { id: 'boy', label: '남부바', icon: '👦' },
            { id: 'girl', label: '여부바', icon: '👧' },
          ].map((f) => (
            <button
              key={f.id}
              onClick={() => setGenderFilter(f.id)}
              className="btn-hover"
              style={{
                padding: '12px 28px', borderRadius: '25px', cursor: 'pointer', fontWeight: '600', fontSize: '15px',
                border: genderFilter === f.id ? 'none' : `2px solid ${COLORS.border}`,
                background: genderFilter === f.id ? `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)` : COLORS.white,
                color: genderFilter === f.id ? COLORS.white : COLORS.text,
                boxShadow: genderFilter === f.id ? '0 4px 15px rgba(179,157,219,0.3)' : 'none',
              }}
            >
              {f.icon} {f.label}
              {f.id !== 'all' && <span style={{ marginLeft: '6px', fontSize: '13px', opacity: 0.8 }}>({templates.filter(t => t.target_gender === f.id || t.target_gender === 'both').length})</span>}
            </button>
          ))}
        </div>

        {/* Template Grid */}
        {filtered.length === 0 ? (
          <div style={{ textAlign: 'center', padding: '60px', color: COLORS.subtitle }}>등록된 스토리가 없습니다</div>
        ) : (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: '24px' }}>
            {filtered.map((template) => (
              <div
                key={template.id}
                className="card-hover"
                onClick={() => { setDetailTemplate(template); setPreviewIdx(0); }}
                style={{
                  background: 'white', borderRadius: '16px', overflow: 'hidden',
                  boxShadow: '0 4px 15px rgba(55,39,74,0.08)', cursor: 'pointer',
                }}
              >
                {/* Thumbnail */}
                <div style={{ height: '180px', overflow: 'hidden', position: 'relative', background: template.colors_primary || COLORS.primary }}>
                  <EmojiFallbackImg
                    src={template.thumbnail_url}
                    emoji={template.emoji || '📖'}
                    emojiSize={56}
                    style={{ width: '100%', height: '100%' }}
                  />
                  <span style={{
                    position: 'absolute', top: '10px', right: '10px',
                    padding: '4px 10px', borderRadius: '12px', fontSize: '11px', fontWeight: '600',
                    background: template.target_gender === 'boy' ? 'rgba(25,118,210,0.9)' : template.target_gender === 'girl' ? 'rgba(194,24,91,0.9)' : 'rgba(126,87,194,0.9)',
                    color: 'white',
                  }}>
                    {template.target_gender === 'boy' ? '👦 남아' : template.target_gender === 'girl' ? '👧 여아' : '공용'}
                  </span>
                  {(template.previews || []).length > 0 && (
                    <span style={{
                      position: 'absolute', bottom: '10px', right: '10px',
                      padding: '3px 8px', borderRadius: '8px', fontSize: '11px', fontWeight: '600',
                      background: 'rgba(0,0,0,0.5)', color: 'white',
                    }}>
                      미리보기 {template.previews.length}장
                    </span>
                  )}
                </div>
                <div style={{ padding: '16px' }}>
                  <h3 style={{ fontSize: '17px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '6px' }}>{template.title}</h3>
                  <p style={{ fontSize: '13px', color: COLORS.subtitle, marginBottom: '8px', lineHeight: '1.5', display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>
                    {template.description || template.story_summary || ''}
                  </p>
                  <p style={{ fontSize: '12px', color: COLORS.subtitle }}>
                    📖 {template.age_range || '3-7세'}
                  </p>
                </div>
              </div>
            ))}
          </div>
        )}
      </div>

      {/* Story Detail Modal */}
      {detailTemplate && (
        <div
          onClick={() => setDetailTemplate(null)}
          style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.6)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000, padding: '20px' }}
        >
          <div
            onClick={(e) => e.stopPropagation()}
            style={{ background: 'white', borderRadius: '20px', maxWidth: '600px', width: '100%', maxHeight: '90vh', overflowY: 'auto', animation: 'fadeInScale 0.3s ease-out' }}
          >
            {/* Preview image slideshow */}
            {(detailTemplate.previews || []).length > 0 ? (
              <div
                className="no-copy-img-wrap no-copy-watermark"
                onContextMenu={(e) => e.preventDefault()}
                style={{ position: 'relative', height: '300px', overflow: 'hidden', borderRadius: '20px 20px 0 0' }}
              >
                <img
                  src={detailTemplate.previews[previewIdx].image_url}
                  alt=""
                  draggable={false}
                  onDragStart={(e) => e.preventDefault()}
                  style={{ width: '100%', height: '100%', objectFit: 'contain', background: '#F5F5F5', WebkitUserDrag: 'none', userSelect: 'none' }}
                />
                {detailTemplate.previews.length > 1 && (
                  <>
                    <button onClick={() => setPreviewIdx(Math.max(0, previewIdx - 1))} disabled={previewIdx === 0} style={{ position: 'absolute', left: '10px', top: '50%', transform: 'translateY(-50%)', background: 'rgba(0,0,0,0.4)', color: 'white', border: 'none', borderRadius: '50%', width: '36px', height: '36px', cursor: 'pointer', fontSize: '16px', opacity: previewIdx === 0 ? 0.3 : 1 }}>&lt;</button>
                    <button onClick={() => setPreviewIdx(Math.min(detailTemplate.previews.length - 1, previewIdx + 1))} disabled={previewIdx === detailTemplate.previews.length - 1} style={{ position: 'absolute', right: '10px', top: '50%', transform: 'translateY(-50%)', background: 'rgba(0,0,0,0.4)', color: 'white', border: 'none', borderRadius: '50%', width: '36px', height: '36px', cursor: 'pointer', fontSize: '16px', opacity: previewIdx === detailTemplate.previews.length - 1 ? 0.3 : 1 }}>&gt;</button>
                    <div style={{ position: 'absolute', bottom: '10px', left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: '6px' }}>
                      {detailTemplate.previews.map((_, i) => (
                        <div key={i} onClick={() => setPreviewIdx(i)} style={{ width: '8px', height: '8px', borderRadius: '50%', background: i === previewIdx ? 'white' : 'rgba(255,255,255,0.5)', cursor: 'pointer' }} />
                      ))}
                    </div>
                  </>
                )}
              </div>
            ) : detailTemplate.thumbnail_url ? (
              <EmojiFallbackImg
                src={detailTemplate.thumbnail_url}
                emoji={detailTemplate.emoji || '📖'}
                emojiSize={72}
                style={{ width: '100%', height: '250px', borderRadius: '20px 20px 0 0' }}
                bgColor={detailTemplate.colors_primary || COLORS.primary}
              />
            ) : (
              <div style={{ height: '200px', background: detailTemplate.colors_primary || COLORS.primary, borderRadius: '20px 20px 0 0', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
                <span style={{ fontSize: '72px' }}>{detailTemplate.emoji || '📖'}</span>
              </div>
            )}

            <div style={{ padding: '28px' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '12px' }}>
                <h2 style={{ fontSize: '24px', fontWeight: 'bold', color: COLORS.dark }}>{detailTemplate.title}</h2>
                <span style={{
                  padding: '4px 12px', borderRadius: '12px', fontSize: '12px', fontWeight: '600',
                  background: detailTemplate.target_gender === 'boy' ? '#E3F2FD' : detailTemplate.target_gender === 'girl' ? '#FCE4EC' : '#F3E5F5',
                  color: detailTemplate.target_gender === 'boy' ? '#1565C0' : detailTemplate.target_gender === 'girl' ? '#C2185B' : COLORS.primaryDark,
                }}>
                  {detailTemplate.target_gender === 'boy' ? '👦 남아' : detailTemplate.target_gender === 'girl' ? '👧 여아' : '공용'}
                </span>
              </div>
              <p style={{ fontSize: '15px', color: COLORS.text, marginBottom: '10px' }}>{detailTemplate.description}</p>
              {detailTemplate.story_summary && (
                <p style={{ fontSize: '14px', color: COLORS.subtitle, lineHeight: '1.7', marginBottom: '16px', whiteSpace: 'pre-line' }}>{detailTemplate.story_summary}</p>
              )}
              <div style={{ display: 'flex', gap: '16px', fontSize: '13px', color: COLORS.subtitle, marginBottom: '24px' }}>
                <span>👶 {detailTemplate.age_range || '3-7세'}</span>
              </div>

              <div style={{ display: 'flex', gap: '12px' }}>
                <button onClick={() => setDetailTemplate(null)} style={{ flex: 1, padding: '14px', borderRadius: '25px', border: `2px solid ${COLORS.border}`, background: 'white', color: COLORS.text, cursor: 'pointer', fontWeight: '600', fontSize: '15px' }}>
                  뒤로
                </button>
                <button
                  onClick={() => {
                    localStorage.setItem('selectedTemplate', JSON.stringify(detailTemplate));
                    onNavigate('create', { templateId: detailTemplate.id });
                  }}
                  className="btn-hover"
                  style={{ flex: 2, padding: '14px', borderRadius: '25px', border: 'none', background: `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)`, color: COLORS.white, cursor: 'pointer', fontWeight: 'bold', fontSize: '15px', boxShadow: '0 4px 15px rgba(179,157,219,0.3)' }}
                >
                  이 스토리로 만들기
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      <SiteFooter variant="light"/>
    </div>
  );
};

// Create Book Page Component
const CreatePage = ({ onNavigate, token, templateId }) => {
  const [step, setStep] = useState(1);
  const [selectedTemplate, setSelectedTemplate] = useState(null);
  const [childName, setChildName] = useState('');
  const [childGender, setChildGender] = useState('남아');
  const [photo, setPhoto] = useState(null);
  const [photoFile, setPhotoFile] = useState(null);
  const [loading, setLoading] = useState(false);
  const [bookId, setBookId] = useState(null);
  const fileInputRef = useRef(null);
  const api = useApi(token);

  useEffect(() => {
    const saved = localStorage.getItem('selectedTemplate');
    if (saved) {
      setSelectedTemplate(JSON.parse(saved));
    }
  }, []);

  const handlePhotoUpload = (file) => {
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (e) => setPhoto(e.target.result);
    reader.readAsDataURL(file);
    setPhotoFile(file);
  };

  const handleNext = async () => {
    if (step === 2 && !childName) {
      alert('아이 이름을 입력해주세요');
      return;
    }
    if (step === 3 && !photo) {
      alert('사진을 업로드해주세요');
      return;
    }

    if (step === 3) {
      // Create book and upload photo
      setStep(4);
      setLoading(true);
      try {
        const createResponse = await api('/books/create', {
          method: 'POST',
          body: JSON.stringify({
            template_id: selectedTemplate.id,
            child_name: childName,
            child_age: parseInt(childGender) || 5,
          }),
        });
        setBookId(createResponse.book_id);

        // Upload photo
        const formData = new FormData();
        formData.append('photo', photoFile);
        const uploadResponse = await fetch(`/api/books/${createResponse.book_id}/upload-photo`, {
          method: 'POST',
          headers: { 'Authorization': `Bearer ${token}` },
          body: formData,
        });
        const uploadData = await uploadResponse.json();
        if (!uploadResponse.ok) throw new Error(uploadData.error || '사진 업로드 실패');

        // Call generate-face API
        const generateResponse = await api(`/books/${createResponse.book_id}/generate-face`, {
          method: 'POST',
        });

        setTimeout(() => {
          localStorage.setItem('lastBookId', createResponse.book_id);
          onNavigate('preview', { bookId: createResponse.book_id });
        }, 2000);
      } catch (err) {
        alert('오류: ' + err.message);
        setStep(3);
      } finally {
        setLoading(false);
      }
    } else {
      setStep(step + 1);
    }
  };

  const handlePrev = () => {
    if (step > 1) setStep(step - 1);
  };

  const stepText = ['템플릿', '정보입력', '사진', '생성중'];
  const messages = [
    'AI가 수채화풍으로 변환 중...',
    '아이의 얼굴을 분석하는 중...',
    '스토리를 생성하는 중...',
    '완성이 거의 다 되었습니다...',
  ];

  return (
    <div style={{ minHeight: '100vh', background: COLORS.lightBackground, padding: '40px 20px' }}>
      {/* Header */}
      <header style={{
        maxWidth: '800px',
        margin: '0 auto 50px',
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
      }}>
        <h1 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark }}>
          동화책 만들기
        </h1>
      </header>

      {/* Progress Bar */}
      <div style={{
        maxWidth: '800px',
        margin: '0 auto 50px',
        display: 'grid',
        gridTemplateColumns: 'repeat(4, 1fr)',
        gap: '10px',
      }}>
        {stepText.map((text, idx) => (
          <div key={idx} style={{ textAlign: 'center' }}>
            <div style={{
              width: '40px',
              height: '40px',
              borderRadius: '50%',
              background: idx < step ? COLORS.primary : idx === step - 1 ? COLORS.primary : COLORS.lightGray,
              color: COLORS.white,
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              fontWeight: 'bold',
              margin: '0 auto 10px',
              fontSize: '14px',
            }}>
              {idx < step ? '✓' : idx + 1}
            </div>
            <p style={{ fontSize: '12px', color: COLORS.subtitle }}>{text}</p>
          </div>
        ))}
      </div>

      {/* Content */}
      <div style={{
        maxWidth: '800px',
        margin: '0 auto',
        background: COLORS.white,
        borderRadius: '20px',
        padding: '50px',
        boxShadow: '0 4px 15px rgba(55,39,74,0.10)',
        minHeight: '500px',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
      }}>
        {step === 1 && selectedTemplate && (
          <div style={{ textAlign: 'center' }}>
            <h2 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '20px' }}>
              선택한 템플릿
            </h2>
            <div style={{
              background: selectedTemplate.colors_primary || selectedTemplate.colors_bg || selectedTemplate.color || COLORS.primary,
              borderRadius: '16px',
              color: COLORS.white,
              marginBottom: '30px',
              overflow: 'hidden',
              textShadow: '0 2px 4px rgba(55,39,74,0.20)',
            }}>
              {selectedTemplate.thumbnail_url ? (
                <div style={{ position: 'relative' }}>
                  <img src={selectedTemplate.thumbnail_url} alt="" style={{ width: '100%', height: '220px', objectFit: 'cover', display: 'block' }} />
                  <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(180deg, transparent 40%, rgba(0,0,0,0.4) 100%)' }} />
                  <div style={{ position: 'absolute', bottom: '20px', left: '0', right: '0', textAlign: 'center' }}>
                    <h3 style={{ fontSize: '24px', fontWeight: 'bold', marginBottom: '6px' }}>{selectedTemplate.title}</h3>
                    <p style={{ fontSize: '14px', opacity: 0.9 }}>{selectedTemplate.description}</p>
                  </div>
                </div>
              ) : (
                <div style={{ padding: '50px', textAlign: 'center' }}>
                  <div style={{ fontSize: '80px', marginBottom: '15px' }}>{selectedTemplate.emoji || '📖'}</div>
                  <h3 style={{ fontSize: '24px', fontWeight: 'bold', marginBottom: '10px' }}>{selectedTemplate.title}</h3>
                  <p style={{ fontSize: '16px', marginBottom: '10px' }}>{selectedTemplate.description}</p>
                  <p style={{ fontSize: '14px', opacity: 0.9 }}>대상: {selectedTemplate.age_range || '3~7세'}</p>
                </div>
              )}
            </div>
          </div>
        )}

        {step === 2 && (
          <div>
            <h2 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px', textAlign: 'center' }}>
              아이 정보 입력
            </h2>
            <div style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
              <div>
                <label style={{ display: 'block', marginBottom: '8px', fontWeight: '600', color: COLORS.dark }}>
                  아이 이름
                </label>
                <input
                  type="text"
                  value={childName}
                  onChange={(e) => setChildName(e.target.value)}
                  placeholder="예: 준호"
                  style={{
                    width: '100%',
                    padding: '14px',
                    borderRadius: '10px',
                    border: `1px solid ${COLORS.border}`,
                    fontSize: '16px',
                    outline: 'none',
                  }}
                />
              </div>

              <div>
                <label style={{ display: 'block', marginBottom: '8px', fontWeight: '600', color: COLORS.dark }}>
                  성별
                </label>
                <div style={{ display: 'flex', gap: '15px' }}>
                  {['남아', '여아'].map((gender) => (
                    <label key={gender} style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
                      <input
                        type="radio"
                        name="gender"
                        value={gender}
                        checked={childGender === gender}
                        onChange={(e) => setChildGender(e.target.value)}
                      />
                      <span style={{ fontWeight: '500', color: COLORS.text }}>
                        {gender === '남아' ? '👦 남아' : '👧 여아'}
                      </span>
                    </label>
                  ))}
                </div>
              </div>
            </div>
          </div>
        )}

        {step === 3 && (
          <div>
            <h2 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px', textAlign: 'center' }}>
              아이 사진 업로드
            </h2>
            <div style={{
              border: `2px dashed ${COLORS.primary}`,
              borderRadius: '16px',
              padding: '50px',
              textAlign: 'center',
              cursor: 'pointer',
              background: COLORS.lightGray,
              minHeight: '250px',
              display: 'flex',
              flexDirection: 'column',
              justifyContent: 'center',
              alignItems: 'center',
            }}
            onClick={() => fileInputRef.current?.click()}
            onDragOver={(e) => {
              e.preventDefault();
              e.currentTarget.style.background = COLORS.warmCream;
            }}
            onDragLeave={(e) => {
              e.currentTarget.style.background = COLORS.lightGray;
            }}
            onDrop={(e) => {
              e.preventDefault();
              e.currentTarget.style.background = COLORS.lightGray;
              const file = e.dataTransfer.files[0];
              if (file) handlePhotoUpload(file);
            }}
            >
              {photo ? (
                <img
                  src={photo}
                  alt="Preview"
                  style={{ maxWidth: '100%', maxHeight: '200px', borderRadius: '8px' }}
                />
              ) : (
                <>
                  <div style={{ fontSize: '48px', marginBottom: '15px' }}>📸</div>
                  <p style={{ fontSize: '16px', fontWeight: '600', color: COLORS.text, marginBottom: '5px' }}>
                    사진을 여기에 드래그하세요
                  </p>
                  <p style={{ fontSize: '14px', color: COLORS.subtitle }}>
                    또는 클릭하여 선택
                  </p>
                </>
              )}
              <input
                ref={fileInputRef}
                type="file"
                accept="image/*"
                onChange={(e) => handlePhotoUpload(e.target.files?.[0])}
                style={{ display: 'none' }}
              />
            </div>
          </div>
        )}

        {step === 4 && (
          <div style={{ textAlign: 'center' }}>
            <div style={{
              width: '80px',
              height: '80px',
              borderRadius: '50%',
              background: 'linear-gradient(135deg, #FFF8E1 0%, #FFE082 100%)',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              fontSize: '36px',
              margin: '0 auto 24px',
              animation: 'gentleFloat 2s ease-in-out infinite',
              boxShadow: '0 4px 20px rgba(255,160,0,0.2)',
            }}>
              ⏳
            </div>
            <h2 style={{ fontSize: '22px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '12px' }}>
              동화가 생성중이에요
            </h2>
            <p style={{ fontSize: '15px', color: COLORS.subtitle, marginBottom: '8px' }}>
              {messages[Math.floor(Math.random() * messages.length)]}
            </p>
            <div style={{
              marginTop: '20px', padding: '14px 24px', borderRadius: '12px',
              background: '#E8F5E9', border: '1px solid #A5D6A7',
              display: 'inline-flex', alignItems: 'center', gap: '8px',
            }}>
              <span style={{ fontSize: '16px' }}>🔔</span>
              <span style={{ fontSize: '14px', color: '#2E7D32', fontWeight: '600' }}>
                완료되면 알림 보내드릴게요!
              </span>
            </div>
          </div>
        )}
      </div>

      {/* Buttons */}
      <div style={{
        maxWidth: '800px',
        margin: '30px auto 0',
        display: 'flex',
        gap: '15px',
        justifyContent: 'center',
      }}>
        {step > 1 && step < 4 && (
          <button
            onClick={handlePrev}
            style={{
              padding: '12px 30px',
              borderRadius: '25px',
              border: `2px solid ${COLORS.primary}`,
              background: COLORS.white,
              color: COLORS.primary,
              fontWeight: 'bold',
              cursor: 'pointer',
              fontSize: '16px',
            }}
          >
            이전
          </button>
        )}
        {step < 4 && (
          <button
            onClick={handleNext}
            disabled={loading}
            style={{
              padding: '12px 30px',
              borderRadius: '25px',
              background: COLORS.primary,
              color: COLORS.white,
              border: 'none',
              fontWeight: 'bold',
              cursor: loading ? 'not-allowed' : 'pointer',
              fontSize: '16px',
              opacity: loading ? 0.6 : 1,
            }}
          >
            {step === 3 ? '생성 시작' : '다음'}
          </button>
        )}
      </div>
    </div>
  );
};

// Preview Page Component
const PreviewPage = ({ onNavigate, token, bookId: propBookId }) => {
  // bookId를 prop 또는 localStorage에서 복원
  const [bookId] = useState(() => {
    const id = propBookId || localStorage.getItem('lastBookId');
    if (propBookId) localStorage.setItem('lastBookId', propBookId);
    return id;
  });
  const [book, setBook] = useState(null);
  const [pages, setPages] = useState([]);
  const [currentPage, setCurrentPage] = useState(0);
  const [paid, setPaid] = useState(false);
  const [loading, setLoading] = useState(true);
  const [paymentStatus, setPaymentStatus] = useState('idle'); // 'idle' | 'confirming' | 'generating' | 'done'
  const [errorMsg, setErrorMsg] = useState('');
  const api = useApi(token);

  // bookId 없으면 템플릿 선택으로 이동
  if (!bookId) {
    return (
      <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', flexDirection: 'column', gap: '20px' }}>
        <p style={{ fontSize: '18px', color: COLORS.subtitle }}>동화책 정보를 찾을 수 없습니다</p>
        <button
          onClick={() => onNavigate('templates')}
          className="btn-hover"
          style={{ padding: '12px 30px', borderRadius: '25px', background: COLORS.primary, color: COLORS.white, border: 'none', fontWeight: 'bold', cursor: 'pointer' }}
        >
          동화책 만들러 가기
        </button>
      </div>
    );
  }

  useEffect(() => {
    const fetchBook = async () => {
      try {
        const response = await api(`/books/${bookId}/status`);
        setBook(response);

        // Fetch pages separately
        const pagesResponse = await api(`/books/${bookId}/pages`);
        const { paid: isPaid, pages: pagesList } = pagesResponse;

        setPaid(isPaid);
        if (isPaid) {
          setPages(pagesList || []);
        } else {
          setPages([pagesList?.[0]] || []);
        }
      } catch (err) {
        setErrorMsg('책 로드 실패: ' + err.message);
      } finally {
        setLoading(false);
      }
    };
    fetchBook();
  }, []);

  // 토스페이먼츠 결제 요청 (SDK v2)
  const handleTossPayment = async () => {
    try {
      // 1) 서버에서 결제 준비 (orderId, amount 생성)
      const prepareRes = await api('/payments/prepare', {
        method: 'POST',
        body: JSON.stringify({ book_id: bookId, amount: 29900 }),
      });

      // 2) 토스페이먼츠 SDK v2 초기화
      const clientKey = prepareRes.clientKey;
      const tossPayments = TossPayments(clientKey);

      // 3) 결제창 객체 생성 (customerKey: 고유 식별자)
      const customerKey = `user_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
      const payment = tossPayments.payment({ customerKey });

      // 4) 서버 기반 successUrl/failUrl (서버가 해시 라우팅으로 리다이렉트)
      const baseUrl = window.location.origin;
      const successUrl = `${baseUrl}/payment/success`;
      const failUrl = `${baseUrl}/payment/fail`;

      // 5) 토스 결제창 호출 (v2 방식: method, amount 객체)
      payment.requestPayment({
        method: 'CARD',
        amount: {
          currency: 'KRW',
          value: prepareRes.amount,
        },
        orderId: prepareRes.orderId,
        orderName: prepareRes.orderName,
        customerName: book?.character_name || '고객',
        successUrl,
        failUrl,
      }).catch((err) => {
        // 사용자가 결제창 닫으면 여기로 옴
        if (err.code === 'USER_CANCEL' || err.code === 'PAY_PROCESS_CANCELED') {
          setErrorMsg('결제가 취소되었습니다. 다시 시도해주세요.');
          setTimeout(() => setErrorMsg(''), 4000);
        } else {
          setErrorMsg('결제 오류: ' + (err.message || err.code || '알 수 없는 오류'));
        }
      });

    } catch (err) {
      setErrorMsg('결제 준비 실패: ' + (err.message || '알 수 없는 오류'));
    }
  };

  // 결제 성공 콜백 처리 (URL hash에서 paymentKey 파싱)
  useEffect(() => {
    const hash = window.location.hash;
    if (hash.includes('payment-success')) {
      const params = new URLSearchParams(hash.split('?')[1]);
      const paymentKey = params.get('paymentKey');
      const orderId = params.get('orderId');
      const amount = params.get('amount');
      const urlBookId = params.get('bookId');

      if (paymentKey && orderId && amount) {
        // URL 정리
        window.history.replaceState(null, '', `#preview`);
        setPaymentStatus('confirming');

        // 서버에 결제 승인 요청
        (async () => {
          try {
            const confirmRes = await api('/payments/confirm', {
              method: 'POST',
              body: JSON.stringify({ paymentKey, orderId, amount: parseInt(amount) }),
            });

            if (confirmRes.status === 'confirmed') {
              setPaymentStatus('generating');

              // 전체 페이지 생성
              await api(`/books/${bookId}/generate-all`, { method: 'POST' });

              // 페이지 다시 불러오기
              const pagesRes = await api(`/books/${bookId}/pages`);
              setPaid(true);
              setPages(pagesRes.pages || []);
              setPaymentStatus('done');

              setTimeout(() => setPaymentStatus('idle'), 3000);
            }
          } catch (err) {
            setErrorMsg('결제 승인 실패: ' + err.message);
            setPaymentStatus('idle');
          }
        })();
      }
    } else if (hash.includes('payment-fail')) {
      window.history.replaceState(null, '', `#preview`);
      const params = new URLSearchParams(hash.split('?')[1]);
      const code = params.get('code');
      const message = params.get('message');
      if (message) setErrorMsg(`결제 실패: ${message}`);
      setPaymentStatus('idle');
    }
  }, []);

  if (loading) {
    return (
      <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <p style={{ fontSize: '18px', color: COLORS.subtitle }}>로딩 중...</p>
      </div>
    );
  }

  if (!book) {
    return (
      <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: COLORS.lightBackground }}>
        <div style={{ textAlign: 'center' }}>
          <p style={{ fontSize: '18px', color: COLORS.error, marginBottom: '20px' }}>책을 찾을 수 없습니다</p>
          <button
            onClick={() => onNavigate('templates')}
            style={{
              background: COLORS.primary,
              color: COLORS.white,
              padding: '12px 30px',
              borderRadius: '25px',
              border: 'none',
              cursor: 'pointer',
              fontWeight: 'bold',
            }}
          >
            템플릿으로 돌아가기
          </button>
        </div>
      </div>
    );
  }

  return (
    <div style={{ minHeight: '100vh', background: COLORS.lightBackground, padding: '40px 20px' }}>
      {/* Header */}
      <header style={{
        maxWidth: '900px',
        margin: '0 auto 30px',
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
      }}>
        <h1 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark }}>
          {book.character_name}의 모험
        </h1>
        <button
          onClick={() => onNavigate('templates')}
          style={{
            background: COLORS.primary,
            color: COLORS.white,
            padding: '10px 24px',
            borderRadius: '25px',
            border: 'none',
            cursor: 'pointer',
            fontWeight: '600',
          }}
        >
          돌아가기
        </button>
      </header>

      {/* Book Preview */}
      <div style={{
        maxWidth: '900px',
        margin: '0 auto',
        background: COLORS.white,
        borderRadius: '20px',
        padding: '40px',
        boxShadow: '0 4px 15px rgba(55,39,74,0.10)',
        minHeight: '600px',
        position: 'relative',
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        alignItems: 'center',
      }}>
        {pages[currentPage] ? (
          <>
            <div
              style={{
                width: '100%',
                maxWidth: '600px',
                aspectRatio: '4/5',
                background: pages[currentPage].bg_gradient || pages[currentPage].backgroundColor || COLORS.warmCream,
                borderRadius: '12px',
                padding: '30px',
                position: 'relative',
                display: 'flex',
                flexDirection: 'column',
                justifyContent: 'center',
                alignItems: 'center',
                boxShadow: '0 8px 25px rgba(55,39,74,0.15)',
                overflow: 'hidden',
                textAlign: 'center',
                color: COLORS.text,
                // 미결제 시 흐림 효과
                filter: !paid ? 'blur(6px)' : 'none',
                // 미결제 시 우클릭/드래그 방지
                userSelect: !paid ? 'none' : 'auto',
                WebkitUserSelect: !paid ? 'none' : 'auto',
                pointerEvents: !paid ? 'none' : 'auto',
              }}
              onContextMenu={(e) => { if (!paid) e.preventDefault(); }}
              onDragStart={(e) => { if (!paid) e.preventDefault(); }}
            >
              {pages[currentPage].image_url && (
                <img
                  src={pages[currentPage].image_url}
                  alt={`Page ${currentPage + 1}`}
                  style={{
                    maxWidth: '100%',
                    maxHeight: '60%',
                    marginBottom: '20px',
                    borderRadius: '8px',
                    // 이미지 저장 방지
                    pointerEvents: !paid ? 'none' : 'auto',
                    WebkitUserDrag: 'none',
                  }}
                  onContextMenu={(e) => e.preventDefault()}
                  draggable="false"
                />
              )}
              <p style={{ fontSize: '16px', lineHeight: '1.6', fontWeight: '500' }}>
                {pages[currentPage].text_content}
              </p>
            </div>

            {/* 미결제 시 워터마크 + 잠금 오버레이 (흐린 컨텐츠 위에) */}
            {!paid && (
              <div
                style={{
                  position: 'absolute',
                  top: '50%', left: '50%',
                  transform: 'translate(-50%, -50%)',
                  width: '100%',
                  maxWidth: '600px',
                  aspectRatio: '4/5',
                  borderRadius: '12px',
                  display: 'flex',
                  flexDirection: 'column',
                  alignItems: 'center',
                  justifyContent: 'center',
                  zIndex: 10,
                  pointerEvents: 'none',
                }}
                onContextMenu={(e) => e.preventDefault()}
              >
                {/* 반복 워터마크 패턴 */}
                <div style={{
                  position: 'absolute', inset: 0, overflow: 'hidden',
                  borderRadius: '12px',
                }}>
                  {[0, 1, 2, 3, 4].map(row => (
                    [0, 1, 2].map(col => (
                      <div key={`${row}-${col}`} style={{
                        position: 'absolute',
                        top: `${15 + row * 20}%`,
                        left: `${5 + col * 35}%`,
                        transform: 'rotate(-30deg)',
                        color: 'rgba(179, 157, 219, 0.3)',
                        fontSize: '18px',
                        fontWeight: 'bold',
                        whiteSpace: 'nowrap',
                        letterSpacing: '2px',
                      }}>
                        부바의 모험
                      </div>
                    ))
                  ))}
                </div>
                {/* 중앙 잠금 아이콘 */}
                <div style={{
                  background: 'rgba(255, 255, 255, 0.9)',
                  borderRadius: '20px',
                  padding: '30px 40px',
                  textAlign: 'center',
                  boxShadow: '0 4px 20px rgba(55,39,74,0.10)',
                  pointerEvents: 'auto',
                }}>
                  <div style={{ fontSize: '48px', marginBottom: '12px' }}>🔒</div>
                  <div style={{ fontSize: '18px', color: COLORS.dark, fontWeight: 'bold', marginBottom: '6px' }}>
                    미리보기
                  </div>
                  <div style={{ fontSize: '14px', color: COLORS.subtitle }}>
                    결제 후 전체 동화책을 감상하세요
                  </div>
                </div>
              </div>
            )}

            {/* Page Navigation */}
            <div style={{ marginTop: '30px', display: 'flex', gap: '10px', justifyContent: 'center', alignItems: 'center' }}>
              <button
                onClick={() => setCurrentPage(Math.max(0, currentPage - 1))}
                disabled={currentPage === 0}
                style={{
                  padding: '10px 20px',
                  borderRadius: '20px',
                  border: `2px solid ${COLORS.primary}`,
                  background: COLORS.white,
                  color: COLORS.primary,
                  fontWeight: 'bold',
                  cursor: currentPage === 0 ? 'not-allowed' : 'pointer',
                  opacity: currentPage === 0 ? 0.5 : 1,
                }}
              >
                ← 이전
              </button>

              <div style={{ display: 'flex', gap: '8px' }}>
                {pages.map((_, idx) => (
                  <button
                    key={idx}
                    onClick={() => !paid && idx > 0 ? null : setCurrentPage(idx)}
                    style={{
                      width: '32px',
                      height: '32px',
                      borderRadius: '50%',
                      background: idx === currentPage ? COLORS.primary : COLORS.lightGray,
                      color: idx === currentPage ? COLORS.white : COLORS.text,
                      border: 'none',
                      cursor: !paid && idx > 0 ? 'not-allowed' : 'pointer',
                      fontWeight: 'bold',
                      position: 'relative',
                    }}
                  >
                    {!paid && idx > 0 && (
                      <span style={{
                        position: 'absolute',
                        fontSize: '14px',
                        left: '50%',
                        top: '50%',
                        transform: 'translate(-50%, -50%)',
                      }}>
                        🔒
                      </span>
                    )}
                    {paid && (idx + 1)}
                  </button>
                ))}
              </div>

              <button
                onClick={() => setCurrentPage(Math.min(pages.length - 1, currentPage + 1))}
                disabled={currentPage === pages.length - 1}
                style={{
                  padding: '10px 20px',
                  borderRadius: '20px',
                  border: `2px solid ${COLORS.primary}`,
                  background: COLORS.white,
                  color: COLORS.primary,
                  fontWeight: 'bold',
                  cursor: currentPage === pages.length - 1 ? 'not-allowed' : 'pointer',
                  opacity: currentPage === pages.length - 1 ? 0.5 : 1,
                }}
              >
                다음 →
              </button>
            </div>

            {/* TTS 읽어주기 + 카카오톡 공유 */}
            {paid && pages[currentPage] && (
              <div style={{ marginTop: '20px', display: 'flex', gap: '12px', justifyContent: 'center', flexWrap: 'wrap' }}>
                <button
                  onClick={() => {
                    if ('speechSynthesis' in window) {
                      window.speechSynthesis.cancel();
                      const utterance = new SpeechSynthesisUtterance(pages[currentPage].text_content);
                      utterance.lang = 'ko-KR';
                      utterance.rate = 0.85;
                      utterance.pitch = 1.1;
                      window.speechSynthesis.speak(utterance);
                    } else {
                      alert('이 브라우저에서는 읽어주기를 지원하지 않습니다.');
                    }
                  }}
                  style={{
                    background: COLORS.warmLight,
                    color: COLORS.primaryDark,
                    padding: '10px 20px',
                    borderRadius: '20px',
                    border: `1px solid ${COLORS.border}`,
                    cursor: 'pointer',
                    fontWeight: '600',
                    fontSize: '14px',
                    display: 'flex',
                    alignItems: 'center',
                    gap: '6px',
                  }}
                >
                  🔊 읽어주기
                </button>
                <button
                  onClick={() => {
                    if (window.speechSynthesis) window.speechSynthesis.cancel();
                  }}
                  style={{
                    background: COLORS.lightGray,
                    color: COLORS.subtitle,
                    padding: '10px 16px',
                    borderRadius: '20px',
                    border: `1px solid ${COLORS.border}`,
                    cursor: 'pointer',
                    fontSize: '14px',
                  }}
                >
                  ⏹ 멈추기
                </button>
                <button
                  onClick={() => {
                    const shareUrl = window.location.origin + '/#preview?bookId=' + bookId;
                    const shareText = `${book.character_name}의 동화책을 만들었어요! BUBA에서 우리 아이만의 동화책을 만들어보세요.`;
                    if (navigator.share) {
                      navigator.share({ title: 'BUBA - 부바의 모험', text: shareText, url: shareUrl });
                    } else {
                      const kakaoShareUrl = `https://sharer.kakao.com/talk/friends/picker/shorturl?url=${encodeURIComponent(shareUrl)}`;
                      window.open(kakaoShareUrl, '_blank', 'width=600,height=400');
                    }
                  }}
                  style={{
                    background: '#FEE500',
                    color: '#191919',
                    padding: '10px 20px',
                    borderRadius: '20px',
                    border: 'none',
                    cursor: 'pointer',
                    fontWeight: '600',
                    fontSize: '14px',
                    display: 'flex',
                    alignItems: 'center',
                    gap: '6px',
                  }}
                >
                  💬 카카오톡 공유
                </button>
              </div>
            )}

            {/* 에러 메시지 */}
            {errorMsg && (
              <div style={{
                marginTop: '20px',
                padding: '14px 20px',
                borderRadius: '12px',
                background: '#FFEBEE',
                color: '#C62828',
                fontSize: '14px',
                textAlign: 'center',
                animation: 'fadeIn 0.3s ease-out',
              }}>
                ❌ {errorMsg}
                <button
                  onClick={() => setErrorMsg('')}
                  style={{ marginLeft: '12px', background: 'none', border: 'none', color: '#C62828', cursor: 'pointer', fontWeight: 'bold' }}
                >
                  ✕
                </button>
              </div>
            )}

            {/* CTA */}
            {!paid && (
              <div style={{ marginTop: '40px', textAlign: 'center' }}>
                <p style={{ fontSize: '16px', color: COLORS.subtitle, marginBottom: '20px' }}>
                  전체 {pages.length}쪽 동화책을 감상하려면 결제해주세요
                </p>
                <button
                  onClick={handleTossPayment}
                  className="btn-hover"
                  style={{
                    background: `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)`,
                    color: COLORS.white,
                    padding: '16px 40px',
                    fontSize: '16px',
                    fontWeight: 'bold',
                    border: 'none',
                    borderRadius: '25px',
                    cursor: 'pointer',
                    boxShadow: '0 8px 20px rgba(179, 157, 219, 0.35)',
                  }}
                >
                  ₩29,900 결제하고 전체 동화 보기
                </button>
              </div>
            )}
          </>
        ) : (
          <p style={{ color: COLORS.error }}>페이지 로드 실패</p>
        )}
      </div>

      {/* 결제 진행 상태 오버레이 (토스 결제창에서 돌아온 후) */}
      {paymentStatus !== 'idle' && (
        <div style={{
          position: 'fixed',
          inset: 0,
          background: 'rgba(0, 0, 0, 0.6)',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          zIndex: 1000,
        }}>
          <div style={{
            background: '#FFFFFF',
            borderRadius: '20px',
            padding: '50px 40px',
            maxWidth: '400px',
            width: '90%',
            textAlign: 'center',
            boxShadow: '0 20px 60px rgba(55,39,74,0.25)',
          }}>
            {paymentStatus === 'confirming' && (
              <>
                <div style={{
                  width: '56px', height: '56px',
                  border: '4px solid #E8EBED', borderTop: '4px solid #3182F6',
                  borderRadius: '50%', margin: '0 auto 24px',
                  animation: 'pgSpin 1s linear infinite',
                }} />
                <h3 style={{ fontSize: '18px', fontWeight: '700', color: '#191F28', marginBottom: '8px' }}>결제 승인 중...</h3>
                <p style={{ fontSize: '14px', color: '#8B95A1' }}>토스페이먼츠 결제를 확인하고 있습니다</p>
                <style>{`@keyframes pgSpin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }`}</style>
              </>
            )}
            {paymentStatus === 'generating' && (
              <>
                <div style={{
                  width: '56px', height: '56px',
                  border: '4px solid #E8EBED', borderTop: '4px solid #FF7043',
                  borderRadius: '50%', margin: '0 auto 24px',
                  animation: 'pgSpin 1s linear infinite',
                }} />
                <h3 style={{ fontSize: '18px', fontWeight: '700', color: '#191F28', marginBottom: '8px' }}>결제 완료!</h3>
                <p style={{ fontSize: '14px', color: '#3182F6', fontWeight: '600', marginBottom: '4px' }}>동화책 전체 페이지 생성 중...</p>
                <p style={{ fontSize: '13px', color: '#8B95A1' }}>잠시만 기다려주세요</p>
              </>
            )}
            {paymentStatus === 'done' && (
              <>
                <div style={{
                  width: '64px', height: '64px', background: '#E8F5E9',
                  borderRadius: '50%', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  margin: '0 auto 20px', fontSize: '32px',
                  animation: 'pgPop 0.4s ease-out',
                }}>
                  ✅
                </div>
                <h3 style={{ fontSize: '20px', fontWeight: '700', color: '#191F28', marginBottom: '8px' }}>모든 준비 완료!</h3>
                <p style={{ fontSize: '14px', color: '#8B95A1' }}>동화책 전체를 감상하세요</p>
                <style>{`@keyframes pgPop { 0% { transform: scale(0); opacity:0; } 60% { transform: scale(1.2); } 100% { transform: scale(1); opacity:1; } }`}</style>
              </>
            )}
          </div>
        </div>
      )}

      <SiteFooter variant="light"/>
    </div>
  );
};

// Admin Login Page Component
const AdminLoginPage = ({ onNavigate, onAdminLoginSuccess }) => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);

  const handleLogin = async (e) => {
    e.preventDefault();
    setError('');
    setLoading(true);

    try {
      const res = await fetch('/api/admin/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password }),
      });
      const data = await res.json();

      if (!res.ok) throw new Error(data.error || '로그인 실패');

      localStorage.setItem('adminToken', data.token);
      onAdminLoginSuccess(data.token);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div style={{
      minHeight: '100vh',
      background: `linear-gradient(135deg, ${COLORS.adminNavy} 0%, #2D3561 100%)`,
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      padding: '20px',
    }}>
      <div style={{
        background: COLORS.white,
        borderRadius: '16px',
        padding: '50px',
        maxWidth: '400px',
        width: '100%',
        boxShadow: '0 10px 40px rgba(55,39,74,0.25)',
      }}>
        <h1 style={{
          fontSize: '28px',
          fontWeight: 'bold',
          color: COLORS.dark,
          marginBottom: '10px',
          textAlign: 'center',
        }}>
          관리자 로그인
        </h1>
        <p style={{
          textAlign: 'center',
          color: COLORS.subtitle,
          marginBottom: '30px',
        }}>
          관리자 계정으로 로그인하세요
        </p>

        <form onSubmit={handleLogin} style={{ display: 'flex', flexDirection: 'column', gap: '20px' }}>
          <input
            type="text"
            placeholder="관리자 아이디"
            value={username}
            onChange={(e) => setUsername(e.target.value)}
            style={{
              padding: '14px',
              borderRadius: '8px',
              border: `1px solid ${COLORS.border}`,
              fontSize: '14px',
              outline: 'none',
            }}
            required
          />

          <input
            type="password"
            placeholder="비밀번호"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            style={{
              padding: '14px',
              borderRadius: '8px',
              border: `1px solid ${COLORS.border}`,
              fontSize: '14px',
              outline: 'none',
            }}
            required
          />

          {error && (
            <div style={{
              background: '#FFEBEE',
              color: COLORS.error,
              padding: '12px',
              borderRadius: '8px',
              fontSize: '14px',
            }}>
              {error}
            </div>
          )}

          <button
            type="submit"
            disabled={loading}
            style={{
              background: COLORS.adminBlue,
              color: COLORS.white,
              padding: '14px',
              borderRadius: '8px',
              border: 'none',
              fontSize: '16px',
              fontWeight: 'bold',
              cursor: loading ? 'not-allowed' : 'pointer',
              opacity: loading ? 0.6 : 1,
            }}
          >
            {loading ? '로그인 중...' : '로그인'}
          </button>
        </form>

        <button
          onClick={() => onNavigate('landing')}
          style={{
            width: '100%',
            marginTop: '20px',
            padding: '12px',
            background: 'transparent',
            color: COLORS.subtitle,
            border: 'none',
            cursor: 'pointer',
            textDecoration: 'underline',
          }}
        >
          홈으로 돌아가기
        </button>
      </div>
    </div>
  );
};

// Admin Pricing/Config Component
const AdminPricing = ({ adminToken }) => {
  const [config, setConfig] = useState({});
  const [saving, setSaving] = useState(false);
  const [saved, setSaved] = useState(false);

  const loadConfig = () => {
    fetch('/api/admin/config', { headers: { Authorization: `Bearer ${adminToken}` } })
      .then(r => r.json()).then(data => {
        const flat = {};
        Object.entries(data).forEach(([k, v]) => { flat[k] = v.value || ''; });
        setConfig(flat);
      }).catch(() => {});
  };
  useEffect(() => { loadConfig(); }, []);

  const handleSave = async () => {
    setSaving(true);
    try {
      const res = await fetch('/api/admin/config', {
        method: 'PUT',
        headers: { Authorization: `Bearer ${adminToken}`, 'Content-Type': 'application/json' },
        body: JSON.stringify(config),
      });
      if (res.ok) { setSaved(true); setTimeout(() => setSaved(false), 2000); }
    } catch (e) { alert('저장 실패'); }
    finally { setSaving(false); }
  };

  const Field = ({ k, type = 'text', suffix = '' }) => (
    <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '12px' }}>
      <label style={{ width: '200px', fontSize: '14px', fontWeight: '600', color: COLORS.dark }}>{
        { price_ebook: '전자책 가격', price_print: '실물 책 가격', coupon_print_amount: '전자책 구매 시 쿠폰', price_catalog: '전체 보기 정가', price_catalog_sale: '전체 보기 할인가', free_story_count: '무료 열람 스토리 수', sub_enabled: '구독 서비스', sub_monthly_price: '월 구독료', sub_discount_pct: '구독자 전자책 할인', sub_monthly_stories: '월 신규 스토리 수', sub_launch_date: '구독 시작 예정일' }[k] || k
      }</label>
      {k === 'sub_enabled' ? (
        <select value={config[k] || 'false'} onChange={e => setConfig({ ...config, [k]: e.target.value })} style={{ padding: '8px 14px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '14px', background: config[k] === 'true' ? '#E8F5E9' : '#FFEBEE' }}>
          <option value="false">비활성</option>
          <option value="true">활성</option>
        </select>
      ) : (
        <div style={{ display: 'flex', alignItems: 'center', gap: '6px' }}>
          <input type={type} value={config[k] || ''} onChange={e => setConfig({ ...config, [k]: e.target.value })} style={{ width: type === 'date' ? '180px' : '140px', padding: '8px 12px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '14px', textAlign: type === 'number' ? 'right' : 'left' }} />
          {suffix && <span style={{ fontSize: '13px', color: COLORS.subtitle }}>{suffix}</span>}
        </div>
      )}
    </div>
  );

  return (
    <div>
      <h1 style={{ fontSize: '28px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '8px' }}>가격/결제 설정</h1>
      <p style={{ color: COLORS.subtitle, marginBottom: '28px', fontSize: '14px' }}>상품 가격, 할인, 구독 서비스를 관리합니다. 변경 즉시 사이트에 반영됩니다.</p>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '24px' }}>
        {/* 가격 설정 */}
        <div style={{ background: '#fff', borderRadius: '16px', padding: '24px', boxShadow: '0 2px 8px rgba(55,39,74,0.06)' }}>
          <h3 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '20px', display: 'flex', alignItems: 'center', gap: '8px' }}>
            <span style={{ fontSize: '20px' }}>💳</span> 상품 가격
          </h3>
          <Field k="price_ebook" type="number" suffix="원" />
          <Field k="price_print" type="number" suffix="원" />
          <Field k="coupon_print_amount" type="number" suffix="원" />
          <div style={{ margin: '16px 0 8px', paddingTop: '16px', borderTop: `1px solid ${COLORS.border}` }}>
            <p style={{ fontSize: '12px', color: COLORS.subtitle, marginBottom: '8px' }}>스토리 카탈로그 열람</p>
          </div>
          <Field k="price_catalog" type="number" suffix="원 (정가)" />
          <Field k="price_catalog_sale" type="number" suffix="원 (할인가)" />
          <Field k="free_story_count" type="number" suffix="편" />
        </div>

        {/* 구독 설정 */}
        <div style={{ background: '#fff', borderRadius: '16px', padding: '24px', boxShadow: '0 2px 8px rgba(55,39,74,0.06)', border: config.sub_enabled === 'true' ? '2px solid #4CAF50' : '2px solid transparent' }}>
          <h3 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '20px', display: 'flex', alignItems: 'center', gap: '8px' }}>
            <span style={{ fontSize: '20px' }}>🔄</span> 구독 서비스
            <span style={{ marginLeft: 'auto', padding: '3px 10px', borderRadius: '10px', fontSize: '11px', fontWeight: '600', background: config.sub_enabled === 'true' ? '#E8F5E9' : '#FFEBEE', color: config.sub_enabled === 'true' ? '#2E7D32' : '#C62828' }}>
              {config.sub_enabled === 'true' ? '활성' : '비활성'}
            </span>
          </h3>
          <Field k="sub_enabled" />
          <Field k="sub_monthly_price" type="number" suffix="원/월" />
          <Field k="sub_discount_pct" type="number" suffix="% 할인" />
          <Field k="sub_monthly_stories" type="number" suffix="편/월" />
          <Field k="sub_launch_date" type="date" />
          {config.sub_enabled !== 'true' && (
            <div style={{ marginTop: '12px', padding: '12px', borderRadius: '10px', background: '#FFF8E1', fontSize: '13px', color: '#E65100' }}>
              구독 서비스가 비활성 상태입니다. 활성화하면 메인 페이지에 구독 플랜이 노출됩니다.
            </div>
          )}
        </div>
      </div>

      <div style={{ marginTop: '24px', display: 'flex', gap: '12px', alignItems: 'center' }}>
        <button onClick={handleSave} disabled={saving} style={{ padding: '12px 32px', borderRadius: '10px', border: 'none', background: '#7E57C2', color: '#fff', fontWeight: '700', fontSize: '15px', cursor: saving ? 'not-allowed' : 'pointer', opacity: saving ? 0.6 : 1 }}>
          {saving ? '저장 중...' : '설정 저장'}
        </button>
        {saved && <span style={{ color: '#2E7D32', fontWeight: '600', fontSize: '14px' }}>저장 완료!</span>}
      </div>
    </div>
  );
};

// Admin Landing Images Component (extracted to avoid hooks-in-IIFE error)
const AdminLandingImages = ({ adminToken }) => {
  const [slots, setSlots] = useState({});
  const [uploading, setUploading] = useState(null);

  const loadImages = () => {
    fetch('/api/admin/landing-images', { headers: { Authorization: `Bearer ${adminToken}` } })
      .then(r => r.json()).then(setSlots).catch(() => {});
  };

  useEffect(() => { loadImages(); }, []);

  const handleUpload = async (slot) => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'image/png,image/jpeg,image/webp';
    input.onchange = async (e) => {
      const file = e.target.files?.[0];
      if (!file) return;
      setUploading(slot);
      const form = new FormData();
      form.append('image', file);
      try {
        const res = await fetch(`/api/admin/landing-images/${slot}`, {
          method: 'POST', headers: { Authorization: `Bearer ${adminToken}` }, body: form
        });
        if (!res.ok) throw new Error('업로드 ���패');
        loadImages();
      } catch (err) { alert(err.message); }
      finally { setUploading(null); }
    };
    input.click();
  };

  const handleDelete = async (slot) => {
    if (!confirm('이 이미지를 삭제할까요?')) return;
    await fetch(`/api/admin/landing-images/${slot}`, {
      method: 'DELETE', headers: { Authorization: `Bearer ${adminToken}` }
    });
    loadImages();
  };

  return (
    <div>
      <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '10px' }}>랜딩 페이지 이미지 관리</h1>
      <p style={{ color: COLORS.subtitle, marginBottom: '30px' }}>메인 페이지에 표시되는 이미지를 업로드/교체할 수 있습니다.</p>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(340px, 1fr))', gap: 20 }}>
        {Object.entries(slots).map(([slot, info]) => (
          <div key={slot} style={{ background: '#fff', borderRadius: 16, border: '1px solid #E8DEF8', overflow: 'hidden', boxShadow: '0 2px 8px rgba(55,39,74,0.06)' }}>
            <div style={{ aspectRatio: slot === 'hero' ? '16/9' : '2/1', background: info.url ? '#000' : 'linear-gradient(135deg, #EDE7F6, #D1C4E9)', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
              {info.url ? <img src={info.url} alt={info.label} style={{ width: '100%', height: '100%', objectFit: 'cover' }} /> : <span style={{ color: '#9575CD', fontSize: 14, fontWeight: 600 }}>미등록</span>}
            </div>
            <div style={{ padding: '16px' }}>
              <div style={{ fontWeight: 700, color: COLORS.dark, marginBottom: 4 }}>{info.label}</div>
              <div style={{ fontSize: 12, color: COLORS.subtitle, marginBottom: 4 }}>{info.desc}</div>
              <div style={{ fontSize: 11, color: COLORS.subtitle, marginBottom: 12 }}>권장 비율: {info.ratio}</div>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => handleUpload(slot)} disabled={uploading === slot} style={{ flex: 1, padding: '8px 12px', borderRadius: 10, background: '#7E57C2', color: '#fff', border: 'none', cursor: 'pointer', fontWeight: 600, fontSize: 13, opacity: uploading === slot ? 0.6 : 1 }}>
                  {uploading === slot ? '업로드 중...' : (info.url ? '교체' : '업로드')}
                </button>
                {info.url && <button onClick={() => handleDelete(slot)} style={{ padding: '8px 12px', borderRadius: 10, background: '#FFEBEE', color: '#C62828', border: 'none', cursor: 'pointer', fontWeight: 600, fontSize: 13 }}>삭제</button>}
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
};

// Admin Panel Component
const AdminPanel = ({ onNavigate, adminToken, onAdminLogout }) => {
  const [adminPage, setAdminPage] = useState('dashboard');
  const [customers, setCustomers] = useState([]);
  const [orders, setOrders] = useState([]);
  const [stats, setStats] = useState({ users: 0, revenue: 0, books: 0, shipments: 0 });
  const [books, setBooks] = useState([]);
  const [templates, setTemplates] = useState([]);
  const [shippingOrders, setShippingOrders] = useState([]);
  const [editingTemplate, setEditingTemplate] = useState(null);
  const [newTemplate, setNewTemplate] = useState(null);
  const [shippingFilter, setShippingFilter] = useState('all');
  const [analyticsData, setAnalyticsData] = useState(null);
  const [flipbooks, setFlipbooks] = useState([]);
  const [selectedFlipbook, setSelectedFlipbook] = useState(null);
  const [flipbookPages, setFlipbookPages] = useState([]);
  const [newFlipbookTitle, setNewFlipbookTitle] = useState('');
  const [flipbookUploading, setFlipbookUploading] = useState(false);
  const api = useApi(adminToken);

  useEffect(() => {
    const fetchData = async () => {
      try {
        if (adminPage === 'dashboard') {
          const statsRes = await api('/admin/stats');
          setStats(statsRes);
          const usersRes = await api('/admin/users');
          setOrders(usersRes.users || []);
        } else if (adminPage === 'customers') {
          const usersRes = await api('/admin/users');
          setCustomers(usersRes.users || []);
        } else if (adminPage === 'books') {
          const booksRes = await api('/admin/reviews');
          setBooks(booksRes.reviews || []);
        } else if (adminPage === 'templates') {
          const tplRes = await api('/admin/templates');
          setTemplates(Array.isArray(tplRes) ? tplRes : []);
        } else if (adminPage === 'analytics') {
          const analyticsRes = await api('/admin/analytics');
          const statsRes = await api('/admin/stats');
          setAnalyticsData({ ...analyticsRes, total_revenue: statsRes.total_revenue || 0, total_payments: statsRes.total_payments || 0 });
        } else if (adminPage === 'flipbooks') {
          const fbRes = await api('/admin/flipbooks');
          setFlipbooks(fbRes.flipbooks || []);
        } else if (adminPage === 'shipping') {
          const shipUrl = shippingFilter === 'all' ? '/admin/shipping' : `/admin/shipping?status=${shippingFilter}`;
          const shipRes = await api(shipUrl);
          setShippingOrders(shipRes.orders || []);
        }
      } catch (err) {
        console.error('데이터 로드 실패:', err);
      }
    };
    fetchData();
  }, [adminPage, shippingFilter]);

  const handleBookReview = async (bookId, status, reviewNote) => {
    try {
      await api(`/admin/reviews/${bookId}`, {
        method: 'PUT',
        body: JSON.stringify({ status, review_score: status === 'approved' ? 5 : 3, review_note: reviewNote || '' }),
      });
      const booksRes = await api('/admin/reviews');
      setBooks(booksRes.reviews || []);
    } catch (err) {
      console.error('검수 처리 실패:', err);
    }
  };

  const handleTemplateUpdate = async (templateId, data) => {
    try {
      await api(`/admin/templates/${templateId}`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
      const tplRes = await api('/admin/templates');
      setTemplates(Array.isArray(tplRes) ? tplRes : []);
      setEditingTemplate(null);
    } catch (err) {
      console.error('템플릿 수정 실패:', err);
    }
  };

  const handleTemplateCreate = async (data) => {
    try {
      await api('/admin/templates', {
        method: 'POST',
        body: JSON.stringify(data),
      });
      const tplRes = await api('/admin/templates');
      setTemplates(Array.isArray(tplRes) ? tplRes : []);
      setNewTemplate(null);
    } catch (err) {
      console.error('템플릿 생성 실패:', err);
    }
  };

  const handleTemplateDelete = async (templateId) => {
    if (!confirm('정말 이 템플릿을 삭제하시겠습니까?')) return;
    try {
      await api(`/admin/templates/${templateId}`, { method: 'DELETE' });
      const tplRes = await api('/admin/templates');
      setTemplates(Array.isArray(tplRes) ? tplRes : []);
    } catch (err) {
      console.error('템플릿 삭제 실패:', err);
    }
  };

  const handleShippingUpdate = async (orderId, data) => {
    try {
      await api(`/admin/shipping/${orderId}`, {
        method: 'PUT',
        body: JSON.stringify(data),
      });
      const shipRes = await api('/admin/shipping');
      setShippingOrders(shipRes.orders || []);
    } catch (err) {
      console.error('배송 업데이트 실패:', err);
    }
  };

  // Flipbook handlers
  const handleFlipbookCreate = async () => {
    if (!newFlipbookTitle.trim()) return;
    try {
      await api('/admin/flipbooks', {
        method: 'POST',
        body: JSON.stringify({ title: newFlipbookTitle.trim() }),
      });
      setNewFlipbookTitle('');
      const fbRes = await api('/admin/flipbooks');
      setFlipbooks(fbRes.flipbooks || []);
    } catch (err) {
      console.error('플립북 생성 실패:', err);
    }
  };

  const handleFlipbookSelect = async (flipbook) => {
    try {
      const res = await api(`/admin/flipbooks/${flipbook.id}`);
      setSelectedFlipbook(res);
      setFlipbookPages(res.pages || []);
    } catch (err) {
      console.error('플립북 로드 실패:', err);
    }
  };

  const handleFlipbookUploadPages = async (e) => {
    const files = e.target.files;
    if (!files || files.length === 0 || !selectedFlipbook) return;
    setFlipbookUploading(true);
    try {
      const formData = new FormData();
      // Sort files by name for correct page ordering
      const sorted = Array.from(files).sort((a, b) => a.name.localeCompare(b.name, undefined, { numeric: true }));
      sorted.forEach(f => formData.append('pages', f));

      const res = await fetch(`/api/admin/flipbooks/${selectedFlipbook.id}/pages`, {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${adminToken}` },
        body: formData,
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error);

      // Reload flipbook
      await handleFlipbookSelect(selectedFlipbook);
      // Refresh list
      const fbRes = await api('/admin/flipbooks');
      setFlipbooks(fbRes.flipbooks || []);
    } catch (err) {
      console.error('페이지 업로드 실패:', err);
      alert('업로드 실패: ' + err.message);
    } finally {
      setFlipbookUploading(false);
      e.target.value = '';
    }
  };

  const handleFlipbookDeletePage = async (pageId) => {
    if (!selectedFlipbook) return;
    try {
      await api(`/admin/flipbooks/${selectedFlipbook.id}/pages/${pageId}`, { method: 'DELETE' });
      await handleFlipbookSelect(selectedFlipbook);
      const fbRes = await api('/admin/flipbooks');
      setFlipbooks(fbRes.flipbooks || []);
    } catch (err) {
      console.error('페이지 삭제 실패:', err);
    }
  };

  const handleFlipbookPublish = async (flipbookId, newStatus) => {
    try {
      await api(`/admin/flipbooks/${flipbookId}`, {
        method: 'PUT',
        body: JSON.stringify({ status: newStatus }),
      });
      const fbRes = await api('/admin/flipbooks');
      setFlipbooks(fbRes.flipbooks || []);
      if (selectedFlipbook && selectedFlipbook.id === flipbookId) {
        setSelectedFlipbook({ ...selectedFlipbook, status: newStatus });
      }
    } catch (err) {
      console.error('상태 변경 실패:', err);
    }
  };

  const handleFlipbookDelete = async (flipbookId) => {
    if (!confirm('정말 이 플립북을 삭제하시겠습니까? 모든 페이지가 함께 삭제됩니다.')) return;
    try {
      await api(`/admin/flipbooks/${flipbookId}`, { method: 'DELETE' });
      if (selectedFlipbook && selectedFlipbook.id === flipbookId) {
        setSelectedFlipbook(null);
        setFlipbookPages([]);
      }
      const fbRes = await api('/admin/flipbooks');
      setFlipbooks(fbRes.flipbooks || []);
    } catch (err) {
      console.error('플립북 삭제 실패:', err);
    }
  };

  const handleFlipbookCoverUpload = async (e) => {
    const file = e.target.files?.[0];
    if (!file || !selectedFlipbook) return;
    try {
      const formData = new FormData();
      formData.append('cover', file);
      const res = await fetch(`/api/admin/flipbooks/${selectedFlipbook.id}/cover`, {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${adminToken}` },
        body: formData,
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error);
      setSelectedFlipbook({ ...selectedFlipbook, cover_url: data.cover_url });
      const fbRes = await api('/admin/flipbooks');
      setFlipbooks(fbRes.flipbooks || []);
    } catch (err) {
      console.error('표지 업로드 실패:', err);
      alert('표지 업로드 실패: ' + err.message);
    } finally {
      e.target.value = '';
    }
  };

  const menuItems = [
    { id: 'dashboard', icon: '📊', label: '대시보드' },
    { id: 'customers', icon: '👥', label: '고객관리' },
    { id: 'photos', icon: '📸', label: '사진/얼굴관리' },
    { id: 'books', icon: '📖', label: '동화검수' },
    { id: 'flipbooks', icon: '📚', label: '플립북관리' },
    { id: 'templates', icon: '🎨', label: '템플릿관리' },
    { id: 'pricing', icon: '💰', label: '가격/결제 설정' },
    { id: 'landing-images', icon: '🖼️', label: '랜딩 이미지' },
    { id: 'api', icon: '🔑', label: 'API 키 설정' },
    { id: 'shipping', icon: '📦', label: '배송관리' },
    { id: 'analytics', icon: '📈', label: '매출분석' },
  ];

  return (
    <div style={{ display: 'flex', minHeight: '100vh', background: COLORS.adminLight }}>
      {/* Sidebar */}
      <div style={{
        width: '240px',
        background: COLORS.adminNavy,
        padding: '30px 20px',
        color: COLORS.white,
        overflowY: 'auto',
        display: 'flex',
        flexDirection: 'column',
      }}>
        <div style={{
          fontSize: '20px',
          fontWeight: 'bold',
          marginBottom: '30px',
          paddingBottom: '20px',
          borderBottom: `1px solid rgba(255, 255, 255, 0.2)`,
        }}>
          BUBA <br /> 관리자
        </div>

        <div style={{ flex: 1 }}>
          {menuItems.map((item) => (
            <button
              key={item.id}
              onClick={() => setAdminPage(item.id)}
              style={{
                width: '100%',
                padding: '12px 16px',
                marginBottom: '8px',
                borderRadius: '8px',
                border: 'none',
                background: adminPage === item.id ? COLORS.adminBlue : 'transparent',
                color: COLORS.white,
                cursor: 'pointer',
                textAlign: 'left',
                display: 'flex',
                alignItems: 'center',
                gap: '12px',
                fontSize: '14px',
                fontWeight: adminPage === item.id ? '600' : '500',
                transition: 'all 0.3s ease',
              }}
              onMouseEnter={(e) => {
                if (adminPage !== item.id) {
                  e.currentTarget.style.background = 'rgba(67, 97, 238, 0.2)';
                }
              }}
              onMouseLeave={(e) => {
                if (adminPage !== item.id) {
                  e.currentTarget.style.background = 'transparent';
                }
              }}
            >
              <span style={{ fontSize: '18px' }}>{item.icon}</span>
              <span>{item.label}</span>
            </button>
          ))}
        </div>

        <button
          onClick={() => {
            localStorage.removeItem('adminToken');
            onAdminLogout();
            onNavigate('landing');
          }}
          style={{
            width: '100%',
            padding: '12px 16px',
            borderRadius: '8px',
            border: 'none',
            background: 'rgba(255, 0, 0, 0.2)',
            color: '#FF6B6B',
            cursor: 'pointer',
            fontWeight: '600',
            fontSize: '14px',
          }}
        >
          로그아웃
        </button>
      </div>

      {/* Content */}
      <div style={{ flex: 1, padding: '30px', overflowY: 'auto' }}>
        {adminPage === 'dashboard' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              대시보드
            </h1>

            {/* Stats */}
            <div style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(4, 1fr)',
              gap: '20px',
              marginBottom: '40px',
            }}>
              {[
                { label: '회원수', value: stats.total_users || stats.users || 0, icon: '👥' },
                { label: '매출', value: `₩${(stats.total_revenue || stats.revenue || 0).toLocaleString()}`, icon: '💰' },
                { label: '제작건', value: stats.total_books || stats.books || 0, icon: '📖' },
                { label: '결제건', value: stats.total_payments || stats.shipments || 0, icon: '📦' },
              ].map((stat, idx) => (
                <div
                  key={idx}
                  style={{
                    background: COLORS.white,
                    padding: '25px',
                    borderRadius: '12px',
                    boxShadow: '0 2px 8px rgba(55,39,74,0.08)',
                    textAlign: 'center',
                  }}
                >
                  <div style={{ fontSize: '28px', marginBottom: '10px' }}>{stat.icon}</div>
                  <p style={{ fontSize: '14px', color: COLORS.subtitle, marginBottom: '8px' }}>
                    {stat.label}
                  </p>
                  <p style={{ fontSize: '24px', fontWeight: 'bold', color: COLORS.dark }}>
                    {stat.value}
                  </p>
                </div>
              ))}
            </div>

            {/* Recent Orders */}
            <div style={{
              background: COLORS.white,
              padding: '25px',
              borderRadius: '12px',
              boxShadow: '0 2px 8px rgba(55,39,74,0.08)',
            }}>
              <h2 style={{ fontSize: '18px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '20px' }}>
                최근 주문
              </h2>
              <table style={{
                width: '100%',
                borderCollapse: 'collapse',
                fontSize: '14px',
              }}>
                <thead>
                  <tr style={{ borderBottom: `2px solid ${COLORS.border}` }}>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>주문자</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>책 제목</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>금액</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>상태</th>
                  </tr>
                </thead>
                <tbody>
                  {orders.slice(0, 5).map((order, idx) => (
                    <tr key={idx} style={{ borderBottom: `1px solid ${COLORS.border}` }}>
                      <td style={{ padding: '12px' }}>{order.customerName || '-'}</td>
                      <td style={{ padding: '12px' }}>{order.bookTitle || '-'}</td>
                      <td style={{ padding: '12px' }}>₩{(order.amount || 0).toLocaleString()}</td>
                      <td style={{ padding: '12px' }}>
                        <span style={{
                          display: 'inline-block',
                          padding: '4px 12px',
                          borderRadius: '12px',
                          background: order.status === 'completed' ? '#E8F5E9' : '#FFF3E0',
                          color: order.status === 'completed' ? COLORS.success : COLORS.warning,
                          fontSize: '12px',
                          fontWeight: '600',
                        }}>
                          {order.status === 'completed' ? '완료' : '진행중'}
                        </span>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {adminPage === 'customers' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              고객관리
            </h1>
            <div style={{
              display: 'flex',
              gap: '10px',
              marginBottom: '20px',
            }}>
              {['전체', '무료', '프리미염'].map((filter) => (
                <button
                  key={filter}
                  style={{
                    padding: '8px 16px',
                    borderRadius: '20px',
                    border: `2px solid ${COLORS.adminBlue}`,
                    background: COLORS.white,
                    color: COLORS.adminBlue,
                    cursor: 'pointer',
                    fontWeight: '600',
                    fontSize: '14px',
                  }}
                >
                  {filter}
                </button>
              ))}
            </div>

            <div style={{
              background: COLORS.white,
              borderRadius: '12px',
              boxShadow: '0 2px 8px rgba(55,39,74,0.08)',
              overflowX: 'auto',
            }}>
              <table style={{
                width: '100%',
                borderCollapse: 'collapse',
                fontSize: '14px',
              }}>
                <thead>
                  <tr style={{ background: COLORS.lightGray, borderBottom: `2px solid ${COLORS.border}` }}>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>이름</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>이메일</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>가입일</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>요금제</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>주문수</th>
                    <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>상태</th>
                  </tr>
                </thead>
                <tbody>
                  {customers.map((customer, idx) => (
                    <tr key={idx} style={{ borderBottom: `1px solid ${COLORS.border}` }}>
                      <td style={{ padding: '12px' }}>{customer.name || '-'}</td>
                      <td style={{ padding: '12px' }}>{customer.email || '-'}</td>
                      <td style={{ padding: '12px' }}>{new Date(customer.createdAt).toLocaleDateString('ko-KR') || '-'}</td>
                      <td style={{ padding: '12px' }}>
                        <span style={{
                          display: 'inline-block',
                          padding: '4px 12px',
                          borderRadius: '12px',
                          background: customer.plan === 'premium' ? '#E3F2FD' : '#F5F5F5',
                          color: customer.plan === 'premium' ? COLORS.adminBlue : COLORS.text,
                          fontSize: '12px',
                          fontWeight: '600',
                        }}>
                          {customer.plan === 'premium' ? '프리미엄' : '무료'}
                        </span>
                      </td>
                      <td style={{ padding: '12px' }}>{customer.orderCount || 0}</td>
                      <td style={{ padding: '12px' }}>
                        <span style={{
                          display: 'inline-block',
                          padding: '4px 12px',
                          borderRadius: '12px',
                          background: customer.active ? '#E8F5E9' : '#FFEBEE',
                          color: customer.active ? COLORS.success : COLORS.error,
                          fontSize: '12px',
                          fontWeight: '600',
                        }}>
                          {customer.active ? '활성' : '비활성'}
                        </span>
                      </td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {adminPage === 'photos' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              사진/얼굴관리
            </h1>
            <div style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))',
              gap: '20px',
            }}>
              {[1, 2, 3, 4, 5, 6].map((idx) => (
                <div
                  key={idx}
                  style={{
                    background: COLORS.white,
                    borderRadius: '12px',
                    overflow: 'hidden',
                    boxShadow: '0 2px 8px rgba(55,39,74,0.08)',
                  }}
                >
                  <div style={{
                    display: 'grid',
                    gridTemplateColumns: '1fr 1fr',
                    background: COLORS.lightGray,
                    aspectRatio: '2/1',
                  }}>
                    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '24px' }}>
                      원본
                    </div>
                    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '24px' }}>
                      변환됨
                    </div>
                  </div>
                  <div style={{ padding: '15px' }}>
                    <p style={{ fontSize: '12px', color: COLORS.subtitle, marginBottom: '10px' }}>
                      2024-01-15
                    </p>
                    <div style={{ display: 'flex', gap: '8px' }}>
                      <button
                        style={{
                          flex: 1,
                          padding: '6px',
                          borderRadius: '6px',
                          border: 'none',
                          background: COLORS.success,
                          color: COLORS.white,
                          cursor: 'pointer',
                          fontSize: '12px',
                          fontWeight: '600',
                        }}
                      >
                        승인
                      </button>
                      <button
                        style={{
                          flex: 1,
                          padding: '6px',
                          borderRadius: '6px',
                          border: 'none',
                          background: COLORS.error,
                          color: COLORS.white,
                          cursor: 'pointer',
                          fontSize: '12px',
                          fontWeight: '600',
                        }}
                      >
                        거절
                      </button>
                    </div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {adminPage === 'pricing' && <AdminPricing adminToken={adminToken} />}
        {adminPage === 'landing-images' && <AdminLandingImages adminToken={adminToken} />}

        {adminPage === 'api' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              API 키 설정
            </h1>
            <div style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(auto-fit, minmax(400px, 1fr))',
              gap: '20px',
            }}>
              {['Midjourney', 'Gemini', 'Stable Diffusion', 'Toss', 'CJ Logistics'].map((service, idx) => (
                <div
                  key={idx}
                  style={{
                    background: COLORS.white,
                    padding: '25px',
                    borderRadius: '12px',
                    boxShadow: '0 2px 8px rgba(55,39,74,0.08)',
                  }}
                >
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
                    <h3 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark }}>
                      {service}
                    </h3>
                    <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
                      <input type="checkbox" defaultChecked />
                      <span style={{ fontSize: '12px', fontWeight: '600' }}>활성</span>
                    </label>
                  </div>

                  <div style={{ display: 'flex', flexDirection: 'column', gap: '15px' }}>
                    <div>
                      <label style={{ display: 'block', fontSize: '12px', fontWeight: '600', marginBottom: '5px', color: COLORS.subtitle }}>
                        API 키
                      </label>
                      <input
                        type="password"
                        placeholder="••••••••••••"
                        style={{
                          width: '100%',
                          padding: '10px',
                          borderRadius: '8px',
                          border: `1px solid ${COLORS.border}`,
                          fontSize: '12px',
                          outline: 'none',
                        }}
                      />
                    </div>

                    <div>
                      <label style={{ display: 'block', fontSize: '12px', fontWeight: '600', marginBottom: '5px', color: COLORS.subtitle }}>
                        엔드포인트 URL
                      </label>
                      <input
                        type="text"
                        placeholder="https://api.example.com"
                        style={{
                          width: '100%',
                          padding: '10px',
                          borderRadius: '8px',
                          border: `1px solid ${COLORS.border}`,
                          fontSize: '12px',
                          outline: 'none',
                        }}
                      />
                    </div>

                    {['Midjourney', 'Gemini', 'Stable Diffusion'].includes(service) && (
                      <div>
                        <label style={{ display: 'block', fontSize: '12px', fontWeight: '600', marginBottom: '5px', color: COLORS.subtitle }}>
                          AI 프롬프트 템플릿
                        </label>
                        <textarea
                          placeholder="사용할 프롬프트 템플릿..."
                          style={{
                            width: '100%',
                            padding: '10px',
                            borderRadius: '8px',
                            border: `1px solid ${COLORS.border}`,
                            fontSize: '12px',
                            outline: 'none',
                            resize: 'vertical',
                            minHeight: '80px',
                          }}
                        />
                      </div>
                    )}

                    <button
                      style={{
                        padding: '10px',
                        borderRadius: '8px',
                        border: 'none',
                        background: COLORS.adminBlue,
                        color: COLORS.white,
                        cursor: 'pointer',
                        fontWeight: '600',
                        fontSize: '12px',
                      }}
                    >
                      연결 테스트
                    </button>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {adminPage === 'analytics' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              매출분석
            </h1>

            {!analyticsData ? (
              <p style={{ color: COLORS.subtitle }}>데이터 로딩 중...</p>
            ) : (
              <>
                {/* Revenue Cards */}
                <div style={{
                  display: 'grid',
                  gridTemplateColumns: 'repeat(3, 1fr)',
                  gap: '20px',
                  marginBottom: '40px',
                }} className="responsive-grid">
                  {[
                    { label: '전체 매출', value: `₩${(analyticsData.total_revenue || 0).toLocaleString()}`, icon: '💰', color: COLORS.primaryDark },
                    { label: '총 결제 건수', value: `${analyticsData.total_payments || 0}건`, icon: '🧾', color: COLORS.success },
                    { label: '건당 평균', value: `₩${analyticsData.total_payments ? Math.round((analyticsData.total_revenue || 0) / analyticsData.total_payments).toLocaleString() : 0}`, icon: '📊', color: COLORS.adminBlue },
                  ].map((item, idx) => (
                    <div key={idx} style={{ background: COLORS.white, padding: '25px', borderRadius: '12px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
                        <p style={{ fontSize: '14px', color: COLORS.subtitle }}>{item.label}</p>
                        <span style={{ fontSize: '24px' }}>{item.icon}</span>
                      </div>
                      <p style={{ fontSize: '28px', fontWeight: 'bold', color: item.color }}>{item.value}</p>
                    </div>
                  ))}
                </div>

                {/* Daily Revenue Chart */}
                <div style={{ background: COLORS.white, padding: '25px', borderRadius: '12px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)', marginBottom: '20px' }}>
                  <h2 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '20px' }}>
                    일별 매출
                  </h2>
                  {analyticsData.daily_revenue && analyticsData.daily_revenue.length > 0 ? (
                    <div>
                      <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-around', height: '200px', padding: '0 10px' }}>
                        {analyticsData.daily_revenue.map((day, idx) => {
                          const maxVal = Math.max(...analyticsData.daily_revenue.map(d => d.daily_total || 0), 1);
                          const pct = ((day.daily_total || 0) / maxVal) * 100;
                          return (
                            <div key={idx} style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', flex: 1 }}>
                              <span style={{ fontSize: '11px', color: COLORS.primaryDark, fontWeight: '600', marginBottom: '6px' }}>
                                ₩{(day.daily_total || 0).toLocaleString()}
                              </span>
                              <div style={{
                                width: '32px',
                                height: `${Math.max(pct, 5)}%`,
                                background: `linear-gradient(180deg, ${COLORS.primaryDark} 0%, ${COLORS.primary} 100%)`,
                                borderRadius: '6px 6px 0 0',
                                minHeight: '10px',
                              }} />
                              <span style={{ fontSize: '11px', color: COLORS.subtitle, marginTop: '8px' }}>
                                {day.date ? day.date.slice(5) : ''}
                              </span>
                            </div>
                          );
                        })}
                      </div>
                    </div>
                  ) : (
                    <p style={{ color: COLORS.subtitle, textAlign: 'center', padding: '40px 0' }}>아직 매출 데이터가 없습니다</p>
                  )}
                </div>

                {/* User Growth + Book Creation */}
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }} className="responsive-grid">
                  <div style={{ background: COLORS.white, padding: '25px', borderRadius: '12px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                    <h2 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '16px' }}>신규 사용자</h2>
                    {(analyticsData.user_growth || []).length > 0 ? (
                      <div>
                        {analyticsData.user_growth.map((day, idx) => (
                          <div key={idx} style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 0', borderBottom: idx < analyticsData.user_growth.length - 1 ? `1px solid ${COLORS.border}` : 'none' }}>
                            <span style={{ fontSize: '13px', color: COLORS.subtitle }}>{day.date}</span>
                            <span style={{ fontSize: '13px', fontWeight: '600', color: COLORS.success }}>+{day.new_users}명</span>
                          </div>
                        ))}
                      </div>
                    ) : (
                      <p style={{ color: COLORS.subtitle, textAlign: 'center' }}>데이터 없음</p>
                    )}
                  </div>
                  <div style={{ background: COLORS.white, padding: '25px', borderRadius: '12px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                    <h2 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '16px' }}>동화책 생성</h2>
                    {(analyticsData.book_creation_trend || []).length > 0 ? (
                      <div>
                        {analyticsData.book_creation_trend.map((day, idx) => (
                          <div key={idx} style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 0', borderBottom: idx < analyticsData.book_creation_trend.length - 1 ? `1px solid ${COLORS.border}` : 'none' }}>
                            <span style={{ fontSize: '13px', color: COLORS.subtitle }}>{day.date}</span>
                            <span style={{ fontSize: '13px', fontWeight: '600', color: COLORS.primaryDark }}>{day.books_created}권</span>
                          </div>
                        ))}
                      </div>
                    ) : (
                      <p style={{ color: COLORS.subtitle, textAlign: 'center' }}>데이터 없음</p>
                    )}
                  </div>
                </div>
              </>
            )}
          </div>
        )}

        {/* 동화검수 */}
        {adminPage === 'books' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              동화검수
            </h1>
            {books.length === 0 ? (
              <div style={{ background: COLORS.white, padding: '50px', borderRadius: '12px', textAlign: 'center', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                <p style={{ color: COLORS.subtitle, fontSize: '16px' }}>검수 대기 중인 동화가 없습니다.</p>
              </div>
            ) : (
              <div style={{ display: 'grid', gap: '16px' }}>
                {books.map((book) => (
                  <div key={book.id} style={{ background: COLORS.white, borderRadius: '12px', padding: '20px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)', display: 'flex', alignItems: 'center', gap: '20px' }}>
                    <div style={{ width: '60px', height: '60px', borderRadius: '12px', background: COLORS.lightGray, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '28px', flexShrink: 0 }}>📖</div>
                    <div style={{ flex: 1 }}>
                      <h3 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '4px' }}>
                        {book.character_name}의 동화책
                      </h3>
                      <p style={{ fontSize: '13px', color: COLORS.subtitle }}>
                        주문자: {book.name} ({book.email}) · {new Date(book.created_at).toLocaleDateString('ko-KR')}
                      </p>
                    </div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                      <span style={{
                        padding: '4px 12px', borderRadius: '12px', fontSize: '12px', fontWeight: '600',
                        background: book.status === 'approved' ? '#E8F5E9' : book.status === 'revision_needed' ? '#FFF3E0' : '#E3F2FD',
                        color: book.status === 'approved' ? COLORS.success : book.status === 'revision_needed' ? COLORS.warning : COLORS.adminBlue,
                      }}>
                        {book.status === 'approved' ? '승인됨' : book.status === 'revision_needed' ? '수정요청' : book.status || '대기'}
                      </span>
                    </div>
                    <div style={{ display: 'flex', gap: '8px', flexShrink: 0 }}>
                      <button onClick={() => handleBookReview(book.id, 'approved', '검수 완료')} style={{ padding: '8px 16px', borderRadius: '8px', border: 'none', background: COLORS.success, color: COLORS.white, cursor: 'pointer', fontSize: '13px', fontWeight: '600' }}>승인</button>
                      <button onClick={() => handleBookReview(book.id, 'revision_needed', '수정 필요')} style={{ padding: '8px 16px', borderRadius: '8px', border: 'none', background: COLORS.warning, color: COLORS.white, cursor: 'pointer', fontSize: '13px', fontWeight: '600' }}>수정요청</button>
                    </div>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}

        {/* 플립북관리 */}
        {adminPage === 'flipbooks' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>
              플립북관리
            </h1>

            {/* Create new flipbook */}
            <div style={{ background: COLORS.white, borderRadius: '12px', padding: '24px', marginBottom: '24px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
              <h3 style={{ fontSize: '16px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '12px' }}>새 플립북 만들기</h3>
              <div style={{ display: 'flex', gap: '12px' }}>
                <input
                  value={newFlipbookTitle}
                  onChange={(e) => setNewFlipbookTitle(e.target.value)}
                  placeholder="플립북 제목 (예: 준호의 마법의 숲 모험)"
                  onKeyDown={(e) => e.key === 'Enter' && handleFlipbookCreate()}
                  style={{ flex: 1, padding: '10px 14px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '14px', outline: 'none' }}
                />
                <button
                  onClick={handleFlipbookCreate}
                  disabled={!newFlipbookTitle.trim()}
                  style={{ padding: '10px 24px', borderRadius: '8px', border: 'none', background: COLORS.adminBlue, color: COLORS.white, cursor: newFlipbookTitle.trim() ? 'pointer' : 'not-allowed', fontWeight: '600', fontSize: '14px', opacity: newFlipbookTitle.trim() ? 1 : 0.5 }}
                >
                  + 생성
                </button>
              </div>
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: selectedFlipbook ? '1fr 2fr' : '1fr', gap: '24px' }}>
              {/* Flipbook list */}
              <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
                {flipbooks.length === 0 ? (
                  <div style={{ background: COLORS.white, padding: '50px', borderRadius: '12px', textAlign: 'center', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                    <p style={{ color: COLORS.subtitle, fontSize: '16px' }}>생성된 플립북이 없습니다.</p>
                  </div>
                ) : flipbooks.map((fb) => (
                  <div
                    key={fb.id}
                    onClick={() => handleFlipbookSelect(fb)}
                    style={{
                      background: selectedFlipbook?.id === fb.id ? '#EDE7F6' : COLORS.white,
                      borderRadius: '12px', padding: '16px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)',
                      cursor: 'pointer', border: selectedFlipbook?.id === fb.id ? `2px solid ${COLORS.primary}` : '2px solid transparent',
                      transition: 'all 0.2s ease',
                    }}
                  >
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'start', marginBottom: '8px' }}>
                      <h3 style={{ fontSize: '15px', fontWeight: 'bold', color: COLORS.dark }}>{fb.title}</h3>
                      <span style={{
                        padding: '2px 8px', borderRadius: '8px', fontSize: '11px', fontWeight: '600',
                        background: fb.status === 'published' ? '#E8F5E9' : '#FFF3E0',
                        color: fb.status === 'published' ? COLORS.success : COLORS.warning,
                      }}>
                        {fb.status === 'published' ? '공개' : '비공개'}
                      </span>
                    </div>
                    <p style={{ fontSize: '12px', color: COLORS.subtitle }}>
                      {fb.page_count || 0}페이지 · {new Date(fb.created_at).toLocaleDateString('ko-KR')}
                    </p>
                    {fb.status === 'published' && (
                      <p style={{ fontSize: '11px', color: COLORS.adminBlue, marginTop: '4px', wordBreak: 'break-all' }}>
                        {window.location.origin}/#flipbook?code={fb.share_code}
                      </p>
                    )}
                  </div>
                ))}
              </div>

              {/* Selected flipbook detail */}
              {selectedFlipbook && (
                <div style={{ background: COLORS.white, borderRadius: '12px', padding: '24px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
                    <div>
                      <h2 style={{ fontSize: '20px', fontWeight: 'bold', color: COLORS.dark }}>{selectedFlipbook.title}</h2>
                      <p style={{ fontSize: '13px', color: COLORS.subtitle, marginTop: '4px' }}>
                        공유코드: {selectedFlipbook.share_code}
                      </p>
                    </div>
                    <div style={{ display: 'flex', gap: '8px' }}>
                      {selectedFlipbook.status === 'draft' ? (
                        <button
                          onClick={() => handleFlipbookPublish(selectedFlipbook.id, 'published')}
                          disabled={flipbookPages.length === 0}
                          style={{ padding: '8px 16px', borderRadius: '8px', border: 'none', background: flipbookPages.length > 0 ? COLORS.success : COLORS.lightGray, color: flipbookPages.length > 0 ? COLORS.white : COLORS.subtitle, cursor: flipbookPages.length > 0 ? 'pointer' : 'not-allowed', fontSize: '13px', fontWeight: '600' }}
                        >
                          공개하기
                        </button>
                      ) : (
                        <button
                          onClick={() => handleFlipbookPublish(selectedFlipbook.id, 'draft')}
                          style={{ padding: '8px 16px', borderRadius: '8px', border: 'none', background: COLORS.warning, color: COLORS.white, cursor: 'pointer', fontSize: '13px', fontWeight: '600' }}
                        >
                          비공개로 전환
                        </button>
                      )}
                      <button
                        onClick={() => {
                          const url = `${window.location.origin}/#flipbook?code=${selectedFlipbook.share_code}`;
                          navigator.clipboard.writeText(url).then(() => alert('링크가 복사되었습니다!'));
                        }}
                        style={{ padding: '8px 16px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, background: 'transparent', cursor: 'pointer', fontSize: '13px', fontWeight: '600', color: COLORS.adminBlue }}
                      >
                        링크 복사
                      </button>
                      <button
                        onClick={() => handleFlipbookDelete(selectedFlipbook.id)}
                        style={{ padding: '8px 16px', borderRadius: '8px', border: 'none', background: '#FFEBEE', color: COLORS.error, cursor: 'pointer', fontSize: '13px', fontWeight: '600' }}
                      >
                        삭제
                      </button>
                    </div>
                  </div>

                  {/* Cover image */}
                  <div style={{ marginBottom: '20px' }}>
                    <h3 style={{ fontSize: '15px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '12px' }}>
                      표지 이미지
                    </h3>
                    <div style={{ display: 'flex', gap: '16px', alignItems: 'center' }}>
                      {selectedFlipbook.cover_url ? (
                        <img src={selectedFlipbook.cover_url} alt="Cover" style={{ width: '120px', aspectRatio: '3/4', objectFit: 'cover', borderRadius: '8px', border: `1px solid ${COLORS.border}` }} />
                      ) : (
                        <div style={{ width: '120px', aspectRatio: '3/4', borderRadius: '8px', border: `2px dashed ${COLORS.border}`, display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#FAFAFA', color: COLORS.subtitle, fontSize: '13px', textAlign: 'center', padding: '8px' }}>
                          표지 없음
                        </div>
                      )}
                      <div>
                        <input type="file" id="flipbook-cover-upload" accept="image/png,image/jpeg" onChange={handleFlipbookCoverUpload} style={{ display: 'none' }} />
                        <label htmlFor="flipbook-cover-upload" style={{ display: 'inline-block', padding: '8px 16px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, background: 'white', cursor: 'pointer', fontSize: '13px', fontWeight: '600', color: COLORS.adminBlue }}>
                          {selectedFlipbook.cover_url ? '표지 변경' : '표지 업로드'}
                        </label>
                        <p style={{ fontSize: '11px', color: COLORS.subtitle, marginTop: '6px' }}>
                          PNG/JPG, 3:4 비율 권장
                        </p>
                      </div>
                    </div>
                  </div>

                  {/* Page upload area */}
                  <div style={{ border: `2px dashed ${COLORS.border}`, borderRadius: '12px', padding: '30px', textAlign: 'center', marginBottom: '20px', background: '#FAFAFA' }}>
                    <input
                      type="file"
                      id="flipbook-upload"
                      multiple
                      accept="image/png,image/jpeg"
                      onChange={handleFlipbookUploadPages}
                      style={{ display: 'none' }}
                    />
                    <label
                      htmlFor="flipbook-upload"
                      style={{ cursor: flipbookUploading ? 'not-allowed' : 'pointer', display: 'block' }}
                    >
                      {flipbookUploading ? (
                        <div>
                          <div style={{ fontSize: '32px', marginBottom: '8px' }}>...</div>
                          <p style={{ fontSize: '14px', color: COLORS.subtitle }}>업로드 중...</p>
                        </div>
                      ) : (
                        <div>
                          <div style={{ fontSize: '32px', marginBottom: '8px' }}>+</div>
                          <p style={{ fontSize: '14px', color: COLORS.subtitle }}>PNG/JPG 이미지를 선택하세요 (여러 파일 가능)</p>
                          <p style={{ fontSize: '12px', color: COLORS.subtitle, marginTop: '4px' }}>파일명 순서대로 페이지가 정렬됩니다</p>
                        </div>
                      )}
                    </label>
                  </div>

                  {/* Page thumbnails */}
                  {flipbookPages.length > 0 && (
                    <div>
                      <h3 style={{ fontSize: '15px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '12px' }}>
                        페이지 ({flipbookPages.length})
                      </h3>
                      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: '12px' }}>
                        {flipbookPages.map((page) => (
                          <div key={page.id} style={{ position: 'relative', borderRadius: '8px', overflow: 'hidden', border: `1px solid ${COLORS.border}`, background: COLORS.lightGray }}>
                            <img
                              src={page.image_url}
                              alt={`Page ${page.page_number}`}
                              style={{ width: '100%', aspectRatio: '3/4', objectFit: 'cover', display: 'block' }}
                            />
                            <div style={{ padding: '6px 8px', display: 'flex', justifyContent: 'space-between', alignItems: 'center', background: 'white' }}>
                              <span style={{ fontSize: '12px', color: COLORS.subtitle, fontWeight: '600' }}>
                                {page.page_number}p
                              </span>
                              <button
                                onClick={(e) => { e.stopPropagation(); handleFlipbookDeletePage(page.id); }}
                                style={{ background: 'none', border: 'none', color: COLORS.error, cursor: 'pointer', fontSize: '14px', padding: '0 4px' }}
                              >
                                x
                              </button>
                            </div>
                          </div>
                        ))}
                      </div>
                    </div>
                  )}

                  {/* Preview button */}
                  {flipbookPages.length > 0 && (
                    <div style={{ marginTop: '20px', textAlign: 'center' }}>
                      <button
                        onClick={() => onNavigate('flipbook', { code: selectedFlipbook.share_code, adminPreview: true })}
                        style={{ padding: '12px 30px', borderRadius: '25px', border: 'none', background: `linear-gradient(135deg, ${COLORS.primary} 0%, ${COLORS.primaryDark} 100%)`, color: COLORS.white, cursor: 'pointer', fontWeight: '600', fontSize: '14px', boxShadow: '0 4px 12px rgba(179, 157, 219, 0.3)' }}
                      >
                        플립북 미리보기
                      </button>
                    </div>
                  )}
                </div>
              )}
            </div>
          </div>
        )}

        {/* 템플릿관리 */}
        {adminPage === 'templates' && (
          <div>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '30px' }}>
              <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark }}>템플릿관리</h1>
              <button onClick={() => setNewTemplate({ id: '', title: '', emoji: '', theme: '', description: '', story_summary: '', target_gender: 'boy', page_count: 12, age_range: '3-7세', colors_primary: '#B39DDB', colors_bg: '#F3E5F5' })} style={{ padding: '10px 20px', borderRadius: '8px', border: 'none', background: COLORS.adminBlue, color: COLORS.white, cursor: 'pointer', fontWeight: '600', fontSize: '14px' }}>+ 새 템플릿</button>
            </div>

            {newTemplate && (
              <div style={{ background: COLORS.white, borderRadius: '12px', padding: '24px', marginBottom: '20px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                <h3 style={{ fontSize: '16px', fontWeight: 'bold', marginBottom: '16px', color: COLORS.dark }}>새 템플릿 만들기</h3>
                <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px', marginBottom: '16px' }}>
                  <input placeholder="ID (영문, 예: brave-knight)" value={newTemplate.id} onChange={(e) => setNewTemplate({...newTemplate, id: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                  <input placeholder="제목 (예: 용감한 꿈의 기사)" value={newTemplate.title} onChange={(e) => setNewTemplate({...newTemplate, title: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                  <input placeholder="이모지 (예: ⚔️)" value={newTemplate.emoji} onChange={(e) => setNewTemplate({...newTemplate, emoji: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                  <select value={newTemplate.target_gender} onChange={(e) => setNewTemplate({...newTemplate, target_gender: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none', background: 'white' }}>
                    <option value="boy">남부바 (남아)</option>
                    <option value="girl">여부바 (여아)</option>
                    <option value="both">공용</option>
                  </select>
                  <input placeholder="테마 (예: adventure)" value={newTemplate.theme} onChange={(e) => setNewTemplate({...newTemplate, theme: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                  <input placeholder="연령대 (예: 3-7세)" value={newTemplate.age_range} onChange={(e) => setNewTemplate({...newTemplate, age_range: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                  <input placeholder="한줄 설명" value={newTemplate.description} onChange={(e) => setNewTemplate({...newTemplate, description: e.target.value})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none', gridColumn: 'span 2' }} />
                  <textarea placeholder="스토리 소개 (3-4줄)" value={newTemplate.story_summary} onChange={(e) => setNewTemplate({...newTemplate, story_summary: e.target.value})} rows={3} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none', gridColumn: 'span 2', resize: 'vertical', fontFamily: 'inherit' }} />
                  <input type="number" placeholder="페이지 수" value={newTemplate.page_count} onChange={(e) => setNewTemplate({...newTemplate, page_count: parseInt(e.target.value) || 12})} style={{ padding: '10px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                </div>
                <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end' }}>
                  <button onClick={() => setNewTemplate(null)} style={{ padding: '8px 16px', borderRadius: '8px', border: `1px solid ${COLORS.border}`, background: 'transparent', cursor: 'pointer', fontSize: '13px' }}>취소</button>
                  <button onClick={() => handleTemplateCreate(newTemplate)} style={{ padding: '8px 16px', borderRadius: '8px', border: 'none', background: COLORS.adminBlue, color: COLORS.white, cursor: 'pointer', fontWeight: '600', fontSize: '13px' }}>생성</button>
                </div>
              </div>
            )}

            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(360px, 1fr))', gap: '20px' }}>
              {templates.map((tpl) => (
                <div key={tpl.id} style={{ background: COLORS.white, borderRadius: '12px', overflow: 'hidden', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                  {/* Header: thumbnail or emoji */}
                  <div style={{ background: tpl.colors_primary || COLORS.primary, padding: tpl.thumbnail_url ? '0' : '24px', textAlign: 'center', position: 'relative', height: '140px', display: 'flex', alignItems: 'center', justifyContent: 'center', overflow: 'hidden' }}>
                    {tpl.thumbnail_url ? (
                      <img src={tpl.thumbnail_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                    ) : (
                      <span style={{ fontSize: '48px' }}>{tpl.emoji || '📖'}</span>
                    )}
                    <div style={{ position: 'absolute', top: '8px', right: '8px', display: 'flex', gap: '4px' }}>
                      <span style={{ padding: '2px 8px', borderRadius: '8px', fontSize: '11px', fontWeight: '600', background: tpl.target_gender === 'boy' ? '#E3F2FD' : tpl.target_gender === 'girl' ? '#FCE4EC' : '#F3E5F5', color: tpl.target_gender === 'boy' ? '#1565C0' : tpl.target_gender === 'girl' ? '#C2185B' : COLORS.primaryDark }}>
                        {tpl.target_gender === 'boy' ? '👦 남아' : tpl.target_gender === 'girl' ? '👧 여아' : '공용'}
                      </span>
                      <span style={{ padding: '2px 8px', borderRadius: '8px', fontSize: '11px', fontWeight: '600', background: tpl.is_active ? '#E8F5E9' : '#FFEBEE', color: tpl.is_active ? COLORS.success : COLORS.error }}>
                        {tpl.is_active ? '활성' : '비활성'}
                      </span>
                    </div>
                  </div>
                  <div style={{ padding: '16px' }}>
                    {editingTemplate === tpl.id ? (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
                        <input defaultValue={tpl.title} id={`tpl-title-${tpl.id}`} placeholder="제목" style={{ padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                        <input defaultValue={tpl.description} id={`tpl-desc-${tpl.id}`} placeholder="한줄 설명" style={{ padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                        <textarea defaultValue={tpl.story_summary} id={`tpl-summary-${tpl.id}`} placeholder="스토리 소개" rows={3} style={{ padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none', resize: 'vertical', fontFamily: 'inherit' }} />
                        <select defaultValue={tpl.target_gender || 'both'} id={`tpl-gender-${tpl.id}`} style={{ padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }}>
                          <option value="boy">남부바 (남아)</option>
                          <option value="girl">여부바 (여아)</option>
                          <option value="both">공용</option>
                        </select>
                        <input defaultValue={tpl.age_range} id={`tpl-age-${tpl.id}`} placeholder="연령대 (예: 3-7세)" style={{ padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                        <input type="number" defaultValue={tpl.page_count} id={`tpl-pages-${tpl.id}`} placeholder="페이지 수" min="1" style={{ padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '13px', outline: 'none' }} />
                        {/* Thumbnail upload */}
                        <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                          <input type="file" id={`tpl-thumb-${tpl.id}`} accept="image/png,image/jpeg" style={{ display: 'none' }} onChange={async (e) => {
                            const file = e.target.files?.[0]; if (!file) return;
                            const fd = new FormData(); fd.append('thumbnail', file);
                            try {
                              const r = await fetch(`/api/admin/templates/${tpl.id}/thumbnail`, { method: 'POST', headers: { 'Authorization': `Bearer ${adminToken}` }, body: fd });
                              if (r.ok) { const tplRes = await api('/admin/templates'); setTemplates(Array.isArray(tplRes) ? tplRes : []); }
                            } catch (err) { console.error(err); }
                            e.target.value = '';
                          }} />
                          <label htmlFor={`tpl-thumb-${tpl.id}`} style={{ padding: '6px 12px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, cursor: 'pointer', fontSize: '12px', color: COLORS.adminBlue }}>
                            {tpl.thumbnail_url ? '썸네일 변경' : '썸네일 업로드'}
                          </label>
                        </div>
                        {/* Preview images upload */}
                        <div>
                          <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '6px' }}>
                            <input type="file" id={`tpl-preview-${tpl.id}`} accept="image/png,image/jpeg" multiple style={{ display: 'none' }} onChange={async (e) => {
                              const files = e.target.files; if (!files?.length) return;
                              const fd = new FormData(); Array.from(files).forEach(f => fd.append('previews', f));
                              try {
                                const r = await fetch(`/api/admin/templates/${tpl.id}/previews`, { method: 'POST', headers: { 'Authorization': `Bearer ${adminToken}` }, body: fd });
                                if (r.ok) { const tplRes = await api('/admin/templates'); setTemplates(Array.isArray(tplRes) ? tplRes : []); }
                              } catch (err) { console.error(err); }
                              e.target.value = '';
                            }} />
                            <label htmlFor={`tpl-preview-${tpl.id}`} style={{ padding: '6px 12px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, cursor: 'pointer', fontSize: '12px', color: COLORS.adminBlue }}>
                              미리보기 이미지 추가
                            </label>
                            <span style={{ fontSize: '11px', color: COLORS.subtitle }}>{(tpl.previews || []).length}장</span>
                          </div>
                          {(tpl.previews || []).length > 0 && (
                            <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap' }}>
                              {tpl.previews.map(pv => (
                                <div key={pv.id} style={{ position: 'relative', width: '60px', height: '60px', borderRadius: '4px', overflow: 'hidden', border: `1px solid ${COLORS.border}` }}>
                                  <img src={pv.image_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                                  <button onClick={async () => {
                                    await api(`/admin/templates/${tpl.id}/previews/${pv.id}`, { method: 'DELETE' });
                                    const tplRes = await api('/admin/templates'); setTemplates(Array.isArray(tplRes) ? tplRes : []);
                                  }} style={{ position: 'absolute', top: '1px', right: '1px', background: 'rgba(0,0,0,0.5)', color: 'white', border: 'none', borderRadius: '50%', width: '16px', height: '16px', fontSize: '10px', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>x</button>
                                </div>
                              ))}
                            </div>
                          )}
                        </div>
                        <div style={{ display: 'flex', gap: '8px' }}>
                          <button onClick={() => setEditingTemplate(null)} style={{ flex: 1, padding: '8px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, background: 'transparent', cursor: 'pointer', fontSize: '12px' }}>취소</button>
                          <button onClick={() => {
                            const pcRaw = document.getElementById(`tpl-pages-${tpl.id}`).value;
                            const pc = parseInt(pcRaw, 10);
                            handleTemplateUpdate(tpl.id, {
                              title: document.getElementById(`tpl-title-${tpl.id}`).value,
                              description: document.getElementById(`tpl-desc-${tpl.id}`).value,
                              story_summary: document.getElementById(`tpl-summary-${tpl.id}`).value,
                              target_gender: document.getElementById(`tpl-gender-${tpl.id}`).value,
                              age_range: document.getElementById(`tpl-age-${tpl.id}`).value,
                              ...(Number.isFinite(pc) && pc > 0 ? { page_count: pc } : {}),
                            });
                          }} style={{ flex: 1, padding: '8px', borderRadius: '6px', border: 'none', background: COLORS.adminBlue, color: COLORS.white, cursor: 'pointer', fontWeight: '600', fontSize: '12px' }}>저장</button>
                        </div>
                      </div>
                    ) : (
                      <>
                        <h3 style={{ fontSize: '15px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '4px' }}>{tpl.title}</h3>
                        <p style={{ fontSize: '12px', color: COLORS.subtitle, marginBottom: '4px' }}>{tpl.description || '-'}</p>
                        {tpl.story_summary && <p style={{ fontSize: '11px', color: COLORS.subtitle, marginBottom: '6px', lineHeight: '1.5', maxHeight: '50px', overflow: 'hidden' }}>{tpl.story_summary}</p>}
                        <p style={{ fontSize: '11px', color: COLORS.subtitle, marginBottom: '10px' }}>
                          {tpl.page_count}p · {tpl.age_range || '-'} · 미리보기 {(tpl.previews || []).length}장 · 사용 {tpl.usage_count || 0}회
                        </p>
                        <div style={{ display: 'flex', gap: '6px' }}>
                          <button onClick={() => setEditingTemplate(tpl.id)} style={{ flex: 1, padding: '7px', borderRadius: '6px', border: 'none', background: COLORS.adminBlue, color: COLORS.white, cursor: 'pointer', fontSize: '12px', fontWeight: '600' }}>수정</button>
                          <button onClick={() => handleTemplateUpdate(tpl.id, { is_active: !tpl.is_active })} style={{ flex: 1, padding: '7px', borderRadius: '6px', border: 'none', background: tpl.is_active ? '#FFEBEE' : '#E8F5E9', color: tpl.is_active ? COLORS.error : COLORS.success, cursor: 'pointer', fontSize: '12px', fontWeight: '600' }}>
                            {tpl.is_active ? '비활성화' : '활성화'}
                          </button>
                          <button onClick={() => handleTemplateDelete(tpl.id)} style={{ padding: '7px 10px', borderRadius: '6px', border: 'none', background: '#FFEBEE', color: COLORS.error, cursor: 'pointer', fontSize: '12px', fontWeight: '600' }}>🗑</button>
                        </div>
                      </>
                    )}
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {/* 배송관리 */}
        {adminPage === 'shipping' && (
          <div>
            <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '30px' }}>배송관리</h1>
            <div style={{ display: 'flex', gap: '10px', marginBottom: '20px' }}>
              {[
                { key: 'all', label: '전체' },
                { key: 'preparing', label: '준비중' },
                { key: 'printing', label: '인쇄중' },
                { key: 'in_transit', label: '배송중' },
                { key: 'delivered', label: '배송완료' },
              ].map((f) => (
                <button key={f.key} onClick={() => setShippingFilter(f.key)} style={{
                  padding: '8px 16px', borderRadius: '20px', cursor: 'pointer', fontWeight: '600', fontSize: '13px',
                  border: shippingFilter === f.key ? 'none' : `2px solid ${COLORS.border}`,
                  background: shippingFilter === f.key ? COLORS.adminBlue : COLORS.white,
                  color: shippingFilter === f.key ? COLORS.white : COLORS.text,
                }}>{f.label}</button>
              ))}
            </div>

            {shippingOrders.length === 0 ? (
              <div style={{ background: COLORS.white, padding: '50px', borderRadius: '12px', textAlign: 'center', boxShadow: '0 2px 8px rgba(55,39,74,0.08)' }}>
                <p style={{ color: COLORS.subtitle, fontSize: '16px' }}>배송 주문이 없습니다.</p>
              </div>
            ) : (
              <div style={{ background: COLORS.white, borderRadius: '12px', boxShadow: '0 2px 8px rgba(55,39,74,0.08)', overflowX: 'auto' }}>
                <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '14px' }}>
                  <thead>
                    <tr style={{ background: COLORS.lightGray, borderBottom: `2px solid ${COLORS.border}` }}>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>주문번호</th>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>수령인</th>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>주소</th>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>상태</th>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>운송장</th>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>날짜</th>
                      <th style={{ textAlign: 'left', padding: '12px', fontWeight: '600' }}>관리</th>
                    </tr>
                  </thead>
                  <tbody>
                    {shippingOrders.map((order) => (
                      <tr key={order.id} style={{ borderBottom: `1px solid ${COLORS.border}` }}>
                        <td style={{ padding: '12px' }}>#{order.id}</td>
                        <td style={{ padding: '12px' }}>{order.recipient_name || order.name || '-'}</td>
                        <td style={{ padding: '12px', maxWidth: '200px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{order.recipient_address || '-'}</td>
                        <td style={{ padding: '12px' }}>
                          <span style={{
                            padding: '4px 10px', borderRadius: '12px', fontSize: '12px', fontWeight: '600',
                            background: order.status === 'delivered' ? '#E8F5E9' : order.status === 'in_transit' ? '#E3F2FD' : order.status === 'printing' ? '#FFF3E0' : '#F5F5F5',
                            color: order.status === 'delivered' ? COLORS.success : order.status === 'in_transit' ? COLORS.adminBlue : order.status === 'printing' ? COLORS.warning : COLORS.text,
                          }}>
                            {order.status === 'delivered' ? '배송완료' : order.status === 'in_transit' ? '배송중' : order.status === 'printing' ? '인쇄중' : '준비중'}
                          </span>
                        </td>
                        <td style={{ padding: '12px', fontSize: '12px' }}>{order.tracking_number || '-'}</td>
                        <td style={{ padding: '12px', fontSize: '12px' }}>{order.created_at ? new Date(order.created_at).toLocaleDateString('ko-KR') : '-'}</td>
                        <td style={{ padding: '12px' }}>
                          <select
                            value={order.status || 'pending'}
                            onChange={(e) => handleShippingUpdate(order.id, { status: e.target.value })}
                            style={{ padding: '6px 10px', borderRadius: '6px', border: `1px solid ${COLORS.border}`, fontSize: '12px', outline: 'none', cursor: 'pointer' }}
                          >
                            <option value="preparing">준비중</option>
                            <option value="printing">인쇄중</option>
                            <option value="in_transit">배송중</option>
                            <option value="delivered">배송완료</option>
                          </select>
                        </td>
                      </tr>
                    ))}
                  </tbody>
                </table>
              </div>
            )}
          </div>
        )}
      </div>
    </div>
  );
};

// Policy / Terms / Support Page Component
const PolicyPage = ({ type, onNavigate }) => {
  const content = {
    privacy: {
      title: '개인정보처리방침',
      sections: [
        { heading: '1. 총칙', body: '부바(BUBA, 이하 "회사")는 「개인정보 보호법」 제30조에 따라 정보주체의 개인정보를 보호하고 이와 관련한 고충을 신속하고 원활하게 처리할 수 있도록 하기 위하여 다음과 같이 개인정보 처리방침을 수립·공개합니다.\n\n본 방침은 회사가 운영하는 AI 맞춤형 동화책 서비스 buba.kr(이하 "서비스")에 적용됩니다.' },
        { heading: '2. 개인정보의 수집 및 이용 목적', body: '회사는 다음의 목적을 위하여 개인정보를 처리합니다. 처리하고 있는 개인정보는 다음의 목적 이외의 용도로는 이용되지 않으며, 이용 목적이 변경되는 경우에는 「개인정보 보호법」 제18조에 따라 별도의 동의를 받는 등 필요한 조치를 이행할 예정입니다.\n\n• 회원 가입 및 관리: 회원제 서비스 이용에 따른 본인확인, 개인식별, 불량회원의 부정이용 방지와 비인가 사용 방지, 가입 의사 확인, 분쟁 조정을 위한 기록 보존, 불만처리 등 민원처리, 고지사항 전달\n• 서비스 제공: AI 맞춤형 동화책 제작, 결제 처리, 주문 관리, 인쇄본 배송 서비스 제공, 콘텐츠 제공\n• AI 이미지 처리: 업로드된 아동 사진의 수채화풍 일러스트 변환 처리 (변환 완료 후 원본 사진은 서버에서 즉시 삭제)\n• 마케팅 및 광고 활용: 이벤트 정보 및 참여 기회 제공, 서비스 이용 통계 수집 및 분석 (선택 동의 시에 한함)\n• 안전한 서비스 운영: 서비스 부정이용 방지, 시스템 보안 유지' },
        { heading: '3. 수집하는 개인정보 항목 및 수집 방법', body: '가. 수집 항목\n\n[필수항목]\n• 회원 가입 시: 이메일 주소, 비밀번호(암호화 저장), 이름\n• 서비스 이용 시: 아동 이름, 아동 성별, 아동 사진(얼굴 이미지)\n• 결제 시: 결제정보(카드사명, 결제 승인번호, 결제 일시)\n• 배송 시: 수령인 이름, 배송지 주소, 연락처\n\n[선택항목]\n• 전화번호, 마케팅 수신 동의 여부\n\n[자동 수집 항목]\n• 접속 IP 주소, 쿠키, 서비스 이용 기록, 접속 로그, 방문 일시, 기기 정보(OS, 브라우저 종류)\n\n나. 수집 방법\n• 웹사이트 회원가입 및 서비스 이용 과정에서 이용자가 직접 입력\n• 서비스 이용 과정에서 자동 생성·수집되는 정보\n• 고객센터를 통한 상담 과정에서 수집' },
        { heading: '4. 개인정보의 보유 및 이용기간', body: '회사는 법령에 따른 개인정보 보유·이용기간 또는 정보주체로부터 개인정보를 수집 시에 동의받은 개인정보 보유·이용기간 내에서 개인정보를 처리·보유합니다.\n\n가. 회원 정보: 회원 탈퇴 시까지 (탈퇴 즉시 파기)\n나. 아동 사진(원본): AI 변환 처리 완료 후 24시간 이내 서버에서 완전 삭제\n다. AI 변환 결과물(일러스트): 서비스 제공 목적으로 회원 탈퇴 시까지 보유\n\n라. 관계 법령에 의한 보유 기간\n• 계약 또는 청약철회 등에 관한 기록: 5년 (전자상거래 등에서의 소비자보호에 관한 법률)\n• 대금결제 및 재화 등의 공급에 관한 기록: 5년 (전자상거래 등에서의 소비자보호에 관한 법률)\n• 소비자의 불만 또는 분쟁처리에 관한 기록: 3년 (전자상거래 등에서의 소비자보호에 관한 법률)\n• 표시·광고에 관한 기록: 6개월 (전자상거래 등에서의 소비자보호에 관한 법률)\n• 웹사이트 방문기록: 3개월 (통신비밀보호법)' },
        { heading: '5. 개인정보의 제3자 제공', body: '회사는 정보주체의 개인정보를 제2조에서 명시한 범위 내에서만 처리하며, 정보주체의 동의, 법률의 특별한 규정 등 「개인정보 보호법」 제17조 및 제18조에 해당하는 경우에만 개인정보를 제3자에게 제공합니다.\n\n현재 개인정보를 제3자에게 제공하는 경우는 다음과 같습니다:\n\n• 결제 서비스 제공업체 (토스페이먼츠): 결제 처리 목적, 결제 완료 후 5년 보유\n• 배송 대행업체: 인쇄본 배송 목적, 배송 완료 후 즉시 파기\n• 인쇄 협력업체: 동화책 인쇄 목적, 인쇄 완료 후 즉시 파기' },
        { heading: '6. 개인정보의 처리 위탁', body: '회사는 원활한 개인정보 업무처리를 위하여 다음과 같이 개인정보 처리업무를 위탁하고 있습니다.\n\n• 클라우드 호스팅: Railway (서버 운영 및 데이터 저장)\n• AI 이미지 처리: Google Gemini API (아동 사진 AI 변환 처리)\n• 결제 처리: 토스페이먼츠 (결제 대행)\n\n회사는 위탁 계약 체결 시 「개인정보 보호법」 제26조에 따라 위탁업무 수행 목적 외 개인정보 처리 금지, 기술적·관리적 보호조치, 재위탁 제한, 수탁자에 대한 관리·감독, 손해배상 등 책임에 관한 사항을 계약서 등 문서에 명시하고, 수탁자가 개인정보를 안전하게 처리하는지를 감독하고 있습니다.' },
        { heading: '7. 개인정보의 파기 절차 및 방법', body: '회사는 개인정보 보유기간의 경과, 처리목적 달성 등 개인정보가 불필요하게 되었을 때에는 지체없이 해당 개인정보를 파기합니다.\n\n가. 파기 절차\n이용자가 입력한 정보는 목적 달성 후 별도의 DB에 옮겨져(종이의 경우 별도의 서류) 내부 방침 및 기타 관련 법령에 따라 일정기간 저장된 후 혹은 즉시 파기됩니다.\n\n나. 파기 방법\n• 전자적 파일 형태: 복구 및 재생이 불가능한 방법으로 영구 삭제\n• 종이 문서: 분쇄기로 분쇄하거나 소각하여 파기\n• 아동 사진 원본: AI 처리 완료 즉시 서버 메모리 및 디스크에서 비가역적으로 삭제' },
        { heading: '8. 정보주체와 법정대리인의 권리·의무 및 행사 방법', body: '가. 정보주체(이용자)는 회사에 대해 언제든지 다음 각 호의 개인정보 보호 관련 권리를 행사할 수 있습니다.\n\n① 개인정보 열람 요구\n② 오류 등이 있을 경우 정정 요구\n③ 삭제 요구\n④ 처리정지 요구\n\n나. 14세 미만 아동의 개인정보 처리 시 법정대리인의 동의를 받아야 하며, 법정대리인은 아동의 개인정보에 대한 열람, 정정·삭제, 처리정지를 요구할 수 있습니다.\n\n다. 권리 행사는 회사에 대해 서면, 전자우편(support@bubaadventure.kr) 등을 통하여 하실 수 있으며, 회사는 이에 대해 지체없이(10일 이내) 조치하겠습니다.\n\n라. 정보주체가 개인정보의 오류 등에 대한 정정 또는 삭제를 요구한 경우에는 회사는 정정 또는 삭제를 완료할 때까지 당해 개인정보를 이용하거나 제공하지 않습니다.' },
        { heading: '9. 아동(14세 미만)의 개인정보 보호', body: '회사는 서비스 특성상 아동(14세 미만)의 사진을 처리합니다. 이에 따라 다음과 같은 보호 조치를 시행합니다.\n\n• 아동의 사진 업로드 시 법정대리인(부모 등)의 동의를 받습니다.\n• 수집된 아동 사진 원본은 AI 변환 처리 완료 후 24시간 이내에 서버에서 완전히 삭제합니다.\n• 아동의 사진은 동화책 제작 목적 이외에는 일체 사용하지 않습니다.\n• 법정대리인은 아동의 개인정보에 대한 열람, 정정·삭제, 처리정지를 언제든지 요구할 수 있습니다.\n• 「개인정보 보호법」 제22조의2에 따라 법정대리인의 동의 없이는 아동의 개인정보를 수집하지 않습니다.' },
        { heading: '10. AI 기반 자동화된 개인정보 처리에 관한 사항', body: '회사는 다음과 같이 AI 기술을 활용하여 개인정보를 자동으로 처리합니다.\n\n가. AI 처리 목적 및 방법\n• 목적: 업로드된 아동 사진을 수채화풍 일러스트로 변환하여 맞춤형 동화책 제작\n• 방법: Google Gemini API를 활용한 이미지 변환 (원본 사진은 API 호출 시에만 일시적으로 전송되며, 변환 완료 후 즉시 삭제)\n• AI 처리 결과: 수채화풍 일러스트 이미지 생성\n\n나. AI 처리에 따른 정보주체의 권리\n• 정보주체는 AI에 의한 자동화된 결정에 대해 설명을 요구할 권리가 있습니다.\n• AI 변환 결과에 불만이 있는 경우, 재처리를 요청하거나 삭제를 요구할 수 있습니다.\n• AI 처리를 거부하고 서비스 이용을 중단할 권리가 있습니다.' },
        { heading: '11. 개인정보의 안전성 확보 조치', body: '회사는 「개인정보 보호법」 제29조에 따라 다음과 같이 안전성 확보에 필요한 기술적·관리적 및 물리적 조치를 하고 있습니다.\n\n가. 관리적 조치\n• 내부관리계획의 수립 및 시행\n• 개인정보 취급 직원의 최소화 및 정기 교육 실시\n\n나. 기술적 조치\n• 비밀번호의 암호화 저장 (bcrypt 해시 처리)\n• 개인정보 전송 시 SSL/TLS 암호화 통신\n• 해킹 등에 대비한 보안 시스템 설치 및 갱신\n• 접근 권한 관리 및 접근 통제\n• 개인정보 접근 기록의 보관 및 위변조 방지\n\n다. 물리적 조치\n• 클라우드 기반 서비스로 물리적 접근 통제는 호스팅 업체(Railway)의 보안 정책을 따릅니다.' },
        { heading: '12. 개인정보 자동 수집 장치의 설치·운영 및 거부에 관한 사항', body: '회사는 이용자에게 개별적인 맞춤 서비스를 제공하기 위해 이용 정보를 저장하고 수시로 불러오는 "쿠키(Cookie)"를 사용합니다.\n\n가. 쿠키의 사용 목적\n• 로그인 상태 유지 (JWT 토큰 저장)\n• 이용자의 접속 빈도나 방문 시간 등을 파악하여 서비스 개선에 활용\n\n나. 쿠키의 설치·운영 및 거부\n• 이용자는 웹 브라우저 설정을 통해 쿠키 저장을 거부할 수 있습니다.\n• 설정방법: 브라우저 상단의 설정 > 개인정보 > 쿠키 설정\n• 다만, 쿠키 저장을 거부할 경우 로그인이 필요한 일부 서비스 이용에 어려움이 발생할 수 있습니다.' },
        { heading: '13. 개인정보 보호책임자', body: '회사는 개인정보 처리에 관한 업무를 총괄해서 책임지고, 개인정보 처리와 관련한 정보주체의 불만처리 및 피해구제 등을 위하여 아래와 같이 개인정보 보호책임자를 지정하고 있습니다.\n\n[개인정보 보호책임자]\n• 성명: 대표이사\n• 직위: 개인정보보호책임자 (CPO)\n• 연락처: support@bubaadventure.kr / 1588-BUBA\n\n이용자께서는 회사의 서비스를 이용하시면서 발생한 모든 개인정보 보호 관련 문의, 불만처리, 피해구제 등에 관한 사항을 개인정보 보호책임자에게 문의하실 수 있습니다. 회사는 정보주체의 문의에 대해 지체없이 답변 및 처리해드리겠습니다.' },
        { heading: '14. 권익침해 구제방법', body: '정보주체는 개인정보침해로 인한 구제를 받기 위하여 개인정보분쟁조정위원회, 한국인터넷진흥원 개인정보침해신고센터 등에 분쟁해결이나 상담 등을 신청할 수 있습니다.\n\n• 개인정보분쟁조정위원회: (국번없이) 1833-6972 (www.kopico.go.kr)\n• 개인정보침해신고센터: (국번없이) 118 (privacy.kisa.or.kr)\n• 대검찰청 사이버수사과: (국번없이) 1301 (www.spo.go.kr)\n• 경찰청 사이버수사국: (국번없이) 182 (ecrm.police.go.kr)' },
        { heading: '15. 개인정보 처리방침 변경에 관한 사항', body: '본 개인정보처리방침은 법령, 정책 또는 보안기술의 변경에 따라 내용의 추가, 삭제 및 수정이 있을 시에는 변경사항의 시행 7일 전부터 웹사이트 공지사항을 통하여 고지할 것입니다.' },
        { heading: '16. 시행일', body: '본 개인정보처리방침은 2024년 1월 1일부터 적용됩니다.\n최종 개정일: 2025년 5월 1일' },
      ],
    },
    terms: {
      title: '이용약관',
      sections: [
        { heading: '제1조 (목적)', body: '이 약관은 부바(BUBA, 이하 "회사")가 운영하는 인터넷 사이트 buba.kr(이하 "사이트")에서 제공하는 AI 맞춤형 동화책 서비스(이하 "서비스")의 이용과 관련하여 회사와 이용자의 권리·의무 및 책임사항, 기타 필요한 사항을 규정함을 목적으로 합니다.' },
        { heading: '제2조 (정의)', body: '① "서비스"란 회사가 제공하는 AI 기반 맞춤형 동화책 제작, 디지털 열람, 인쇄본 배송 등 일체의 서비스를 말합니다.\n② "이용자"란 이 약관에 따라 회사가 제공하는 서비스를 받는 회원 및 비회원을 말합니다.\n③ "회원"이란 회사에 개인정보를 제공하여 회원등록을 한 자로서, 회사의 서비스를 계속적으로 이용할 수 있는 자를 말합니다.\n④ "비회원"이란 회원으로 가입하지 않고 회사가 제공하는 서비스를 이용하는 자를 말합니다.\n⑤ "동화책"이란 이용자가 선택한 템플릿과 아동 정보를 기반으로 AI가 제작한 맞춤형 디지털 동화책을 말합니다.\n⑥ "콘텐츠"란 회사가 서비스에서 제공하는 텍스트, 이미지, 일러스트레이션, 템플릿 등 일체의 디지털 자료를 말합니다.' },
        { heading: '제3조 (약관의 게시 및 개정)', body: '① 회사는 이 약관의 내용을 이용자가 쉽게 알 수 있도록 서비스 초기 화면에 게시합니다.\n② 회사는 「약관의 규제에 관한 법률」, 「전자상거래 등에서의 소비자보호에 관한 법률」, 「정보통신망 이용촉진 및 정보보호 등에 관한 법률」 등 관련 법령을 위배하지 않는 범위에서 이 약관을 개정할 수 있습니다.\n③ 회사가 약관을 개정할 경우에는 적용일자 및 개정사유를 명시하여 현행 약관과 함께 서비스 초기 화면에 그 적용일자 7일 이전부터 적용일자 전일까지 공지합니다. 다만, 이용자에게 불리하게 변경되는 경우에는 30일 이전부터 공지합니다.\n④ 이용자가 개정약관의 적용에 동의하지 않는 경우, 이용자는 이용계약을 해지(탈퇴)할 수 있습니다.' },
        { heading: '제4조 (서비스의 제공 및 변경)', body: '① 회사가 제공하는 서비스는 다음과 같습니다.\n• AI 얼굴 변환 서비스: 이용자가 업로드한 아동 사진을 수채화풍 일러스트로 변환\n• 맞춤형 동화책 제작: 다양한 템플릿을 기반으로 아동 이름과 변환된 일러스트가 삽입된 개인화 동화책 제작\n• 디지털 동화책 열람 서비스 (플립북 뷰어)\n• 동화책 인쇄 및 배송 서비스\n• 무료 체험: 얼굴 변환 1회 무료 체험 제공\n\n② 회사는 서비스의 내용을 기술적 사양의 변경 등의 사유로 변경할 수 있으며, 변경 시 변경 내용과 적용일자를 명시하여 서비스 내에 공지합니다.\n③ 회사는 무료로 제공되는 서비스의 일부 또는 전부를 회사의 정책 및 운영의 필요상 수정, 중단, 변경할 수 있으며, 이에 대하여 관련 법령에 특별한 규정이 없는 한 이용자에게 별도의 보상을 하지 않습니다.' },
        { heading: '제5조 (회원가입)', body: '① 이용자는 회사가 정한 가입 양식에 따라 회원정보를 기입한 후 이 약관에 동의한다는 의사표시를 함으로써 회원가입을 신청합니다.\n② 회사는 제1항과 같이 회원으로 가입할 것을 신청한 이용자 중 다음 각 호에 해당하지 않는 한 회원으로 등록합니다.\n• 가입신청자가 이 약관에 의하여 이전에 회원자격을 상실한 적이 있는 경우\n• 등록 내용에 허위, 기재누락, 오기가 있는 경우\n• 기타 회원으로 등록하는 것이 회사의 기술상 현저히 지장이 있다고 판단되는 경우\n③ 회원가입 계약의 성립 시기는 회사의 승낙이 회원에게 도달한 시점으로 합니다.' },
        { heading: '제6조 (회원 탈퇴 및 자격 상실)', body: '① 회원은 회사에 언제든지 탈퇴를 요청할 수 있으며, 회사는 즉시 회원탈퇴를 처리합니다.\n② 회원이 다음 각 호의 사유에 해당하는 경우, 회사는 회원자격을 제한 및 정지시킬 수 있습니다.\n• 가입 신청 시에 허위 내용을 등록한 경우\n• 다른 사람의 서비스 이용을 방해하거나 그 정보를 도용하는 경우\n• 타인의 사진을 무단으로 업로드하는 경우\n• 서비스를 이용하여 법령 또는 이 약관이 금지하거나 공서양속에 반하는 행위를 하는 경우\n③ 회원 탈퇴 시 관련 법령 및 개인정보처리방침에 따라 회사가 회원정보를 보유하는 경우를 제외하고는 개인정보를 즉시 삭제합니다.' },
        { heading: '제7조 (이용 요금 및 결제)', body: '① 서비스 이용 요금은 회사가 서비스 내에 별도로 표시한 바에 따릅니다.\n② 회사는 요금을 변경할 경우 변경 사유와 적용일자를 명시하여 적용일 7일 전에 공지합니다.\n③ 결제는 신용카드, 체크카드, 계좌이체, 간편결제 등 회사가 정한 결제 수단으로 할 수 있습니다.\n④ 결제 대행 서비스는 토스페이먼츠를 통해 제공되며, 결제 과정에서 토스페이먼츠의 이용약관이 적용될 수 있습니다.\n⑤ 회사는 이용자의 결제 정보를 직접 저장하지 않으며, 결제 처리는 PG사를 통해 안전하게 진행됩니다.' },
        { heading: '제8조 (청약철회 및 환불)', body: '① 이용자는 「전자상거래 등에서의 소비자보호에 관한 법률」 등 관련 법령의 규정에 따라 청약을 철회할 수 있습니다.\n② 환불 정책은 다음과 같습니다.\n• 결제 후 동화책 제작 시작 전: 전액 환불\n• 동화책 제작 중 (AI 생성 진행 중): 환불 불가 (「전자상거래법」 제17조 제2항 제5호, 이용자의 주문에 의해 개별적으로 생산되는 재화로서 청약철회 제한 고지 및 동의를 받은 경우)\n• 인쇄본 배송 완료 후: 상품 하자 시 수령 후 7일 이내 교환 또는 환불 가능\n• 인쇄본 배송 완료 후: 단순 변심에 의한 반품은 수령 후 7일 이내 가능 (반품 배송비 이용자 부담)\n③ 환불 처리 기간: 환불 승인 후 3~5 영업일 이내 원래 결제 수단으로 환불됩니다.\n④ 다음의 경우 청약철회가 제한됩니다 (사전 고지 및 동의를 받은 경우에 한함).\n• 이용자의 주문에 의해 개별적으로 제작되는 맞춤형 상품 (AI 동화책)\n• 디지털 콘텐츠의 제공이 개시된 경우\n⑤ 환불 신청은 마이페이지 또는 고객센터(support@bubaadventure.kr, 1588-BUBA)를 통해 가능합니다.' },
        { heading: '제9조 (서비스 이용 제한 및 중지)', body: '① 회사는 다음 각 호의 경우 서비스 제공을 일시적으로 중단할 수 있습니다.\n• 서비스 설비의 보수 등 공사로 인한 부득이한 경우\n• 「전기통신사업법」에 규정된 기간통신사업자가 전기통신 서비스를 중지한 경우\n• 기타 불가항력적 사유가 있는 경우\n② 회사는 서비스의 중단으로 인하여 이용자가 입은 손해에 대해 배상하지 않습니다. 단, 회사의 고의 또는 과실에 의한 경우에는 그러하지 아니합니다.' },
        { heading: '제10조 (이용자의 의무)', body: '이용자는 다음 행위를 하여서는 안 됩니다.\n\n• 신청 또는 변경 시 허위 내용의 등록\n• 타인의 정보 도용\n• 타인의 사진(아동 사진 포함)을 법정대리인 동의 없이 무단으로 업로드하는 행위\n• 회사가 게시한 정보의 변경\n• 회사가 정한 정보 이외의 정보(컴퓨터 프로그램 등)의 송신 또는 게시\n• 회사 기타 제3자의 저작권 등 지적재산권에 대한 침해\n• 회사 기타 제3자의 명예를 손상시키거나 업무를 방해하는 행위\n• 외설 또는 폭력적인 메시지, 화상, 음성, 기타 공서양속에 반하는 정보를 서비스에 공개 또는 게시하는 행위\n• 서비스를 이용하여 얻은 정보를 회사의 사전 승낙 없이 복제, 배포, 상업적으로 이용하는 행위\n• 기타 관련 법령에 위반되는 행위' },
        { heading: '제11조 (지적재산권)', body: '① 서비스에 사용된 템플릿, 일러스트레이션, 스토리 텍스트, 디자인, 소프트웨어, UI/UX 등에 대한 지적재산권은 회사에 귀속됩니다.\n② AI가 생성한 동화책 결과물에 대한 개인적 이용 권리는 이용자에게 있습니다. 다만, 상업적 이용은 회사의 사전 서면 동의가 필요합니다.\n③ 이용자가 업로드한 아동 사진에 대한 권리는 이용자(법정대리인)에게 있습니다. 회사는 서비스 제공 목적으로만 해당 사진을 이용하며, 처리 완료 후 즉시 삭제합니다.\n④ 이용자는 서비스를 이용함으로써 얻은 정보 중 회사에 지적재산권이 귀속된 정보를 회사의 사전 승낙 없이 복제, 송신, 출판, 배포, 방송 기타 방법에 의하여 영리목적으로 이용하거나 제3자에게 이용하게 하여서는 안 됩니다.' },
        { heading: '제12조 (AI 서비스에 관한 고지)', body: '① 본 서비스는 AI(인공지능) 기술을 활용하여 동화책을 제작합니다. AI 기술의 특성상 다음 사항을 고지합니다.\n• AI 변환 결과물(일러스트)의 품질은 원본 사진의 품질, 조명, 각도 등에 따라 달라질 수 있습니다.\n• AI가 생성한 스토리 및 이미지는 자동 생성된 것으로, 회사는 최선의 결과를 위해 노력하되 완벽한 결과를 보장하지 않습니다.\n• AI 처리 과정에서 외부 AI 서비스(Google Gemini API)를 활용하며, 처리에 필요한 최소한의 데이터만 일시적으로 전송됩니다.\n② 이용자는 AI 생성 결과물이 만족스럽지 않은 경우, 재생성을 요청하거나 고객센터를 통해 문의할 수 있습니다.' },
        { heading: '제13조 (손해배상 및 면책)', body: '① 회사는 무료로 제공되는 서비스와 관련하여 관련 법령에 특별한 규정이 없는 한 책임을 지지 않습니다.\n② 회사는 천재지변, 전쟁, 기간통신사업자의 서비스 중지 등 불가항력으로 인하여 서비스를 제공할 수 없는 경우에는 서비스 제공에 관한 책임이 면제됩니다.\n③ 회사는 이용자의 귀책사유로 인한 서비스 이용 장애에 대하여 책임을 지지 않습니다.\n④ 회사는 이용자가 서비스를 이용하여 기대하는 수익을 상실한 것에 대하여 책임을 지지 않으며, 서비스를 통하여 얻은 자료로 인한 손해에 관하여 책임을 지지 않습니다.' },
        { heading: '제14조 (분쟁해결)', body: '① 회사는 이용자가 제기하는 정당한 의견이나 불만을 반영하고, 그 피해를 보상 처리하기 위하여 피해보상처리 기구를 설치·운영합니다.\n② 회사와 이용자 간에 발생한 전자상거래 분쟁에 관한 소송은 제소 당시의 이용자의 주소에 의하고, 주소가 없는 경우에는 거소를 관할하는 지방법원의 전속관할로 합니다. 다만, 제소 당시 이용자의 주소 또는 거소가 분명하지 않거나 외국 거주자의 경우에는 민사소송법상의 관할법원에 제기합니다.\n③ 회사와 이용자 간에 발생한 분쟁은 전자문서·전자거래분쟁조정위원회에 조정을 신청할 수 있습니다.' },
        { heading: '부칙', body: '본 약관은 2024년 1월 1일부터 시행됩니다.\n최종 개정일: 2025년 5월 1일' },
      ],
    },
    support: {
      title: '고객 지원',
      sections: [
        { heading: '고객센터 안내', body: '부바(BUBA) 서비스 이용 중 궁금하신 점이나 문제가 있으시면 아래 방법으로 연락해주세요. 친절하고 신속하게 도움을 드리겠습니다.\n\n• 이메일: support@bubaadventure.kr (24시간 접수, 영업일 기준 1일 이내 답변)\n• 전화: 1588-BUBA (평일 09:00~18:00, 점심시간 12:00~13:00 제외)\n• 카카오톡: @부바의모험 (평일 09:00~18:00 실시간 상담)', kakaoButton: true },
        { heading: '자주 묻는 질문 (FAQ)', body: '' },
        { heading: 'Q. 사진은 어떤 것이 좋나요?', body: '정면을 바라보는 밝은 조명의 사진이 가장 좋은 결과를 만들어냅니다. 아이 얼굴이 전체 사진의 30% 이상을 차지하는 것을 권장합니다. 모자나 선글라스 등으로 얼굴이 가려진 사진은 변환 품질이 떨어질 수 있습니다.' },
        { heading: 'Q. 제작 기간은 얼마나 걸리나요?', body: 'AI 동화책 생성은 약 5~10분 소요됩니다. 인쇄본 배송을 선택하신 경우, 인쇄 제작 2~3일 + 배송 1~2일로 총 3~5일 정도 소요됩니다.' },
        { heading: 'Q. 사진은 안전한가요?', body: '네, 안전합니다. 업로드된 아이 사진은 AI 변환 처리가 완료된 후 24시간 이내에 서버에서 완전히 삭제됩니다. 절대 외부에 공유되거나 다른 용도로 사용되지 않습니다. 자세한 사항은 개인정보처리방침을 참고해주세요.' },
        { heading: 'Q. 환불은 어떻게 하나요?', body: '제작 시작 전에는 전액 환불이 가능합니다. 결제 후 마이페이지에서 취소 요청을 하시거나, 고객센터로 연락해주세요. 인쇄본 배송 후 상품 하자가 있는 경우에는 수령 후 7일 이내에 교환 또는 환불이 가능합니다. 자세한 환불 정책은 배송·교환·환불 안내를 참고해주세요.' },
        { heading: 'Q. 동화책을 수정할 수 있나요?', body: '생성된 동화책의 아이 이름, 템플릿은 제작 완료 전까지 수정이 가능합니다. 인쇄 후에는 수정이 불가합니다.' },
        { heading: 'Q. 14세 미만 아이의 사진도 업로드할 수 있나요?', body: '네, 가능합니다. 다만 법정대리인(부모 등)의 동의가 필요합니다. 회원가입 및 서비스 이용 과정에서 법정대리인 동의 절차를 진행합니다.' },
        { heading: 'Q. AI가 만든 동화책의 저작권은 누구에게 있나요?', body: '서비스의 템플릿, 일러스트 디자인 등의 지적재산권은 회사에 귀속됩니다. 이용자가 제작한 동화책의 개인적 이용 권리는 이용자에게 있습니다. 상업적 이용을 원하시는 경우 별도로 문의해주세요.' },
        { heading: '서비스 이용 관련 문서', body: '• 개인정보처리방침: 개인정보 수집·이용·보호에 관한 안내\n• 이용약관: 서비스 이용 조건 및 권리·의무\n• 청소년보호정책: 아동 및 청소년 보호를 위한 정책\n• 배송·교환·환불 안내: 상세 배송 및 환불 정책\n• 사진 이용 동의: 아동 사진의 AI 처리 및 이용에 관한 동의 안내' },
      ],
    },
    'youth-protection': {
      title: '청소년보호정책',
      sections: [
        { heading: '1. 목적', body: '부바(BUBA, 이하 "회사")는 아동 및 청소년이 건전한 인격체로 성장할 수 있도록 「청소년 보호법」 및 「아동·청소년의 성보호에 관한 법률」 등 관련 법령에 따라 청소년보호정책을 수립·시행합니다.\n\n본 서비스는 아동을 위한 맞춤형 동화책을 제작하는 서비스로서, 아동의 건전한 성장과 안전한 디지털 환경 조성을 최우선 가치로 두고 있습니다.' },
        { heading: '2. 청소년보호 기본 원칙', body: '① 회사는 아동 및 청소년에게 유해한 콘텐츠를 제공하지 않으며, 모든 동화책 콘텐츠는 전 연령 이용 가능하도록 제작합니다.\n② 회사는 아동의 개인정보 보호를 최우선으로 하며, 「개인정보 보호법」 및 「정보통신망법」에 따른 보호 조치를 시행합니다.\n③ 회사는 아동에 대한 성적 착취, 학대 등에 관한 콘텐츠를 일체 허용하지 않습니다.\n④ 회사의 서비스는 법정대리인(부모 등)의 관리 하에 이용되는 것을 원칙으로 합니다.' },
        { heading: '3. 아동 사진 보호 정책', body: '회사는 아동 사진의 안전한 처리를 위해 다음과 같은 보호 조치를 시행합니다.\n\n① 아동 사진은 동화책 제작을 위한 AI 일러스트 변환 목적으로만 사용됩니다.\n② 원본 사진은 AI 변환 처리 완료 후 24시간 이내에 서버에서 완전히 삭제됩니다.\n③ 아동 사진은 외부에 공유, 판매, 양도되지 않습니다.\n④ 아동 사진의 AI 처리는 수채화풍 일러스트 변환만을 목적으로 하며, 딥페이크 등 유해한 목적으로의 사용을 엄격히 금지합니다.\n⑤ 부적절한 콘텐츠(폭력적, 선정적 등)가 포함된 사진이 감지될 경우 즉시 삭제 처리하며, 해당 이용자의 서비스 이용을 제한할 수 있습니다.\n⑥ 법정대리인은 언제든지 아동의 사진 및 관련 정보의 열람, 삭제를 요청할 수 있습니다.' },
        { heading: '4. 콘텐츠 보호 기준', body: '① 회사가 제공하는 모든 동화책 콘텐츠(스토리, 일러스트)는 아동에게 적합한 내용으로만 구성됩니다.\n② 다음과 같은 유해 콘텐츠는 서비스 내에서 제작 및 유통되지 않습니다.\n• 폭력적이거나 잔인한 내용\n• 성적으로 부적절한 내용\n• 차별, 혐오를 조장하는 내용\n• 범죄를 미화하거나 조장하는 내용\n• 음주, 흡연, 약물 사용을 조장하는 내용\n③ AI가 생성하는 콘텐츠에 대해 자동 필터링 시스템을 운영하여 부적절한 콘텐츠가 생성되지 않도록 관리합니다.\n④ 이용자가 부적절한 콘텐츠를 발견한 경우, 고객센터를 통해 신고할 수 있으며, 회사는 즉시 조치합니다.' },
        { heading: '5. 법정대리인의 권리와 책임', body: '① 14세 미만 아동의 서비스 이용은 법정대리인(부모 등)의 동의가 필요합니다.\n② 법정대리인은 아동의 개인정보에 대해 다음의 권리를 행사할 수 있습니다.\n• 아동의 개인정보 열람 요구\n• 아동의 개인정보 정정·삭제 요구\n• 아동의 개인정보 처리정지 요구\n• 아동의 사진 및 동화책 데이터 삭제 요구\n③ 법정대리인은 아동이 안전하게 서비스를 이용할 수 있도록 관리·감독할 책임이 있습니다.\n④ 법정대리인의 동의 없이 아동의 사진이 업로드된 경우, 회사에 신고하시면 즉시 삭제 조치합니다.' },
        { heading: '6. 청소년 유해 정보 차단', body: '① 회사는 「정보통신망 이용촉진 및 정보보호 등에 관한 법률」 제44조의7에 따라 청소년에게 유해한 정보가 서비스를 통해 유통되지 않도록 기술적 조치를 취하고 있습니다.\n② 이용자가 유해 정보를 게시하거나 서비스를 악용하는 경우, 해당 콘텐츠를 삭제하고 이용자의 서비스 이용을 제한할 수 있습니다.\n③ 아동·청소년 이용음란물 등 법률에 의해 금지된 콘텐츠가 발견될 경우, 관련 법령에 따라 수사기관에 신고합니다.' },
        { heading: '7. 청소년보호 책임자', body: '회사는 청소년보호를 위한 업무를 수행하기 위하여 다음과 같이 청소년보호 책임자를 지정합니다.\n\n[청소년보호 책임자]\n• 직위: 대표이사 (청소년보호 책임자 겸임)\n• 이메일: support@bubaadventure.kr\n• 전화: 1588-BUBA\n\n아동·청소년 관련 우려 사항이 있으시면 언제든지 연락해주시기 바랍니다.' },
        { heading: '8. 관련 기관 안내', body: '아동·청소년 보호와 관련된 도움이 필요하신 경우 아래 기관에 문의하실 수 있습니다.\n\n• 방송통신심의위원회 (청소년 유해 정보 신고): www.kocsc.or.kr / (국번없이) 1377\n• 아동보호전문기관 (아동학대 신고): (국번없이) 112\n• 청소년사이버상담센터: www.cyber1388.kr / (국번없이) 1388\n• 경찰청 사이버수사국: ecrm.police.go.kr / (국번없이) 182' },
        { heading: '9. 시행일', body: '본 청소년보호정책은 2024년 1월 1일부터 적용됩니다.\n최종 개정일: 2025년 5월 1일' },
      ],
    },
    'refund-policy': {
      title: '배송·교환·환불 안내',
      sections: [
        { heading: '1. 서비스 상품 안내', body: '부바(BUBA)가 제공하는 상품은 다음과 같습니다.\n\n가. 디지털 동화책 (플립북)\n• AI가 제작한 맞춤형 동화책의 디지털 버전\n• 온라인에서 플립북 형태로 열람 가능\n• 공유 링크를 통해 가족, 친구와 공유 가능\n\n나. 인쇄본 동화책\n• 디지털 동화책을 고품질 인쇄한 실물 도서\n• 하드커버 / 소프트커버 선택 가능\n• 택배 배송' },
        { heading: '2. 결제 안내', body: '① 결제 수단\n• 신용카드 / 체크카드\n• 계좌이체\n• 간편결제 (토스페이, 카카오페이, 네이버페이 등)\n\n② 결제 대행: 토스페이먼츠\n③ 결제 완료 즉시 디지털 동화책 제작이 시작됩니다.\n④ 인쇄본 배송 상품의 경우, 결제 완료 후 인쇄 및 배송이 진행됩니다.\n⑤ 모든 가격은 부가가치세(VAT) 포함 가격입니다.' },
        { heading: '3. 배송 안내', body: '① 배송 대상: 인쇄본 동화책을 주문한 경우에 한함\n② 배송 지역: 대한민국 전역 (해외 배송은 추후 지원 예정)\n③ 배송 기간\n• 인쇄 제작: 결제 완료 후 2~3 영업일\n• 택배 배송: 발송 후 1~2 영업일\n• 총 소요 기간: 3~5 영업일 (공휴일, 명절 기간 제외)\n④ 배송비\n• 기본 배송비는 상품 금액에 포함되어 있습니다.\n• 도서산간 지역의 경우 추가 배송비가 발생할 수 있습니다.\n⑤ 배송 조회: 발송 시 등록된 이메일로 송장번호가 안내되며, 택배사 홈페이지에서 조회 가능합니다.\n⑥ 배송 업체: CJ대한통운 (변경 시 사전 고지)' },
        { heading: '4. 교환 안내', body: '① 교환 가능한 경우\n• 인쇄 불량 (인쇄 누락, 색상 이상, 페이지 오류 등)\n• 제본 불량 (페이지 이탈, 커버 손상 등)\n• 배송 중 파손\n• 주문과 다른 상품 배송\n\n② 교환 신청 기간\n• 상품 수령 후 7일 이내\n\n③ 교환 절차\n• 고객센터 연락 (support@bubaadventure.kr / 1588-BUBA)\n• 불량 부분 사진 촬영 후 전송\n• 회사 확인 후 교환 승인\n• 택배 수거 후 새 상품 발송 (회사 부담)\n\n④ 교환이 불가능한 경우\n• 이용자의 책임 있는 사유로 상품이 멸실 또는 훼손된 경우\n• 수령 후 7일이 경과한 경우\n• 상품의 내용(아이 이름, 사진 등)은 이용자가 지정한 것이므로 내용에 대한 교환은 불가합니다.' },
        { heading: '5. 환불 안내', body: '「전자상거래 등에서의 소비자보호에 관한 법률」에 따라 다음과 같이 환불 정책을 운영합니다.\n\n가. 디지털 동화책 (플립북)\n• 결제 후 AI 제작 시작 전: 전액 환불\n• AI 제작 중 또는 완료 후: 환불 불가\n  ※ 맞춤 제작 상품으로 「전자상거래법」 제17조 제2항 제5호에 의거, 이용자 주문에 의해 개별적으로 생산되는 재화는 청약철회가 제한됩니다. (결제 시 사전 고지 및 동의)\n  ※ 디지털 콘텐츠 제공이 개시된 경우 「전자상거래법」 제17조 제2항 제6호에 의거, 청약철회가 제한됩니다.\n\n나. 인쇄본 동화책\n• 인쇄 제작 시작 전: 전액 환불\n• 인쇄 제작 중: 환불 불가 (맞춤 제작 상품)\n• 배송 완료 후 - 상품 하자: 수령 후 7일 이내 전액 환불 또는 교환 (반품 배송비 회사 부담)\n• 배송 완료 후 - 단순 변심: 수령 후 7일 이내 환불 가능 (반품 배송비 이용자 부담, 상품 미개봉 및 원 상태 유지 필요)\n\n다. 환불 처리 기간\n• 환불 승인 후 3~5 영업일 이내 원래 결제 수단으로 환불\n• 신용카드 결제 취소의 경우, 카드사에 따라 추가 기간이 소요될 수 있습니다.\n\n라. 환불 신청 방법\n• 마이페이지에서 주문 취소/환불 요청\n• 고객센터 연락: support@bubaadventure.kr / 1588-BUBA' },
        { heading: '6. 환불이 불가능한 경우', body: '다음의 경우에는 환불이 제한됩니다 (사전 고지 및 동의를 받은 경우에 한함).\n\n• AI 맞춤 제작이 시작된 디지털 동화책 (이용자 주문에 의해 개별 생산되는 재화)\n• 디지털 콘텐츠 제공이 개시된 경우 (플립북 열람 시작)\n• 인쇄 제작이 시작된 인쇄본 동화책\n• 이용자의 책임 있는 사유로 상품이 멸실 또는 훼손된 경우\n• 수령 후 7일이 경과한 경우\n\n※ 상기 청약철회 제한 사유에 해당하더라도, 「전자상거래법」상 소비자의 정당한 권리는 보장됩니다.' },
        { heading: '7. 소비자 피해보상 기준', body: '환불 및 교환에 관한 일반적인 소비자 피해보상 기준은 공정거래위원회 고시 「소비자분쟁해결기준」에 따릅니다.\n\n• 공정거래위원회: www.ftc.go.kr / (국번없이) 1372\n• 한국소비자원: www.kca.go.kr / (국번없이) 1372\n• 전자거래분쟁조정위원회: www.ecmc.or.kr' },
        { heading: '8. 시행일', body: '본 배송·교환·환불 안내는 2024년 1월 1일부터 적용됩니다.\n최종 개정일: 2025년 5월 1일' },
      ],
    },
    'photo-consent': {
      title: '사진 이용 동의 안내',
      sections: [
        { heading: '1. 개요', body: '부바(BUBA, 이하 "회사")는 AI 맞춤형 동화책 제작 서비스를 제공하기 위해 이용자(법정대리인)가 업로드하는 아동 사진을 처리합니다. 본 문서는 「개인정보 보호법」 및 「정보통신망 이용촉진 및 정보보호 등에 관한 법률」에 따라 아동 사진의 수집, 이용, 처리, 삭제에 관한 사항을 안내합니다.\n\n본 서비스는 아동의 얼굴 사진을 업로드받아 AI 기술로 수채화풍 일러스트로 변환하여 맞춤형 동화책을 제작하며, 이 과정에서 법정대리인의 명시적 동의를 필수적으로 받습니다.' },
        { heading: '2. 수집하는 사진 정보', body: '① 수집 항목\n• 아동 얼굴 사진 (이미지 파일: JPG, PNG 등)\n• 아동 이름, 아동 성별 (동화책 맞춤 제작용)\n\n② 수집 방법\n• 이용자(법정대리인)가 서비스 내에서 직접 업로드\n\n③ 사진 요구 사양\n• 정면 얼굴이 명확하게 보이는 사진\n• 얼굴이 전체 사진의 30% 이상을 차지하는 사진 권장\n• 밝은 조명에서 촬영된 사진 권장' },
        { heading: '3. 사진의 이용 목적', body: '수집된 아동 사진은 오직 다음의 목적으로만 이용됩니다.\n\n① AI 일러스트 변환: 업로드된 사진을 AI 기술(Google Gemini API)을 활용하여 수채화풍 일러스트로 변환\n② 맞춤형 동화책 제작: 변환된 일러스트를 이용자가 선택한 동화책 템플릿에 삽입\n③ 인쇄본 제작: 이용자가 인쇄본 배송을 선택한 경우, 인쇄를 위한 이미지 데이터로 활용\n\n※ 상기 목적 이외에는 아동 사진을 일체 사용하지 않습니다.\n※ 아동 사진은 마케팅, 광고, AI 학습 데이터, 프로필 표시 등 어떠한 부가적 목적으로도 사용되지 않습니다.' },
        { heading: '4. 사진 처리 과정 및 보안', body: '① 사진 업로드\n• SSL/TLS 암호화 통신을 통해 안전하게 서버로 전송됩니다.\n• 업로드된 원본 사진은 임시 저장소에 암호화하여 보관됩니다.\n\n② AI 변환 처리\n• Google Gemini API를 통해 수채화풍 일러스트로 변환됩니다.\n• API 호출 시 이미지 데이터가 일시적으로 Google 서버에 전송되며, Google의 AI 서비스 약관에 따라 처리됩니다.\n• Google은 API를 통해 전송된 데이터를 AI 모델 학습에 사용하지 않습니다 (Google Cloud AI 데이터 처리 약관 적용).\n\n③ 원본 사진 삭제\n• AI 변환 처리가 완료된 후 24시간 이내에 서버에서 원본 사진을 비가역적으로 완전 삭제합니다.\n• 삭제 확인 로그가 기록됩니다.\n\n④ 변환 결과물 (일러스트) 보관\n• 수채화풍 일러스트 결과물은 서비스 제공 목적으로 보관됩니다.\n• 회원 탈퇴 시 모든 일러스트 데이터를 삭제합니다.\n• 법정대리인 요청 시 즉시 삭제합니다.' },
        { heading: '5. 법정대리인의 동의', body: '① 14세 미만 아동의 사진 업로드 시 반드시 법정대리인(부모 등)의 동의가 필요합니다.\n② 동의 내용\n• 아동 사진의 수집 및 AI 변환 처리에 대한 동의\n• 변환된 일러스트의 동화책 삽입에 대한 동의\n• 인쇄본 제작 시 인쇄 협력업체에 이미지 데이터 제공에 대한 동의\n③ 동의 철회\n• 법정대리인은 언제든지 동의를 철회할 수 있습니다.\n• 동의 철회 시 아동의 사진 및 변환된 일러스트, 동화책 데이터가 모두 삭제됩니다.\n• 철회 방법: 마이페이지에서 삭제 요청 또는 고객센터 연락 (support@bubaadventure.kr / 1588-BUBA)\n④ 법정대리인의 동의 없이 아동의 사진이 업로드된 경우, 회사에 신고하시면 즉시 삭제 조치합니다.' },
        { heading: '6. 사진의 제3자 제공', body: '아동 사진(원본 및 변환 결과물)은 다음의 경우에만 제3자에게 제공됩니다.\n\n① AI 변환 처리: Google Gemini API (변환 처리 시 일시적 전송, 처리 후 즉시 삭제)\n② 인쇄본 제작: 인쇄 협력업체 (인쇄 완료 후 즉시 삭제)\n③ 법률에 의한 요청: 수사기관의 적법한 요청이 있는 경우\n\n※ 상기 이외의 제3자에게는 어떠한 경우에도 아동 사진을 제공하지 않습니다.' },
        { heading: '7. 이용자의 권리', body: '법정대리인(또는 이용자)은 아동 사진과 관련하여 다음의 권리를 행사할 수 있습니다.\n\n① 사진 데이터 열람 요구\n② 사진 데이터 삭제 요구 (원본 사진, 변환 일러스트, 동화책 데이터 포함)\n③ 사진 처리 중단 요구\n④ AI 변환 결과물에 대한 재처리 또는 삭제 요구\n⑤ 동의 철회\n\n권리 행사 방법:\n• 마이페이지에서 직접 삭제\n• 이메일: support@bubaadventure.kr\n• 전화: 1588-BUBA\n• 회사는 요청 접수 후 10일 이내에 조치 완료합니다.' },
        { heading: '8. 금지 사항', body: '이용자는 다음의 행위를 하여서는 안 됩니다.\n\n• 법정대리인의 동의 없이 타인의 아동 사진을 업로드하는 행위\n• 부적절한 사진(폭력적, 선정적, 불법적 내용 포함)을 업로드하는 행위\n• 서비스를 통해 생성된 일러스트를 딥페이크 등 유해한 목적으로 사용하는 행위\n• 타인의 초상권을 침해하는 행위\n\n위반 시 서비스 이용이 즉시 제한되며, 관련 법령에 따라 법적 책임을 질 수 있습니다.' },
        { heading: '9. 사진 보관 기간 요약', body: '• 원본 사진: AI 변환 처리 완료 후 24시간 이내 삭제\n• AI 변환 일러스트: 회원 탈퇴 시 또는 법정대리인 요청 시 삭제\n• 동화책 데이터: 회원 탈퇴 시 또는 법정대리인 요청 시 삭제\n• 인쇄용 데이터: 인쇄 완료 후 즉시 삭제 (인쇄 협력업체에서도 삭제)\n• 백업 데이터: 원본 삭제 후 최대 30일 이내 백업에서도 완전 삭제' },
        { heading: '10. 시행일', body: '본 사진 이용 동의 안내는 2024년 1월 1일부터 적용됩니다.\n최종 개정일: 2025년 5월 1일' },
      ],
    },
  };

  const { title, sections } = content[type] || content.support;

  return (
    <div style={{ minHeight: '100vh', background: COLORS.lightBackground }}>
      <header style={{
        padding: '20px 40px',
        background: 'rgba(255, 255, 255, 0.9)',
        backdropFilter: 'blur(10px)',
        borderBottom: `1px solid ${COLORS.border}`,
        display: 'flex',
        justifyContent: 'space-between',
        alignItems: 'center',
      }}>
        <div style={{ cursor: 'pointer' }} onClick={() => onNavigate('landing')}>
          <img src="/bubalog.jpg" alt="BUBA" style={{ height: '36px', objectFit: 'contain' }} />
        </div>
        <button onClick={() => onNavigate('landing')} style={{
          background: 'none', border: `1px solid ${COLORS.border}`, padding: '8px 20px',
          borderRadius: '20px', cursor: 'pointer', color: COLORS.text, fontWeight: '500',
        }}>
          홈으로
        </button>
      </header>

      <div style={{ maxWidth: '800px', margin: '0 auto', padding: '60px 20px' }}>
        <h1 style={{ fontSize: '32px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '40px', textAlign: 'center' }}>
          {title}
        </h1>
        {sections.map((section, i) => (
          <div key={i} style={{ marginBottom: '30px' }}>
            <h2 style={{ fontSize: '18px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '12px' }}>
              {section.heading}
            </h2>
            <p style={{ fontSize: '15px', color: COLORS.text, lineHeight: '1.8', whiteSpace: 'pre-line' }}>
              {section.body}
            </p>
            {section.kakaoButton && (
              <button
                onClick={() => window.open(KAKAO_OPEN_CHAT_URL, '_blank')}
                style={{
                  marginTop: '20px', background: '#FEE500', border: 'none',
                  borderRadius: '12px', padding: '14px 28px', cursor: 'pointer',
                  display: 'inline-flex', alignItems: 'center', gap: '10px',
                  fontWeight: '700', color: '#3C1E1E', fontSize: '15px',
                  boxShadow: '0 2px 10px rgba(55,39,74,0.10)',
                  transition: 'transform 0.2s ease',
                }}
                onMouseOver={(e) => e.currentTarget.style.transform = 'translateY(-2px)'}
                onMouseOut={(e) => e.currentTarget.style.transform = 'translateY(0)'}
              >
                <svg width="22" height="22" viewBox="0 0 256 256" fill="none">
                  <path d="M128 36C70.6 36 24 72.2 24 116.8c0 28.8 19.2 54.2 48.2 68.6l-10 36.4c-.8 2.8 2.6 5 4.8 3.4l42.6-28.2c5.8.8 11.8 1.2 18.4 1.2 57.4 0 104-36.2 104-80.8S185.4 36 128 36z" fill="#3C1E1E"/>
                </svg>
                카카오톡으로 상담하기
              </button>
            )}
          </div>
        ))}
      </div>

      <SiteFooter variant="light"/>
    </div>
  );
};

// Flipbook Viewer — pure CSS flip, no library dependency
const FlipbookViewer = ({ onNavigate, shareCode, adminPreview }) => {
  const [flipbook, setFlipbook] = useState(null);
  const [pages, setPages] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [currentIdx, setCurrentIdx] = useState(0);
  const [flipping, setFlipping] = useState(false);
  const [flipDir, setFlipDir] = useState('');
  const [isFullscreen, setIsFullscreen] = useState(false);
  const flipAudioRef = useRef(null);
  const [started, setStarted] = useState(false);

  const computeView = (fs) => {
    const W = window.innerWidth;
    const H = window.innerHeight;
    const ratio = W / H;
    const isMobile = W < 768;
    const isPortraitPhone = W < 768 && H > W;

    const overheadH = fs ? Math.round(H * 0.10) : (W < 480 ? 96 : 130);
    const overheadW = fs ? 16 : (W < 480 ? 16 : 64);
    const availW = Math.max(260, W - overheadW);
    const availH = Math.max(180, H - overheadH);

    let bookRatio;
    if (ratio >= 1.5) bookRatio = 2.0;        // desktop / fold unfolded landscape
    else if (ratio >= 1.0) bookRatio = 1.5;   // landscape phone / square fold
    else if (ratio >= 0.65) bookRatio = 1.0;  // fold portrait / tablet portrait
    else bookRatio = 0.72;                    // narrow phone portrait

    let w = Math.min(availW, fs ? availW : 1200);
    let h = w / bookRatio;
    if (h > availH) { h = availH; w = h * bookRatio; }

    return {
      width: Math.round(w),
      height: Math.round(h),
      isMobile,
      isPortraitPhone,
      useContain: isPortraitPhone, // avoid horizontal crop on narrow portrait phones
    };
  };

  const [view, setView] = useState(() => computeView(false));

  // Preload page-turn sound
  useEffect(() => {
    const audio = new Audio('/sounds/page-turn.wav');
    audio.preload = 'auto';
    audio.volume = 0.6;
    flipAudioRef.current = audio;
  }, []);

  // Fullscreen change + viewport recompute listeners
  useEffect(() => {
    const onFsChange = () => {
      const fs = !!document.fullscreenElement;
      setIsFullscreen(fs);
      setView(computeView(fs));
    };
    const onResize = () => setView(computeView(!!document.fullscreenElement));
    document.addEventListener('fullscreenchange', onFsChange);
    window.addEventListener('resize', onResize);
    window.addEventListener('orientationchange', onResize);
    return () => {
      document.removeEventListener('fullscreenchange', onFsChange);
      window.removeEventListener('resize', onResize);
      window.removeEventListener('orientationchange', onResize);
    };
  }, []);

  const code = shareCode || (() => {
    const hash = window.location.hash;
    const params = new URLSearchParams(hash.split('?')[1] || '');
    return params.get('code');
  })();

  useEffect(() => {
    const fetchFlipbook = async () => {
      try {
        const headers = {};
        const adminToken = localStorage.getItem('adminToken');
        if (adminToken) headers['Authorization'] = `Bearer ${adminToken}`;
        const res = await fetch(`/api/flipbooks/${code}`, { headers });
        const data = await res.json();
        if (!res.ok) throw new Error(data.error || 'Not found');
        setFlipbook(data);
        const allImgs = [];
        if (data.cover_url) allImgs.push(data.cover_url);
        (data.pages || []).forEach(p => allImgs.push(p.image_url));
        setPages(allImgs);
      } catch (err) { setError(err.message); }
      finally { setLoading(false); }
    };
    if (code) fetchFlipbook();
    else { setError('공유 코드가 없습니다'); setLoading(false); }
  }, [code]);

  const [nextIdx, setNextIdx] = useState(0);

  const goTo = (idx) => {
    if (!started) return;
    if (flipping || idx < 0 || idx >= pages.length || idx === currentIdx) return;
    const dir = idx > currentIdx ? 'next' : 'prev';
    setFlipDir(dir);
    setNextIdx(idx);
    setFlipping(true);
    if (flipAudioRef.current) {
      try {
        flipAudioRef.current.currentTime = 0;
        flipAudioRef.current.play().catch(() => {});
      } catch (_) {}
    }
    setTimeout(() => {
      setCurrentIdx(idx);
      setFlipping(false);
      setFlipDir('');
    }, 500);
  };

  const handleStart = () => {
    // Unlock audio on first user gesture (mobile autoplay policy)
    if (flipAudioRef.current) {
      try {
        const a = flipAudioRef.current;
        a.volume = 0;
        a.play().then(() => {
          a.pause();
          a.currentTime = 0;
          a.volume = 0.6;
        }).catch(() => { a.volume = 0.6; });
      } catch (_) {}
    }
    setStarted(true);
  };

  // Keyboard & touch
  useEffect(() => {
    const onKey = (e) => {
      if (e.key === 'ArrowRight' || e.key === ' ') goTo(currentIdx + 1);
      if (e.key === 'ArrowLeft') goTo(currentIdx - 1);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [currentIdx, flipping]);

  // Touch swipe
  const touchStart = useRef(0);
  const onTouchStart = (e) => { touchStart.current = e.touches[0].clientX; };
  const onTouchEnd = (e) => {
    const diff = touchStart.current - e.changedTouches[0].clientX;
    if (diff > 50) goTo(currentIdx + 1);
    if (diff < -50) goTo(currentIdx - 1);
  };

  if (loading) return (
    <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#0d0d1a' }}>
      <div style={{ width: '44px', height: '44px', border: '3px solid rgba(179,157,219,0.2)', borderTop: '3px solid #B39DDB', borderRadius: '50%', margin: '0 auto', animation: 'pgSpin 1s linear infinite' }} />
      <style>{`@keyframes pgSpin{from{transform:rotate(0)}to{transform:rotate(360deg)}}`}</style>
    </div>
  );

  if (error) return (
    <div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: '#0d0d1a', flexDirection: 'column', gap: '16px' }}>
      <p style={{ color: 'rgba(255,255,255,0.6)' }}>{error}</p>
      <button onClick={() => onNavigate('landing')} style={{ padding: '10px 28px', borderRadius: '22px', background: '#7E57C2', color: '#fff', border: 'none', cursor: 'pointer', fontWeight: '600' }}>홈으로</button>
    </div>
  );

  return (
    <div
      style={{
        minHeight: '100vh',
        background: 'radial-gradient(ellipse at center, #1a1433 0%, #0d0d1a 70%)',
        display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
        padding: '8px', position: 'relative', overflow: 'hidden', userSelect: 'none',
      }}
      onTouchStart={onTouchStart}
      onTouchEnd={onTouchEnd}
    >
      {/* Ambient glow */}
      <div style={{ position: 'absolute', width: '60%', height: '60%', background: 'radial-gradient(circle, rgba(126,87,194,0.1) 0%, transparent 70%)', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', pointerEvents: 'none' }} />

      {/* Title */}
      <div style={{ textAlign: 'center', marginBottom: view.isMobile ? '6px' : '8px', zIndex: 1, padding: '0 56px' }}>
        <h1 style={{ fontSize: view.isMobile ? '14px' : '16px', fontWeight: '700', color: 'rgba(255,255,255,0.85)', fontFamily: "'Jua','Gaegu',sans-serif", margin: 0, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
          {flipbook.title}
        </h1>
      </div>

      {/* Book */}
      <div
        className="no-copy-img-wrap no-copy-watermark"
        onContextMenu={(e) => e.preventDefault()}
        style={{
        position: 'relative', zIndex: 1,
        width: `${view.width}px`,
        height: `${view.height}px`,
        borderRadius: '6px',
        overflow: 'hidden',
        background: '#0d0d1a',
        boxShadow: '0 20px 60px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05)',
      }}>
        {/* Book shadow */}
        <div style={{ position: 'absolute', bottom: '-20px', left: '50%', transform: 'translateX(-50%)', width: '80%', height: '30px', background: 'radial-gradient(ellipse, rgba(0,0,0,0.5) 0%, transparent 70%)', borderRadius: '50%', filter: 'blur(10px)', zIndex: -1 }} />

        {/* Bottom layer: destination page (visible during flip) */}
        {flipping && (
          <img
            src={pages[nextIdx]}
            alt=""
            draggable={false}
            onDragStart={(e) => e.preventDefault()}
            style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: view.useContain ? 'contain' : 'cover', zIndex: 1, WebkitUserDrag: 'none', userSelect: 'none' }}
          />
        )}

        {/* Top layer: current page (flips away to reveal destination) */}
        <img
          src={pages[currentIdx]}
          alt={`${currentIdx + 1}페이지`}
          draggable={false}
          onDragStart={(e) => e.preventDefault()}
          style={{
            position: 'absolute', top: 0, left: 0,
            width: '100%', height: '100%',
            objectFit: view.useContain ? 'contain' : 'cover',
            zIndex: 2,
            transformOrigin: flipDir === 'next' ? 'left center' : 'right center',
            animation: flipping ? `pageFlip${flipDir} 0.6s ease-in-out forwards` : 'none',
            WebkitUserDrag: 'none', userSelect: 'none',
          }}
        />

        {/* Click zones for navigation */}
        <div
          onClick={() => goTo(currentIdx - 1)}
          style={{ position: 'absolute', top: 0, left: 0, width: '30%', height: '100%', cursor: started && currentIdx > 0 ? 'pointer' : 'default', zIndex: 2 }}
        />
        <div
          onClick={() => goTo(currentIdx + 1)}
          style={{ position: 'absolute', top: 0, right: 0, width: '30%', height: '100%', cursor: started && currentIdx < pages.length - 1 ? 'pointer' : 'default', zIndex: 2 }}
        />

        {/* Page number overlay */}
        <div style={{ position: 'absolute', bottom: view.isMobile ? '8px' : '12px', left: '50%', transform: 'translateX(-50%)', padding: '4px 14px', borderRadius: '12px', background: 'rgba(0,0,0,0.4)', color: 'rgba(255,255,255,0.7)', fontSize: view.isMobile ? '11px' : '12px', zIndex: 3, backdropFilter: 'blur(4px)' }}>
          {currentIdx + 1} / {pages.length}
        </div>

        {/* Interaction gate (first tap unlocks audio) */}
        {!started && (
          <div
            onClick={(e) => { e.stopPropagation(); handleStart(); }}
            onTouchEnd={(e) => { e.preventDefault(); e.stopPropagation(); handleStart(); }}
            style={{
              position: 'absolute', inset: 0, zIndex: 20,
              display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
              background: 'radial-gradient(ellipse at center, rgba(26,20,51,0.55) 0%, rgba(13,13,26,0.85) 100%)',
              backdropFilter: 'blur(2px)',
              cursor: 'pointer', userSelect: 'none',
              padding: '20px',
            }}
          >
            <div style={{ fontSize: view.isMobile ? '36px' : '44px', marginBottom: '14px', filter: 'drop-shadow(0 4px 12px rgba(126,87,194,0.5))' }}>📖</div>
            <button
              type="button"
              style={{
                padding: view.isMobile ? '12px 28px' : '14px 36px',
                borderRadius: '999px',
                background: 'linear-gradient(135deg, #7E57C2 0%, #B39DDB 100%)',
                color: '#fff',
                border: 'none',
                fontSize: view.isMobile ? '15px' : '16px',
                fontWeight: '700',
                fontFamily: "'Jua','Gaegu',sans-serif",
                letterSpacing: '0.02em',
                boxShadow: '0 8px 28px rgba(126,87,194,0.45), 0 0 0 1px rgba(255,255,255,0.08) inset',
                cursor: 'pointer',
                animation: 'pgPulse 2.4s ease-in-out infinite',
              }}
            >
              이야기 시작하기
            </button>
            <p style={{ marginTop: '14px', fontSize: view.isMobile ? '11px' : '12px', color: 'rgba(255,255,255,0.5)', textAlign: 'center', maxWidth: '280px', lineHeight: 1.6 }}>
              탭하면 책장 넘기는 소리와 함께 동화가 시작돼요
            </p>
          </div>
        )}
      </div>

      {/* Controls */}
      <div style={{ display: 'flex', alignItems: 'center', gap: view.isMobile ? '14px' : '20px', marginTop: view.isMobile ? '8px' : '12px', zIndex: 1 }}>
        <button onClick={() => goTo(currentIdx - 1)} disabled={!started || currentIdx <= 0} style={{
          width: view.isMobile ? '36px' : '40px', height: view.isMobile ? '36px' : '40px', borderRadius: '50%', border: '1.5px solid rgba(179,157,219,0.4)',
          background: 'rgba(255,255,255,0.06)', color: 'rgba(255,255,255,0.7)', fontSize: view.isMobile ? '16px' : '18px',
          cursor: (!started || currentIdx <= 0) ? 'default' : 'pointer', opacity: (!started || currentIdx <= 0) ? 0.3 : 1,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>&lsaquo;</button>
        <span style={{ color: 'rgba(255,255,255,0.5)', fontSize: view.isMobile ? '12px' : '13px', minWidth: '60px', textAlign: 'center' }}>
          {currentIdx + 1} / {pages.length}
        </span>
        <button onClick={() => goTo(currentIdx + 1)} disabled={!started || currentIdx >= pages.length - 1} style={{
          width: view.isMobile ? '36px' : '40px', height: view.isMobile ? '36px' : '40px', borderRadius: '50%', border: '1.5px solid rgba(179,157,219,0.4)',
          background: 'rgba(255,255,255,0.06)', color: 'rgba(255,255,255,0.7)', fontSize: view.isMobile ? '16px' : '18px',
          cursor: (!started || currentIdx >= pages.length - 1) ? 'default' : 'pointer', opacity: (!started || currentIdx >= pages.length - 1) ? 0.3 : 1,
          display: 'flex', alignItems: 'center', justifyContent: 'center',
        }}>&rsaquo;</button>
      </div>

      {/* Top buttons */}
      <button onClick={() => onNavigate(adminPreview ? 'admin' : 'landing')} style={{
        position: 'absolute', top: view.isMobile ? '8px' : '12px', left: view.isMobile ? '8px' : '12px',
        background: 'rgba(255,255,255,0.08)', border: '1px solid rgba(255,255,255,0.15)',
        color: 'rgba(255,255,255,0.7)', padding: view.isMobile ? '6px 14px' : '7px 18px', borderRadius: '18px',
        cursor: 'pointer', fontSize: view.isMobile ? '12px' : '13px', zIndex: 10, backdropFilter: 'blur(8px)',
      }}>
        {adminPreview ? '관리자' : '홈'}
      </button>
      <button onClick={() => { if (!document.fullscreenElement) document.documentElement.requestFullscreen?.(); else document.exitFullscreen?.(); }} style={{
        position: 'absolute', top: view.isMobile ? '8px' : '12px', right: view.isMobile ? '8px' : '12px',
        background: 'rgba(255,255,255,0.08)', border: '1px solid rgba(255,255,255,0.15)',
        color: 'rgba(255,255,255,0.7)', padding: view.isMobile ? '6px 12px' : '7px 14px', borderRadius: '18px',
        cursor: 'pointer', fontSize: view.isMobile ? '12px' : '13px', zIndex: 10, backdropFilter: 'blur(8px)',
      }}>⛶</button>

      {/* Page turn animation CSS */}
      <style>{`
        @keyframes pageFlipnext {
          0% { transform: perspective(2000px) rotateY(0deg); box-shadow: none; }
          40% { transform: perspective(2000px) rotateY(-90deg); box-shadow: 30px 0 50px rgba(0,0,0,0.3); }
          100% { transform: perspective(2000px) rotateY(-180deg); box-shadow: none; opacity: 0; }
        }
        @keyframes pageFlipprev {
          0% { transform: perspective(2000px) rotateY(0deg); box-shadow: none; }
          40% { transform: perspective(2000px) rotateY(90deg); box-shadow: -30px 0 50px rgba(0,0,0,0.3); }
          100% { transform: perspective(2000px) rotateY(180deg); box-shadow: none; opacity: 0; }
        }
        @keyframes pgPulse {
          0%, 100% { transform: scale(1); box-shadow: 0 8px 28px rgba(126,87,194,0.45), 0 0 0 1px rgba(255,255,255,0.08) inset; }
          50% { transform: scale(1.04); box-shadow: 0 12px 36px rgba(126,87,194,0.6), 0 0 0 1px rgba(255,255,255,0.12) inset; }
        }
      `}</style>
    </div>
  );
};

// KakaoTalk Floating Chat Button
const KAKAO_OPEN_CHAT_URL = 'https://open.kakao.com/o/gXXXXXXX'; // TODO: 실제 오픈채팅 URL로 교체

const KakaoFloatingButton = () => {
  const [showTooltip, setShowTooltip] = useState(false);
  return (
    <div style={{ position: 'fixed', bottom: '30px', right: '30px', zIndex: 9998 }}>
      {showTooltip && (
        <div style={{
          position: 'absolute', bottom: '70px', right: '0',
          background: '#FEE500', color: '#3C1E1E', padding: '10px 16px',
          borderRadius: '12px', fontSize: '13px', fontWeight: '600',
          whiteSpace: 'nowrap', boxShadow: '0 4px 12px rgba(55,39,74,0.15)',
        }}>
          카카오톡 상담하기
          <div style={{
            position: 'absolute', bottom: '-6px', right: '20px',
            width: '12px', height: '12px', background: '#FEE500',
            transform: 'rotate(45deg)',
          }} />
        </div>
      )}
      <button
        onClick={() => window.open(KAKAO_OPEN_CHAT_URL, '_blank')}
        onMouseEnter={() => setShowTooltip(true)}
        onMouseLeave={() => setShowTooltip(false)}
        style={{
          width: '60px', height: '60px', borderRadius: '50%',
          background: '#FEE500', border: 'none', cursor: 'pointer',
          boxShadow: '0 4px 20px rgba(55,39,74,0.20)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          transition: 'transform 0.2s ease, box-shadow 0.2s ease',
        }}
        onMouseOver={(e) => { e.currentTarget.style.transform = 'scale(1.1)'; e.currentTarget.style.boxShadow = '0 6px 25px rgba(55,39,74,0.25)'; }}
        onMouseOut={(e) => { e.currentTarget.style.transform = 'scale(1)'; e.currentTarget.style.boxShadow = '0 4px 20px rgba(55,39,74,0.20)'; }}
        aria-label="카카오톡 상담"
      >
        <svg width="32" height="32" viewBox="0 0 256 256" fill="none">
          <path d="M128 36C70.6 36 24 72.2 24 116.8c0 28.8 19.2 54.2 48.2 68.6l-10 36.4c-.8 2.8 2.6 5 4.8 3.4l42.6-28.2c5.8.8 11.8 1.2 18.4 1.2 57.4 0 104-36.2 104-80.8S185.4 36 128 36z" fill="#3C1E1E"/>
        </svg>
      </button>
    </div>
  );
};

// Footer Component
const Footer = ({ onNavigate }) => {
  return (
    <footer style={{
      background: COLORS.dark,
      color: COLORS.white,
      padding: '50px 40px 30px',
      marginTop: '80px',
    }}>
      <div style={{
        maxWidth: '1200px',
        margin: '0 auto',
        display: 'grid',
        gridTemplateColumns: 'repeat(4, 1fr)',
        gap: '40px',
        marginBottom: '40px',
      }}>
        <div>
          <img src="/bubalog.jpg" alt="BUBA" style={{ height: '32px', objectFit: 'contain', marginBottom: '15px' }} />
          <p style={{ fontSize: '14px', lineHeight: '1.8', opacity: 0.7 }}>
            AI 기술로 우리 아이의 얼굴을 담은 맞춤형 동화책을 만들어보세요.
          </p>
        </div>

        <div>
          <h4 style={{ fontWeight: 'bold', marginBottom: '15px', fontSize: '16px' }}>
            서비스
          </h4>
          <ul style={{ listStyle: 'none', fontSize: '14px' }}>
            {['템플릿 둘러보기', '요금제 확인', '자주 묻는 질문'].map((item) => (
              <li key={item} style={{ marginBottom: '8px' }}>
                <button
                  onClick={() => onNavigate('templates')}
                  style={{
                    background: 'none',
                    border: 'none',
                    color: COLORS.white,
                    cursor: 'pointer',
                    opacity: 0.7,
                    fontSize: '14px',
                  }}
                >
                  {item}
                </button>
              </li>
            ))}
          </ul>
        </div>

        <div>
          <h4 style={{ fontWeight: 'bold', marginBottom: '15px', fontSize: '16px' }}>
            법률 및 정책
          </h4>
          <ul style={{ listStyle: 'none', fontSize: '14px' }}>
            {[
              { label: '개인정보처리방침', route: 'privacy' },
              { label: '이용약관', route: 'terms' },
              { label: '청소년보호정책', route: 'youth-protection' },
              { label: '배송·교환·환불', route: 'refund-policy' },
              { label: '사진 이용 동의', route: 'photo-consent' },
              { label: '고객 지원', route: 'support' },
            ].map((item) => (
              <li key={item.label} style={{ marginBottom: '8px' }}>
                <button
                  onClick={() => onNavigate(item.route)}
                  style={{
                    background: 'none',
                    border: 'none',
                    color: COLORS.white,
                    cursor: 'pointer',
                    opacity: 0.7,
                    fontSize: '14px',
                  }}
                >
                  {item.label}
                </button>
              </li>
            ))}
          </ul>
        </div>

        <div>
          <h4 style={{ fontWeight: 'bold', marginBottom: '15px', fontSize: '16px' }}>
            연락처
          </h4>
          <p style={{ fontSize: '14px', opacity: 0.7, marginBottom: '10px' }}>
            📧 support@bubaadventure.kr
          </p>
          <p style={{ fontSize: '14px', opacity: 0.7, marginBottom: '15px' }}>
            ☎️ 1588-BUBA
          </p>
          <div style={{ display: 'flex', gap: '15px', fontSize: '16px', alignItems: 'center' }}>
            <button
              onClick={() => window.open(KAKAO_OPEN_CHAT_URL, '_blank')}
              style={{
                background: '#FEE500', border: 'none', borderRadius: '8px',
                padding: '8px 16px', cursor: 'pointer', display: 'flex',
                alignItems: 'center', gap: '6px', fontWeight: '600',
                color: '#3C1E1E', fontSize: '13px',
              }}
            >
              <svg width="18" height="18" viewBox="0 0 256 256" fill="none">
                <path d="M128 36C70.6 36 24 72.2 24 116.8c0 28.8 19.2 54.2 48.2 68.6l-10 36.4c-.8 2.8 2.6 5 4.8 3.4l42.6-28.2c5.8.8 11.8 1.2 18.4 1.2 57.4 0 104-36.2 104-80.8S185.4 36 128 36z" fill="#3C1E1E"/>
              </svg>
              카톡 상담
            </button>
          </div>
        </div>
      </div>

      <div style={{
        borderTop: `1px solid rgba(255, 255, 255, 0.2)`,
        paddingTop: '30px',
        textAlign: 'center',
        color: 'rgba(255, 255, 255, 0.6)',
        fontSize: '14px',
      }}>
        <p style={{ marginBottom: '10px' }}>
          © 2024 BUBA. All rights reserved.
        </p>
        <button
          onClick={() => onNavigate('admin-login')}
          style={{
            background: 'none',
            border: 'none',
            color: 'rgba(255, 255, 255, 0.4)',
            cursor: 'pointer',
            fontSize: '12px',
            textDecoration: 'underline',
          }}
        >
          관리자 로그인
        </button>
      </div>
    </footer>
  );
};

// URL 해시에서 초기 페이지 파싱
const getInitialPage = () => {
  const hash = window.location.hash.replace('#', '').split('?')[0];
  // 토스 결제 콜백 처리 — payment-success/fail이면 preview로 이동
  if (hash === 'payment-success' || hash === 'payment-fail') {
    return 'preview';
  }
  const validPages = ['landing', 'login', 'register', 'templates', 'create', 'preview', 'mypage', 'flipbook', 'catalog', 'storyDetail', 'upload', 'reader', 'checkout', 'admin-login', 'admin', 'privacy', 'terms', 'support', 'youth-protection', 'refund-policy', 'photo-consent'];
  return validPages.includes(hash) ? hash : 'landing';
};

// Parse initial route params from URL hash (e.g. #flipbook?code=xxx)
const getInitialRouteParams = () => {
  const hash = window.location.hash;
  const qIdx = hash.indexOf('?');
  if (qIdx === -1) return {};
  const params = new URLSearchParams(hash.substring(qIdx + 1));
  const result = {};
  if (params.get('code')) result.code = params.get('code');
  if (params.get('bookId')) result.bookId = params.get('bookId');
  if (params.get('templateId')) result.templateId = params.get('templateId');
  return result;
};

// Main App Component
function App() {
  const [page, setPage] = useState(getInitialPage);
  const [user, setUser] = useState(null);
  const [token, setToken] = useState(localStorage.getItem('token'));
  const [adminLoggedIn, setAdminLoggedIn] = useState(!!localStorage.getItem('adminToken'));
  const [adminToken, setAdminToken] = useState(localStorage.getItem('adminToken'));
  const [routeParams, setRouteParams] = useState(getInitialRouteParams);

  const handleNavigate = (newPage, params = {}) => {
    setPage(newPage);
    setRouteParams(params);
    let hashUrl = newPage === 'landing' ? '/' : `#${newPage}`;
    if (newPage === 'flipbook' && params.code) {
      hashUrl += `?code=${params.code}`;
    }
    window.history.pushState({ page: newPage, params }, '', hashUrl);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };

  const handleLoginSuccess = (userData, userToken) => {
    setUser(userData);
    setToken(userToken);
    setPage('templates');
    window.history.pushState({ page: 'templates' }, '', '#templates');
  };

  const handleAdminLoginSuccess = (tkn) => {
    setAdminToken(tkn);
    setAdminLoggedIn(true);
    setPage('admin');
    window.history.pushState({ page: 'admin' }, '', '#admin');
  };

  const handleAdminLogout = () => {
    setAdminLoggedIn(false);
    setAdminToken(null);
    localStorage.removeItem('adminToken');
    setPage('landing');
    window.history.pushState({ page: 'landing' }, '', '/');
  };

  // Check if already logged in + URL 해시 기반 초기 라우팅
  useEffect(() => {
    const initialPage = getInitialPage();

    // 어드민 페이지 접근 시 토큰 확인 — 어드민이면 유저 자동로그인 스킵
    if (initialPage === 'admin' || initialPage === 'admin-login') {
      if (initialPage === 'admin' && adminToken) {
        setPage('admin');
      } else if (initialPage === 'admin' && !adminToken) {
        setPage('admin-login');
      }
      // 어드민 접근 시 유저 자동로그인 로직 실행하지 않음
      return;
    }

    // 유저 토큰으로 자동 로그인 시도
    if (token && !user) {
      const api = useApi(token);
      api('/auth/me')
        .then((res) => {
          setUser(res.user || res);
          // 보호된 페이지로 바로 진입 허용
          if (['templates', 'create', 'preview', 'mypage'].includes(initialPage)) {
            setPage(initialPage);
          }
        })
        .catch(() => {
          localStorage.removeItem('token');
          setToken(null);
          if (['templates', 'create', 'preview', 'mypage'].includes(initialPage)) {
            setPage('login');
          }
        });
    }
  }, []);

  // Browser back/forward button handling
  useEffect(() => {
    const handlePopState = (e) => {
      if (e.state && e.state.page) {
        setPage(e.state.page);
        setRouteParams(e.state.params || {});
      } else {
        const hash = window.location.hash.replace('#', '').split('?')[0];
        if (hash && hash !== page) {
          setPage(hash);
        } else {
          setPage(token ? 'templates' : 'landing');
        }
      }
    };
    const handleHashChange = () => {
      const hash = window.location.hash.replace('#', '').split('?')[0];
      const valid = ['landing', 'login', 'register', 'templates', 'create', 'preview', 'mypage', 'flipbook', 'catalog', 'storyDetail', 'upload', 'reader', 'checkout', 'admin-login', 'admin', 'privacy', 'terms', 'support', 'youth-protection', 'refund-policy', 'photo-consent'];
      if (hash && valid.includes(hash)) {
        setPage(hash);
        window.scrollTo(0, 0);
      }
    };
    window.addEventListener('popstate', handlePopState);
    window.addEventListener('hashchange', handleHashChange);
    window.history.replaceState({ page, params: routeParams }, '', page === 'landing' ? '/' : `#${page}`);
    return () => { window.removeEventListener('popstate', handlePopState); window.removeEventListener('hashchange', handleHashChange); };
  }, []);

  // Route guard for protected pages
  if (!token && ['templates', 'create', 'preview', 'mypage'].includes(page)) {
    return (
      <div style={{
        position: 'fixed',
        inset: 0,
        background: 'rgba(0, 0, 0, 0.5)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        zIndex: 9999,
      }}>
        <div style={{
          background: COLORS.white,
          borderRadius: '20px',
          padding: '40px',
          maxWidth: '400px',
          textAlign: 'center',
          boxShadow: '0 10px 40px rgba(55,39,74,0.20)',
        }}>
          <h2 style={{ fontSize: '24px', fontWeight: 'bold', color: COLORS.dark, marginBottom: '15px' }}>
            로그인이 필요합니다
          </h2>
          <p style={{ color: COLORS.subtitle, marginBottom: '30px' }}>
            동화책을 만들려면 먼저 로그인해주세요
          </p>
          <div style={{ display: 'flex', gap: '15px' }}>
            <button
              onClick={() => handleNavigate('login')}
              style={{
                flex: 1,
                padding: '12px',
                borderRadius: '20px',
                border: `2px solid ${COLORS.primary}`,
                background: COLORS.white,
                color: COLORS.primary,
                fontWeight: 'bold',
                cursor: 'pointer',
              }}
            >
              로그인
            </button>
            <button
              onClick={() => handleNavigate('register')}
              style={{
                flex: 1,
                padding: '12px',
                borderRadius: '20px',
                border: 'none',
                background: COLORS.primary,
                color: COLORS.white,
                fontWeight: 'bold',
                cursor: 'pointer',
              }}
            >
              회원가입
            </button>
          </div>
          <button
            onClick={() => handleNavigate('landing')}
            style={{
              width: '100%',
              marginTop: '15px',
              padding: '10px',
              background: 'none',
              border: 'none',
              color: COLORS.subtitle,
              cursor: 'pointer',
              textDecoration: 'underline',
            }}
          >
            홈으로 돌아가기
          </button>
        </div>
      </div>
    );
  }

  // Render pages
  return (
    <div key={page} style={{ animation: 'fadeIn 0.3s ease-out' }}>
      {page === 'landing' && (window.LandingPage
        ? React.createElement(window.LandingPage, { onNavigate: handleNavigate, user, token, onLogout: () => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); } })
        : <LandingPage onNavigate={handleNavigate} user={user} token={token} onLogout={() => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); }} />
      )}
      {page === 'login' && <AuthPage isRegister={false} onNavigate={handleNavigate} onLoginSuccess={handleLoginSuccess} />}
      {page === 'register' && <AuthPage isRegister={true} onNavigate={handleNavigate} onLoginSuccess={handleLoginSuccess} />}
      {page === 'mypage' && token && <MyPage onNavigate={handleNavigate} token={token} user={user} />}
      {page === 'catalog' && (window.CatalogPage
        ? React.createElement(window.CatalogPage, { onNavigate: handleNavigate, user, token, onLogout: () => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); } })
        : <TemplatesPage onNavigate={handleNavigate} token={token} user={user} />
      )}
      {page === 'storyDetail' && window.StoryDetailPage &&
        React.createElement(window.StoryDetailPage, { onNavigate: handleNavigate, user, token, onLogout: () => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); }, context: routeParams })
      }
      {page === 'upload' && (window.UploadPage
        ? React.createElement(window.UploadPage, { onNavigate: handleNavigate, user, token, onLogout: () => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); } })
        : (token && <CreatePage onNavigate={handleNavigate} token={token} templateId={routeParams.templateId} />)
      )}
      {page === 'reader' && (window.ReaderPage
        ? React.createElement(window.ReaderPage, { onNavigate: handleNavigate, user, token, onLogout: () => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); }, context: routeParams })
        : <FlipbookViewer onNavigate={handleNavigate} shareCode={routeParams.code} adminPreview={routeParams.adminPreview} />
      )}
      {page === 'checkout' && window.CheckoutPage &&
        React.createElement(window.CheckoutPage, { onNavigate: handleNavigate, user, token, onLogout: () => { setUser(null); setToken(null); localStorage.removeItem('token'); setPage('landing'); }, context: routeParams })
      }
      {page === 'templates' && token && <TemplatesPage onNavigate={handleNavigate} token={token} user={user} />}
      {page === 'create' && token && <CreatePage onNavigate={handleNavigate} token={token} templateId={routeParams.templateId} />}
      {page === 'preview' && token && <PreviewPage onNavigate={handleNavigate} token={token} bookId={routeParams.bookId} />}
      {page === 'flipbook' && <FlipbookViewer onNavigate={handleNavigate} shareCode={routeParams.code} adminPreview={routeParams.adminPreview} />}
      {page === 'admin-login' && <AdminLoginPage onNavigate={handleNavigate} onAdminLoginSuccess={handleAdminLoginSuccess} />}
      {page === 'admin' && adminLoggedIn && <AdminPanel onNavigate={handleNavigate} adminToken={adminToken} onAdminLogout={handleAdminLogout} />}
      {page === 'privacy' && <PolicyPage type="privacy" onNavigate={handleNavigate} />}
      {page === 'terms' && <PolicyPage type="terms" onNavigate={handleNavigate} />}
      {page === 'support' && <PolicyPage type="support" onNavigate={handleNavigate} />}
      {page === 'youth-protection' && <PolicyPage type="youth-protection" onNavigate={handleNavigate} />}
      {page === 'refund-policy' && <PolicyPage type="refund-policy" onNavigate={handleNavigate} />}
      {page === 'photo-consent' && <PolicyPage type="photo-consent" onNavigate={handleNavigate} />}
      {/* 카카오톡 플로팅 상담 버튼 - 어드민/플립북 페이지 제외 */}
      {page !== 'admin' && page !== 'admin-login' && page !== 'flipbook' && <KakaoFloatingButton />}
    </div>
  );
}

// Render app
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(React.createElement(App));
