Files
homeclaw/web-ui/html/pptx-wizard.html
T
kimandClaude Sonnet 5 434dadf038 feat: 논문검색 소스 박스에 주제별 라우팅 안내 추가
각 소스 설명을 "적합 주제" 중심으로 재작성하고, 임상=PubMed /
보건정책·경제=OpenAlex+Semantic / 자연어문장=Semantic / vs 빼기
힌트 줄을 추가. ptitle "PubMed 논문 검색" → "논문 검색".

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XZX9JHFSLZRuK9rR4sCVBs
2026-09-01 10:30:41 +09:00

824 lines
55 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>📊 슬라이드 제작</title>
<style>
:root{
--bg:#0f1117;--panel:#1a1d27;--panel2:#22263a;--line:#2e3250;
--text:#e2e8f0;--muted:#94a3b8;--brand:#6366f1;--brand2:#818cf8;
--green:#22c55e;--red:#ef4444;--yellow:#f59e0b;--r:10px;
}
body.theme-light{
--bg:#eef1f8;--panel:#ffffff;--panel2:#f0f3fb;--line:#cdd3e8;
--text:#1e2337;--muted:#5a6480;--brand:#4f52cc;--brand2:#6366f1;
--green:#15803d;--red:#dc2626;--yellow:#b45309;
}
body.theme-warm{
--bg:#f5f0e8;--panel:#fffdf7;--panel2:#ede8dc;--line:#d6ccbb;
--text:#2c2318;--muted:#7a6e5e;--brand:#7c5c2e;--brand2:#a07840;
--green:#15803d;--red:#dc2626;--yellow:#b45309;
}
.theme-btn{background:none;border:1.5px solid var(--line);border-radius:6px;padding:4px 10px;font-size:12px;color:var(--muted);cursor:pointer;transition:.15s;}
.theme-btn:hover,.theme-btn.active{border-color:var(--brand);color:var(--brand2);background:rgba(99,102,241,.08);}
.src-chk{display:flex;align-items:flex-start;gap:6px;font-size:12px;font-weight:600;color:var(--muted);cursor:pointer;border:1.5px solid var(--line);border-radius:8px;padding:8px 11px;transition:.15s;user-select:none;width:168px;flex-shrink:0;box-sizing:border-box;}
.src-chk input{width:13px;height:13px;cursor:pointer;margin-top:2px;flex-shrink:0;}
.src-chk-desc{display:block;font-size:10px;font-weight:400;color:var(--muted);margin-top:4px;line-height:1.5;}
#src-pubmed{background:rgba(239,68,68,.07);}
#src-pubmed:has(input:checked){background:rgba(239,68,68,.18);border-color:#f87171;color:#fca5a5;}
#src-pubmed input{accent-color:#ef4444;}
#src-openalex{background:rgba(34,197,94,.07);}
#src-openalex:has(input:checked){background:rgba(34,197,94,.18);border-color:var(--green);color:#86efac;}
#src-openalex input{accent-color:#22c55e;}
#src-semantic{background:rgba(251,191,36,.07);}
#src-semantic:has(input:checked){background:rgba(251,191,36,.18);border-color:#fbbf24;color:#fde68a;}
#src-semantic input{accent-color:#f59e0b;}
#src-europepmc{background:rgba(96,165,250,.07);}
#src-europepmc:has(input:checked){background:rgba(96,165,250,.18);border-color:#60a5fa;color:#bfdbfe;}
#src-europepmc input{accent-color:#3b82f6;}
*{margin:0;padding:0;box-sizing:border-box;}
body{background:var(--bg);color:var(--text);font-family:'Segoe UI',system-ui,sans-serif;height:100vh;display:flex;flex-direction:column;overflow:hidden;font-size:14px;}
.header{display:flex;align-items:center;gap:10px;padding:10px 18px;background:var(--panel);border-bottom:1px solid var(--line);flex-shrink:0;}
.header h1{font-size:16px;font-weight:700;}
.steps{display:flex;gap:2px;margin-left:auto;align-items:center;}
.step-hint{font-size:10px;color:var(--muted);margin-right:6px;}
.sdot{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted);padding:5px 12px;border-radius:6px;cursor:pointer;transition:.15s;user-select:none;}
.sdot.active{color:var(--brand2);background:rgba(99,102,241,.15);font-weight:700;}
.sdot.done{color:var(--green);}
.sdot .n{width:20px;height:20px;border-radius:50%;border:1.5px solid currentColor;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;flex-shrink:0;}
.body{display:flex;flex:1;min-height:0;}
.sv{display:none;flex-direction:column;flex:1;min-height:0;}
.sv.active{display:flex;}
.ptitle{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;padding:11px 16px 8px;border-bottom:1px solid var(--line);flex-shrink:0;}
.scroll{flex:1;overflow-y:auto;padding:14px 16px;}
/* Buttons */
.btn{padding:8px 16px;border:none;border-radius:var(--r);font-size:13px;font-weight:600;cursor:pointer;transition:.15s;white-space:nowrap;}
.btn:disabled{opacity:.4;cursor:not-allowed;}
.bp{background:var(--brand);color:#fff;}.bp:not(:disabled):hover{background:var(--brand2);}
.bg{background:var(--panel2);color:var(--text);border:1px solid var(--line);}.bg:not(:disabled):hover{background:var(--line);}
.bgreen{background:#166534;color:#86efac;border:1px solid #166534;}.bgreen:not(:disabled):hover{background:#15803d;}
.bred{background:#7f1d1d;color:#fca5a5;border:1px solid #7f1d1d;}
/* Search */
.srow{display:flex;gap:8px;margin-bottom:12px;}
.srow input{flex:1;background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:8px 12px;font-size:13px;color:var(--text);outline:none;}
.srow input:focus{border-color:var(--brand);}
.srow .yin{width:52px;flex:none;padding:8px 4px;text-align:center;}
.srow .yin::-webkit-inner-spin-button,.srow .yin::-webkit-outer-spin-button{-webkit-appearance:none;}
.srow .yin{-moz-appearance:textfield;}
/* Paper cards */
.pcard{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:11px 13px;margin-bottom:8px;display:flex;gap:10px;align-items:flex-start;transition:.15s;}
.pcard.sel{border-color:var(--brand);background:rgba(99,102,241,.07);}
.pcard input[type=checkbox]{margin-top:3px;flex-shrink:0;accent-color:var(--brand);width:15px;height:15px;cursor:pointer;}
.pmeta{flex:1;min-width:0;}
.ptitle2{font-size:13px;font-weight:600;line-height:1.45;margin-bottom:4px;}
.psub{font-size:11px;color:var(--muted);}
.badge{display:inline-block;font-size:10px;padding:2px 6px;border-radius:3px;margin-right:3px;font-weight:700;}
.bpmc{background:rgba(34,197,94,.15);color:var(--green);}
.byear{background:rgba(99,102,241,.15);color:var(--brand2);}
.btype{background:rgba(245,158,11,.1);color:var(--yellow);}
.bnopmc{background:rgba(239,68,68,.1);color:var(--red);}
.bupload{background:rgba(99,102,241,.15);color:var(--brand2);}
.dropzone{border:2px dashed var(--line);border-radius:10px;padding:18px 14px;text-align:center;cursor:pointer;transition:.15s;color:var(--muted);font-size:12px;margin-bottom:6px;}
.dropzone:hover,.dropzone.drag{border-color:var(--brand);color:var(--brand2);background:rgba(99,102,241,.05);}
.dropzone input[type=file]{display:none;}
.pbtns{display:flex;gap:5px;margin-top:6px;}
/* Prep */
.prog{padding:8px 10px;border-bottom:1px solid var(--line);font-size:13px;border-radius:6px;transition:background .2s;}
.prog.active{background:rgba(99,102,241,.08);border-left:3px solid var(--brand2);padding-left:8px;}
.psp{display:inline-block;padding:2px 9px;border-radius:10px;font-size:11px;font-weight:600;white-space:nowrap;}
.psp-wait{background:var(--line);color:var(--muted);}
.psp-run{background:rgba(99,102,241,.2);color:var(--brand2);}
.psp-done{background:rgba(34,197,94,.15);color:var(--green);}
.psp-fail{background:rgba(239,68,68,.15);color:var(--red);}
.psp-skip{background:var(--line);color:var(--muted);}
@keyframes blink{0%,100%{opacity:1}50%{opacity:.4}}
.psp-run{animation:blink 1.2s ease-in-out infinite;}
.prog:last-child{border-bottom:none;}
.pstat{width:16px;flex-shrink:0;margin-top:1px;}
/* Img grid */
.igrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:8px;}
.icard{position:relative;border:1.5px solid var(--line);border-radius:7px;overflow:hidden;cursor:pointer;aspect-ratio:4/3;background:var(--panel2);transition:.15s;}
.icard:hover{border-color:var(--brand);}
.icard img{width:100%;height:100%;object-fit:cover;}
.ilabel{position:absolute;bottom:0;left:0;right:0;background:rgba(0,0,0,.65);color:#fff;font-size:9px;padding:2px 5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
/* Slide cards */
/* slide editor */
.slide-eg{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px;padding-bottom:8px;}
.scard{background:var(--panel2);border:1.5px solid var(--line);border-radius:10px;overflow:hidden;transition:.15s;}
.scard.open{border-color:var(--brand);}
.scard-hd{display:flex;align-items:center;gap:6px;padding:7px 10px;cursor:pointer;background:var(--panel);user-select:none;}
.scard-hd:hover{background:var(--line);}
.slide-mini{aspect-ratio:16/9;padding:8% 9%;position:relative;overflow:hidden;cursor:pointer;box-sizing:border-box;}
.slide-mini-title{font-weight:700;line-height:1.3;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;word-break:keep-all;overflow-wrap:break-word;}
.slide-mini-bullets{margin-top:5px;opacity:.75;}
.slide-mini-img{position:absolute;right:5%;top:15%;width:38%;height:70%;object-fit:cover;border-radius:3px;opacity:.88;}
.slide-edit-area{padding:12px;border-top:1px solid var(--line);}
.slide-edit-row{display:flex;gap:8px;flex-wrap:wrap;align-items:flex-end;margin-top:8px;}
.sbul-ta{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 8px;font-size:12px;color:var(--text);resize:vertical;outline:none;line-height:1.5;min-height:60px;font-family:monospace;}
.sbul-ta:focus{border-color:var(--brand);}
.elabel{font-size:10px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;display:block;margin-bottom:3px;}
/* translation modal */
.txlmodal{width:min(680px,94vw);max-height:86vh;}
.txlmodal-hd{padding:14px 18px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;flex-shrink:0;}
.txlmodal-body{flex:1;overflow-y:auto;padding:18px 20px;font-size:13px;line-height:1.85;white-space:pre-wrap;color:var(--text);}
.txlmodal-ft{padding:10px 14px;border-top:1px solid var(--line);display:flex;gap:8px;justify-content:flex-end;flex-shrink:0;}
.snum{width:22px;height:22px;border-radius:50%;background:var(--brand);color:#fff;font-size:10px;font-weight:700;display:flex;align-items:center;justify-content:center;flex-shrink:0;}
.stype-tag{font-size:10px;color:var(--muted);background:var(--panel);padding:2px 6px;border-radius:3px;}
.sin{background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 9px;font-size:13px;color:var(--text);width:100%;outline:none;}
.sin:focus{border-color:var(--brand);}
.sbul textarea{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:6px 9px;font-size:12px;color:var(--text);font-family:'IBM Plex Mono',monospace;resize:vertical;outline:none;margin-top:5px;line-height:1.5;}
.sbul textarea:focus{border-color:var(--brand);}
.simg-row{display:flex;align-items:center;gap:8px;margin-top:7px;}
.sthumb{width:52px;height:40px;border-radius:5px;object-fit:cover;border:1px solid var(--line);}
.sno-img{width:52px;height:40px;border-radius:5px;border:1px dashed var(--line);display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:14px;flex-shrink:0;}
.pickbtn{font-size:11px;padding:3px 9px;border-radius:5px;background:var(--panel);border:1px solid var(--line);color:var(--muted);cursor:pointer;}
.pickbtn:hover{border-color:var(--brand);color:var(--brand2);}
/* Skin picker */
.skin-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:5px;margin-top:5px;}
.skin-sw{width:100%;aspect-ratio:1;border-radius:5px;cursor:pointer;border:2px solid transparent;transition:.15s;}
.skin-sw.active{border-color:var(--brand);box-shadow:0 0 0 2px var(--brand);transform:scale(1.12);}
.skin-sw:hover{transform:scale(1.08);}
/* Preview grid */
.preview-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;}
.preview-card{position:relative;background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;transition:.15s;}
.preview-card:hover{border-color:var(--brand);}
.preview-card img{width:100%;display:block;}
.prev-edit-btn{position:absolute;top:6px;right:6px;opacity:0;transition:.15s;z-index:2;background:rgba(30,30,40,.75);color:#fff;border:none;border-radius:5px;padding:3px 9px;font-size:11px;cursor:pointer;backdrop-filter:blur(4px);}
.preview-card:hover .prev-edit-btn{opacity:1;}
.prev-edit-btn:hover{background:var(--brand)!important;opacity:1!important;}
.preview-card[data-edited]::after{content:'● 수정됨';position:absolute;top:6px;left:6px;background:rgba(99,102,241,.85);color:#fff;font-size:10px;padding:2px 7px;border-radius:10px;pointer-events:none;z-index:3;}
.preview-label{font-size:11px;padding:6px 10px;color:var(--muted);text-align:center;}
/* Settings sidebar — LEFT */
.sidebar{width:230px;flex-shrink:0;border-right:1px solid var(--line);background:var(--panel);display:flex;flex-direction:column;overflow:hidden;order:-1;}
.sidebar .scroll{padding:12px;}
.field{margin-bottom:12px;}
.flabel{display:block;font-size:10px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px;}
.field select,.field input[type=text],.field input[type=number]{width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:6px 8px;font-size:12px;color:var(--text);outline:none;}
.field select:focus,.field input:focus{border-color:var(--brand);}
/* Bottom bar */
.bbar{padding:9px 14px;border-top:1px solid var(--line);background:var(--panel);flex-shrink:0;display:flex;gap:7px;align-items:center;}
.bbar .sp{flex:1;}
.smsg{font-size:12px;color:var(--muted);}
.smsg.running{animation:blink 1.2s ease-in-out infinite;}
/* Modals */
.mbg{display:none;position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:200;align-items:center;justify-content:center;}
.mbg.open{display:flex;}
.modal{background:var(--panel);border:1px solid var(--line);border-radius:14px;display:flex;flex-direction:column;gap:0;}
/* Abstract modal */
.amodal{width:min(740px,94vw);max-height:88vh;}
.amodal-hd{padding:16px 20px;border-bottom:1px solid var(--line);flex-shrink:0;}
.amodal-title{font-size:15px;font-weight:700;line-height:1.4;margin-bottom:5px;}
.amodal-meta{font-size:12px;color:var(--muted);}
.atabs{display:flex;gap:2px;padding:8px 16px;border-bottom:1px solid var(--line);flex-shrink:0;}
.atab{padding:5px 14px;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;color:var(--muted);background:none;border:none;}
.atab.active{color:var(--brand2);background:rgba(99,102,241,.15);}
.amodal-body{flex:1;overflow-y:auto;padding:18px 20px;font-size:14px;line-height:1.85;white-space:pre-wrap;color:var(--text);}
.amodal-ft{padding:12px 18px;border-top:1px solid var(--line);flex-shrink:0;display:flex;gap:8px;justify-content:flex-end;align-items:center;}
/* Image picker modal */
.imodal{width:min(680px,94vw);max-height:82vh;}
.imodal-hd{padding:14px 18px;border-bottom:1px solid var(--line);font-size:14px;font-weight:700;flex-shrink:0;}
.imodal-body{flex:1;overflow-y:auto;padding:14px;}
.imodal-ft{padding:10px 16px;border-top:1px solid var(--line);flex-shrink:0;display:flex;justify-content:flex-end;}
/* PDF capture modal */
.pdfmodal{width:min(900px,96vw);max-height:94vh;height:94vh;}
.pdfmodal-hd{padding:10px 16px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;flex-shrink:0;}
.pdfmodal-body{flex:1;overflow:hidden;display:flex;flex-direction:column;align-items:center;background:#111;position:relative;}
.pdfmodal-ft{padding:8px 14px;border-top:1px solid var(--line);display:flex;gap:8px;align-items:center;flex-shrink:0;}
#pdf-canvas-wrap{overflow:auto;flex:1;width:100%;display:flex;justify-content:flex-start;align-items:flex-start;background:#111;}
#pdf-main-canvas{display:block;cursor:crosshair;}
/* Slideshow overlay */
#slideshow{display:none;position:fixed;inset:0;background:#000;z-index:300;flex-direction:column;align-items:center;justify-content:center;}
#slideshow.open{display:flex;}
.ss-img-wrap{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;width:100%;padding:16px 80px;}
#ss-img{max-width:100%;max-height:100%;object-fit:contain;border-radius:4px;}
.ss-bar{width:100%;padding:14px 20px;display:flex;align-items:center;gap:12px;background:rgba(0,0,0,.6);flex-shrink:0;}
.ss-btn{background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.2);color:#fff;border-radius:8px;padding:8px 18px;font-size:14px;cursor:pointer;transition:.15s;}
.ss-btn:hover{background:rgba(255,255,255,.22);}
.ss-counter{color:#fff;font-size:14px;font-weight:600;min-width:60px;text-align:center;}
.ss-title{color:rgba(255,255,255,.7);font-size:13px;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.ss-nav{position:absolute;top:50%;transform:translateY(-50%);background:rgba(0,0,0,.4);border:none;color:#fff;font-size:28px;width:52px;height:52px;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:.2s;}
.ss-nav:hover{background:rgba(99,102,241,.6);}
#ss-prev{left:12px;}
#ss-nav-next{right:12px;}
/* ── Slide Editor Modal ─────────────────────────────────────────────────── */
.sedmodal{width:1200px;height:90vh;max-width:98vw;max-height:98vh;border-radius:10px;position:fixed;box-shadow:0 8px 40px rgba(0,0,0,.6);cursor:default;overflow:hidden;left:50%;top:50%;transform:translate(-50%,-50%);}
.sed-hd{cursor:move;user-select:none;}
.sed-hd{display:flex;align-items:center;gap:8px;padding:10px 18px;border-bottom:1px solid var(--line);flex-shrink:0;}
.sed-body{display:flex;flex:1;min-height:0;overflow:hidden;}
.sed-ctrl{width:340px;flex-shrink:0;border-right:1px solid var(--line);overflow-y:auto;padding:16px 18px;display:flex;flex-direction:column;gap:16px;}
.sed-stage{flex:1;background:#080b12;display:flex;align-items:center;justify-content:center;padding:28px;min-width:0;position:relative;}
.sed-preview{position:relative;border-radius:6px;box-shadow:0 8px 48px rgba(0,0,0,.7);overflow:hidden;transition:background .2s;}
.sed-section-lbl{font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px;display:block;}
.sed-hint{display:flex;gap:10px;font-size:10px;color:var(--muted);margin-top:3px;margin-bottom:4px;opacity:.7}
.sed-hint span{background:var(--panel2);padding:1px 6px;border-radius:4px}
.layout-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:5px;}
.layout-btn{background:var(--panel2);border:1.5px solid var(--line);border-radius:7px;padding:8px 4px 6px;cursor:pointer;text-align:center;transition:.15s;user-select:none;}
.layout-btn:hover{border-color:var(--brand);background:rgba(99,102,241,.08);}
.layout-btn.active{border-color:var(--brand);background:rgba(99,102,241,.15);color:var(--brand2);}
.layout-btn .li{font-size:13px;display:block;margin-bottom:3px;letter-spacing:.5px;font-family:monospace;}
.layout-btn .lt{font-size:11px;color:var(--muted);}
.layout-btn.active .lt{color:var(--brand2);font-weight:700;}
.sed-inp{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:7px;padding:9px 12px;font-size:16px;color:var(--text);outline:none;font-family:inherit;resize:none;line-height:1.5;min-height:46px;}
.sed-inp:focus{border-color:var(--brand);}
.sed-ta{width:100%;background:var(--panel);border:1px solid var(--line);border-radius:7px;padding:9px 12px;font-size:15px;color:var(--text);font-family:'IBM Plex Mono',monospace;resize:vertical;outline:none;line-height:1.65;min-height:110px;}
.sed-ta:focus{border-color:var(--brand);}
.sed-row{display:flex;align-items:center;gap:8px;margin-top:6px;}
.sed-range{flex:1;accent-color:var(--brand);}
.sed-val{font-size:13px;font-weight:700;color:var(--brand2);min-width:40px;text-align:right;}
.sed-skin-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-top:5px;}
.sed-skin-sw{aspect-ratio:1;border-radius:5px;cursor:pointer;border:2px solid transparent;transition:.15s;}
.sed-skin-sw.active{border-color:var(--brand);box-shadow:0 0 0 2px var(--brand);transform:scale(1.15);}
.sed-skin-sw:hover{transform:scale(1.1);}
.fx-btn{font-size:11px;padding:3px 8px;border-radius:5px;background:var(--panel);border:1px solid var(--line);color:var(--muted);cursor:pointer;transition:.12s;}
.fx-btn:hover{border-color:var(--brand);color:var(--brand2);}
.fx-btn.active{background:var(--brand);border-color:var(--brand);color:#fff;}
.clr-row{display:flex;align-items:center;gap:6px;margin-top:5px;}
.clr-row label{font-size:11px;color:var(--muted);min-width:36px;}
.clr-row input[type=color]{width:28px;height:22px;border:1px solid var(--line);border-radius:4px;padding:0 2px;background:var(--panel);cursor:pointer;}
.clr-row .clr-reset{font-size:10px;color:var(--muted);cursor:pointer;padding:2px 5px;border:1px solid var(--line);border-radius:4px;background:var(--panel);}
.clr-row .clr-reset:hover{color:var(--red);border-color:var(--red);}
.sed-img-thumb{width:100%;height:100px;border-radius:6px;background:var(--panel) center/cover no-repeat;border:1px solid var(--line);display:flex;align-items:center;justify-content:center;font-size:28px;color:var(--muted);cursor:pointer;transition:.15s;}
.sed-img-thumb:hover{border-color:var(--brand);}
.sed-nav-info{font-size:12px;color:var(--muted);text-align:center;flex:1;}
/* ── mob-tab (inline, styles.css not loaded) ── */
.mob-tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;border:none;background:transparent;color:var(--muted);font-family:inherit;font-size:10px;font-weight:700;letter-spacing:.04em;cursor:pointer;padding:6px 4px;border-top:2px solid transparent;transition:color .15s,border-color .15s;-webkit-tap-highlight-color:transparent;}
.mob-tab.active{color:var(--brand);border-top-color:var(--brand);}
/* ── Mobile ── */
@media(max-width:1024px){
/* Header: compact */
.header{flex-wrap:wrap;padding:7px 12px;gap:6px;}
.header h1{font-size:13px;}
.header > div:has(.theme-btn){display:none;}
/* step dots: hide text labels, keep numbers */
.sdot{padding:5px 8px;font-size:0;}
.sdot .n{font-size:10px;}
.step-hint{display:none;}
.steps{gap:0;margin-left:auto;}
/* Sidebar: left overlay */
.sidebar{
position:fixed;top:0;left:0;bottom:52px;z-index:500;
width:82vw;max-width:310px;
transform:translateX(-100%);transition:transform .25s ease;
box-shadow:4px 0 28px rgba(0,0,0,.5);
order:0;
}
.sidebar.mob-open{transform:translateX(0);}
.sidebar-mob-theme{display:flex !important;}
#mob-backdrop{display:none;position:fixed;inset:0 0 52px 0;background:rgba(0,0,0,.55);z-index:499;}
#mob-backdrop.show{display:block;}
#mob-tabbar{display:flex !important;position:fixed;bottom:0;left:0;right:0;z-index:600;background:var(--bg);border-top:1px solid var(--line);height:52px;}
/* bottom padding for tabbar */
.body{padding-bottom:52px;}
.sv .scroll{padding-bottom:16px;}
/* Search row: wrap */
.srow{flex-wrap:wrap;}
.srow input{min-width:0;}
/* Source checkboxes: narrower */
.src-chk{width:calc(50% - 4px);min-width:0;}
/* Step 2: stack layout */
#step-2 .scroll > div[style*="flex:2"],
#step-2 .scroll > div[style*="flex:1"]{flex:1 1 100%;}
#step-2 .scroll{flex-wrap:wrap;}
/* Slide editor modal: full screen */
.sedmodal{width:100vw !important;height:100dvh !important;max-width:100vw;max-height:100dvh;border-radius:0;left:0;top:0;transform:none;}
.sed-body{flex-direction:column;}
.sed-ctrl{width:100%;max-height:40vh;border-right:none;border-bottom:1px solid var(--line);}
/* iOS zoom prevention */
input,textarea,select{font-size:16px !important;}
}
@media(min-width:1025px){
#mob-backdrop{display:none !important;}
#mob-tabbar{display:none !important;}
.sidebar-mob-theme{display:none !important;}
}
</style>
</head>
<body>
<div class="header">
<span style="font-size:18px">📊</span>
<h1>슬라이드 제작 마법사</h1>
<div style="display:flex;gap:4px;margin-left:14px">
<button class="theme-btn active" id="tbtn-dark" onclick="setTheme('dark')">🌙 다크</button>
<button class="theme-btn" id="tbtn-light" onclick="setTheme('light')">☀️ 라이트</button>
<button class="theme-btn" id="tbtn-warm" onclick="setTheme('warm')">🌿 웜</button>
</div>
<div class="steps">
<span class="step-hint">← 번호 클릭으로 이동</span>
<div class="sdot active" id="sd1" onclick="goStep(1)"><div class="n">1</div>논문 검색</div>
<div class="sdot" id="sd2" onclick="goStep(2)"><div class="n">2</div>준비</div>
<div class="sdot" id="sd3" onclick="goStep(3)"><div class="n">3</div>아웃라인</div>
<div class="sdot" id="sd4" onclick="goStep(4)"><div class="n">4</div>프리뷰</div>
</div>
</div>
<div id="mob-backdrop" onclick="mobCloseAll()"></div>
<div id="mob-tabbar" style="display:none">
<button class="mob-tab" id="mobtab-settings" onclick="mobToggle('settings')"><span style="font-size:18px">⚙</span>설정</button>
<button class="mob-tab active" id="mobtab-work" onclick="mobCloseAll()"><span style="font-size:18px">📊</span>작업</button>
</div>
<div class="body">
<!-- ── STEP 1 ── -->
<div class="sv active" id="step-1">
<div class="ptitle">논문 검색</div>
<div class="scroll">
<div style="display:flex;gap:6px;margin-bottom:6px;align-items:flex-start;flex-wrap:wrap">
<span style="font-size:11px;font-weight:700;color:var(--muted);margin-top:7px">검색 소스:</span>
<label class="src-chk" id="src-pubmed">
<input type="checkbox" checked onchange="updSrcState()">
<span>🔬 PubMed<span class="src-chk-desc"><b>임상·약물·생명과학.</b> NIH/NLM 공식 색인 — AHRQ·CDC 등 美 보건당국 지원 연구 포함. PMC 전문 PDF.</span></span>
</label>
<label class="src-chk" id="src-openalex">
<input type="checkbox" onchange="updSrcState()">
<span>🌐 OpenAlex<span class="src-chk-desc"><b>전 분야 2억+.</b> 보건정책·의료경제·사회과학까지. Nature·Science 포함, OA PDF.</span></span>
</label>
<label class="src-chk" id="src-semantic">
<input type="checkbox" onchange="updSrcState()">
<span>🧠 Semantic<span class="src-chk-desc"><b>자연어 문장 검색에 강함.</b> AI·CS·학제간, 인용 영향력 지수 제공.</span></span>
</label>
<label class="src-chk" id="src-europepmc">
<input type="checkbox" onchange="updSrcState()">
<span>🇪🇺 Europe PMC<span class="src-chk-desc"><b>생명과학, PubMed보다 넓음.</b> 유럽 저널·전임상 강세, PMC 전문 포함.</span></span>
</label>
</div>
<div style="font-size:10.5px;color:var(--muted);line-height:1.6;margin-bottom:8px;padding:6px 9px;background:rgba(99,102,241,.06);border-radius:7px">
💡 임상·약물·질병은 <b>PubMed</b> · 보건정책/의료경제/비교연구는 <b>OpenAlex + Semantic</b> · 자연어 문장으로 검색하면 <b>Semantic</b> · <b>“vs / versus”는 빼고</b> 키워드만 넣으세요.
</div>
<div class="srow">
<input id="qi" placeholder="예: sinus lift augmentation" onkeydown="if(event.key==='Enter')doSearch()">
<input class="yin" id="qy" type="number" placeholder="연도" min="1990" max="2030" value="2017">
<span style="font-size:11px;color:var(--muted);white-space:nowrap">이후 (선택)</span>
<select id="cfg-sort" style="background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:7px 9px;font-size:13px;color:var(--text);flex-shrink:0">
<option value="relevance">관련도순</option>
<option value="date">최신순</option>
</select>
<button id="pmc-filter-btn" class="btn bg" onclick="togglePmcFilter()" title="PMC 전문 있는 논문만 표시 (PDF 다운로드 가능)" style="flex-shrink:0;font-size:13px;padding:7px 11px;opacity:.6">PMC <span style="font-size:10px">PDF</span></button>
<button class="btn bp" onclick="doSearch()" id="sbtn" style="font-size:13px;padding:7px 14px">🔍 검색</button>
</div>
<div id="search-legend" style="display:none;padding:7px 12px;background:rgba(99,102,241,.07);border-radius:7px;margin-bottom:6px;font-size:11px;color:var(--muted);line-height:1.7">
<span style="color:var(--green);font-weight:700">■ PMC등재</span> — PubMed Central에 전문(PDF) 있음. 체크박스로 선택해 PPTX에 활용 가능.<br>
<span style="color:var(--red);font-weight:700">■ PMC미등재</span> — PMC에 전문 없음. 초록 보기 가능, PDF 다운로드 불가.<br>
<span style="color:var(--brand2);font-weight:700">■ 연도</span> — 출판 연도 &nbsp;|&nbsp; <span style="color:#fcd34d;font-weight:700">■ 유형</span> — 논문 종류 (RCT, Review 등)
</div>
<div id="results"></div>
<div style="padding:8px 0 2px;display:flex;align-items:center;gap:8px;color:var(--muted);font-size:11px">
<div style="flex:1;height:1px;background:var(--line)"></div>또는 PDF 직접 업로드<div style="flex:1;height:1px;background:var(--line)"></div>
</div>
<div class="dropzone" id="pdf-dropzone"
onclick="document.getElementById('pdf-file-input').click()"
ondragover="event.preventDefault();this.classList.add('drag')"
ondragleave="this.classList.remove('drag')"
ondrop="this.classList.remove('drag');handlePdfDrop(event)">
<input type="file" id="pdf-file-input" accept=".pdf" multiple onchange="handlePdfFileInput(this)">
📄 PDF 파일을 드래그하거나 클릭해서 선택<br>
<span style="font-size:10px">여러 파일 동시 업로드 가능</span>
</div>
<div id="upload-list"></div>
</div>
<div class="bbar">
<span class="smsg" id="s1msg"></span><div class="sp"></div>
<button class="btn bp" id="s1next" onclick="goStep(2)" disabled>▶ PDF 준비 →</button>
</div>
</div>
<!-- ── STEP 2 ── -->
<div class="sv" id="step-2">
<div class="ptitle">PDF 다운로드</div>
<div class="scroll" style="display:flex;gap:14px">
<div style="flex:1;min-width:0">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:8px">
<span style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em">진행 상황</span>
<span id="s2-overall" style="display:none;font-size:11px;color:var(--brand2);font-weight:700"></span>
</div>
<div id="proglist"></div>
<div id="img-search-section" style="margin-top:14px;border-top:1px solid var(--line);padding-top:10px">
<div style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em;margin-bottom:6px">🔍 이미지 검색</div>
<div style="display:flex;gap:6px">
<input id="img-search-input" type="text" placeholder="예: 구강 해부도, TMJ X-ray"
style="flex:1;font-size:12px;padding:4px 8px;background:var(--panel2);border:1px solid var(--line);border-radius:5px;color:var(--fg);outline:none"
onkeydown="if(event.key==='Enter')doImgSearch()">
<button class="btn bg" style="font-size:11px;padding:3px 10px;flex-shrink:0" onclick="doImgSearch()">검색</button>
</div>
<div id="img-search-results" style="margin-top:8px;max-height:260px;overflow-y:auto"></div>
</div>
</div>
<div style="flex:2;min-width:0">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px">
<span style="font-size:10px;color:var(--muted);font-weight:600;text-transform:uppercase;letter-spacing:.04em">캡처 이미지 <span id="imgcnt"></span></span>
<button id="btn-analyze-imgs" onclick="analyzeImages()" style="font-size:11px;color:#10b981;background:rgba(16,185,129,.1);border:1px solid #10b981;border-radius:5px;padding:2px 8px;cursor:pointer;flex-shrink:0" title="미분석 이미지를 mistral vision으로 재분석 (준비 실행 시 자동 처리됨)">🔍 재분석</button>
<button onclick="downloadAllImgs()" style="font-size:11px;color:#60a5fa;background:rgba(96,165,250,.1);border:1px solid #60a5fa;border-radius:5px;padding:2px 8px;cursor:pointer;flex-shrink:0" title="전체 이미지 다운로드">⬇ 전체</button>
<label style="display:flex;align-items:center;gap:4px;font-size:11px;color:var(--brand2);background:rgba(99,102,241,.1);border:1px solid var(--brand);border-radius:5px;padding:2px 8px;cursor:pointer;flex-shrink:0" title="이미지 파일 업로드">
<input type="file" id="img-upload-input" accept="image/*" multiple style="display:none" onchange="handleImgUpload(this.files)">
+ 이미지 업로드
</label>
</div>
<div id="img-dropzone"
style="border:2px dashed var(--line);border-radius:7px;padding:6px 10px;text-align:center;font-size:11px;color:var(--muted);margin-bottom:7px;cursor:pointer;transition:.15s"
onclick="document.getElementById('img-upload-input').click()"
ondragover="event.preventDefault();this.style.borderColor='var(--brand)';this.style.color='var(--brand2)'"
ondragleave="this.style.borderColor='';this.style.color=''"
ondrop="event.preventDefault();this.style.borderColor='';this.style.color='';handleImgUpload(event.dataTransfer.files)">
이미지 파일을 여기에 드래그하거나 클릭
</div>
<div class="igrid" id="imgrid"></div>
</div>
</div>
<div class="bbar">
<span class="smsg" id="s2msg"></span><div class="sp"></div>
<button class="btn bp" id="s2start" onclick="startPrep()">▶ 시작</button>
</div>
</div>
<!-- ── STEP 3 ── -->
<div class="sv" id="step-3">
<div class="ptitle">슬라이드 아웃라인 편집</div>
<div class="scroll" id="outline-scroll">
<div id="outline-cards" style="padding-bottom:8px">
<div style="color:var(--muted);font-size:12px;text-align:center;padding:24px 0">준비 단계 완료 후 아웃라인이 자동 생성됩니다</div>
</div>
</div>
<div class="bbar">
<span class="smsg" id="s3msg"></span><div class="sp"></div>
<button class="btn bgreen" id="s3create" onclick="createPptx()" disabled>✅ PPTX 생성 →</button>
</div>
</div>
<!-- ── STEP 4 ── -->
<div class="sv" id="step-4">
<div class="ptitle">슬라이드 프리뷰</div>
<div class="scroll">
<div id="preview-hint" style="display:none;padding:7px 14px;background:rgba(99,102,241,.07);border-radius:7px;margin-bottom:8px;font-size:12px;color:var(--muted);line-height:1.6">
카드에 마우스를 올리면 <strong>✏ 편집</strong> 버튼이 나타납니다. 편집 후 <strong>🔄 PPTX 재생성</strong>으로 업데이트하세요. &nbsp;|&nbsp; 카드 이미지를 클릭하면 슬라이드 쇼를 시작합니다.
</div>
<div id="preview-grid" class="preview-grid">
<div style="color:var(--muted);font-size:12px;text-align:center;padding:24px 0;grid-column:1/-1">PPTX 생성 후 프리뷰가 표시됩니다</div>
</div>
<div style="margin-top:14px;padding:8px 12px;border-top:1px solid var(--line);font-size:11px;color:var(--muted);line-height:1.7">
↑ 상단 <strong>1 · 2 · 3</strong> 단계 버튼을 클릭하면 이전 단계로 돌아갈 수 있습니다.&ensp;
논문 추가·변경 → <strong>1단계</strong>, PDF 처리 재실행 → <strong>2단계</strong>, 아웃라인 수정 → <strong>3단계</strong>.
</div>
</div>
<div class="bbar">
<span class="smsg" id="s4msg"></span><div class="sp"></div>
<button class="btn bg" onclick="reloadPreview()">↺ 새로고침</button>
<button class="btn bg" id="ss-launch" onclick="ssStart()" disabled>▶ 슬라이드 쇼</button>
<button class="btn bgreen" id="s4-regen" onclick="s4Regen()" style="display:none">🔄 PPTX 재생성</button>
<a id="dl-btn" class="btn bgreen" style="text-decoration:none;display:none" download>⬇ 다운로드</a>
</div>
</div>
<!-- ── SETTINGS SIDEBAR ── -->
<div class="sidebar">
<div class="ptitle" style="display:flex;align-items:center;justify-content:space-between">
<span>설정</span>
<div class="sidebar-mob-theme" style="display:none;gap:4px;align-items:center">
<button class="theme-btn" id="tbtn-dark2" onclick="setTheme('dark')" style="padding:2px 8px;font-size:11px">🌙</button>
<button class="theme-btn" id="tbtn-light2" onclick="setTheme('light')" style="padding:2px 8px;font-size:11px">☀️</button>
<button class="theme-btn" id="tbtn-warm2" onclick="setTheme('warm')" style="padding:2px 8px;font-size:11px">🌿</button>
<button onclick="mobCloseAll()" style="background:none;border:none;color:var(--muted);cursor:pointer;font-size:16px;padding:0 4px;line-height:1">✕</button>
</div>
</div>
<div class="scroll">
<div class="field">
<button class="btn bgreen" style="width:100%;font-size:12px;padding:7px 0" onclick="newProject()">+ 새 프로젝트</button>
</div>
<div class="field">
<label class="flabel">기존 프로젝트 열기</label>
<div style="display:flex;gap:5px">
<select id="cfg-open-proj" style="flex:1;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:4px 6px;font-size:12px;color:var(--text);outline:none" onchange="onOpenProjChange(this.value)">
<option value="">— 선택 —</option>
</select>
<button class="btn bg" style="font-size:11px;padding:4px 8px;flex-shrink:0" onclick="loadProjList()" title="목록 새로고침">↺</button>
<button class="btn bred" style="font-size:11px;padding:4px 8px;flex-shrink:0" onclick="deleteSelectedProject()" title="선택한 프로젝트 폴더 삭제">🗑</button>
</div>
</div>
<div class="field">
<label class="flabel">모델 요청</label>
<textarea id="cfg-topic" placeholder="예: 상악동 거상술 최신 동향에 대해 치과의사 대상 학회 발표 자료를 만들어주세요. 임상 적용 위주로 구성하고 핵심 수치를 강조해주세요." style="width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:7px 9px;font-size:12px;color:var(--text);resize:vertical;outline:none;line-height:1.6;min-height:72px;font-family:inherit" onfocus="this.style.borderColor='var(--brand)'" onblur="this.style.borderColor='var(--line)'"></textarea>
</div>
<div class="field">
<label class="flabel">프로젝트 폴더명</label>
<input type="text" id="cfg-project" placeholder="자동 (아웃라인 생성 후 채워짐)" style="width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:7px;padding:5px 8px;font-size:12px;color:var(--text);outline:none;font-family:inherit" onfocus="this.style.borderColor='var(--brand)'" onblur="this.style.borderColor='var(--line)'">
</div>
<div class="field">
<label class="flabel">슬라이드 수</label>
<input type="number" id="cfg-slides" min="5" max="30" value="12">
</div>
<div class="field">
<label class="flabel">템플릿 <span id="tmpl-lbl" style="font-weight:400;text-transform:none;font-size:11px;margin-left:4px;color:var(--text)">creative</span></label>
<input type="hidden" id="cfg-tmpl" value="creative">
<div class="skin-grid" id="tmpl-grid" style="grid-template-columns:repeat(6,1fr)"></div>
</div>
<div class="field">
<label class="flabel">배경 스킨 <span id="skin-name-lbl" style="font-weight:400;text-transform:none;margin-left:4px"></span></label>
<div class="skin-grid" id="skin-grid"></div>
</div>
<div class="field">
<label class="flabel">PDF 이미지 자동 추출</label>
<label style="display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text);cursor:pointer;line-height:1.5">
<input type="checkbox" id="cfg-auto-img" checked onchange="onAutoImgToggle()" style="accent-color:var(--brand);width:15px;height:15px;cursor:pointer;margin-top:1px;flex-shrink:0">
<span id="cfg-auto-img-lbl"></span>
</label>
</div>
<div class="field">
<label class="flabel">PDF 본문 텍스트 추출</label>
<label style="display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text);cursor:pointer;line-height:1.5">
<input type="checkbox" id="cfg-extract-txt" checked onchange="onExtractTxtToggle()" style="accent-color:var(--brand);width:15px;height:15px;cursor:pointer;margin-top:1px;flex-shrink:0">
<span id="cfg-extract-txt-lbl"></span>
</label>
</div>
<div class="field">
<label class="flabel">본문 자동 번역</label>
<label style="display:flex;align-items:flex-start;gap:8px;font-size:12px;color:var(--text);cursor:pointer;line-height:1.5">
<input type="checkbox" id="cfg-auto-txl" checked onchange="onAutoTxlToggle()" style="accent-color:var(--brand);width:15px;height:15px;cursor:pointer;margin-top:1px;flex-shrink:0">
<span id="cfg-auto-txl-lbl"></span>
</label>
</div>
<div class="field" style="margin-top:14px;border-top:1px solid var(--line);padding-top:12px">
<label class="flabel">선택된 논문</label>
<div id="sel-summary" style="font-size:10px;color:var(--muted)">없음</div>
</div>
</div>
</div>
</div>
<!-- Abstract modal -->
<div class="mbg" id="abg">
<div class="modal amodal">
<div class="amodal-hd">
<div class="amodal-title" id="am-title"></div>
<div class="amodal-meta" id="am-meta"></div>
</div>
<div class="atabs">
<button class="atab active" id="at-en" onclick="switchAbTab('en')">영문</button>
<button class="atab" id="at-ko" onclick="switchAbTab('ko')">한국어 번역</button>
</div>
<div class="amodal-body" id="am-body">로딩 중...</div>
<div class="amodal-ft">
<button class="btn bg" id="am-translate-btn" onclick="translateAbstract()">🌐 번역</button>
<button class="btn bg" onclick="closeAbModal()">닫기</button>
</div>
</div>
</div>
<!-- Slideshow overlay -->
<div id="slideshow">
<button class="ss-nav" id="ss-prev" onclick="ssPrev()">&#8249;</button>
<button class="ss-nav" id="ss-nav-next" onclick="ssNext()">&#8250;</button>
<div class="ss-img-wrap"><img id="ss-img" src="" alt=""></div>
<div class="ss-bar">
<button class="ss-btn" onclick="ssPrev()">← 이전</button>
<span class="ss-counter" id="ss-counter">1 / 1</span>
<button class="ss-btn" onclick="ssNext()">다음 →</button>
<span class="ss-title" id="ss-title"></span>
<button class="ss-btn" onclick="ssToggleAuto()" id="ss-auto-btn">⏵ 자동</button>
<button class="ss-btn" onclick="ssClose()" style="margin-left:auto">✕ 닫기</button>
</div>
</div>
<!-- Image picker modal -->
<div class="mbg" id="ibg" style="z-index:600">
<div class="modal imodal">
<div class="imodal-hd">이미지 선택</div>
<div class="imodal-body"><div class="igrid" id="imodal-grid"></div></div>
<div class="imodal-ft">
<button class="btn bg" onclick="closeIModal()">취소</button>
</div>
</div>
</div>
<!-- PDF Translation modal -->
<div class="mbg" id="txlbg" onclick="if(event.target===this)closeTxlModal()">
<div class="modal txlmodal" onclick="event.stopPropagation()">
<div class="txlmodal-hd">
<span style="font-size:14px">📄</span>
<span id="txl-title" style="font-size:13px;font-weight:700;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">전문</span>
<button class="btn bg" style="padding:3px 10px;font-size:11px" id="txl-tab-en" onclick="switchTxlTab('en')">원문</button>
<button class="btn bg" style="padding:3px 10px;font-size:11px" id="txl-tab-ko" onclick="switchTxlTab('ko')">번역</button>
<button class="btn bg" style="padding:3px 10px;font-size:11px" onclick="copyTxlText()">복사</button>
<button class="btn bg" style="padding:3px 10px;font-size:11px" onclick="downloadTxlText()">⬇ 다운로드</button>
<button class="btn bg" style="padding:3px 10px;font-size:11px" onclick="closeTxlModal()">✕</button>
</div>
<div class="txlmodal-body" id="txl-body"></div>
<div class="txlmodal-ft">
<span id="txl-status" style="font-size:11px;color:var(--muted);flex:1"></span>
<button class="btn bg" onclick="closeTxlModal()">닫기</button>
</div>
</div>
</div>
<!-- Image lightbox -->
<div class="mbg" id="lbg" onclick="closeImgPreview()" style="z-index:400">
<div style="position:relative;max-width:90vw;max-height:90vh;display:flex;flex-direction:column;gap:8px" onclick="event.stopPropagation()">
<div style="display:flex;justify-content:space-between;align-items:center">
<span id="lb-label" style="color:rgba(255,255,255,.7);font-size:12px;max-width:80vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
<button onclick="closeImgPreview()" style="background:rgba(255,255,255,.15);border:none;color:#fff;border-radius:6px;padding:4px 10px;cursor:pointer;font-size:13px;margin-left:12px">✕</button>
</div>
<img id="lb-img" src="" style="max-width:88vw;max-height:82vh;border-radius:8px;display:block;box-shadow:0 8px 32px rgba(0,0,0,.6)">
</div>
</div>
<!-- Slide Editor Modal -->
<div class="mbg" id="sedbg" onclick="if(event.target===this)closeSed()" style="padding:0;align-items:center;justify-content:center">
<div class="modal sedmodal" onclick="event.stopPropagation()">
<div class="sed-hd">
<div class="snum" id="sed-num">1</div>
<span class="stype-tag" id="sed-type"></span>
<span id="sed-title-lbl" style="flex:1;font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0 10px;color:var(--text)"></span>
<span class="sed-nav-info"><span id="sed-cur">1</span> / <span id="sed-total">1</span></span>
<button class="btn bg" style="padding:5px 12px" onclick="sedNav(-1)">← 이전</button>
<button class="btn bg" style="padding:5px 12px" onclick="sedNav(1)">다음 →</button>
<button class="btn bg" style="padding:5px 12px" onclick="closeSed()">✕ 닫기</button>
</div>
<div class="sed-body">
<!-- Controls -->
<div class="sed-ctrl">
<!-- Layout -->
<div id="sed-layout-sec">
<span class="sed-section-lbl">레이아웃</span>
<div class="layout-grid">
<div class="layout-btn" data-layout="split-right" onclick="sedSetLayout('split-right')"><span class="li">T|I</span><span class="lt">텍스트+이미지</span></div>
<div class="layout-btn" data-layout="split-left" onclick="sedSetLayout('split-left')"><span class="li">I|T</span><span class="lt">이미지+텍스트</span></div>
<div class="layout-btn" data-layout="text" onclick="sedSetLayout('text')"><span class="li">T</span><span class="lt">텍스트만</span></div>
<div class="layout-btn" data-layout="fullscreen" onclick="sedSetLayout('fullscreen')"><span class="li">[I]</span><span class="lt">전체이미지</span></div>
<div class="layout-btn" data-layout="compare" onclick="sedSetLayout('compare')"><span class="li">||</span><span class="lt">2단비교</span></div>
</div>
</div>
<!-- Title -->
<div>
<span class="sed-section-lbl">제목</span>
<textarea class="sed-inp" id="sed-title-inp" oninput="sedChange()" onkeydown="setTimeout(sedRenderPreview,0)" placeholder="슬라이드 제목" rows="2"></textarea>
<div class="sed-row">
<span style="font-size:11px;color:var(--muted)">제목 크기</span>
<input type="range" class="sed-range" id="sed-title-size" min="14" max="52" step="1" oninput="sedChange()">
<span class="sed-val" id="sed-title-size-val">28pt</span>
</div>
</div>
<!-- Subtitle (title-type only) -->
<div id="sed-subtitle-sec">
<span class="sed-section-lbl">부제목</span>
<textarea class="sed-inp" id="sed-subtitle-inp" oninput="sedChange()" onkeydown="setTimeout(sedRenderPreview,0)" placeholder="부제목" rows="2"></textarea>
</div>
<!-- Bullets -->
<div id="sed-bullets-sec">
<span class="sed-section-lbl">내용</span>
<textarea class="sed-ta" id="sed-bullets-ta" oninput="sedChange()" onkeydown="setTimeout(sedRenderPreview,0)"></textarea>
<div class="sed-hint">
<span>Enter = 같은 항목 줄바꿈</span>
<span>빈 줄 = 새 항목 ●</span>
<span>- 시작 = 하위 항목 –</span>
</div>
<div class="sed-row">
<span style="font-size:11px;color:var(--muted)">본문 크기</span>
<input type="range" class="sed-range" id="sed-body-size" min="10" max="36" step="1" oninput="sedChange()">
<span class="sed-val" id="sed-body-size-val">18pt</span>
</div>
</div>
<!-- Image -->
<div id="sed-img-sec">
<span class="sed-section-lbl">이미지</span>
<div class="sed-img-thumb" id="sed-img-thumb" onclick="sedPickImg()">🖼</div>
<input type="text" class="sed-inp" id="sed-img-url-inp" placeholder="URL 직접 붙여넣기" style="margin-top:5px;font-size:11px" oninput="sedImgUrlInput()">
<div style="display:flex;gap:6px;margin-top:5px">
<button class="btn bg" style="flex:1;font-size:12px" onclick="sedPickImg()">🖼 선택</button>
<button class="btn bp" style="flex:1;font-size:12px" onclick="sedAutoExtract()">📷 자동추출</button>
<button class="btn bg" style="font-size:12px;color:var(--red)" onclick="sedClearImg()">✕</button>
</div>
<button class="btn bg" style="width:100%;font-size:11px;margin-top:4px;color:var(--muted)" onclick="sedOpenPdfPicker()">✂ 수동 캡처 (PDF 드래그)</button>
<div class="sed-row" style="margin-top:8px">
<span style="font-size:11px;color:var(--muted)">이미지 크기</span>
<input type="range" class="sed-range" id="sed-img-scale" min="20" max="80" step="5" oninput="sedChange()">
<span class="sed-val" id="sed-img-scale-val">50%</span>
</div>
</div>
<!-- Font -->
<div>
<span class="sed-section-lbl">폰트</span>
<div class="sed-row" style="margin-top:2px">
<span style="font-size:11px;color:var(--muted);min-width:36px">패밀리</span>
<select id="sed-font-family" style="flex:1;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:3px 6px;font-size:12px;color:var(--text)" onchange="sedChange()">
<option value="">기본 (Calibri/맑은고딕)</option>
<option value="Malgun Gothic">맑은 고딕</option>
<option value="NanumGothic">나눔고딕</option>
<option value="Arial">Arial</option>
<option value="Calibri">Calibri</option>
<option value="Georgia">Georgia</option>
<option value="Times New Roman">Times New Roman</option>
</select>
</div>
<div class="clr-row">
<label>제목색</label>
<input type="color" id="sed-title-color" value="#1a1a2e" oninput="sedChange()">
<button class="clr-reset" onclick="sedResetColor('title')">초기화</button>
</div>
<div class="clr-row">
<label>본문색</label>
<input type="color" id="sed-body-color" value="#2d3748" oninput="sedChange()">
<button class="clr-reset" onclick="sedResetColor('body')">초기화</button>
</div>
</div>
<!-- Image FX -->
<div id="sed-img-fx-sec">
<span class="sed-section-lbl">이미지 효과</span>
<div style="display:flex;gap:4px;flex-wrap:wrap;margin-top:4px">
<button class="fx-btn active" data-fx="" onclick="sedSetFx('')">원본</button>
<button class="fx-btn" data-fx="blur" onclick="sedSetFx('blur')">흐리게</button>
<button class="fx-btn" data-fx="grayscale" onclick="sedSetFx('grayscale')">흑백</button>
<button class="fx-btn" data-fx="contrast" onclick="sedSetFx('contrast')">대비↑</button>
<button class="fx-btn" data-fx="bright" onclick="sedSetFx('bright')">밝기↑</button>
<button class="fx-btn" data-fx="round" onclick="sedSetFx('round')">모서리</button>
</div>
<div id="sed-fx-blur-row" class="sed-row" style="display:none;margin-top:6px">
<span style="font-size:11px;color:var(--muted)">강도</span>
<input type="range" class="sed-range" id="sed-fx-blur" min="1" max="20" value="5" oninput="sedFxSlider()">
<span class="sed-val" id="sed-fx-blur-val">5</span>
</div>
<div id="sed-fx-round-row" class="sed-row" style="display:none;margin-top:6px">
<span style="font-size:11px;color:var(--muted)">반경</span>
<input type="range" class="sed-range" id="sed-fx-radius" min="5" max="50" value="15" oninput="sedFxSlider()">
<span class="sed-val" id="sed-fx-radius-val">15%</span>
</div>
</div>
<!-- Background -->
<div>
<span class="sed-section-lbl">배경 <span id="sed-skin-lbl" style="font-weight:400;text-transform:none;font-size:11px;margin-left:4px;color:var(--text)"></span></span>
<div class="sed-skin-grid" id="sed-skin-grid"></div>
<div style="display:flex;gap:5px;align-items:center;margin-top:6px">
<div id="sed-bg-img-thumb" style="width:38px;height:26px;border:1px solid var(--line);border-radius:3px;background-size:cover;background-position:center;flex-shrink:0;font-size:10px;display:flex;align-items:center;justify-content:center;color:var(--muted)">🖼</div>
<button class="pickbtn" style="font-size:11px;padding:3px 8px" onclick="sedPickBgImg()">이미지 배경</button>
<button class="pickbtn" id="sed-bg-img-clear" style="font-size:11px;padding:3px 8px;color:var(--red);display:none" onclick="sedClearBgImg()">✕</button>
</div>
</div>
</div>
<!-- Preview Stage -->
<div class="sed-stage" id="sed-stage">
<div class="sed-preview" id="sed-preview"></div>
</div>
</div>
</div>
</div>
<!-- PDF Capture modal -->
<div class="mbg" id="pdfbg" onclick="if(event.target===this)closePdfModal()">
<div class="modal pdfmodal" onclick="event.stopPropagation()">
<div class="pdfmodal-hd">
<span style="font-size:13px;font-weight:700">📄 PDF 캡처</span>
<span id="pdf-modal-name" style="font-size:11px;color:var(--muted);flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></span>
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfPrevPage()">◀</button>
<span id="pdf-page-lbl" style="font-size:12px;color:var(--muted);min-width:60px;text-align:center">1 / 1</span>
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfNextPage()">▶</button>
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfZoomStep(-1)">-</button>
<span id="pdf-zoom-lbl" style="font-size:12px;color:var(--muted);min-width:42px;text-align:center;cursor:pointer" title="클릭하여 초기화" onclick="pdfZoomReset()">100%</span>
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="pdfZoomStep(1)">+</button>
<button class="btn bg" style="padding:4px 10px;font-size:11px" onclick="closePdfModal()">✕</button>
</div>
<div class="pdfmodal-body" id="pdfmodal-body">
<div id="pdf-canvas-wrap">
<canvas id="pdf-main-canvas"></canvas>
</div>
<div id="pdf-load-msg" style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#aaa;font-size:14px">페이지 로딩 중...</div>
</div>
<div class="pdfmodal-ft">
<span style="font-size:11px;color:var(--muted)">드래그로 영역 선택 → 캡처</span>
<div style="flex:1"></div>
<span id="pdf-sel-info" style="font-size:11px;color:var(--brand2);margin-right:8px"></span>
<button class="btn bg" id="pdf-capture-btn" onclick="pdfCapture()" disabled>📷 캡처</button>
<button class="btn bg" onclick="pdfClearSel()">✕ 선택 해제</button>
</div>
</div>
</div>
<script src="/js/pptx/pptx-wizard.js"></script>
</body>
</html>