Recap-shan / index.html
Phoe2004's picture
Upload 2 files
8d55b02 verified
Raw
History Blame
273 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Recap Studio</title>
<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#1a1a2e">
<link rel="apple-touch-icon" href="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/logo.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,300&family=DM+Serif+Display:ital@0;1&family=Noto+Sans+Myanmar:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<style>
:root{
/* Warm ivory/parchment light palette */
--bg:#f7f4ef;--bg2:#fdfcfa;--bg3:#f0ece4;--bg4:#e8e2d8;
--border:#ddd6c8;--border2:#c9c0b0;
--text:#1c1917;--muted:#6b6460;--muted2:#a39b93;
--primary:#c2410c;--primary2:#9a3409;
/* Warm accent palette */
--orange:#ea580c;--orange2:#c2410c;
--green:#15803d;--red:#b91c1c;--blue:#1d4ed8;--purple:#7c3aed;
--gold:#b45309;
--cream:#fdfcfa;--warm:#f7f4ef;--amber:#fef3c7;
--F:'DM Sans',sans-serif;
--FS:'DM Serif Display',serif;
--shadow:0 1px 3px rgba(0,0,0,.06),0 4px 16px rgba(0,0,0,.04);
--shadow-md:0 2px 8px rgba(0,0,0,.08),0 8px 32px rgba(0,0,0,.06);
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--text);font-family:var(--F);min-height:100vh;-webkit-font-smoothing:antialiased}
#login-screen{display:flex;align-items:center;justify-content:center;min-height:100vh;padding:20px;
background:linear-gradient(160deg,#1c1008 0%,#2d1a0a 30%,#1a0e1a 70%,#0d1a2e 100%);
position:relative;overflow:hidden}
#login-screen::before{content:'';position:absolute;inset:0;
background:radial-gradient(ellipse at 25% 40%,rgba(234,88,12,.18) 0%,transparent 55%),
radial-gradient(ellipse at 75% 20%,rgba(180,83,9,.12) 0%,transparent 50%),
radial-gradient(ellipse at 55% 85%,rgba(194,65,12,.1) 0%,transparent 50%);
pointer-events:none}
/* Film grain overlay */
#login-screen::after{content:'';position:absolute;inset:0;opacity:.03;
background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='1'/%3E%3C/svg%3E");
background-size:200px;pointer-events:none}
#app-screen{display:none}
/* ── LOGIN GLASS ── */
.lw{width:100%;max-width:400px;position:relative;z-index:1}
.lb{text-align:center;margin-bottom:20px}
.lb .ico{width:64px;height:64px;background:rgba(255,255,255,.08);backdrop-filter:blur(16px);
border:1px solid rgba(255,255,255,.15);border-radius:16px;
display:inline-flex;align-items:center;justify-content:center;font-size:1.6rem;
margin-bottom:12px;box-shadow:0 8px 32px rgba(0,0,0,.4)}
.lb h1{font-size:2rem;font-weight:400;color:#fff;letter-spacing:-.01em;font-family:var(--FS);font-style:italic}
.lb p{color:rgba(255,255,255,.45);font-size:.8rem;margin-top:6px;letter-spacing:.04em;text-transform:uppercase;font-weight:500}
.lc{background:rgba(255,250,245,.07);backdrop-filter:blur(32px);-webkit-backdrop-filter:blur(32px);
border:1px solid rgba(255,255,255,.1);border-radius:20px;padding:28px;
box-shadow:0 24px 64px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.08)}
.tabs{display:flex;gap:2px;background:rgba(0,0,0,.25);border-radius:10px;padding:3px;margin-bottom:22px;border:1px solid rgba(255,255,255,.06)}
.tab{flex:1;padding:8px;border:none;background:transparent;color:rgba(255,255,255,.4);
font-family:var(--F);font-size:.8rem;font-weight:600;border-radius:7px;cursor:pointer;transition:.2s;letter-spacing:.02em}
.tab.on{background:rgba(255,255,255,.12);color:#fff;box-shadow:0 2px 8px rgba(0,0,0,.3)}
.fi{margin-bottom:14px}
.fi label{display:block;font-size:.65rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
color:rgba(255,255,255,.4);margin-bottom:6px}
.inp{width:100%;padding:11px 14px;background:rgba(255,255,255,.06);
border:1px solid rgba(255,255,255,.1);border-radius:10px;
color:#fff;font-family:var(--F);font-size:.88rem;outline:none;transition:.2s}
.inp::placeholder{color:rgba(255,255,255,.25)}
.inp:focus{border-color:rgba(234,88,12,.6);background:rgba(255,255,255,.09);
box-shadow:0 0 0 3px rgba(234,88,12,.15)}
.bp{width:100%;padding:13px;
background:linear-gradient(135deg,#ea580c,#c2410c);
border:none;border-radius:10px;color:#fff;font-family:var(--F);
font-size:.88rem;font-weight:700;cursor:pointer;transition:.2s;margin-top:4px;
box-shadow:0 4px 20px rgba(194,65,12,.4);letter-spacing:.02em}
.bp:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(194,65,12,.5)}
.am{font-size:.79rem;padding:9px 12px;border-radius:9px;margin-top:10px;display:none}
.am-ok{background:rgba(21,128,61,.2);border:1px solid rgba(21,128,61,.4);color:#86efac}
.am-err{background:rgba(185,28,28,.15);border:1px solid rgba(185,28,28,.3);color:#fca5a5}
/* Google button */
.ldiv{display:flex;align-items:center;gap:8px;margin:14px 0}
.ldiv hr{flex:1;border:none;border-top:1px solid rgba(255,255,255,.08)}
.ldiv span{color:rgba(255,255,255,.3);font-size:.72rem;font-weight:500;letter-spacing:.04em;text-transform:uppercase}
.gbtn{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;
padding:12px;background:rgba(255,255,255,.92);border:none;border-radius:10px;
color:#1c1917;font-family:var(--F);font-size:.86rem;font-weight:600;
text-decoration:none;cursor:pointer;transition:.2s;
box-shadow:0 2px 12px rgba(0,0,0,.25)}
.gbtn:hover{background:#fff;transform:translateY(-1px);box-shadow:0 6px 20px rgba(0,0,0,.3)}
.lfoot{text-align:center;padding:14px 0 0;font-size:.68rem;color:rgba(255,255,255,.25)}
.lfoot a{color:rgba(255,255,255,.35);text-decoration:none}
.lfoot a:hover{color:rgba(255,255,255,.6)}
@keyframes floatOrb{0%,100%{transform:translate(0,0) scale(1)}33%{transform:translate(20px,-20px) scale(1.05)}66%{transform:translate(-15px,15px) scale(.97)}}
@keyframes logoPop{0%{transform:scale(.5);opacity:0}100%{transform:scale(1);opacity:1}}
@keyframes srtprog{0%{width:20%}100%{width:80%}}
@keyframes pandaBob{0%,100%{transform:translateY(0)}50%{transform:translateY(-6px)}}
@keyframes earWiggle{0%,100%{transform:rotate(-38deg)}50%{transform:rotate(-28deg)}}
@keyframes earWiggleR{0%,100%{transform:rotate(38deg)}50%{transform:rotate(28deg)}}
@keyframes eyeBlink{0%,90%,100%{transform:scaleY(1)}95%{transform:scaleY(0.1)}}
@keyframes eyeLook{0%,100%{transform:translateX(0)}40%{transform:translateX(3px)}70%{transform:translateX(-3px)}}
/* ── PANDA CHARACTER ── */
.panda-wrap{position:relative;display:flex;justify-content:center;margin-bottom:-22px;z-index:10;animation:pandaBob 3s ease-in-out infinite}
.panda{position:relative;width:100px;height:90px}
/* ears */
.panda .ear{position:absolute;width:28px;height:28px;background:#1a1a1a;border-radius:50%;top:4px}
.panda .ear-l{left:10px;transform:rotate(-38deg);transform-origin:bottom right;animation:earWiggle 3s ease-in-out infinite}
.panda .ear-r{right:10px;transform:rotate(38deg);transform-origin:bottom left;animation:earWiggleR 3s ease-in-out infinite}
/* head */
.panda .head{position:absolute;width:80px;height:74px;background:#fff;border-radius:50%;left:10px;top:10px;box-shadow:0 4px 12px rgba(0,0,0,.2)}
/* eye patches */
.panda .patch{position:absolute;width:24px;height:20px;background:#1a1a1a;border-radius:50%;top:18px}
.panda .patch-l{left:14px;transform:rotate(20deg)}
.panda .patch-r{right:14px;transform:rotate(-20deg)}
/* eyes */
.panda .eye{position:absolute;width:10px;height:10px;background:#fff;border-radius:50%;top:22px;animation:eyeBlink 4s ease-in-out infinite}
.panda .eye-l{left:17px}
.panda .eye-r{right:17px}
.panda .pupil{position:absolute;width:6px;height:6px;background:#1a1a1a;border-radius:50%;top:2px;left:2px;animation:eyeLook 5s ease-in-out infinite}
/* nose */
.panda .nose{position:absolute;width:16px;height:10px;background:#ffb8c0;border-radius:50%;left:50%;transform:translateX(-50%);top:38px}
/* mouth */
.panda .mouth{position:absolute;width:20px;height:10px;border-bottom:2.5px solid #555;border-left:2.5px solid #555;border-right:2.5px solid #555;border-radius:0 0 12px 12px;left:50%;transform:translateX(-50%);top:46px}
/* blush */
.panda .blush{position:absolute;width:22px;height:16px;background:#ffb8c0;border-radius:50%;opacity:.6;top:36px}
.panda .blush-l{left:8px;transform:rotate(25deg)}
.panda .blush-r{right:8px;transform:rotate(-25deg)}
/* arms gripping card sides */
.panda .arm{position:absolute;width:22px;height:36px;background:#1a1a1a;border-radius:12px;bottom:-10px;transition:all .4s cubic-bezier(.34,1.2,.64,1)}
.panda .arm-l{left:-4px;transform:rotate(-20deg);transform-origin:top center}
.panda .arm-r{right:-4px;transform:rotate(20deg);transform-origin:top center}
/* covering eyes state */
.panda.peek-off .arm-l{left:10px;bottom:38px;transform:rotate(30deg);transform-origin:bottom center}
.panda.peek-off .arm-r{right:10px;bottom:38px;transform:rotate(-30deg);transform-origin:bottom center}
.panda.peek-off .eye-l,.panda.peek-off .eye-r{transform:scaleY(0.05)}
.panda .eye{position:absolute;width:10px;height:10px;background:#fff;border-radius:50%;top:22px;animation:eyeBlink 4s ease-in-out infinite;transition:transform .3s ease}
.panda.peek-off .eye-l,.panda.peek-off .eye-r{animation:none}
/* ── HEADER ── */
.hdr{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:54px;background:var(--cream);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:100;box-shadow:0 1px 0 var(--border),0 2px 12px rgba(0,0,0,.04)}
.brand{display:flex;align-items:center;gap:9px;font-weight:600;font-size:.95rem;color:var(--text);letter-spacing:-.01em}
.brand-i{width:28px;height:28px;background:linear-gradient(135deg,var(--orange),var(--primary));border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:.72rem;box-shadow:0 2px 8px rgba(194,65,12,.25)}
.hr{display:flex;align-items:center;gap:7px}
.cpill{display:flex;align-items:center;gap:5px;padding:5px 11px;background:var(--amber);border:1px solid rgba(180,83,9,.2);border-radius:20px;font-size:.76rem;font-weight:700;color:var(--gold);cursor:pointer;transition:.2s}
.cpill:hover{box-shadow:0 2px 8px rgba(180,83,9,.12)}
.hb{padding:6px 12px;border-radius:7px;border:1px solid var(--border);background:var(--cream);color:var(--muted);font-family:var(--F);font-size:.76rem;font-weight:600;cursor:pointer;transition:.2s}
.hb:hover{border-color:var(--orange);color:var(--orange)}
.hb-p{background:linear-gradient(135deg,var(--orange),var(--primary));border-color:transparent;color:#fff}
.hb-p:hover{box-shadow:0 4px 14px rgba(194,65,12,.3);color:#fff;transform:translateY(-1px)}
.huser{display:flex;align-items:center;gap:6px;padding:4px 10px 4px 5px;background:var(--bg3);border:1px solid var(--border);border-radius:20px;cursor:pointer;transition:.2s;max-width:160px}
.huser:hover{border-color:var(--orange);background:var(--amber)}
.huser-av{width:24px;height:24px;border-radius:7px;background:linear-gradient(135deg,var(--orange),var(--primary));display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.62rem;color:#fff;flex-shrink:0}
.huser-name{font-size:.71rem;font-weight:700;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mbtn{width:32px;height:32px;border:1px solid var(--border);background:var(--cream);border-radius:7px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;transition:.2s}
.mbtn:hover{border-color:var(--orange)}
.mbtn span{display:block;width:14px;height:1.5px;background:var(--muted);border-radius:2px}
.mbtn:hover span{background:var(--orange)}
/* ── DRAWER ── */
.dov{display:none;position:fixed;inset:0;z-index:200}
.dov.on{display:block}
.dbg{position:absolute;inset:0;background:rgba(28,25,23,.45);backdrop-filter:blur(4px)}
.drw{position:absolute;top:0;right:0;width:275px;height:100%;background:var(--cream);box-shadow:-8px 0 40px rgba(0,0,0,.1);display:flex;flex-direction:column;animation:sli .2s ease;border-left:1px solid var(--border)}
@keyframes sli{from{transform:translateX(100%)}to{transform:translateX(0)}}
.drw-h{padding:18px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;background:var(--cream)}
.drw-u{display:flex;align-items:center;gap:11px}
.av{width:40px;height:40px;border-radius:10px;background:linear-gradient(135deg,var(--orange),var(--primary));display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.9rem;color:#fff}
.dn{font-weight:700;font-size:.88rem;color:var(--text)}
.drl{font-size:.67rem;color:var(--muted);margin-top:1px}
.dxbtn{width:28px;height:28px;border:1px solid var(--border);background:var(--cream);color:var(--muted);border-radius:7px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:.75rem;transition:.2s}
.dxbtn:hover{border-color:var(--red);color:var(--red)}
.drw-s{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:14px 18px;border-bottom:1px solid var(--border)}
.ds{background:var(--bg3);border-radius:9px;padding:12px;text-align:center;border:1px solid var(--border)}
.dsv{font-size:1.25rem;font-weight:700;color:var(--orange)}
.dsl{font-size:.62rem;color:var(--muted);margin-top:2px;text-transform:uppercase;letter-spacing:.04em}
.drw-n{flex:1;padding:8px}
.dni{display:flex;align-items:center;gap:9px;padding:10px 13px;border-radius:8px;cursor:pointer;transition:.15s;border:none;background:transparent;width:100%;text-align:left;font-family:var(--F);font-size:.82rem;font-weight:500;color:var(--text)}
.dni:hover{background:var(--bg3)}
.dni i{width:17px;font-size:.8rem;color:var(--muted)}
.dni-r{color:var(--red)}.dni-r i{color:var(--red)}
.drw-f{padding:12px 18px;border-top:1px solid var(--border);font-size:.65rem;color:var(--muted2);text-align:center}
/* ── BODY ── */
.ab{max-width:880px;margin:0 auto;padding:18px 14px 70px}
/* ── CARD ── */
.card{background:var(--cream);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:12px;box-shadow:var(--shadow)}
.ch{display:flex;align-items:center;gap:8px;margin-bottom:13px}
.ci{width:28px;height:28px;border-radius:7px;display:flex;align-items:center;justify-content:center;font-size:.72rem}
.ci-p{background:linear-gradient(135deg,#fef3c7,#fde68a);color:var(--gold)}
.ci-o{background:linear-gradient(135deg,#ffedd5,#fed7aa);color:var(--orange)}
.ci-g{background:linear-gradient(135deg,#dcfce7,#bbf7d0);color:var(--green)}
.ci-b{background:linear-gradient(135deg,#dbeafe,#bfdbfe);color:var(--blue)}
.ci-pu{background:linear-gradient(135deg,#ede9fe,#ddd6fe);color:var(--purple)}
.ct{font-weight:700;font-size:.86rem;color:var(--text);letter-spacing:-.01em}
/* ── URL ── */
.uw{position:relative}
.uinp{width:100%;padding:11px 100px 11px 42px;background:var(--bg3);border:1px solid var(--border);border-radius:10px;color:var(--text);font-family:var(--F);font-size:.85rem;outline:none;transition:.2s}
.uinp:focus{border-color:var(--orange);background:var(--cream);box-shadow:0 0 0 3px rgba(234,88,12,.08)}
.uico{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--muted);font-size:.8rem;pointer-events:none}
.ubadge{position:absolute;right:80px;top:50%;transform:translateY(-50%);font-size:.62rem;font-weight:700;padding:3px 8px;border-radius:20px;display:none}
.paste-btn{position:absolute;right:10px;top:50%;transform:translateY(-50%);padding:5px 11px;background:var(--orange);border:none;border-radius:7px;color:#fff;font-family:var(--F);font-size:.71rem;font-weight:700;cursor:pointer;transition:.2s;display:flex;align-items:center;gap:4px}
.paste-btn:hover{background:var(--primary);box-shadow:0 2px 8px rgba(194,65,12,.3)}
.b-yt{background:#fee2e2;color:#dc2626;border:1px solid #fca5a5}
.b-tt{background:var(--bg3);color:#374151;border:1px solid var(--border)}
.b-ig{background:#fdf2f8;color:#be185d;border:1px solid #fbcfe8}
.b-fb{background:#eff6ff;color:#1d4ed8;border:1px solid #bfdbfe}
.b-rn{background:#fff0f0;color:#e53935;border:1px solid #ffcdd2}
.orsep{text-align:center;color:var(--muted2);font-size:.72rem;margin:10px 0;position:relative}
.orsep::before,.orsep::after{content:'';position:absolute;top:50%;width:44%;height:1px;background:var(--border)}
.orsep::before{left:0}.orsep::after{right:0}
.upz{border:2px dashed var(--border2);border-radius:10px;padding:14px;text-align:center;cursor:pointer;transition:.2s;position:relative;background:var(--bg3)}
.upz:hover{border-color:var(--orange);background:var(--amber)}
.upz input{position:absolute;inset:0;opacity:0;cursor:pointer}
.upz-t{font-size:.77rem;color:var(--muted)}
.upz-n{font-size:.75rem;color:var(--green);margin-top:3px;display:none;font-weight:600}
.prev-loading{display:none;margin-top:8px;padding:9px 13px;background:var(--amber);border:1px solid rgba(180,83,9,.15);border-radius:9px;font-size:.77rem;color:var(--gold);font-weight:600;align-items:center;gap:7px}
.prev-loading.on{display:flex}
/* ── SETTINGS ── */
.sgrid{display:grid;grid-template-columns:1fr 1fr;gap:9px}
@media(max-width:460px){.sgrid{grid-template-columns:1fr}}
.si{background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:11px 13px;transition:.2s}
.si:focus-within{border-color:var(--orange);background:var(--cream)}
.sil{font-size:.63rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
.ssel{width:100%;background:transparent;border:none;color:var(--text);font-family:var(--F);font-size:.83rem;font-weight:500;outline:none;cursor:pointer}
.ssel option{background:var(--cream);color:var(--text)}
.vrow{display:flex;align-items:center;gap:7px}
.vrow .ssel{flex:1;background:var(--bg3);border:1px solid var(--border);border-radius:9px;padding:9px 11px}
.pvbtn{width:34px;height:34px;flex-shrink:0;background:var(--cream);border:1px solid var(--border);border-radius:9px;color:var(--muted);cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;font-size:.78rem}
.pvbtn:hover{border-color:var(--green);color:var(--green);box-shadow:0 2px 8px rgba(21,128,61,.12)}
.spd-row{display:flex;align-items:center;gap:9px;margin-top:9px}
.spd-row label{font-size:.68rem;font-weight:600;color:var(--muted);white-space:nowrap;width:52px}
.spd-sl{flex:1;-webkit-appearance:none;height:3px;border-radius:2px;background:var(--bg4);outline:none;cursor:pointer}
.spd-sl::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--orange);cursor:pointer;box-shadow:0 0 0 3px rgba(234,88,12,.12)}
.spd-v{font-size:.72rem;color:var(--orange);font-weight:700;width:36px;text-align:right}
/* ── VIDEO OPTIONS ── */
.egrid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
@media(max-width:420px){.egrid{grid-template-columns:1fr 1fr}}
.ei{background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:10px 12px;transition:.2s}
.ei:focus-within{border-color:var(--orange)}
.eil{font-size:.62rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin-bottom:5px}
.esel{width:100%;background:transparent;border:none;color:var(--text);font-family:var(--F);font-size:.8rem;font-weight:500;outline:none;cursor:pointer}
.esel option{background:var(--cream)}
.icon-toggle{display:flex;align-items:center;justify-content:center;gap:5px;padding:8px 10px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;cursor:pointer;transition:.2s;font-size:.78rem;font-weight:600;color:var(--muted);font-family:var(--F);width:100%}
.icon-toggle:hover{border-color:var(--orange);color:var(--orange)}
.icon-toggle.on{background:var(--amber);border-color:rgba(180,83,9,.35);color:var(--gold)}
.winp{width:100%;padding:9px 11px;background:var(--bg3);border:1px solid var(--border);border-radius:9px;color:var(--text);font-family:var(--F);font-size:.8rem;font-weight:500;outline:none;transition:.2s}
.winp:focus{border-color:var(--orange);background:var(--cream)}
.winp::placeholder{color:var(--muted2)}
/* ── WATERMARK TOGGLE ── */
.wm-row{display:flex;align-items:center;justify-content:space-between;margin-top:12px;border-top:1px solid var(--border);padding-top:12px}
.wm-lbl{font-size:.66rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);display:flex;align-items:center;gap:6px}
.wm-wrap{margin-top:8px;display:none}
.wm-toggle{padding:5px 13px;border-radius:20px;border:1px solid var(--border);background:var(--bg3);color:var(--muted);font-family:var(--F);font-size:.74rem;font-weight:700;cursor:pointer;transition:.2s}
.wm-toggle.on{background:var(--amber);border-color:rgba(180,83,9,.3);color:var(--gold)}
/* ── OVERLAY (REMOVED: watermark, logo, blur boxes) ── */
/* Only subtitle settings remain */
.canvas-wrap{position:relative;background:#1c1008;border-radius:10px;overflow:hidden;margin-top:10px;min-height:200px}
.canvas-bg-blur{position:absolute;inset:0;background-size:cover;background-position:center;filter:blur(18px) brightness(.6);transform:scale(1.1);pointer-events:none;display:none;z-index:0}
.canvas-video-wrap{position:relative;z-index:1}
.canvas-wrap video{width:100%;display:block;height:auto}
.canvas-ph{display:flex;align-items:center;justify-content:center;height:200px;color:rgba(255,255,255,.3);font-size:.77rem;flex-direction:column;gap:6px;pointer-events:none}
.canvas-ph i{font-size:1.8rem;opacity:.4}
/* Overlay buttons hidden */
.ov-controls{display:grid;grid-template-columns:repeat(4,1fr);gap:7px;margin-top:10px}
.ov-btn{padding:9px 5px;background:var(--bg3);border:1px solid var(--border);border-radius:9px;color:var(--muted);font-family:var(--F);font-size:.7rem;font-weight:600;cursor:pointer;transition:.2s;text-align:center;display:flex;flex-direction:column;align-items:center;gap:4px}
.ov-btn i{font-size:.86rem}
.ov-btn:hover{border-color:var(--orange);color:var(--orange);background:var(--amber)}
.ov-btn.on-wm {background:var(--amber);border-color:rgba(180,83,9,.3);color:var(--gold)}
.ov-btn.on-logo{background:#ecfdf5;border-color:#6ee7b7;color:#065f46}
.ov-btn.on-sub {background:#eff6ff;border-color:#93c5fd;color:#1d4ed8}
.ov-btn.on-blur{background:#fef2f2;border-color:#fca5a5;color:#991b1b}
.sub-settings{background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:11px;margin-top:9px;display:none}
.sub-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.sub-inp{width:100%;padding:7px 9px;background:var(--cream);border:1px solid var(--border);border-radius:7px;color:var(--text);font-family:var(--F);font-size:.78rem;font-weight:500;outline:none;transition:.2s}
.sub-inp:focus{border-color:var(--blue)}
.slbl{font-size:.63rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin-bottom:4px}
.btn-auto{width:100%;padding:14px;background:linear-gradient(135deg,var(--orange),var(--primary));border:none;border-radius:11px;color:#fff;font-family:var(--F);font-size:.92rem;font-weight:700;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:8px;box-shadow:0 4px 18px rgba(194,65,12,.3);letter-spacing:.01em}
.btn-auto:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 28px rgba(194,65,12,.4)}
.btn-auto:disabled{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}
/* ── PROGRESS ── */
.pc{background:var(--cream);border:1px solid var(--border);border-radius:14px;padding:18px;margin-top:12px;display:none;box-shadow:var(--shadow)}
.ph{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
.ptit{font-weight:700;font-size:.85rem;color:var(--text)}
.ptmr{font-size:.72rem;color:var(--orange);font-variant-numeric:tabular-nums;font-weight:700;background:var(--amber);padding:3px 9px;border-radius:20px}
.pb-bg{height:5px;background:var(--bg4);border-radius:3px;overflow:hidden;margin-bottom:9px}
.pb{height:100%;background:linear-gradient(90deg,var(--orange),var(--gold));border-radius:3px;width:0%;transition:width .4s ease}
.pmsg{font-size:.79rem;color:var(--muted);font-weight:500}
.psteps{display:flex;gap:5px;margin-top:11px;flex-wrap:wrap}
.ps{font-size:.65rem;font-weight:600;padding:4px 10px;border-radius:20px;background:var(--bg3);color:var(--muted2);border:1px solid var(--border);transition:.3s}
.ps.active{background:var(--amber);color:var(--gold);border-color:rgba(180,83,9,.25)}
.ps.done{background:#dcfce7;color:#15803d;border-color:#86efac}
/* ── RESULT ── */
.rc{background:var(--cream);border:1px solid var(--border);border-radius:14px;overflow:hidden;margin-top:12px;display:none;box-shadow:var(--shadow)}
.rvw{background:#1c1008}
.rvw video{width:100%;display:block;max-height:380px;object-fit:contain}
.rb{padding:15px}
.rtm{font-size:.69rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:4px;font-weight:500}
.rtit{font-weight:700;font-size:.92rem;margin-bottom:5px;line-height:1.3;color:var(--text)}
.rtag{font-size:.72rem;color:var(--orange);line-height:1.6;margin-bottom:12px;font-weight:500}
.ract{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.rb-btn{padding:11px;border-radius:9px;border:none;font-family:var(--F);font-size:.8rem;font-weight:700;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:6px}
.rb-g{background:#dcfce7;color:#15803d}
.rb-g:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(21,128,61,.15)}
.rb-b{background:#dbeafe;color:#1d4ed8}
.rb-b:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(29,78,216,.15)}
/* ── ADMIN ── */
.admp{background:var(--cream);border:1px solid rgba(180,83,9,.2);border-radius:14px;padding:16px;margin-top:12px;display:none;box-shadow:0 2px 12px rgba(180,83,9,.06)}
.admbadge{font-size:.62rem;font-weight:700;padding:3px 8px;background:var(--amber);color:var(--gold);border-radius:20px;border:1px solid rgba(180,83,9,.2)}
.admg{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-bottom:11px}
@media(max-width:460px){.admg{grid-template-columns:1fr}}
.ai-row{display:flex;gap:5px}
.ai{flex:1;padding:8px 10px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--F);font-size:.8rem;font-weight:500;outline:none}
.ai:focus{border-color:var(--orange)}
.ai::placeholder{color:var(--muted2)}
.abtn{padding:8px 12px;border-radius:8px;border:none;font-family:var(--F);font-size:.75rem;font-weight:700;cursor:pointer;transition:.2s;white-space:nowrap}
.ab-g{background:var(--amber);color:var(--gold)}
.ab-g:hover{background:#fde68a}
.ab-r{background:#fee2e2;color:#b91c1c}
.ab-r:hover{background:#fecaca}
.admmsg{font-size:.75rem;margin-top:7px;min-height:18px;color:var(--green);font-weight:600}
.adm-act-btn{padding:7px 13px;background:var(--bg3);border:1px solid var(--border);border-radius:8px;color:var(--muted);font-family:var(--F);font-size:.74rem;font-weight:600;cursor:pointer;transition:.2s}
.adm-act-btn:hover{border-color:var(--orange);color:var(--orange)}
/* pending payment card */
.adm-pay-card{background:var(--bg3);border:1px solid var(--border);border-radius:12px;padding:12px 14px;margin-bottom:8px}
.adm-pay-card-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
.adm-pay-card-user{font-weight:700;font-size:.84rem;color:var(--text)}
.adm-pay-card-coins{font-size:.77rem;font-weight:700;color:var(--orange)}
.adm-pay-card-info{font-size:.71rem;color:var(--muted);margin-bottom:10px;line-height:1.6}
.adm-pay-card-btns{display:flex;gap:7px}
.adm-pay-approve{flex:1;padding:8px;background:linear-gradient(135deg,#15803d,#16a34a);border:none;border-radius:8px;color:#fff;font-family:var(--F);font-size:.77rem;font-weight:700;cursor:pointer;transition:.2s}
.adm-pay-approve:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(21,128,61,.3)}
.adm-pay-reject{padding:8px 14px;background:rgba(185,28,28,.08);border:1px solid rgba(185,28,28,.2);border-radius:8px;color:var(--red);font-family:var(--F);font-size:.77rem;font-weight:700;cursor:pointer;transition:.2s}
.adm-pay-reject:hover{background:rgba(185,28,28,.14)}
.adm-pay-slip-btn{padding:8px 12px;background:rgba(234,88,12,.08);border:1px solid rgba(234,88,12,.2);border-radius:8px;color:var(--orange);font-family:var(--F);font-size:.77rem;font-weight:700;cursor:pointer;transition:.2s}
.adm-pay-slip-btn:hover{background:rgba(234,88,12,.14)}
.adm-slip-img{width:100%;max-height:180px;object-fit:contain;border-radius:10px;margin-top:8px;display:none;border:1px solid var(--border)}
.ut{width:100%;border-collapse:collapse;font-size:.75rem;margin-top:10px}
.ut th{padding:7px 9px;text-align:left;font-size:.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);border-bottom:1px solid var(--border)}
.ut td{padding:7px 9px;border-bottom:1px solid var(--bg4);color:var(--text);font-weight:500}
.ut tr:last-child td{border-bottom:none}
.delbtn{background:transparent;border:none;color:var(--muted2);cursor:pointer;padding:2px 5px;border-radius:5px;transition:.2s;font-size:.72rem}
.delbtn:hover{color:var(--red);background:#fee2e2}
#toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%) translateY(14px);background:var(--text);border-radius:10px;padding:9px 16px;font-size:.79rem;color:#fff;z-index:9999;opacity:0;transition:.3s;pointer-events:none;white-space:nowrap;max-width:88vw;box-shadow:0 8px 28px rgba(0,0,0,.3);font-weight:600;letter-spacing:.01em}
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
@keyframes spin{to{transform:rotate(360deg)}}
.sp{display:inline-block;animation:spin .7s linear infinite}
.modal-ov{display:none;position:fixed;inset:0;z-index:300;align-items:flex-end;justify-content:center}
.modal-ov.on{display:flex}
.modal-bg{position:absolute;inset:0;background:rgba(28,25,23,.5);backdrop-filter:blur(4px)}
.modal-sheet{position:relative;width:100%;max-width:480px;background:var(--cream);border-radius:20px 20px 0 0;padding:24px 20px 36px;animation:slideUp .25s ease;box-shadow:0 -4px 40px rgba(0,0,0,.12);border-top:1px solid var(--border)}
@keyframes slideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}
.modal-sheet h3{font-size:1.05rem;font-weight:700;margin-bottom:4px;color:var(--text);font-family:var(--FS)}
.modal-sheet p{font-size:.79rem;color:var(--muted);margin-bottom:18px}
.pkg-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
.pkg-card{background:var(--bg3);border:1px solid var(--border);border-radius:12px;padding:14px 12px;text-align:center;cursor:pointer;transition:.2s;position:relative}
.pkg-card:hover{border-color:var(--orange);background:var(--amber);transform:translateY(-2px);box-shadow:0 4px 16px rgba(194,65,12,.1)}
.pkg-card.popular{border-color:var(--orange);background:var(--amber)}
.pkg-pop-badge{position:absolute;top:-9px;left:50%;transform:translateX(-50%);background:var(--orange);color:#fff;font-size:.6rem;font-weight:700;padding:2px 8px;border-radius:10px;white-space:nowrap}
.pkg-emoji{font-size:1.5rem;margin-bottom:5px}
.pkg-name{font-size:.74rem;font-weight:700;color:var(--text);margin-bottom:3px}
.pkg-coins{font-size:1.2rem;font-weight:700;color:var(--orange)}
.pkg-coins span{font-size:.7rem;font-weight:500;color:var(--muted)}
.pkg-contact{background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:12px;text-align:center;font-size:.79rem;color:var(--muted)}
.pkg-contact b{color:var(--text)}
.pkg-price{font-size:.71rem;font-weight:700;color:var(--green);margin-top:3px}
.pkg-contact a{color:var(--orange);font-weight:600;text-decoration:none}
.modal-close{position:absolute;top:14px;right:16px;width:28px;height:28px;border:1px solid var(--border);background:var(--cream);border-radius:7px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:.75rem;color:var(--muted);transition:.2s}
.modal-close:hover{border-color:var(--red);color:var(--red)}
/* ══ PAYMENT MODAL ══ */
.pov{display:none;position:fixed;inset:0;z-index:400;
background:rgba(20,14,8,.82);backdrop-filter:blur(16px);
align-items:flex-end;justify-content:center}
.pov.on{display:flex}
@keyframes sheetUp{from{transform:translateY(100%);opacity:0}to{transform:translateY(0);opacity:1}}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
@keyframes shimmer{0%{background-position:200% center}100%{background-position:-200% center}}
@keyframes pulse-glow{0%,100%{box-shadow:0 0 0 0 rgba(234,88,12,.3)}50%{box-shadow:0 0 0 8px rgba(234,88,12,0)}}
.paysheet{
position:relative;width:100%;max-width:520px;
background:linear-gradient(165deg,#1c1008 0%,#261609 60%,#1a1020 100%);
border-radius:28px 28px 0 0;
padding:0 0 44px;max-height:93vh;overflow-y:auto;
box-shadow:0 -4px 60px rgba(234,88,12,.2),0 -1px 0 rgba(255,255,255,.05);
animation:sheetUp .32s cubic-bezier(.34,1.1,.64,1)}
.paysheet::-webkit-scrollbar{width:3px}
.paysheet::-webkit-scrollbar-track{background:transparent}
.paysheet::-webkit-scrollbar-thumb{background:rgba(194,65,12,.3);border-radius:10px}
/* header */
.paysheet-hdr{
padding:20px 22px 0;
display:flex;align-items:center;justify-content:space-between;
position:sticky;top:0;z-index:2;
background:linear-gradient(165deg,#1c1008,#261609);
padding-bottom:16px;
border-bottom:1px solid rgba(255,255,255,.05)}
.paysheet-hdr h2{font-size:1.05rem;font-weight:400;color:#fff;display:flex;align-items:center;gap:8px;font-family:var(--FS);font-style:italic}
.paysheet-hdr h2 span{
display:inline-flex;align-items:center;justify-content:center;
width:32px;height:32px;background:linear-gradient(135deg,var(--orange),var(--primary));
border-radius:9px;font-size:.9rem;font-style:normal}
.pclose{
width:32px;height:32px;border:1px solid rgba(255,255,255,.1);
background:rgba(255,255,255,.05);border-radius:9px;cursor:pointer;
display:flex;align-items:center;justify-content:center;
font-size:.8rem;color:rgba(255,255,255,.45);transition:.2s}
.pclose:hover{background:rgba(185,28,28,.15);border-color:rgba(185,28,28,.4);color:#f87171}
/* tab2 */
.tab2{display:flex;gap:6px;margin:18px 22px 0}
.tab2 button{
flex:1;padding:10px;border:1px solid rgba(255,255,255,.07);
background:rgba(255,255,255,.04);
color:rgba(255,255,255,.4);font-family:var(--F);font-size:.8rem;font-weight:600;
border-radius:10px;cursor:pointer;transition:.2s}
.tab2 button.on{
border-color:rgba(234,88,12,.5);
background:linear-gradient(135deg,rgba(234,88,12,.18),rgba(194,65,12,.12));
color:#fdba74}
/* ── MODE TOGGLE ── */
.mode-bar{display:flex;gap:0;background:var(--bg3);border-bottom:1px solid var(--border);padding:0}
.mode-btn{flex:1;padding:11px 8px;border:none;background:transparent;font-family:var(--F);font-size:.8rem;font-weight:700;color:var(--muted);cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:6px;border-bottom:2px solid transparent;letter-spacing:.01em}
.mode-btn.on{background:var(--cream);color:var(--orange);border-bottom-color:var(--orange)}
.mode-btn:hover:not(.on){background:rgba(234,88,12,.04);color:var(--orange)}
/* ── SRT SECTION ── */
.srt-drop{border:2px dashed var(--border2);border-radius:10px;padding:20px;text-align:center;cursor:pointer;transition:.2s;position:relative;background:var(--bg3)}
.srt-drop:hover{border-color:var(--orange);background:var(--amber)}
.srt-drop input{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.srt-drop-t{font-size:.8rem;color:var(--muted);margin-top:6px}
.srt-step{display:flex;align-items:center;gap:10px;padding:12px 14px;background:var(--bg3);border:1px solid var(--border);border-radius:10px;margin-bottom:8px;transition:.2s}
.srt-step.done{border-color:var(--green);background:#f0fdf4}
.srt-step.active{border-color:var(--orange);background:var(--amber)}
.srt-step-n{width:26px;height:26px;border-radius:50%;background:var(--border);color:var(--muted);font-size:.72rem;font-weight:800;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.srt-step.done .srt-step-n{background:var(--green);color:#fff}
.srt-step.active .srt-step-n{background:var(--orange);color:#fff}
.srt-step-t{font-size:.8rem;font-weight:600;color:var(--text)}
.srt-step-s{font-size:.7rem;color:var(--muted);margin-top:1px}
.srt-preview{background:#1c1008;border-radius:10px;padding:12px;max-height:200px;overflow-y:auto;font-size:.72rem;color:#fdba74;font-family:monospace;line-height:1.6;white-space:pre-wrap;word-break:break-word}
.srt-dl-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:13px;background:linear-gradient(135deg,var(--green),#16a34a);border:none;border-radius:11px;color:#fff;font-family:var(--F);font-size:.88rem;font-weight:700;cursor:pointer;transition:.2s;margin-top:8px}
.srt-dl-btn:hover{transform:translateY(-1px);box-shadow:0 6px 20px rgba(21,128,61,.3)}
.srt-burn-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:13px;background:linear-gradient(135deg,var(--orange),var(--primary));border:none;border-radius:11px;color:#fff;font-family:var(--F);font-size:.88rem;font-weight:700;cursor:pointer;transition:.2s;margin-top:8px}
.srt-burn-btn:hover{transform:translateY(-1px);box-shadow:0 6px 20px rgba(194,65,12,.3)}
.srt-burn-btn:disabled{opacity:.4;cursor:not-allowed;transform:none}
.ppkg{
border:1px solid rgba(255,255,255,.07);
border-radius:16px;padding:14px 10px 12px;cursor:pointer;
transition:all .22s cubic-bezier(.34,1.1,.64,1);
background:rgba(255,255,255,.04);
text-align:center;position:relative;overflow:hidden}
.ppkg::before{
content:'';position:absolute;inset:0;
background:radial-gradient(ellipse at 50% 0%,rgba(234,88,12,.1),transparent 70%);
opacity:0;transition:.2s}
.ppkg:hover{border-color:rgba(234,88,12,.4);transform:translateY(-3px);
box-shadow:0 8px 24px rgba(194,65,12,.2);background:rgba(234,88,12,.07)}
.ppkg:hover::before{opacity:1}
.ppkg.sel{
border-color:rgba(253,186,116,.6);
background:linear-gradient(145deg,rgba(234,88,12,.16),rgba(194,65,12,.1));
box-shadow:0 0 0 3px rgba(234,88,12,.15),0 8px 28px rgba(194,65,12,.2)}
.ppkg.sel::before{opacity:1}
.ppkg.pop{border-color:rgba(251,191,36,.35);background:rgba(251,191,36,.05)}
.ppkg.pop::after{
content:'🔥 Popular';position:absolute;top:-1px;left:50%;transform:translateX(-50%);
background:linear-gradient(90deg,#b45309,#d97706);color:#fff;
font-size:.58rem;font-weight:800;padding:3px 10px;border-radius:0 0 10px 10px;
white-space:nowrap;letter-spacing:.03em}
.ppkg.pop:hover{border-color:rgba(251,191,36,.6);box-shadow:0 8px 24px rgba(180,83,9,.2)}
.ppkg.pop.sel{border-color:#d97706;box-shadow:0 0 0 3px rgba(180,83,9,.15),0 8px 28px rgba(180,83,9,.2)}
.ppkg-icon{font-size:1.6rem;margin-bottom:6px;display:block;
filter:drop-shadow(0 2px 8px rgba(0,0,0,.3))}
.ppkg-c{
font-size:1.8rem;font-weight:700;
background:linear-gradient(135deg,#fdba74,#fb923c);
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;
line-height:1;margin-bottom:2px}
.ppkg.pop .ppkg-c{
background:linear-gradient(135deg,#fde68a,#fbbf24);
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.ppkg-u{font-size:.65rem;color:rgba(255,255,255,.4);text-transform:uppercase;letter-spacing:.08em;margin-bottom:8px}
.ppkg-p{
font-size:.78rem;font-weight:700;
background:rgba(255,255,255,.08);border-radius:6px;
padding:4px 8px;color:rgba(255,255,255,.7);display:inline-block}
.ppkg.pop .ppkg-p{background:rgba(251,191,36,.12);color:#fbbf24}
/* selected badge */
.ppkg.sel .ppkg-c{background:linear-gradient(135deg,#fdba74,#fb923c);
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
/* pinfo */
.pinfo{
margin:14px 22px 0;padding:10px 14px;
background:rgba(234,88,12,.1);border:1px solid rgba(234,88,12,.2);
border-radius:10px;font-size:.78rem;color:#fdba74;
text-align:center;min-height:36px;display:flex;align-items:center;justify-content:center;
font-weight:600}
/* payment info box */
.pkbz{
margin:14px 22px 0;
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
border-radius:14px;padding:14px;overflow:hidden;position:relative}
.pkbz::before{
content:'';position:absolute;top:0;left:0;right:0;height:1px;
background:linear-gradient(90deg,transparent,rgba(234,88,12,.35),transparent)}
.pkbz-t{
font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;
color:rgba(255,255,255,.35);margin-bottom:10px;display:flex;align-items:center;gap:6px}
.pkbz-t::after{content:'';flex:1;height:1px;background:rgba(255,255,255,.06)}
.pkbz-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}
.pkbz-row:last-child{margin-bottom:0}
.pkbz-lbl{font-size:.7rem;color:rgba(255,255,255,.35);font-weight:500}
.pkbz-val{font-size:.88rem;font-weight:700;color:rgba(255,255,255,.9)}
.pcopy{
background:rgba(234,88,12,.1);border:1px solid rgba(234,88,12,.25);
color:#fdba74;font-size:.65rem;padding:4px 10px;border-radius:6px;
cursor:pointer;font-family:var(--F);font-weight:700;transition:.2s}
.pcopy:hover{background:rgba(234,88,12,.22);border-color:rgba(253,186,116,.5);color:#fed7aa}
/* slip upload */
.pslip-label{
font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;
color:rgba(255,255,255,.4);margin:14px 22px 8px;display:block}
.pslip-drop{
margin:0 22px;border:1.5px dashed rgba(234,88,12,.28);border-radius:14px;
padding:24px 20px;text-align:center;cursor:pointer;transition:.25s;
position:relative;overflow:hidden;
background:rgba(234,88,12,.04)}
.pslip-drop:hover{border-color:rgba(253,186,116,.55);background:rgba(234,88,12,.09)}
.pslip-drop input{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.pslip-drop .pi{font-size:2rem;margin-bottom:8px;display:block;
filter:drop-shadow(0 2px 8px rgba(234,88,12,.4))}
.pslip-drop .pt{font-size:.75rem;color:rgba(255,255,255,.35);line-height:1.5}
.pslip-preview{width:100%;max-height:160px;object-fit:contain;border-radius:10px;display:none;margin-top:10px;
box-shadow:0 4px 20px rgba(0,0,0,.4)}
/* submit button */
.psubmit{
display:none;width:calc(100% - 44px);margin:16px 22px 0;
padding:15px;border:none;border-radius:14px;
background:linear-gradient(135deg,var(--orange),var(--primary));
background-size:200% auto;
color:#fff;font-family:var(--F);font-size:.92rem;font-weight:700;
cursor:pointer;transition:.3s;letter-spacing:.01em;
box-shadow:0 4px 24px rgba(194,65,12,.35)}
.psubmit.on{display:block}
.psubmit:hover:not(:disabled){
background-position:right center;
transform:translateY(-2px);box-shadow:0 8px 32px rgba(194,65,12,.5)}
.psubmit:disabled{opacity:.4;cursor:not-allowed;transform:none}
/* history tab */
.pmeth-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:9px;padding:16px 22px 0}
.pmeth{border:1px solid rgba(255,255,255,.08);border-radius:14px;padding:14px 8px 11px;
cursor:pointer;text-align:center;transition:.22s;background:rgba(255,255,255,.03)}
.pmeth:hover{border-color:rgba(234,88,12,.4);background:rgba(234,88,12,.08);transform:translateY(-2px)}
.pmeth.sel{border-color:#fdba74;background:rgba(234,88,12,.16);box-shadow:0 0 0 3px rgba(234,88,12,.12)}
.pmeth-icon{font-size:1.5rem;display:block;margin-bottom:6px;width:44px;height:44px;object-fit:contain;margin-left:auto;margin-right:auto;border-radius:10px}
.pmeth-name{font-size:.65rem;font-weight:700;color:rgba(255,255,255,.7);line-height:1.3}
.pmeth-sub{font-size:.6rem;color:rgba(255,255,255,.35);margin-top:2px}
.pinfo-box{margin:12px 22px 0;padding:12px 14px;background:rgba(255,255,255,.03);
border:1px solid rgba(255,255,255,.08);border-radius:13px}
.pinfo-row{display:flex;align-items:center;justify-content:space-between;padding:5px 0;
border-bottom:1px solid rgba(255,255,255,.04)}
.pinfo-row:last-child{border-bottom:none}
.pinfo-lbl{font-size:.69rem;color:rgba(255,255,255,.35);font-weight:500}
.pinfo-val{font-size:.86rem;font-weight:700;color:rgba(255,255,255,.88)}
.pcopy{background:rgba(234,88,12,.1);border:1px solid rgba(234,88,12,.22);
color:#fdba74;font-size:.62rem;padding:3px 9px;border-radius:6px;
cursor:pointer;font-family:var(--F);font-weight:700;transition:.2s}
.pcopy:hover{background:rgba(234,88,12,.24);color:#fed7aa}
.pstep-lbl{font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;
color:rgba(255,255,255,.3);padding:16px 22px 0;display:flex;align-items:center;gap:8px}
.pstep-lbl::after{content:'';flex:1;height:1px;background:rgba(255,255,255,.05)}
.pstep-num{width:18px;height:18px;border-radius:50%;background:rgba(234,88,12,.3);
color:#fdba74;font-size:.6rem;font-weight:800;display:inline-flex;align-items:center;justify-content:center}
.buy-now-btn{display:block;width:calc(100% - 44px);margin:14px 22px 0;
padding:14px;border:none;border-radius:14px;
background:linear-gradient(135deg,var(--orange),var(--primary));
color:#fff;font-family:var(--F);font-size:.9rem;font-weight:700;
cursor:pointer;transition:.3s;box-shadow:0 4px 20px rgba(194,65,12,.3)}
.buy-now-btn:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 8px 28px rgba(194,65,12,.45)}
.buy-now-btn:disabled{opacity:.35;cursor:not-allowed}
.pay-step{display:none}.pay-step.on{display:block}
.pback-btn{background:none;border:1px solid rgba(255,255,255,.1);color:rgba(255,255,255,.45);
font-size:.75rem;padding:6px 14px;border-radius:8px;cursor:pointer;font-family:var(--F);
margin:12px 22px 0;display:inline-flex;align-items:center;gap:6px;transition:.2s}
.pback-btn:hover{border-color:rgba(255,255,255,.22);color:rgba(255,255,255,.75)}
.ph-card{
background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.07);
border-radius:14px;padding:14px 16px;margin-bottom:9px;
animation:fadeIn .2s ease both}
.ph-top{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:8px}
.ph-coins{font-size:1.05rem;font-weight:700;
background:linear-gradient(135deg,#fdba74,#fb923c);
-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.ph-badge{font-size:.65rem;padding:4px 10px;border-radius:20px;font-weight:700;letter-spacing:.03em}
.ph-badge.pending{background:rgba(251,191,36,.12);color:#fbbf24;border:1px solid rgba(251,191,36,.25)}
.ph-badge.approved{background:rgba(21,128,61,.12);color:#4ade80;border:1px solid rgba(21,128,61,.25)}
.ph-badge.rejected{background:rgba(185,28,28,.12);color:#f87171;border:1px solid rgba(185,28,28,.25)}
.ph-meta{font-size:.69rem;color:rgba(255,255,255,.3)}
.ph-empty{text-align:center;padding:36px 0;color:rgba(255,255,255,.25);font-size:.85rem}
.ph-list-wrap{padding:0 22px}
/* ── PROFILE SETTINGS ── */
.pov2{display:none;position:fixed;inset:0;z-index:500;background:rgba(28,25,23,.5);backdrop-filter:blur(6px);align-items:flex-end;justify-content:center}
.pov2.on{display:flex}
.ps-sheet{position:relative;width:100%;max-width:500px;background:var(--cream);border-radius:24px 24px 0 0;max-height:92vh;overflow-y:auto;animation:slideUp .28s cubic-bezier(.34,1.1,.64,1);border-top:1px solid var(--border);box-shadow:0 -4px 40px rgba(0,0,0,.12)}
.ps-hdr{padding:20px 20px 0;position:sticky;top:0;background:var(--cream);z-index:2;border-bottom:1px solid var(--border);padding-bottom:14px}
.ps-hdr-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
.ps-hdr h3{font-size:1rem;font-weight:700;color:var(--text);font-family:var(--FS)}
.ps-close{width:28px;height:28px;border:1px solid var(--border);background:var(--cream);border-radius:7px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:.75rem;color:var(--muted);transition:.2s}
.ps-close:hover{border-color:var(--red);color:var(--red)}
.ps-av-row{display:flex;align-items:center;gap:12px;margin-bottom:14px}
.ps-av{width:48px;height:48px;border-radius:12px;background:linear-gradient(135deg,var(--orange),var(--primary));display:flex;align-items:center;justify-content:center;font-size:1.5rem}
.ps-dname{font-weight:700;font-size:.96rem;color:var(--text)}
.ps-role{font-size:.68rem;color:var(--muted);margin-top:2px;text-transform:uppercase;letter-spacing:.06em}
.ps-coins{font-size:.72rem;color:var(--orange);font-weight:700;margin-top:2px}
.ps-tabs{display:flex;gap:2px;background:var(--bg3);border-radius:9px;padding:3px;border:1px solid var(--border)}
.ps-tab{flex:1;padding:7px;border:none;background:transparent;font-family:var(--F);font-size:.74rem;font-weight:600;color:var(--muted);border-radius:6px;cursor:pointer;transition:.2s}
.ps-tab.on{background:var(--cream);color:var(--orange);box-shadow:0 1px 4px rgba(0,0,0,.08)}
.ps-body{padding:16px 20px 36px}
.ps-card{background:var(--bg3);border:1px solid var(--border);border-radius:12px;padding:14px;margin-bottom:10px}
.ps-label{font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin-bottom:10px;display:flex;align-items:center;gap:5px}
.ps-field{margin-bottom:10px}
.ps-field label{font-size:.65rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);display:block;margin-bottom:5px}
.ps-inp{width:100%;padding:9px 11px;background:var(--cream);border:1px solid var(--border);border-radius:8px;color:var(--text);font-family:var(--F);font-size:.83rem;outline:none;transition:.2s}
.ps-inp:focus{border-color:var(--orange);box-shadow:0 0 0 2px rgba(234,88,12,.08)}
.ps-btn{width:100%;padding:11px;background:linear-gradient(135deg,var(--orange),var(--primary));border:none;border-radius:9px;color:#fff;font-family:var(--F);font-size:.84rem;font-weight:700;cursor:pointer;transition:.2s;margin-top:4px;box-shadow:0 3px 12px rgba(194,65,12,.25)}
.ps-btn:hover{transform:translateY(-1px);box-shadow:0 6px 18px rgba(194,65,12,.3)}
.ps-msg{font-size:.76rem;padding:8px 10px;border-radius:7px;margin-top:6px;display:none}
.ps-stat{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:10px}
.ps-stat-box{background:var(--bg3);border:1px solid var(--border);border-radius:10px;padding:12px;text-align:center}
.ps-stat-v{font-size:1.3rem;font-weight:700;color:var(--orange)}
.ps-stat-l{font-size:.62rem;color:var(--muted);margin-top:2px;text-transform:uppercase;letter-spacing:.04em}
/* ── AI MODEL / ENGINE TABS ── */
.model-tabs{display:flex;gap:8px}
.model-tab{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;
padding:10px 8px;background:var(--bg3);border:1px solid var(--border);
border-radius:11px;cursor:pointer;transition:.2s;font-family:var(--F);position:relative}
.model-tab:hover{border-color:var(--orange);background:var(--amber)}
.model-tab.on{background:var(--amber);border-color:rgba(194,65,12,.4);
box-shadow:0 2px 10px rgba(194,65,12,.12)}
.model-tab.on::after{content:'✓';position:absolute;top:6px;right:8px;
font-size:.58rem;font-weight:700;color:var(--orange)}
.model-tab-icon{font-size:1.3rem;line-height:1}
.model-tab-name{font-size:.78rem;font-weight:700;color:var(--text)}
.model-tab.on .model-tab-name{color:var(--orange)}
.model-tab-sub{font-size:.6rem;color:var(--muted2);font-weight:500}
/* ── VOICE SCROLL CARDS ── */
.voice-scroll{display:flex;gap:8px;overflow-x:auto;padding-bottom:6px;
scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch}
.voice-scroll::-webkit-scrollbar{height:3px}
.voice-scroll::-webkit-scrollbar-track{background:var(--bg3);border-radius:2px}
.voice-scroll::-webkit-scrollbar-thumb{background:var(--border2);border-radius:2px}
.vc{flex:0 0 82px;scroll-snap-align:start;
background:var(--bg3);border:1px solid var(--border);border-radius:12px;
padding:10px 7px 8px;display:flex;flex-direction:column;align-items:center;gap:5px;
cursor:pointer;transition:.2s;position:relative;text-align:center}
.vc:hover{border-color:var(--orange);background:var(--amber);transform:translateY(-2px)}
.vc.sel{background:var(--amber);border-color:rgba(194,65,12,.5);
box-shadow:0 3px 12px rgba(194,65,12,.15)}
.vc.sel::after{content:'✓';position:absolute;top:5px;right:7px;
font-size:.58rem;font-weight:700;color:var(--orange)}
.vc-name{font-size:.72rem;font-weight:700;color:var(--text);line-height:1.3;
max-width:68px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vc.sel .vc-name{color:var(--orange)}
.vc-gender{font-size:.6rem;color:var(--muted2);font-weight:600;
text-transform:uppercase;letter-spacing:.04em}
.vc-play{width:26px;height:26px;border-radius:50%;
background:linear-gradient(135deg,var(--orange),var(--primary));
border:none;color:#fff;font-size:.62rem;cursor:pointer;
display:flex;align-items:center;justify-content:center;
box-shadow:0 2px 8px rgba(194,65,12,.3);transition:.2s;flex-shrink:0}
.vc-play:hover{transform:scale(1.12);box-shadow:0 4px 12px rgba(194,65,12,.4)}
/* ── EMOTION GRID ── */
.emotion-grid{display:flex;flex-wrap:wrap;gap:6px}
.emobtn{padding:6px 11px;background:var(--bg3);border:1px solid var(--border);
border-radius:20px;font-family:var(--F);font-size:.73rem;font-weight:600;
color:var(--muted);cursor:pointer;transition:.2s;white-space:nowrap}
.emobtn:hover{border-color:var(--orange);color:var(--orange);background:var(--amber)}
.emobtn.on{background:var(--amber);border-color:rgba(194,65,12,.4);color:var(--orange)}
.ps-tx{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)}
.ps-tx:last-child{border-bottom:none}
</style>
</head>
<body>
<!-- LOGIN -->
<div id="login-screen">
<!-- Animated floating orbs -->
<div style="position:absolute;width:300px;height:300px;border-radius:50%;background:radial-gradient(circle,rgba(234,88,12,.22),transparent);top:-80px;left:-80px;animation:floatOrb 8s ease-in-out infinite;pointer-events:none"></div>
<div style="position:absolute;width:250px;height:250px;border-radius:50%;background:radial-gradient(circle,rgba(180,83,9,.18),transparent);bottom:-60px;right:-60px;animation:floatOrb 10s ease-in-out infinite reverse;pointer-events:none"></div>
<div style="position:absolute;width:180px;height:180px;border-radius:50%;background:radial-gradient(circle,rgba(194,65,12,.14),transparent);top:40%;right:10%;animation:floatOrb 12s ease-in-out infinite .5s;pointer-events:none"></div>
<div class="lw">
<!-- Brand -->
<div class="lb">
<h1 style="font-size:2.1rem;background:linear-gradient(135deg,#fff 0%,rgba(253,186,116,.9) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text">Recap Studio</h1>
<p style="color:rgba(255,255,255,.5);font-size:.82rem;margin-top:6px;letter-spacing:.06em;text-transform:uppercase;font-weight:600">AI-Powered Video Recap Generator</p>
</div>
<!-- Panda character -->
<div class="panda-wrap">
<div class="panda">
<div class="ear ear-l"></div>
<div class="ear ear-r"></div>
<div class="head">
<div class="patch patch-l"></div>
<div class="patch patch-r"></div>
<div class="eye eye-l"><div class="pupil"></div></div>
<div class="eye eye-r"><div class="pupil"></div></div>
<div class="nose"></div>
<div class="mouth"></div>
<div class="blush blush-l"></div>
<div class="blush blush-r"></div>
</div>
<div class="arm arm-l"></div>
<div class="arm arm-r"></div>
</div>
</div>
<!-- Card -->
<div class="lc" style="position:relative;padding-top:32px">
<div class="tabs">
<button class="tab on" id="tab-li" onclick="stab('li')">Login</button>
<button class="tab" id="tab-re" onclick="stab('re')">Register</button>
</div>
<div id="pane-li">
<div class="fi">
<label>USERNAME</label>
<div style="position:relative">
<span style="position:absolute;left:13px;top:50%;transform:translateY(-50%);color:rgba(255,255,255,.35);font-size:.85rem"><i class="fas fa-user"></i></span>
<input class="inp" id="l-u" placeholder="your username" autocomplete="off" style="padding-left:36px">
</div>
</div>
<div class="fi">
<label>PASSWORD</label>
<div style="position:relative">
<span style="position:absolute;left:13px;top:50%;transform:translateY(-50%);color:rgba(255,255,255,.35);font-size:.85rem"><i class="fas fa-lock"></i></span>
<input class="inp" id="l-p" type="password" placeholder="••••••••" style="padding-left:36px">
</div>
</div>
<button class="bp" onclick="doLogin()" style="margin-top:8px;letter-spacing:.03em;font-size:.95rem">
Sign In &nbsp;<i class="fas fa-arrow-right" style="font-size:.8rem"></i>
</button>
<div id="google-wrap" style="display:none">
<div class="ldiv"><hr><span>or</span><hr></div>
<a href="/auth/google" class="gbtn">
<svg width="18" height="18" viewBox="0 0 48 48"><path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z"/><path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z"/><path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z"/><path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.18 1.48-4.97 2.29-8.16 2.29-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z"/></svg>
Continue with Google
</a>
</div>
</div>
<div id="pane-re" style="display:none">
<div style="background:rgba(255,255,255,.05);border:1px solid rgba(253,186,116,.15);border-radius:10px;padding:10px 12px;margin-bottom:12px;font-size:.73rem;color:rgba(255,255,255,.65);line-height:1.7">
<div style="font-weight:700;color:#fdba74;margin-bottom:5px">📋 Account ဖန်တီးရာမှာ သတိပြုရန်</div>
<div>• Username ကို Login ဝင်ရာတွင် သုံးမည် — မှတ်ထားပါ</div>
<div>• Nickname ကို အခြားသူများ မမြင်ရ — Profile တွင်သာ ပြသည်</div>
<div>• Password ကို 6 လုံးနှင့်အထက် ထည့်ပါ</div>
<div>• Username/Password ကို မည်သူ့ကိုမျှ မပြောပါနှင့်</div>
</div>
<div class="fi">
<label>USERNAME <span style="color:rgba(255,100,100,.8);font-size:.65rem">* လိုအပ်သည်</span></label>
<div style="position:relative">
<span style="position:absolute;left:13px;top:50%;transform:translateY(-50%);color:rgba(255,255,255,.35);font-size:.85rem"><i class="fas fa-user"></i></span>
<input class="inp" id="r-u" placeholder="username (English + numbers)" autocomplete="off" style="padding-left:36px">
</div>
<div style="font-size:.67rem;color:rgba(255,255,255,.35);margin-top:3px;padding-left:2px">Login ဝင်ရာမှာ သုံးမည် — သေချာထည့်ပါ</div>
</div>
<input type="hidden" id="r-nick" value="">
<div class="fi">
<label>PASSWORD <span style="color:rgba(255,100,100,.8);font-size:.65rem">* 6 လုံးနှင့်အထက်</span></label>
<div style="position:relative">
<span style="position:absolute;left:13px;top:50%;transform:translateY(-50%);color:rgba(255,255,255,.35);font-size:.85rem"><i class="fas fa-lock"></i></span>
<input class="inp" id="r-p" type="password" placeholder="••••••••" style="padding-left:36px">
</div>
</div>
<div class="fi">
<label>PASSWORD ထပ်ထည့်</label>
<div style="position:relative">
<span style="position:absolute;left:13px;top:50%;transform:translateY(-50%);color:rgba(255,255,255,.35);font-size:.85rem"><i class="fas fa-lock"></i></span>
<input class="inp" id="r-p2" type="password" placeholder="••••••••" style="padding-left:36px">
</div>
</div>
<button class="bp" onclick="doReg()" style="margin-top:8px;letter-spacing:.03em;font-size:.95rem">
Account ဖန်တီးမည် &nbsp;<i class="fas fa-arrow-right" style="font-size:.8rem"></i>
</button>
</div>
<div id="am" class="am"></div>
</div>
<!-- Panda bottom paws gripping the card -->
<div style="display:flex;justify-content:space-between;padding:0 28px;margin-top:-4px;position:relative;z-index:11">
<div style="width:34px;height:28px;background:#1a1a1a;border-radius:50%;position:relative">
<span style="position:absolute;width:10px;height:10px;background:#2a2a2a;border-radius:50%;top:-3px;left:2px"></span>
<span style="position:absolute;width:10px;height:10px;background:#2a2a2a;border-radius:50%;top:-3px;left:14px"></span>
<span style="position:absolute;width:10px;height:10px;background:#2a2a2a;border-radius:50%;top:-3px;right:2px"></span>
</div>
<div style="width:34px;height:28px;background:#1a1a1a;border-radius:50%;position:relative">
<span style="position:absolute;width:10px;height:10px;background:#2a2a2a;border-radius:50%;top:-3px;left:2px"></span>
<span style="position:absolute;width:10px;height:10px;background:#2a2a2a;border-radius:50%;top:-3px;left:14px"></span>
<span style="position:absolute;width:10px;height:10px;background:#2a2a2a;border-radius:50%;top:-3px;right:2px"></span>
</div>
</div>
<div class="lfoot">
<a href="/terms">Terms of Service</a> &nbsp;·&nbsp; <a href="/privacy">Privacy Policy</a>
</div>
</div>
</div>
<!-- APP -->
<div id="app-screen">
<header class="hdr">
<div class="brand"><div class="brand-i"><img src="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/logo.png" alt="Recap Studio" style="width:100%;height:100%;object-fit:contain;border-radius:8px"></div>Recap Studio</div>
<div class="hr">
<div class="cpill" id="cpill" onclick="openPay()">🪙 <span id="hcoins">0</span> coins</div>
<button class="hb hb-p" onclick="openPay()">Buy Coins</button>
<button class="mbtn" onclick="odw()"><span></span><span></span><span></span></button>
</div>
</header>
<!-- DRAWER -->
<div class="dov" id="dov">
<div class="dbg" onclick="cdw()"></div>
<div class="drw">
<div class="drw-h" style="cursor:pointer" onclick="cdw();openProfile()">
<div class="drw-u">
<div class="av" id="dav" style="overflow:hidden;position:relative">
<img id="dav-img" src="" style="display:none;width:100%;height:100%;object-fit:cover;border-radius:12px">
<span id="dav-init">U</span>
</div>
<div>
<div class="dn" id="dun"></div>
<div class="drl" id="drl">Member</div>
<div id="dav-coins" style="font-size:.68rem;color:var(--orange);font-weight:700;margin-top:1px">🪙 0 coins</div>
</div>
</div>
<button class="dxbtn" onclick="event.stopPropagation();cdw()"><i class="fas fa-times"></i></button>
</div>
<div class="drw-n">
<button class="dni" onclick="cdw()"><i class="fas fa-home"></i>Home</button>
<button class="dni" onclick="cdw();openVideoHistory()"><i class="fas fa-film"></i>Video History</button>
<button class="dni" onclick="cdw();openPay('his')"><i class="fas fa-receipt"></i>Order History</button>
<button class="dni" id="adm-dlink" style="display:none" onclick="scrollToAdmin();cdw()"><i class="fas fa-crown"></i>Admin Panel</button>
<a href="https://t.me/recapstudio" target="_blank" class="dni" style="text-decoration:none"><i class="fab fa-telegram" style="color:#29b6f6"></i>Telegram Channel</a>
<button class="dni" onclick="cdw();openProfile()"><i class="fas fa-user-circle"></i>Profile & Settings</button>
<button class="dni dni-r" onclick="doLogout()"><i class="fas fa-sign-out-alt"></i>Logout</button>
</div>
<div class="drw-f">recap.psonline.shop</div>
</div>
</div>
<!-- ══ HOME LAUNCHER ══ -->
<div id="section-home" style="display:none">
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;padding:18px 16px">
<div onclick="goSection('recap')" style="background:linear-gradient(135deg,#c2410c,#9a3409);border-radius:20px;padding:22px 14px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;cursor:pointer;position:relative;min-height:140px;box-shadow:0 4px 20px rgba(194,65,12,.3)">
<span style="position:absolute;top:10px;right:10px;font-size:.6rem;font-weight:700;padding:3px 8px;border-radius:20px;background:rgba(255,215,0,.2);color:#ffd700;border:1px solid rgba(255,215,0,.35)">👑 Premium</span>
<div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#fff"><i class="fas fa-film"></i></div>
<div style="font-size:.82rem;font-weight:700;color:#fff;letter-spacing:.06em;text-transform:uppercase">Movie Recap</div>
<div style="font-size:.67rem;color:rgba(255,255,255,.75);text-align:center">AI Video Recap ဖန်တီးပါ</div>
</div>
<div onclick="goSection('srt')" style="background:linear-gradient(135deg,#1d4ed8,#1e40af);border-radius:20px;padding:22px 14px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;cursor:pointer;position:relative;min-height:140px;box-shadow:0 4px 20px rgba(29,78,216,.25)">
<span style="position:absolute;top:10px;right:10px;font-size:.6rem;font-weight:700;padding:3px 8px;border-radius:20px;background:rgba(255,215,0,.2);color:#ffd700;border:1px solid rgba(255,215,0,.35)">👑 Premium</span>
<div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#fff"><i class="fas fa-closed-captioning"></i></div>
<div style="font-size:.82rem;font-weight:700;color:#fff;letter-spacing:.06em;text-transform:uppercase">Translate SRT</div>
<div style="font-size:.67rem;color:rgba(255,255,255,.75);text-align:center">Video မြန်မာဘာသာပြောင်းပါ</div>
</div>
<div onclick="goSection('dubbing')" style="background:linear-gradient(135deg,#0f766e,#0d9488);border-radius:20px;padding:22px 14px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;cursor:pointer;position:relative;min-height:140px;box-shadow:0 4px 20px rgba(15,118,110,.3)">
<span style="position:absolute;top:10px;right:10px;font-size:.6rem;font-weight:700;padding:3px 8px;border-radius:20px;background:rgba(255,215,0,.2);color:#ffd700;border:1px solid rgba(255,215,0,.35)">👑 Premium</span>
<div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#fff"><i class="fas fa-microphone"></i></div>
<div style="font-size:.82rem;font-weight:700;color:#fff;letter-spacing:.06em;text-transform:uppercase">AI Dubbing</div>
<div style="font-size:.67rem;color:rgba(255,255,255,.75);text-align:center">Video Voice ကို မြန်မာ Dub ပြောင်းပါ</div>
</div>
<div style="opacity:.5;pointer-events:none;background:linear-gradient(135deg,#6d28d9,var(--purple));border-radius:20px;padding:22px 14px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;position:relative;min-height:130px">
<span style="position:absolute;top:10px;right:10px;font-size:.6rem;font-weight:700;padding:3px 8px;border-radius:20px;background:rgba(255,255,255,.12);color:rgba(255,255,255,.65);border:1px solid rgba(255,255,255,.18)">Coming Soon</span>
<div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#fff"><i class="fas fa-book-open"></i></div>
<div style="font-size:.82rem;font-weight:700;color:#fff;letter-spacing:.06em;text-transform:uppercase">Story Creator</div>
</div>
<div style="opacity:.5;pointer-events:none;background:linear-gradient(135deg,#b45309,#d97706);border-radius:20px;padding:22px 14px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;position:relative;min-height:130px">
<span style="position:absolute;top:10px;right:10px;font-size:.6rem;font-weight:700;padding:3px 8px;border-radius:20px;background:rgba(255,255,255,.12);color:rgba(255,255,255,.65);border:1px solid rgba(255,255,255,.18)">Coming Soon</span>
<div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#fff"><i class="fas fa-image"></i></div>
<div style="font-size:.82rem;font-weight:700;color:#fff;letter-spacing:.06em;text-transform:uppercase">Thumbnail</div>
</div>
<div style="opacity:.5;pointer-events:none;background:linear-gradient(135deg,#15803d,#16a34a);border-radius:20px;padding:22px 14px 18px;display:flex;flex-direction:column;align-items:center;gap:10px;position:relative;min-height:130px">
<span style="position:absolute;top:10px;right:10px;font-size:.6rem;font-weight:700;padding:3px 8px;border-radius:20px;background:rgba(255,255,255,.12);color:rgba(255,255,255,.65);border:1px solid rgba(255,255,255,.18)">Coming Soon</span>
<div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;font-size:1.5rem;color:#fff"><i class="fas fa-language"></i></div>
<div style="font-size:.82rem;font-weight:700;color:#fff;letter-spacing:.06em;text-transform:uppercase">Translate</div>
</div>
</div>
</div>
<!-- MODE TOGGLE BAR -->
<div class="mode-bar" style="display:none"></div>
<!-- ══ MOVIE RECAP MODE ══ -->
<div id="section-recap" style="display:none">
<div style="padding:6px 14px 0">
<button onclick="goHome()" style="background:none;border:none;color:var(--orange);font-size:.82rem;font-weight:700;cursor:pointer;padding:4px 0;display:flex;align-items:center;gap:5px"><i class="fas fa-arrow-left"></i> Home</button>
</div>
<div class="ab">
<!-- VIDEO SOURCE -->
<div class="card">
<div class="ch"><div class="ci ci-p"><i class="fas fa-video"></i></div><div class="ct">Video Source</div></div>
<div class="uw">
<i class="fas fa-link uico"></i>
<input class="uinp" id="vurl" placeholder="Paste YouTube / TikTok / RedNote / Facebook / Instagram link…" oninput="onUrl(this.value)" style="padding-right:80px">
<span class="ubadge" id="ubadge"></span>
<button class="paste-btn" onclick="doPaste()" title="Paste from clipboard"><i class="fas fa-paste"></i> Paste</button>
</div>
<div class="prev-loading" id="prev-loading"><i class="fas fa-spinner sp"></i> Loading thumbnail…</div>
<div class="orsep">or upload file</div>
<div class="upz">
<input type="file" id="vfile" accept="video/*" onchange="onFile(this)">
<div class="upz-t"><i class="fas fa-cloud-upload-alt" style="margin-right:6px;font-size:1.1rem"></i>Click or drag video file here</div>
<div class="upz-n" id="upzn"></div>
</div>
</div>
<!-- SETTINGS -->
<div class="card">
<div class="ch"><div class="ci ci-o"><i class="fas fa-sliders-h"></i></div><div class="ct">Settings</div></div>
<!-- Row 1: Language + Content Type -->
<div class="sgrid" style="margin-bottom:10px">
<div class="si"><div class="sil">Language</div>
<select class="ssel" id="vlang" onchange="onLang()">
<option value="my">🇲🇲 Myanmar</option>
<option value="th">🇹🇭 Thai</option>
<option value="en">🇬🇧 English</option>
</select>
</div>
<div class="si"><div class="sil">Content Type</div>
<select class="ssel" id="ctype">
<option value="Movie Recap">🎬 Movie Recap</option>
<option value="Medical/Health">💊 Medical</option>
</select>
</div>
</div>
<!-- ── AI MODEL SECTION ── -->
<div style="margin-bottom:12px">
<div class="sil" style="margin-bottom:8px;display:flex;align-items:center;gap:6px">
<i class="fas fa-robot" style="color:var(--orange)"></i> AI Model
</div>
<div class="model-tabs" id="aimodel-tabs">
<button class="model-tab on" data-val="Gemini" onclick="pickAiModel('Gemini',this)">
<span class="model-tab-icon"></span>
<span class="model-tab-name">Gemini</span>
<span class="model-tab-sub">Google AI</span>
</button>
<button class="model-tab" data-val="DeepSeek" onclick="pickAiModel('DeepSeek',this)">
<span class="model-tab-icon">🤖</span>
<span class="model-tab-name">DeepSeek</span>
<span class="model-tab-sub">Fast & Smart</span>
</button>
</div>
<input type="hidden" id="aimodel" value="Gemini">
</div>
<!-- ── TTS ENGINE SECTION ── -->
<div style="margin-bottom:12px">
<div class="sil" style="margin-bottom:8px;display:flex;align-items:center;gap:6px">
<i class="fas fa-microphone-alt" style="color:var(--orange)"></i> Voice Engine
</div>
<div class="model-tabs" id="engine-tabs">
<button class="model-tab on" data-val="ms" onclick="pickEngine('ms',this)">
<span class="model-tab-icon">🎙️</span>
<span class="model-tab-name">Edge TTS</span>
<span class="model-tab-sub">Microsoft</span>
</button>
<button class="model-tab" data-val="gemini" onclick="pickEngine('gemini',this)">
<span class="model-tab-icon">🔮</span>
<span class="model-tab-name">Gemini TTS</span>
<span class="model-tab-sub">Google AI</span>
</button>
</div>
<input type="hidden" id="engine" value="ms">
</div>
<!-- ── VOICE CARDS ── -->
<div>
<div class="sil" style="margin-bottom:8px;display:flex;align-items:center;justify-content:space-between">
<span style="display:flex;align-items:center;gap:6px">
<i class="fas fa-user-circle" style="color:var(--orange)"></i> Voice
</span>
<button class="pvbtn" id="pvbtn" onclick="doPrevVoice()" title="Preview Voice" style="width:auto;padding:5px 11px;gap:5px;font-size:.72rem;font-weight:700">
<i class="fas fa-play"></i> Preview
</button>
</div>
<!-- Voice card scroll row -->
<div class="voice-scroll" id="voice-scroll">
<!-- populated by renderVoiceCards() -->
</div>
<input type="hidden" id="vsel" value="">
<!-- Gemini TTS Emotion (shown when engine=gemini) -->
<div id="emotion-wrap" style="display:none;margin-top:10px">
<div class="sil" style="margin-bottom:7px;display:flex;align-items:center;gap:6px">
<i class="fas fa-theater-masks" style="color:var(--orange)"></i> Voice Emotion
</div>
<div class="emotion-grid" id="emotion-grid">
<button class="emobtn on" data-val="" onclick="pickEmo('',this)">😐 Normal</button>
<button class="emobtn" data-val="[excitedly]" onclick="pickEmo('[excitedly]',this)">😊 Excited</button>
<button class="emobtn" data-val="[motivationally]" onclick="pickEmo('[motivationally]',this)">💪 Motivate</button>
<button class="emobtn" data-val="[sadly]" onclick="pickEmo('[sadly]',this)">😢 Sad</button>
<button class="emobtn" data-val="[whispers]" onclick="pickEmo('[whispers]',this)">🤫 Whisper</button>
<button class="emobtn" data-val="[shouting]" onclick="pickEmo('[shouting]',this)">📢 Shout</button>
<button class="emobtn" data-val="[storytelling]" onclick="pickEmo('[storytelling]',this)">📖 Story</button>
<button class="emobtn" data-val="[angrily]" onclick="pickEmo('[angrily]',this)">😠 Angry</button>
<button class="emobtn" data-val="[fearfully]" onclick="pickEmo('[fearfully]',this)">😨 Fear</button>
<button class="emobtn" data-val="[in a spooky horror voice]" onclick="pickEmo('[in a spooky horror voice]',this)">👻 Horror</button>
<button class="emobtn" data-val="[in a funny and playful voice]" onclick="pickEmo('[in a funny and playful voice]',this)">😂 Funny</button>
<button class="emobtn" data-val="[cheerfully]" onclick="pickEmo('[cheerfully]',this)">🌟 Cheer</button>
<button class="emobtn" data-val="[tenderly]" onclick="pickEmo('[tenderly]',this)">🥰 Tender</button>
<button class="emobtn" data-val="[mysteriously]" onclick="pickEmo('[mysteriously]',this)">🔮 Mystery</button>
<button class="emobtn" data-val="[sarcastically]" onclick="pickEmo('[sarcastically]',this)">😏 Sarcasm</button>
<button class="emobtn" data-val="[in a dramatic voice]" onclick="pickEmo('[in a dramatic voice]',this)">🎭 Drama</button>
</div>
<input type="hidden" id="tts-emotion" value="">
</div>
<!-- Speed (always visible) -->
<div style="margin-top:10px">
<button onclick="toggleAdvanced()" id="adv-btn" style="background:none;border:none;color:var(--muted);font-size:.72rem;font-weight:600;cursor:pointer;display:flex;align-items:center;gap:5px;padding:0;font-family:var(--F)">
<i class="fas fa-chevron-right" id="adv-icon" style="font-size:.6rem;transition:.2s"></i> Advanced
</button>
<div id="adv-wrap" style="display:none;margin-top:8px">
<div class="spd-row">
<label>Speed</label>
<input type="range" class="spd-sl" id="spd" min="-50" max="100" value="35" oninput="document.getElementById('spdv').textContent=this.value+'%'">
<span class="spd-v" id="spdv">35%</span>
</div>
</div>
</div>
</div>
</div>
<!-- VIDEO OPTIONS -->
<div class="card">
<div class="ch"><div class="ci ci-g"><i class="fas fa-film"></i></div><div class="ct">Video Options</div></div>
<div class="egrid" style="grid-template-columns:1fr 1fr;gap:8px">
<div class="ei"><div class="eil">Aspect Ratio</div>
<select class="esel" id="crop" onchange="syncCanvasInner(document.getElementById('pvid'));_filterSubSize();">
<option value="original" selected>Original</option>
<option value="9:16">9:16 TikTok</option>
<option value="16:9">16:9 YouTube</option>
<option value="1:1">1:1 Square</option>
</select>
</div>
<div class="ei"><div class="eil">Flip</div>
<button class="icon-toggle" id="btn-flip" onclick="toggleOpt('flip')"><i class="fas fa-arrows-alt-h"></i> Off</button>
</div>
<div class="ei"><div class="eil">Color Boost</div>
<button class="icon-toggle" id="btn-col" onclick="toggleOpt('col')"><i class="fas fa-adjust"></i> Off</button>
</div>
<div class="ei"><div class="eil">Background Music</div>
<button class="icon-toggle" id="btn-bgm" onclick="toggleBgm()"><i class="fas fa-music"></i> Off</button>
</div>
<div class="ei" style="grid-column:1/-1;padding:0;border:none;background:none">
<div id="bgm-wrap" style="display:none">
<label style="display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.05);border:1px dashed rgba(168,85,247,.3);border-radius:9px;padding:10px 12px;cursor:pointer">
<i class="fas fa-cloud-upload-alt" style="color:#a855f7;font-size:1.1rem"></i>
<span id="bgm-name" style="color:rgba(255,255,255,.5);font-size:.82rem">Click to upload MP3 / WAV</span>
<input type="file" id="bgm-file" accept=".mp3,.wav,audio/*" style="display:none" onchange="onBgmFile(this)">
</label>
</div>
</div>
<!-- Watermark moved to Canvas Overlay panel below -->
</div>
</div>
<!-- PREVIEW CANVAS + SUBTITLES -->
<div class="card" style="padding:0;overflow:hidden">
<div class="canvas-wrap" id="canvas-wrap" style="margin-top:0;border-radius:0">
<div class="canvas-bg-blur" id="canvas-bg-blur"></div>
<div class="canvas-video-wrap" id="canvas-video-wrap" style="position:relative">
<video id="pvid" controls playsinline style="display:none;width:100%;height:auto;display:block"></video>
<img id="pthumb" style="display:none;width:100%;height:auto;object-fit:cover;display:block" alt="thumbnail">
<div id="canvas-inner" class="canvas-inner" style="position:absolute;inset:0;pointer-events:none;z-index:10">
<div id="db-blur" style="display:none;position:absolute;left:20px;top:80px;width:160px;height:90px;pointer-events:auto;cursor:move;border:2px dashed rgba(255,100,100,.85);background:rgba(0,0,0,.25);border-radius:6px;box-sizing:border-box;touch-action:none">
<div style="position:absolute;top:2px;left:0;right:0;text-align:center;font-size:.58rem;font-weight:700;color:rgba(255,160,160,.9);letter-spacing:.05em;pointer-events:none;user-select:none">BLUR ZONE</div>
<div class="rh" style="position:absolute;right:0;bottom:0;width:18px;height:18px;cursor:se-resize;background:rgba(255,100,100,.6);border-radius:3px 0 4px 0;display:flex;align-items:center;justify-content:center">
<i class="fas fa-expand-arrows-alt" style="font-size:.5rem;color:#fff;pointer-events:none"></i>
</div>
</div>
<div id="db-wm" style="display:none;position:absolute;left:10px;bottom:40px;width:180px;height:36px;pointer-events:auto;cursor:move;border:2px dashed rgba(251,191,36,.85);background:rgba(0,0,0,.22);border-radius:6px;box-sizing:border-box;touch-action:none">
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none">
<span id="db-wm-txt" style="font-size:.8rem;font-weight:700;color:#fef9c3;text-shadow:0 1px 3px rgba(0,0,0,.9);white-space:nowrap;overflow:hidden;max-width:92%;pointer-events:none">Watermark</span>
</div>
<div class="rh" style="position:absolute;right:0;bottom:0;width:16px;height:16px;cursor:se-resize;background:rgba(251,191,36,.6);border-radius:3px 0 4px 0;display:flex;align-items:center;justify-content:center">
<i class="fas fa-expand-arrows-alt" style="font-size:.45rem;color:#fff;pointer-events:none"></i>
</div>
</div>
<div id="db-logo" style="display:none;position:absolute;right:10px;top:10px;width:72px;height:72px;pointer-events:auto;cursor:move;border:2px dashed rgba(52,211,153,.85);background:rgba(0,0,0,.22);border-radius:6px;box-sizing:border-box;touch-action:none;background-size:contain;background-repeat:no-repeat;background-position:center">
<div id="db-logo-lbl" style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;pointer-events:none">
<i class="fas fa-image" style="font-size:.9rem;color:rgba(52,211,153,.8)"></i>
<span style="font-size:.52rem;font-weight:700;color:rgba(52,211,153,.8)">LOGO</span>
</div>
<div class="rh" style="position:absolute;right:0;bottom:0;width:16px;height:16px;cursor:se-resize;background:rgba(52,211,153,.6);border-radius:3px 0 4px 0;display:flex;align-items:center;justify-content:center">
<i class="fas fa-expand-arrows-alt" style="font-size:.45rem;color:#fff;pointer-events:none"></i>
</div>
</div>
</div>
</div>
<div id="canvas-ph" class="canvas-ph"><i class="fas fa-film"></i><span>Preview appears after URL is pasted</span></div>
</div>
<!-- Canvas Overlay Controls panel -->
<div style="background:linear-gradient(135deg,#0e2233,#0a1f2e);padding:10px 12px">
<!-- Canvas Overlays Section -->
<div style="margin-bottom:2px">
<div style="font-size:.62rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#94a3b8;margin-bottom:8px;display:flex;align-items:center;gap:5px">
<i class="fas fa-layer-group" style="color:#a78bfa"></i>Canvas Overlays
</div>
<!-- 3-column toggle grid -->
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:10px">
<!-- Watermark card -->
<div style="background:rgba(251,191,36,.05);border:1.5px solid rgba(251,191,36,.18);border-radius:10px;padding:8px 6px;display:flex;flex-direction:column;align-items:center;gap:5px">
<div style="width:30px;height:30px;border-radius:8px;background:rgba(251,191,36,.12);display:flex;align-items:center;justify-content:center">
<i class="fas fa-stamp" style="color:rgba(251,191,36,.9);font-size:.85rem"></i>
</div>
<div style="font-size:.62rem;font-weight:700;color:rgba(251,191,36,.8);text-align:center">Watermark</div>
<button id="ov-wm" onclick="ovToggle('wm')" style="width:100%;padding:4px 0;font-size:.68rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(251,191,36,.35);background:rgba(251,191,36,.07);color:rgba(251,191,36,.8);cursor:pointer;transition:.2s">
Off
</button>
</div>
<!-- Logo card -->
<div style="background:rgba(52,211,153,.05);border:1.5px solid rgba(52,211,153,.18);border-radius:10px;padding:8px 6px;display:flex;flex-direction:column;align-items:center;gap:5px">
<div style="width:30px;height:30px;border-radius:8px;background:rgba(52,211,153,.12);display:flex;align-items:center;justify-content:center">
<i class="fas fa-image" style="color:rgba(52,211,153,.9);font-size:.85rem"></i>
</div>
<div style="font-size:.62rem;font-weight:700;color:rgba(52,211,153,.8);text-align:center">Logo</div>
<button id="ov-logo" onclick="ovToggle('logo')" style="width:100%;padding:4px 0;font-size:.68rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(52,211,153,.35);background:rgba(52,211,153,.07);color:rgba(52,211,153,.8);cursor:pointer;transition:.2s">
Off
</button>
</div>
<!-- Blur card -->
<div style="background:rgba(239,68,68,.04);border:1.5px solid rgba(252,165,165,.18);border-radius:10px;padding:8px 6px;display:flex;flex-direction:column;align-items:center;gap:5px">
<div style="width:30px;height:30px;border-radius:8px;background:rgba(239,68,68,.1);display:flex;align-items:center;justify-content:center">
<i class="fas fa-eraser" style="color:rgba(252,165,165,.9);font-size:.85rem"></i>
</div>
<div style="font-size:.62rem;font-weight:700;color:rgba(252,165,165,.8);text-align:center">Blur</div>
<button id="ov-blur" onclick="ovToggle('blur')" style="width:100%;padding:4px 0;font-size:.68rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(252,165,165,.35);background:rgba(239,68,68,.07);color:rgba(252,165,165,.8);cursor:pointer;transition:.2s">
Off
</button>
</div>
</div>
<!-- Watermark panel -->
<div id="ov-wm-wrap" style="display:none;margin-bottom:8px;padding:10px 12px;background:rgba(251,191,36,.05);border:1px solid rgba(251,191,36,.22);border-radius:10px">
<div style="font-size:.58rem;font-weight:700;color:rgba(251,191,36,.7);letter-spacing:.06em;text-transform:uppercase;margin-bottom:6px">
<i class="fas fa-stamp" style="margin-right:4px"></i>Watermark Text
</div>
<input id="wm-text2" class="winp" placeholder="@YourPage သို့မဟုတ် Recap Studio" maxlength="40"
oninput="document.getElementById('db-wm-txt').textContent=this.value||'Watermark'"
style="width:100%;font-size:.8rem;background:rgba(255,255,255,.06);border-color:rgba(251,191,36,.3);color:#fef9c3;box-sizing:border-box">
<div style="font-size:.6rem;color:rgba(251,191,36,.4);margin-top:5px;display:flex;align-items:center;gap:4px">
<i class="fas fa-hand-pointer"></i>Preview canvas ပေါ်မှာ drag ပြီး position ချိန်ပါ
</div>
</div>
<!-- Logo panel -->
<div id="ov-logo-wrap" style="display:none;margin-bottom:8px;padding:10px 12px;background:rgba(52,211,153,.05);border:1px solid rgba(52,211,153,.22);border-radius:10px">
<div style="font-size:.58rem;font-weight:700;color:rgba(52,211,153,.7);letter-spacing:.06em;text-transform:uppercase;margin-bottom:6px">
<i class="fas fa-image" style="margin-right:4px"></i>Logo Image
</div>
<label style="display:flex;align-items:center;gap:8px;background:rgba(255,255,255,.04);border:1px dashed rgba(52,211,153,.3);border-radius:8px;padding:8px 10px;cursor:pointer;transition:.2s">
<i class="fas fa-cloud-upload-alt" style="color:rgba(52,211,153,.7);font-size:1rem"></i>
<span id="logo-name" style="color:rgba(52,211,153,.55);font-size:.78rem;flex:1">Click to upload PNG / JPG</span>
<input type="file" id="logo-file2" accept="image/*" style="display:none" onchange="onLogoFile(this)">
</label>
<div style="font-size:.6rem;color:rgba(52,211,153,.4);margin-top:5px;display:flex;align-items:center;gap:4px">
<i class="fas fa-hand-pointer"></i>Canvas ပေါ်မှာ drag / resize ပြီး position ချိန်ပါ
</div>
</div>
<!-- Blur hint panel -->
<div id="ov-blur-hint" style="display:none;margin-bottom:8px;padding:10px 12px;background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.2);border-radius:10px">
<div style="font-size:.6rem;color:rgba(252,165,165,.7);display:flex;align-items:center;gap:5px">
<i class="fas fa-hand-pointer"></i>Preview canvas ပေါ်မှာ blur zone ကို drag နှင့် resize လုပ်ပါ
</div>
</div>
</div>
<!-- Divider -->
<div style="height:1px;background:rgba(255,255,255,.07);margin:6px 0 8px"></div>
<!-- Row 2: Subtitle toggle -->
<div>
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:6px">
<div style="font-size:.65rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#38bdf8;display:flex;align-items:center;gap:5px">
<i class="fas fa-closed-captioning"></i>Subtitles (Auto)
</div>
<button class="wm-toggle" id="btn-sub" onclick="toggleSub()" style="border-color:#38bdf8;background:rgba(56,189,248,.08);color:#38bdf8;padding:3px 12px;font-size:.72rem">Off</button>
</div>
<div id="sub-wrap" style="display:none;margin-top:8px">
<div style="padding:6px 9px;background:rgba(56,189,248,.08);border:1px solid rgba(56,189,248,.2);border-radius:7px;font-size:.7rem;color:#7dd3fc;margin-bottom:8px">
<i class="fas fa-info-circle" style="margin-right:4px"></i>9:16 ratio အတွက် <b>Small</b> font size ကိုသာ သုံးပါ။ ဝါကျရှည်တွေကို 3 ကြောင်း ခွဲပြသည်။
</div>
<div style="padding:5px 9px;background:rgba(56,189,248,.05);border:1px solid rgba(56,189,248,.15);border-radius:7px;font-size:.68rem;color:rgba(56,189,248,.7);margin-bottom:8px;display:flex;align-items:center;gap:5px">
<i class="fas fa-hand-pointer"></i>Preview canvas ပေါ်တွင် subtitle box ကို <b>drag</b> (ရွှေ့) နှင့် <b>resize</b> (အရွယ်ချိန်) လုပ်နိုင်သည်
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:6px;margin-bottom:8px">
<div>
<div style="font-size:.58rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:rgba(56,189,248,.6);margin-bottom:3px">Font Size</div>
<select class="esel" id="sub-size" style="color:#e0f2fe;background:rgba(255,255,255,.06);border:1px solid rgba(56,189,248,.2);border-radius:6px;padding:4px 6px;width:100%;font-size:.75rem">
<option value="0.0350">XSmall</option>
<option value="0.0469" selected>Small</option>
<option value="0.0625">Medium</option>
<option value="0.0781">Large</option>
</select>
</div>
<div>
<div style="font-size:.58rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:rgba(56,189,248,.6);margin-bottom:3px">Color</div>
<select class="esel" id="sub-color" style="color:#e0f2fe;background:rgba(255,255,255,.06);border:1px solid rgba(56,189,248,.2);border-radius:6px;padding:4px 6px;width:100%;font-size:.75rem">
<option value="white" selected>⬜ White</option>
<option value="yellow">🟡 Yellow</option>
<option value="cyan">🔵 Cyan</option>
<option value="green">🟢 Green</option>
<option value="orange">🟠 Orange</option>
<option value="pink">🩷 Pink</option>
<option value="red">🔴 Red</option>
<option value="lime">💚 Lime</option>
<option value="hotpink">💗 Hot Pink</option>
<option value="gold">✨ Gold</option>
<option value="violet">💜 Violet</option>
<option value="deepskyblue">🩵 Sky Blue</option>
<option value="coral">🪸 Coral</option>
</select>
</div>
<div>
<div style="font-size:.58rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:rgba(56,189,248,.6);margin-bottom:3px">Style</div>
<select class="esel" id="sub-style" style="color:#e0f2fe;background:rgba(255,255,255,.06);border:1px solid rgba(56,189,248,.2);border-radius:6px;padding:4px 6px;width:100%;font-size:.75rem">
<option value="outline" selected>Outline</option>
<option value="box">Box</option>
<option value="shadow">Shadow</option>
<option value="glow">Glow</option>
<option value="stroke">Stroke</option>
<option value="plain">Plain</option>
</select>
</div>
</div>
<div>
<input type="hidden" id="sub-pos" value="85">
<div style="display:flex;align-items:center;gap:7px;padding:7px 10px;background:rgba(239,68,68,.07);border:1px solid rgba(239,68,68,.25);border-radius:7px;margin-top:2px">
<i class="fas fa-object-group" style="color:rgba(252,165,165,.8);font-size:.85rem;flex-shrink:0"></i>
<span style="font-size:.68rem;color:rgba(252,165,165,.85);line-height:1.4">Subtitle position ကို <b style="color:#fca5a5">Blur Box</b> center မှ အလိုအလျောက် ယူမည်</span>
</div>
</div>
</div>
</div><!-- /subtitle hidden -->
</div>
</div>
<!-- AUTO PROCESS -->
<div style="margin-bottom:12px">
<button class="btn-auto" id="btnauto" onclick="doAuto()">
<i class="fas fa-magic"></i> Auto Process
<span style="opacity:.7;font-size:.78em;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px">1 Coin</span>
</button>
</div>
<!-- PROGRESS -->
<div class="pc" id="pc">
<div class="ph"><span class="ptit">⚙️ Processing…</span><span class="ptmr" id="ptmr">⏱ 0s</span></div>
<div class="pb-bg"><div class="pb" id="pb"></div></div>
<div class="pmsg" id="pmsg">Starting…</div>
<div class="psteps">
<span class="ps" id="ps-dl">📥 Download</span>
<span class="ps" id="ps-tr">🎙️ Transcribe</span>
<span class="ps" id="ps-ai">🤖 AI Script</span>
<span class="ps" id="ps-ts">🔊 TTS</span>
<span class="ps" id="ps-vd">🎬 Render</span>
</div>
</div>
<!-- LIVE OUTPUTS -->
<div id="live-outputs" style="display:none;flex-direction:column;gap:8px;margin-top:8px">
<!-- Transcript -->
<div id="out-transcript" style="display:none;background:rgba(99,102,241,.07);border:1px solid rgba(99,102,241,.25);border-radius:12px;overflow:hidden">
<div onclick="toggleOut('transcript')" style="display:flex;align-items:center;justify-content:space-between;padding:9px 12px;cursor:pointer;user-select:none">
<span style="font-size:.72rem;font-weight:700;color:#a5b4fc;display:flex;align-items:center;gap:6px"><i class="fas fa-microphone-alt"></i> Whisper Transcript <span id="out-tr-lang" style="font-size:.62rem;opacity:.7"></span></span>
<i class="fas fa-chevron-down" id="out-tr-chv" style="color:#a5b4fc;font-size:.65rem;transition:.2s"></i>
</div>
<div id="out-tr-body" style="padding:0 12px 10px;display:none">
<div id="out-tr-text" style="font-size:.75rem;color:#cbd5e1;line-height:1.6;max-height:120px;overflow-y:auto;white-space:pre-wrap;background:rgba(0,0,0,.2);border-radius:8px;padding:8px 10px"></div>
</div>
</div>
<!-- AI Script -->
<div id="out-script" style="display:none;background:rgba(16,185,129,.07);border:1px solid rgba(16,185,129,.25);border-radius:12px;overflow:hidden">
<div onclick="toggleOut('script')" style="display:flex;align-items:center;justify-content:space-between;padding:9px 12px;cursor:pointer;user-select:none">
<span style="font-size:.72rem;font-weight:700;color:#6ee7b7;display:flex;align-items:center;gap:6px"><i class="fas fa-robot"></i> AI Script (Myanmar)</span>
<i class="fas fa-chevron-down" id="out-sc-chv" style="color:#6ee7b7;font-size:.65rem;transition:.2s"></i>
</div>
<div id="out-sc-body" style="padding:0 12px 10px;display:none">
<div id="out-sc-text" style="font-size:.75rem;color:#cbd5e1;line-height:1.7;max-height:150px;overflow-y:auto;white-space:pre-wrap;background:rgba(0,0,0,.2);border-radius:8px;padding:8px 10px;font-family:'NotoSansMyanmar',sans-serif"></div>
</div>
</div>
<!-- TTS Audio -->
<div id="out-tts" style="display:none;background:rgba(245,158,11,.07);border:1px solid rgba(245,158,11,.25);border-radius:12px;overflow:hidden">
<div onclick="toggleOut('tts')" style="display:flex;align-items:center;justify-content:space-between;padding:9px 12px;cursor:pointer;user-select:none">
<span style="font-size:.72rem;font-weight:700;color:#fcd34d;display:flex;align-items:center;gap:6px"><i class="fas fa-volume-up"></i> TTS Audio Preview</span>
<i class="fas fa-chevron-down" id="out-tts-chv" style="color:#fcd34d;font-size:.65rem;transition:.2s"></i>
</div>
<div id="out-tts-body" style="padding:0 12px 10px;display:none">
<audio id="out-tts-audio" controls style="width:100%;border-radius:8px;accent-color:#f59e0b"></audio>
</div>
</div>
</div>
<!-- RESULT -->
<div class="rc" id="rc">
<div class="rvw"><video id="rvid" controls playsinline></video></div>
<div class="rb">
<div class="rtm" id="rtm" style="display:none"><i class="fas fa-clock"></i><span></span></div>
<div class="rtit" id="rtit" style="display:none"></div>
<div class="rtag" id="rtag" style="display:none"></div>
<div class="ract">
<button class="rb-btn rb-g" onclick="dlVideo()"><i class="fas fa-download"></i> Download MP4</button>
<button class="rb-btn rb-b" onclick="copyCap()"><i class="fas fa-copy"></i> Copy Caption</button>
</div>
<!-- Re-render button -->
<button id="rr-toggle-btn" onclick="toggleRrPanel()"
style="width:100%;margin-top:10px;padding:10px;border-radius:9px;border:1.5px dashed rgba(234,88,12,.5);background:rgba(234,88,12,.06);color:var(--orange);font-family:var(--F);font-size:.78rem;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:7px;transition:.2s">
<i class="fas fa-redo"></i> Re-render (FREE)
<i class="fas fa-chevron-down" id="rr-chv" style="font-size:.6rem;transition:.2s;margin-left:auto"></i>
</button>
<!-- Re-render Panel -->
<div id="rr-panel" style="display:none;margin-top:10px;padding:12px;background:var(--bg3);border-radius:10px;border:1px solid var(--border)">
<div style="font-size:.62rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin-bottom:10px;display:flex;align-items:center;gap:5px">
<i class="fas fa-sliders-h" style="color:var(--orange)"></i>Re-render Settings
</div>
<!-- TTS Silent Remover only -->
<div style="padding:10px;background:rgba(0,0,0,.12);border-radius:8px;margin-bottom:10px;border:1px solid rgba(255,255,255,.06)">
<div style="font-size:.6rem;font-weight:700;color:var(--muted2);text-transform:uppercase;letter-spacing:.06em;margin-bottom:10px;display:flex;align-items:center;gap:5px">
<i class="fas fa-cut" style="color:#f59e0b"></i> TTS Silent Remover
</div>
<!-- Trailing Pad -->
<div style="margin-bottom:10px">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
<span style="font-size:.7rem;font-weight:600;color:var(--muted)">Trailing Pad <span style="font-weight:400;color:var(--muted2)">(နောက်ဆုံး အသံ ကျန်ချိန်)</span></span>
<span id="rr-pad-v" style="font-size:.72rem;font-weight:700;color:#38bdf8">0.10s</span>
</div>
<input type="range" class="spd-sl" id="rr-pad" min="0" max="10" step="0.1" value="0.1"
oninput="document.getElementById('rr-pad-v').textContent=parseFloat(this.value).toFixed(2)+'s'">
</div>
<!-- Crossfade -->
<div>
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px">
<span style="font-size:.7rem;font-weight:600;color:var(--muted)">Crossfade <span style="font-weight:400;color:var(--muted2)">(ကြားထပ် ပေါင်းချိန်)</span></span>
<span id="rr-cf-v" style="font-size:.72rem;font-weight:700;color:#38bdf8">0.50s</span>
</div>
<input type="range" class="spd-sl" id="rr-cf" min="0.1" max="1.0" step="0.05" value="0.5"
oninput="document.getElementById('rr-cf-v').textContent=parseFloat(this.value).toFixed(2)+'s'">
</div>
</div>
<div id="rr-msg" style="display:none;font-size:.75rem;padding:7px 10px;border-radius:7px;margin-bottom:8px"></div>
<button id="rr-btn" onclick="doRerender()"
style="width:100%;padding:11px;border-radius:9px;border:none;background:linear-gradient(135deg,#ea580c,#c2410c);color:#fff;font-family:var(--F);font-size:.82rem;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;box-shadow:0 4px 16px rgba(194,65,12,.35)">
<i class="fas fa-redo"></i> ပြန် Render လုပ်မည် (FREE)
</button>
</div>
</div>
</div>
<!-- ADMIN -->
<div class="admp" id="admp">
<div class="ch"><div class="ci ci-p"><i class="fas fa-crown"></i></div><div class="ct">Admin Panel</div><span class="admbadge">Admin</span></div>
<div class="admg">
<div><div class="sil" style="margin-bottom:5px">Add Coins</div>
<div class="ai-row"><input class="ai" id="au-add" placeholder="username"><input class="ai" id="an-add" type="number" placeholder="n" style="width:60px"><button class="abtn ab-g" onclick="admCoins('add')">Add</button></div>
</div>
<div><div class="sil" style="margin-bottom:5px">Set Coins</div>
<div class="ai-row"><input class="ai" id="au-set" placeholder="username"><input class="ai" id="an-set" type="number" placeholder="n" style="width:60px"><button class="abtn ab-g" onclick="admCoins('set')">Set</button></div>
</div>
<div><div class="sil" style="margin-bottom:5px">Create User</div>
<div class="ai-row"><input class="ai" id="au-new" placeholder="name (blank=auto)"><button class="abtn ab-g" onclick="admCreate()">Create</button></div>
<div id="au-res" style="font-size:.71rem;color:var(--green);margin-top:3px;font-weight:600"></div>
</div>
<div><div class="sil" style="margin-bottom:5px">Delete User</div>
<div class="ai-row"><input class="ai" id="au-del" placeholder="username"><button class="abtn ab-r" onclick="admDel()">Delete</button></div>
</div>
</div>
<div id="admmsg" class="admmsg"></div>
<div style="display:flex;gap:8px;margin-top:8px;flex-wrap:wrap">
<button class="adm-act-btn" onclick="loadUsers()"><i class="fas fa-users"></i> Users</button>
<button class="adm-act-btn" style="background:rgba(239,68,68,.1);border-color:rgba(239,68,68,.3);color:#ef4444" onclick="loadPendingPayments()"><i class="fas fa-clock"></i> Pending Payments <span id="adm-pending-count" style="background:#ef4444;color:#fff;border-radius:20px;padding:1px 7px;font-size:.62rem;margin-left:4px;display:none">0</span></button>
<button class="adm-act-btn" style="background:rgba(99,102,241,.1);border-color:rgba(99,102,241,.3);color:#6366f1" onclick="openBroadcast()"><i class="fas fa-bullhorn"></i> Broadcast</button>
</div>
<div id="utw" style="overflow-x:auto;margin-top:8px"></div>
<!-- Pending Payments -->
<div id="adm-pending-wrap" style="display:none;margin-top:10px">
<div style="font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;justify-content:space-between">
<span>💰 Pending Payments</span>
<button onclick="loadPendingPayments()" style="background:none;border:none;color:var(--primary);font-size:.75rem;cursor:pointer;font-family:var(--F);font-weight:600"><i class="fas fa-sync-alt"></i> Refresh</button>
</div>
<div id="adm-pending-list"></div>
</div>
</div>
</div>
</div><!-- /section-recap -->
<!-- ══ AI DUBBING MODE ══ -->
<div id="section-dubbing" style="display:none">
<div style="padding:6px 14px 0">
<button onclick="goHome()" style="background:none;border:none;color:var(--orange);font-size:.82rem;font-weight:700;cursor:pointer;padding:4px 0;display:flex;align-items:center;gap:5px"><i class="fas fa-arrow-left"></i> Home</button>
</div>
<div class="ab">
<!-- ══ STEP 1: VIDEO INPUT ══ -->
<div class="card" style="padding:0;overflow:hidden" id="dub-step1-card">
<div style="padding:10px 14px 0;display:flex;align-items:center;gap:8px">
<div style="width:22px;height:22px;border-radius:50%;background:linear-gradient(135deg,#0f766e,#0d9488);display:flex;align-items:center;justify-content:center;font-size:.7rem;font-weight:800;color:#fff;flex-shrink:0">1</div>
<span style="font-size:.78rem;font-weight:700;color:var(--text)">Video ထည့်ပါ</span>
</div>
<div style="padding:8px 12px 0">
<div class="uw">
<i class="fas fa-link uico"></i>
<input class="uinp" id="dub-vurl" placeholder="YouTube / TikTok / Facebook URL…" oninput="onDubUrl(this.value)" style="padding-right:80px">
<span class="ubadge" id="dub-ubadge"></span>
<button class="paste-btn" onclick="dubPaste()"><i class="fas fa-paste"></i> Paste</button>
</div>
<div class="orsep" style="margin:6px 0">or upload file</div>
<div class="upz" style="margin-bottom:8px">
<input type="file" id="dub-vfile" accept="video/*" onchange="onDubVFile(this)">
<div class="upz-t"><i class="fas fa-cloud-upload-alt" style="margin-right:6px;font-size:1.1rem"></i>Click or drag video file here</div>
<div class="upz-n" id="dub-upzn"></div>
</div>
</div>
<div style="padding:6px 12px 0">
<div style="font-size:.68rem;color:var(--muted2);line-height:1.5;background:rgba(15,118,110,.08);border:1px solid rgba(15,118,110,.2);border-radius:8px;padding:8px 10px">
🎙️ <b>AI Dubbing</b> — မူရင်း video ရဲ့ speaker voice ကို ဖျက်ပြီး မြန်မာ dub voice နဲ့ အစားထိုးပေးမယ်။ Original timing အတိုင်း sentence တစ်ခုချင်းစီကို sync လုပ်ပေးပါတယ်။ Background music ပါရင် ဖျက်သွားနိုင်ပါတယ်။
</div>
</div>
<div style="padding:10px 12px 12px">
<button class="btn-auto" id="dub-gen-btn" onclick="doDubProcess()" style="background:linear-gradient(135deg,#0f766e,#0d9488)">
<i class="fas fa-microphone"></i> AI Dubbing စတင်ပါ
<span style="opacity:.7;font-size:.78em;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px">1 Coin</span>
</button>
</div>
</div>
<!-- Progress -->
<div class="pc" id="dub-pc" style="display:none">
<div class="ph"><span class="ptit">🎙️ AI Dubbing လုပ်နေသည်…</span><span class="ptmr" id="dub-ptmr">⏱ 0s</span></div>
<div class="pb-bg"><div class="pb" id="dub-pb"></div></div>
<div class="pmsg" id="dub-pmsg">Starting…</div>
<div class="psteps">
<span class="ps" id="dub-ps-dl">📥 Download</span>
<span class="ps" id="dub-ps-tr">🎙️ Transcript</span>
<span class="ps" id="dub-ps-tts">🔊 Dubbing</span>
<span class="ps" id="dub-ps-render">🎬 Render</span>
</div>
</div>
<!-- Result -->
<div class="rc" id="dub-rc" style="display:none">
<div class="rvw"><video id="dub-rvid" controls playsinline></video></div>
<div class="rb">
<div class="ract">
<button class="rb-btn rb-g" onclick="dubDlVideo()"><i class="fas fa-download"></i> Download MP4</button>
<button class="rb-btn" style="background:var(--bg);border:1.5px solid var(--border);color:var(--text)" onclick="dubReset()"><i class="fas fa-redo"></i> Reset</button>
</div>
</div>
</div>
</div><!-- /ab -->
</div><!-- /section-dubbing -->
<!-- ══ TRANSLATE SRT MODE ══ -->
<div id="section-srt" style="display:none">
<div style="padding:6px 14px 0">
<button onclick="goHome()" style="background:none;border:none;color:var(--orange);font-size:.82rem;font-weight:700;cursor:pointer;padding:4px 0;display:flex;align-items:center;gap:5px"><i class="fas fa-arrow-left"></i> Home</button>
</div>
<div class="ab">
<!-- ══ STEP 1: VIDEO INPUT ══ -->
<div class="card" style="padding:0;overflow:hidden" id="srt-step1-card">
<!-- Step label -->
<div style="padding:10px 14px 0;display:flex;align-items:center;gap:8px">
<div style="width:22px;height:22px;border-radius:50%;background:linear-gradient(135deg,var(--purple),var(--purple));display:flex;align-items:center;justify-content:center;font-size:.7rem;font-weight:800;color:#fff;flex-shrink:0">1</div>
<span style="font-size:.78rem;font-weight:700;color:var(--text)">Video ထည့်ပါ</span>
</div>
<!-- URL input -->
<div style="padding:8px 12px 0">
<div class="uw">
<i class="fas fa-link uico"></i>
<input class="uinp" id="srt-vurl" placeholder="YouTube / TikTok / XHS / Facebook URL…" oninput="onSrtUrl(this.value)" style="padding-right:80px">
<span class="ubadge" id="srt-ubadge"></span>
<button class="paste-btn" onclick="srtPaste()"><i class="fas fa-paste"></i> Paste</button>
</div>
<div class="prev-loading" id="srt-prev-loading" style="display:none"><i class="fas fa-spinner sp"></i> Loading…</div>
<div class="orsep" style="margin:6px 0">or upload file</div>
<div class="upz" style="margin-bottom:8px">
<input type="file" id="srt-vfile" accept="video/*" onchange="onSrtVFile(this)">
<div class="upz-t"><i class="fas fa-cloud-upload-alt" style="margin-right:6px;font-size:1.1rem"></i>Click or drag video file here</div>
<div class="upz-n" id="srt-upzn"></div>
</div>
</div>
<!-- Generate SRT button -->
<div style="padding:10px 12px 12px">
<button class="btn-auto" id="srt-gen-btn" onclick="doGenerateSrt()" style="background:linear-gradient(135deg,var(--purple),var(--purple))">
<i class="fas fa-robot"></i> Generate Myanmar SRT
<span style="opacity:.7;font-size:.78em;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px">1 Coin</span>
</button>
</div>
</div>
<!-- Generate progress -->
<div class="pc" id="srt-gen-pc" style="display:none">
<div class="ph"><span class="ptit">🤖 SRT ထုတ်နေသည်…</span><span class="ptmr" id="srt-gen-ptmr">⏱ 0s</span></div>
<div class="pb-bg"><div class="pb" id="srt-gen-pb"></div></div>
<div class="pmsg" id="srt-gen-pmsg">Starting…</div>
<div class="psteps">
<span class="ps" id="srt-ps-dl">📥 Download</span>
<span class="ps" id="srt-ps-ai">🤖 Gemini SRT</span>
</div>
</div>
<!-- ══ STEP 2: SRT PREVIEW + SETTINGS ══ -->
<div id="srt-step2-wrap" style="display:none">
<!-- Step label -->
<div style="display:flex;align-items:center;gap:8px;padding:4px 4px 0">
<div style="width:22px;height:22px;border-radius:50%;background:linear-gradient(135deg,#0ea5e9,#6366f1);display:flex;align-items:center;justify-content:center;font-size:.7rem;font-weight:800;color:#fff;flex-shrink:0">2</div>
<span style="font-size:.78rem;font-weight:700;color:var(--text)">SRT စစ်ဆေးပြီး Render လုပ်ပါ</span>
</div>
<!-- SRT Preview card -->
<div class="card" style="padding:12px">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px">
<div style="font-size:.65rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#94a3b8;display:flex;align-items:center;gap:5px">
<i class="fas fa-closed-captioning" style="color:#a78bfa"></i>Myanmar SRT Preview
<span id="srt-block-count" style="background:rgba(167,139,250,.15);color:#a78bfa;border-radius:10px;padding:1px 7px;font-size:.62rem"></span>
</div>
<button onclick="doRegenSrt()" style="padding:5px 10px;background:rgba(251,191,36,.1);border:1px solid rgba(251,191,36,.3);border-radius:7px;color:#fbbf24;font-family:var(--F);font-size:.7rem;font-weight:700;cursor:pointer;display:flex;align-items:center;gap:4px;transition:.2s">
<i class="fas fa-redo"></i> Regenerate
</button>
</div>
<!-- First subtitle shown on thumbnail -->
<div id="srt-first-sub-wrap" style="display:none;margin-bottom:8px;padding:7px 10px;background:rgba(167,139,250,.08);border:1px solid rgba(167,139,250,.2);border-radius:8px">
<div style="font-size:.58rem;font-weight:700;color:var(--orange);text-transform:uppercase;letter-spacing:.06em;margin-bottom:3px">First Subtitle</div>
<div id="srt-first-sub-txt" style="font-size:.82rem;color:#e0f2fe;font-weight:500"></div>
</div>
<!-- SRT scrollable preview -->
<div class="srt-preview" id="srt-preview-box" style="max-height:180px"></div>
</div>
<!-- PROCESS button -->
<div style="margin-bottom:12px;margin-top:4px">
<button class="btn-auto" id="srt-burn-btn" onclick="doProcessSrt()" style="background:linear-gradient(135deg,#0ea5e9,#6366f1)">
<i class="fas fa-film"></i> Render Video
</button>
</div>
<!-- Render progress -->
<div class="pc" id="srt-pc" style="display:none">
<div class="ph"><span class="ptit">⚙️ Render လုပ်နေသည်…</span><span class="ptmr" id="srt-ptmr">⏱ 0s</span></div>
<div class="pb-bg"><div class="pb" id="srt-pb"></div></div>
<div class="pmsg" id="srt-pmsg">Starting…</div>
<div class="psteps">
<span class="ps" id="srt-ps-burn">🎬 Render</span>
</div>
</div>
<!-- VIDEO RESULT -->
<div class="rc" id="srt-rc" style="display:none">
<div class="rvw"><video id="srt-rvid" controls playsinline></video></div>
<div class="rb">
<div class="ract">
<button class="rb-btn rb-g" onclick="srtDlVideo()"><i class="fas fa-download"></i> Download MP4</button>
<button class="rb-btn" style="background:var(--bg);border:1.5px solid var(--border);color:var(--text)" onclick="srtReset()"><i class="fas fa-redo"></i> Reset</button>
</div>
</div>
</div>
</div><!-- /step2-wrap -->
<!-- VIDEO FX OVERLAYS — exact movie recap style canvas drag/resize -->
<div class="card" style="padding:0;overflow:hidden">
<!-- Canvas preview with draggable overlays -->
<div class="canvas-wrap" id="srt-canvas-wrap" style="margin-top:0;border-radius:0;position:relative">
<div class="canvas-bg-blur" id="srt-canvas-bg-blur"></div>
<div class="canvas-video-wrap" id="srt-canvas-video-wrap" style="position:relative;min-height:130px;border-radius:10px;overflow:hidden">
<video id="srt-pvid" controls playsinline style="width:100%;height:auto;max-height:480px;object-fit:contain;display:none"></video>
<img id="srt-pthumb" style="display:none;width:100%;height:auto;object-fit:cover;display:block;border-radius:10px;transition:transform .3s ease" alt="">
<!-- Draggable overlay elements -->
<div id="srt-canvas-inner" class="canvas-inner" style="position:absolute;inset:0;pointer-events:none;z-index:10">
<!-- Blur zone -->
<div id="srt-db-blur" style="display:none;position:absolute;left:20px;top:80px;width:160px;height:90px;pointer-events:auto;cursor:move;border:2px dashed rgba(255,100,100,.85);background:rgba(0,0,0,.25);border-radius:6px;box-sizing:border-box;touch-action:none">
<div style="position:absolute;top:2px;left:0;right:0;text-align:center;font-size:.58rem;font-weight:700;color:rgba(255,160,160,.9);letter-spacing:.05em;pointer-events:none;user-select:none">BLUR ZONE</div>
<div class="rh" style="position:absolute;right:0;bottom:0;width:18px;height:18px;cursor:se-resize;background:rgba(255,100,100,.6);border-radius:3px 0 4px 0;display:flex;align-items:center;justify-content:center">
<i class="fas fa-expand-arrows-alt" style="font-size:.5rem;color:#fff;pointer-events:none"></i>
</div>
</div>
<!-- Watermark -->
<div id="srt-db-wm" style="display:none;position:absolute;left:10px;bottom:40px;width:180px;height:36px;pointer-events:auto;cursor:move;border:2px dashed rgba(251,191,36,.85);background:rgba(0,0,0,.22);border-radius:6px;box-sizing:border-box;touch-action:none">
<div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;pointer-events:none">
<span id="srt-db-wm-txt" style="font-size:.8rem;font-weight:700;color:#fef9c3;text-shadow:0 1px 3px rgba(0,0,0,.9);white-space:nowrap;overflow:hidden;max-width:92%;pointer-events:none">Watermark</span>
</div>
<div class="rh" style="position:absolute;right:0;bottom:0;width:16px;height:16px;cursor:se-resize;background:rgba(251,191,36,.6);border-radius:3px 0 4px 0;display:flex;align-items:center;justify-content:center">
<i class="fas fa-expand-arrows-alt" style="font-size:.45rem;color:#fff;pointer-events:none"></i>
</div>
</div>
<!-- Logo -->
<div id="srt-db-logo" style="display:none;position:absolute;right:10px;top:10px;width:72px;height:72px;pointer-events:auto;cursor:move;border:2px dashed rgba(52,211,153,.85);background:rgba(0,0,0,.22);border-radius:6px;box-sizing:border-box;touch-action:none;background-size:contain;background-repeat:no-repeat;background-position:center">
<div id="srt-db-logo-lbl" style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;pointer-events:none">
<i class="fas fa-image" style="font-size:.9rem;color:rgba(52,211,153,.8)"></i>
<span style="font-size:.52rem;font-weight:700;color:rgba(52,211,153,.8)">LOGO</span>
</div>
<div class="rh" style="position:absolute;right:0;bottom:0;width:16px;height:16px;cursor:se-resize;background:rgba(52,211,153,.6);border-radius:3px 0 4px 0;display:flex;align-items:center;justify-content:center">
<i class="fas fa-expand-arrows-alt" style="font-size:.45rem;color:#fff;pointer-events:none"></i>
</div>
</div>
<!-- Subtitle preview — movie recap db-sub style -->
<div id="srt-sub-overlay" style="display:none;position:absolute;left:4%;right:4%;pointer-events:none;border:2px dashed rgba(56,189,248,.7);border-radius:8px;background:rgba(0,180,255,.08);box-sizing:border-box;transition:top .15s">
<div style="display:flex;align-items:center;justify-content:center;gap:6px;padding:10px 8px;pointer-events:none">
<i class="fas fa-closed-captioning" style="color:rgba(56,189,248,.8);font-size:.75rem;flex-shrink:0"></i>
<span id="srt-sub-preview-span" style="font-size:.72rem;font-weight:600;color:rgba(56,189,248,.9);white-space:nowrap"> စာတန်းထိုး</span>
</div>
</div>
</div>
</div>
<div id="srt-canvas-ph" style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:130px;color:rgba(255,255,255,.3);font-size:.78rem;gap:6px">
<i class="fas fa-film" style="font-size:1.8rem;opacity:.4"></i>
<span>Preview appears after URL is pasted</span>
</div>
</div>
<!-- Overlay Controls panel — exact movie recap style -->
<div style="background:linear-gradient(135deg,#0e2233,#0a1f2e);padding:10px 12px">
<!-- Subtitle Position slider — top of controls -->
<div style="margin-bottom:10px">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:3px">
<div style="font-size:.58rem;font-weight:700;text-transform:uppercase;color:#64748b">Subtitle Position</div>
<span id="srt-sub-pos-lbl" style="font-size:.68rem;font-weight:700;color:#38bdf8">90%</span>
</div>
<input type="range" id="srt-sub-pos" min="5" max="95" value="90"
oninput="document.getElementById('srt-sub-pos-lbl').textContent=this.value+'%';syncSrtSubPreview()"
style="width:100%;accent-color:#38bdf8;cursor:pointer">
</div>
<!-- Divider -->
<div style="height:1px;background:rgba(255,255,255,.07);margin:0 0 10px"></div>
<!-- CANVAS OVERLAYS: 4-col grid: Watermark | Logo | Blur | Gentle Zoom -->
<div style="font-size:.62rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#94a3b8;margin-bottom:8px;display:flex;align-items:center;gap:5px">
<i class="fas fa-layer-group" style="color:#a78bfa"></i>Canvas Overlays
</div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr 1fr;gap:5px;margin-bottom:10px">
<!-- Watermark -->
<div style="background:rgba(251,191,36,.05);border:1.5px solid rgba(251,191,36,.18);border-radius:10px;padding:8px 4px;display:flex;flex-direction:column;align-items:center;gap:4px">
<div style="width:26px;height:26px;border-radius:7px;background:rgba(251,191,36,.12);display:flex;align-items:center;justify-content:center">
<i class="fas fa-stamp" style="color:rgba(251,191,36,.9);font-size:.8rem"></i>
</div>
<div style="font-size:.58rem;font-weight:700;color:rgba(251,191,36,.8);text-align:center">Watermark</div>
<button id="srt-ov-wm" onclick="srtOvToggle('wm')" style="width:100%;padding:3px 0;font-size:.62rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(251,191,36,.35);background:rgba(251,191,36,.07);color:rgba(251,191,36,.8);cursor:pointer;transition:.2s">Off</button>
</div>
<!-- Logo -->
<div style="background:rgba(52,211,153,.05);border:1.5px solid rgba(52,211,153,.18);border-radius:10px;padding:8px 4px;display:flex;flex-direction:column;align-items:center;gap:4px">
<div style="width:26px;height:26px;border-radius:7px;background:rgba(52,211,153,.12);display:flex;align-items:center;justify-content:center">
<i class="fas fa-image" style="color:rgba(52,211,153,.9);font-size:.8rem"></i>
</div>
<div style="font-size:.58rem;font-weight:700;color:rgba(52,211,153,.8);text-align:center">Logo</div>
<button id="srt-ov-logo" onclick="srtOvToggle('logo')" style="width:100%;padding:3px 0;font-size:.62rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(52,211,153,.35);background:rgba(52,211,153,.07);color:rgba(52,211,153,.8);cursor:pointer;transition:.2s">Off</button>
</div>
<!-- Blur -->
<div style="background:rgba(239,68,68,.04);border:1.5px solid rgba(252,165,165,.18);border-radius:10px;padding:8px 4px;display:flex;flex-direction:column;align-items:center;gap:4px">
<div style="width:26px;height:26px;border-radius:7px;background:rgba(239,68,68,.1);display:flex;align-items:center;justify-content:center">
<i class="fas fa-eraser" style="color:rgba(252,165,165,.9);font-size:.8rem"></i>
</div>
<div style="font-size:.58rem;font-weight:700;color:rgba(252,165,165,.8);text-align:center">Blur</div>
<button id="srt-ov-blur" onclick="srtOvToggle('blur')" style="width:100%;padding:3px 0;font-size:.62rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(252,165,165,.35);background:rgba(239,68,68,.07);color:rgba(252,165,165,.8);cursor:pointer;transition:.2s">Off</button>
</div>
<!-- Gentle Zoom hidden -->
<div style="display:none;background:rgba(234,88,12,.05);border:1.5px solid rgba(234,88,12,.18);border-radius:10px;padding:8px 4px;flex-direction:column;align-items:center;gap:4px">
<div style="width:26px;height:26px;border-radius:7px;background:rgba(234,88,12,.12);display:flex;align-items:center;justify-content:center">
<i class="fas fa-search-plus" style="color:var(--orange);font-size:.8rem"></i>
</div>
<div style="font-size:.58rem;font-weight:700;color:var(--orange);text-align:center">G.Zoom</div>
<button id="srt-ov-zoom" onclick="srtOvToggle('zoom')" style="width:100%;padding:3px 0;font-size:.62rem;font-weight:700;font-family:var(--F);border-radius:6px;border:1.5px solid rgba(234,88,12,.35);background:rgba(234,88,12,.07);color:var(--orange);cursor:pointer;transition:.2s">Off</button>
</div>
</div>
<!-- Expandable panels -->
<!-- Watermark panel -->
<div id="srt-ov-wm-wrap" style="display:none;margin-bottom:8px;padding:10px 12px;background:rgba(251,191,36,.05);border:1px solid rgba(251,191,36,.22);border-radius:10px">
<div style="font-size:.58rem;font-weight:700;color:rgba(251,191,36,.7);letter-spacing:.06em;text-transform:uppercase;margin-bottom:6px">
<i class="fas fa-stamp" style="margin-right:4px"></i>Watermark Text
</div>
<input id="srt-wm-text" class="winp" placeholder="@YourPage သို့မဟုတ် Channel Name" maxlength="40"
oninput="document.getElementById('srt-db-wm-txt').textContent=this.value||'Watermark'"
style="width:100%;font-size:.8rem;background:rgba(255,255,255,.06);border-color:rgba(251,191,36,.3);color:#fef9c3;box-sizing:border-box">
<div style="font-size:.6rem;color:rgba(251,191,36,.4);margin-top:5px;display:flex;align-items:center;gap:4px">
<i class="fas fa-hand-pointer"></i>Preview canvas ပေါ်မှာ drag ပြီး position ချိန်ပါ
</div>
</div>
<!-- Logo panel -->
<div id="srt-ov-logo-wrap" style="display:none;margin-bottom:8px;padding:10px 12px;background:rgba(52,211,153,.05);border:1px solid rgba(52,211,153,.22);border-radius:10px">
<div style="font-size:.58rem;font-weight:700;color:rgba(52,211,153,.7);letter-spacing:.06em;text-transform:uppercase;margin-bottom:6px">
<i class="fas fa-image" style="margin-right:4px"></i>Logo Image
</div>
<label style="display:flex;align-items:center;gap:8px;background:rgba(255,255,255,.04);border:1px dashed rgba(52,211,153,.3);border-radius:8px;padding:8px 10px;cursor:pointer;transition:.2s">
<i class="fas fa-cloud-upload-alt" style="color:rgba(52,211,153,.7);font-size:1rem"></i>
<span id="srt-logo-name" style="color:rgba(52,211,153,.55);font-size:.78rem;flex:1">Click to upload PNG / JPG</span>
<input type="file" id="srt-logo-file" accept="image/*" style="display:none" onchange="onSrtLogoFile(this)">
</label>
<div style="font-size:.6rem;color:rgba(52,211,153,.4);margin-top:5px;display:flex;align-items:center;gap:4px">
<i class="fas fa-hand-pointer"></i>Canvas ပေါ်မှာ drag / resize ပြီး position ချိန်ပါ
</div>
</div>
<!-- Blur hint panel -->
<div id="srt-ov-blur-hint" style="display:none;margin-bottom:8px;padding:10px 12px;background:rgba(239,68,68,.04);border:1px solid rgba(239,68,68,.2);border-radius:10px">
<div style="font-size:.6rem;color:rgba(252,165,165,.7);display:flex;align-items:center;gap:5px">
<i class="fas fa-hand-pointer"></i>Preview canvas ပေါ်မှာ blur zone ကို drag နှင့် resize လုပ်ပါ
</div>
</div>
<!-- Zoom slider removed (now always visible below) -->
<!-- Divider -->
<div style="height:1px;background:rgba(255,255,255,.07);margin:4px 0 8px"></div>
<!-- Flip | Color | Audio Boost — 3 buttons below canvas overlays, above subtitle settings -->
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:5px;margin-bottom:8px">
<button id="srt-btn-flip" onclick="srtToggleOpt('flip')" style="padding:6px 2px;font-size:.68rem;font-weight:700;font-family:var(--F);border-radius:7px;border:1.5px solid rgba(255,255,255,.12);background:rgba(255,255,255,.05);color:rgba(255,255,255,.55);cursor:pointer;transition:.2s"><i class="fas fa-arrows-alt-h"></i> Flip</button>
<button id="srt-btn-col" onclick="srtToggleOpt('col')" style="padding:6px 2px;font-size:.68rem;font-weight:700;font-family:var(--F);border-radius:7px;border:1.5px solid rgba(255,255,255,.12);background:rgba(255,255,255,.05);color:rgba(255,255,255,.55);cursor:pointer;transition:.2s"><i class="fas fa-adjust"></i> Color</button>
<button id="srt-ov-audio" onclick="srtOvToggle('audio')" style="padding:6px 2px;font-size:.68rem;font-weight:700;font-family:var(--F);border-radius:7px;border:1.5px solid rgba(59,130,246,.35);background:rgba(59,130,246,.07);color:rgba(96,165,250,.8);cursor:pointer;transition:.2s"><i class="fas fa-volume-up"></i> Audio</button>
</div>
<!-- Divider -->
<div style="height:1px;background:rgba(255,255,255,.07);margin:4px 0 8px"></div>
<!-- Zoom Factor slider hidden -->
<!-- SUBTITLE SETTINGS label -->
<div style="font-size:.62rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:#94a3b8;margin-bottom:8px;display:flex;align-items:center;gap:5px">
<i class="fas fa-closed-captioning" style="color:#60a5fa"></i>Subtitle Settings
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px">
<div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:7px 9px">
<div style="font-size:.58rem;font-weight:700;text-transform:uppercase;color:#64748b;margin-bottom:4px">Color</div>
<select id="srt-sub-color" onchange="syncSrtSubPreview()" style="width:100%;background:transparent;border:none;color:#e0f2fe;font-family:var(--F);font-size:.78rem;font-weight:500;outline:none;cursor:pointer">
<option value="white" selected>⬜ White</option>
<option value="yellow">🟡 Yellow</option>
<option value="cyan">🔵 Cyan</option>
<option value="green">🟢 Green</option>
<option value="orange">🟠 Orange</option>
<option value="pink">🩷 Pink</option>
<option value="red">🔴 Red</option>
<option value="lime">💚 Lime</option>
<option value="hotpink">💗 Hot Pink</option>
<option value="gold">✨ Gold</option>
<option value="violet">💜 Violet</option>
<option value="deepskyblue">🩵 Sky Blue</option>
<option value="coral">🪸 Coral</option>
</select>
</div>
<div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:7px 9px">
<div style="font-size:.58rem;font-weight:700;text-transform:uppercase;color:#64748b;margin-bottom:4px">Font Size</div>
<select id="srt-sub-size" onchange="syncSrtSubPreview()" style="width:100%;background:transparent;border:none;color:#e0f2fe;font-family:var(--F);font-size:.78rem;font-weight:500;outline:none;cursor:pointer">
<option value="0.0350">XSmall</option>
<option value="0.0469" selected>Small</option>
<option value="0.0625">Medium</option>
<option value="0.0781">Large</option>
</select>
</div>
<div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:7px 9px">
<div style="font-size:.58rem;font-weight:700;text-transform:uppercase;color:#64748b;margin-bottom:4px">Style</div>
<select id="srt-sub-style" onchange="syncSrtSubPreview()" style="width:100%;background:transparent;border:none;color:#e0f2fe;font-family:var(--F);font-size:.78rem;font-weight:500;outline:none;cursor:pointer">
<option value="outline" selected>Outline</option>
<option value="box">Box</option>
<option value="shadow">Shadow</option>
<option value="glow">Glow</option>
<option value="stroke">Stroke</option>
<option value="plain">Plain</option>
</select>
</div>
<div style="background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:8px;padding:7px 9px">
<div style="font-size:.58rem;font-weight:700;text-transform:uppercase;color:#64748b;margin-bottom:4px">Aspect Ratio</div>
<select id="srt-crop" onchange="onSrtCropChange()" style="width:100%;background:transparent;border:none;color:#e0f2fe;font-family:var(--F);font-size:.78rem;font-weight:500;outline:none;cursor:pointer">
<option value="original" selected>Original</option>
<option value="9:16">9:16</option>
<option value="16:9">16:9</option>
<option value="1:1">1:1</option>
</select>
</div>
</div>
</div><!-- /overlay controls panel -->
</div><!-- /canvas card -->
</div><!-- /ab -->
</div><!-- /section-srt -->
</div><!-- /app-screen -->
<div id="toast"></div>
<audio id="pva"></audio>
<script>
/* ══ STATE ══ */
let U='',COINS=0,ISADM=false;
let OUT_URL='',OUT_CAP='',OUT_TAGS='';
let SSE=null,TICK=null,T0=0,COIN_POLL=null;
let FLIP_ON=false,COL_ON=false,BGM_ON=false,SUB_ON=false;
function toggleAdvanced(){
const w=document.getElementById('adv-wrap');
const ic=document.getElementById('adv-icon');
const open=w.style.display==='none';
w.style.display=open?'block':'none';
ic.style.transform=open?'rotate(90deg)':'rotate(0deg)';
}
function toggleSub(){
SUB_ON=!SUB_ON;
const btn=document.getElementById('btn-sub');
const wrap=document.getElementById('sub-wrap');
btn.textContent=SUB_ON?'On':'Off';
btn.className='wm-toggle'+(SUB_ON?' on':'');
btn.style.borderColor=SUB_ON?'#38bdf8':'';
wrap.style.display=SUB_ON?'block':'none';
}
// sub_pos = blur box center-Y as % of the CROPPED OUTPUT frame height.
// Backend _make_ass places subtitle at (pos_y = play_h * sub_pos/100).
//
// The crop filter uses letterbox/pillarbox (scale to fit, blurred bg fills rest).
// So we must convert blur box center from original-video-% to cropped-frame-%.
//
// For letterbox case (landscape src → portrait crop):
// scaled video height = tw * srcH/srcW (scale to fit width tw)
// offset Y in output = (th - scaledH) / 2
// subtitle Y in output = offsetY + (blurCenterY_pct * scaledH)
//
// For pillarbox case (portrait src → landscape crop):
// scaled video width = th * srcW/srcH
// offset X in output = (tw - scaledW) / 2
// Y is fully preserved: subtitle Y in output = blurCenterY_pct * th
//
// For original or same-ratio: subtitle Y = blurCenterY_pct * th (no change)
function _getSubPosFromBlur(){
if(BLUR_ON){
try{
const video=document.getElementById('pvid');
const srcW=video.videoWidth||1280, srcH=video.videoHeight||720;
const crop=document.getElementById('crop').value;
const ci=document.getElementById('canvas-inner');
const el=document.getElementById('db-blur');
const ciR=ci.getBoundingClientRect();
const elR=el.getBoundingClientRect();
// Blur box center as fraction of canvas-inner (= fraction of original video)
const blurCY = ((elR.top - ciR.top) + elR.height / 2) / ciR.height;
// Target crop output dimensions
let tw, th;
if(crop==='9:16'){tw=720;th=1280;}
else if(crop==='16:9'){tw=1280;th=720;}
else if(crop==='1:1'){tw=720;th=720;}
else{ // original — no crop, 1:1 mapping
return Math.round(Math.max(5, Math.min(95, blurCY * 100)));
}
const srcRatio = srcW / srcH;
const tgtRatio = tw / th;
let outputY; // subtitle center Y in cropped output pixels
if(Math.abs(srcRatio - tgtRatio) < 0.05){
// Same ratio — direct mapping
outputY = blurCY * th;
} else if(srcRatio > tgtRatio){
// Pillarbox: scale to fit height → Y preserved, X has side bars
// scaledH = th, scaledW = th * srcRatio
// Y in output = blurCY * th
outputY = blurCY * th;
} else {
// Letterbox: scale to fit width → scaledW = tw, scaledH = tw/srcRatio
const scaledH = tw / srcRatio;
const offsetY = (th - scaledH) / 2;
outputY = offsetY + blurCY * scaledH;
}
return Math.round(Math.max(5, Math.min(95, outputY / th * 100)));
}catch(e){}
}
return parseInt((document.getElementById('sub-pos')||{value:85}).value)||85;
}
let CACHE_KEY='';
let URL_DEBOUNCE=null;
const OV={sub:{on:false}}; // Only subtitles
const EV={
my:[
{id:'my-MM-ThihaNeural', name:'Thiha (Male)'},
{id:'my-MM-NilarNeural', name:'Nilar (Female)'},
{id:'fr-FR-RemyMultilingualNeural', name:'Remy (Male)'},
// ── Multilingual Neural (support Myanmar & all languages) ──
{id:'en-US-AndrewMultilingualNeural', name:'Andrew (Male)'},
{id:'en-US-AvaMultilingualNeural', name:'Ava (Female)'},
{id:'en-US-BrianMultilingualNeural', name:'Brian (Male)'},
{id:'en-US-EmmaMultilingualNeural', name:'Emma (Female)'},
{id:'en-US-JennyMultilingualNeural', name:'Jenny (Female)'},
{id:'en-US-RyanMultilingualNeural', name:'Ryan (Male)'},
{id:'zh-CN-XiaoxiaoMultilingualNeural', name:'Xiaoxiao (Female)'},
{id:'zh-CN-YunxiMultilingualNeural', name:'Yunxi (Male)'},
{id:'de-DE-FlorianMultilingualNeural', name:'Florian (Male)'},
{id:'de-DE-SeraphinaMultilingualNeural',name:'Seraphina (Female)'},
{id:'fr-FR-VivienneMultilingualNeural', name:'Vivienne (Female)'}
],
th:[
{id:'th-TH-NiwatNeural', name:'Niwat (Male)'},
{id:'th-TH-PremwadeeNeural', name:'Premwadee (Female)'},
{id:'th-TH-AcharaNeural', name:'Achara (Female)'},
// ── Multilingual Neural (support Thai & all languages) ──
{id:'en-US-AndrewMultilingualNeural', name:'Andrew (Male)'},
{id:'en-US-AvaMultilingualNeural', name:'Ava (Female)'},
{id:'en-US-BrianMultilingualNeural', name:'Brian (Male)'},
{id:'en-US-EmmaMultilingualNeural', name:'Emma (Female)'},
{id:'en-US-JennyMultilingualNeural', name:'Jenny (Female)'},
{id:'en-US-RyanMultilingualNeural', name:'Ryan (Male)'},
{id:'zh-CN-XiaoxiaoMultilingualNeural', name:'Xiaoxiao (Female)'},
{id:'zh-CN-YunxiMultilingualNeural', name:'Yunxi (Male)'},
{id:'de-DE-FlorianMultilingualNeural', name:'Florian (Male)'},
{id:'de-DE-SeraphinaMultilingualNeural',name:'Seraphina (Female)'},
{id:'fr-FR-RemyMultilingualNeural', name:'Remy (Male)'},
{id:'fr-FR-VivienneMultilingualNeural', name:'Vivienne (Female)'}
],
en:[
{id:'en-US-GuyNeural', name:'Guy – US (Male)'},
{id:'en-US-JennyNeural', name:'Jenny – US (Female)'},
{id:'en-US-AriaNeural', name:'Aria – US (Female)'},
{id:'en-US-DavisNeural', name:'Davis – US (Male)'},
{id:'en-US-JasonNeural', name:'Jason – US (Male)'},
{id:'en-US-SaraNeural', name:'Sara – US (Female)'},
{id:'en-US-TonyNeural', name:'Tony – US (Male)'},
{id:'en-US-AndrewNeural', name:'Andrew – US (Male)'},
{id:'en-US-EmmaNeural', name:'Emma – US (Female)'},
{id:'en-GB-RyanNeural', name:'Ryan – GB (Male)'},
{id:'en-GB-SoniaNeural', name:'Sonia – GB (Female)'},
{id:'en-GB-LibbyNeural', name:'Libby – GB (Female)'},
{id:'en-AU-NatashaNeural', name:'Natasha – AU (Female)'},
{id:'en-AU-WilliamNeural', name:'William – AU (Male)'},
{id:'en-IN-NeerjaNeural', name:'Neerja – IN (Female)'},
{id:'en-IN-PrabhatNeural', name:'Prabhat – IN (Male)'},
// ── Multilingual Neural (all-language support) ──
{id:'en-US-AndrewMultilingualNeural', name:'Andrew (Male)'},
{id:'en-US-AvaMultilingualNeural', name:'Ava (Female)'},
{id:'en-US-BrianMultilingualNeural', name:'Brian (Male)'},
{id:'en-US-EmmaMultilingualNeural', name:'Emma (Female)'},
{id:'en-US-JennyMultilingualNeural', name:'Jenny (Female)'},
{id:'en-US-RyanMultilingualNeural', name:'Ryan (Male)'},
{id:'zh-CN-XiaoxiaoMultilingualNeural', name:'Xiaoxiao (Female)'},
{id:'zh-CN-YunxiMultilingualNeural', name:'Yunxi (Male)'},
{id:'de-DE-FlorianMultilingualNeural', name:'Florian (Male)'},
{id:'de-DE-SeraphinaMultilingualNeural',name:'Seraphina (Female)'},
{id:'fr-FR-RemyMultilingualNeural', name:'Remy (Male)'},
{id:'fr-FR-VivienneMultilingualNeural', name:'Vivienne (Female)'}
]
};
let GV=[];
/* ══ INIT ══ */
addEventListener('DOMContentLoaded',()=>{
// Google button visibility
fetch('/api/auth/google_enabled').then(r=>r.json()).then(d=>{
if(d.enabled) document.getElementById('google-wrap').style.display='block';
}).catch(()=>{});
// Enter key on login
document.addEventListener('keydown',e=>{
if(e.key==='Enter'&&document.getElementById('login-screen').style.display!=='none'){
if(document.getElementById('pane-li').style.display!=='none') doLogin();
else doReg();
}
});
// Google OAuth callback
const sp=new URLSearchParams(location.search);
if(sp.get('auth')==='google'){
const u=sp.get('u'),n=sp.get('n'),c=parseInt(sp.get('c')||'0'),a=sp.get('a')==='1';
if(u){
sessionStorage.setItem('recap_user',JSON.stringify({u,coins:c,is_admin:a,name:n}));
history.replaceState({},'','/');
eApp(u,c,a,n); return;
}
} else if(sp.get('auth_error')){
history.replaceState({},'','/');
sam('❌ Google login failed: '+sp.get('auth_error'),false);
}
// Session restore
const saved=sessionStorage.getItem('recap_user');
if(saved){try{const s=JSON.parse(saved);eApp(s.u,s.coins,s.is_admin,s.name);return;}catch{}}
renderV();
window.addEventListener('resize',()=>{const v=document.getElementById('pvid');if(v.src&&v.videoWidth)syncCanvasInner(v);});
fetch('/api/gemini_voices').then(r=>r.ok?r.json():null).then(d=>{if(d?.ok){GV=d.voices;if(document.getElementById('engine').value==='gemini')renderV();}}).catch(()=>{});
initDrag();
initSrtDrag();
});
/* ══ LOGIN ══ */
function stab(t){['li','re'].forEach(x=>{document.getElementById('tab-'+x).classList.toggle('on',x===t);document.getElementById('pane-'+x).style.display=x===t?'':'none';});document.getElementById('am').style.display='none';if(t==='re')setTimeout(regenNick,50);}
function sam(msg,ok){const e=document.getElementById('am');e.textContent=msg;e.className='am '+(ok?'am-ok':'am-err');e.style.display='block';}
async function doLogin(){
const u=document.getElementById('l-u').value.trim(),p=document.getElementById('l-p').value;
if(!u){sam('❌ Username required',false);return;}
const btn=document.querySelector('#pane-li .bp');
if(btn){btn.disabled=true;btn.textContent='⏳ နေပါ...';}
try{
const r=await fetch('/api/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:u,password:p})});
const d=await r.json();
if(d.ok){
sessionStorage.setItem('recap_user',JSON.stringify({u,coins:d.coins,is_admin:d.is_admin}));
eApp(u,d.coins,d.is_admin);
} else {
sam(d.msg||'❌ Login failed',false);
if(btn){btn.disabled=false;btn.textContent='Login';}
}
} catch{
sam('❌ Connection error',false);
if(btn){btn.disabled=false;btn.textContent='Login';}
}
}
const _NICK_ADJS=['ရဲရင့်သော','လိမ္မာသော','သတ္တိရှိသော','ဉာဏ်ကြီးသော','ချစ်ဖွယ်သော','မြန်မာသော','ထက်မြက်သော','ဂုဏ်ရည်ရှိသော'];
const _NICK_NOUNS=['ကျားသူရဲ','ဖြူဖြူလေး','နဂါးငယ်','ကြယ်တောက်','ငှက်ဖျော်','မြေနဂါး','ဆင်မင်း','သမင်လေး','ယူနီကောင်','ကင်းမြင်'];
function regenNick(){
const el=document.getElementById('r-nick');
if(!el) return;
const adj=_NICK_ADJS[Math.floor(Math.random()*_NICK_ADJS.length)];
const noun=_NICK_NOUNS[Math.floor(Math.random()*_NICK_NOUNS.length)];
const num=Math.floor(Math.random()*900)+100;
el.value=adj+' '+noun+num;
}
async function doReg(){
const u=document.getElementById('r-u').value.trim();
const nick=document.getElementById('r-nick').value.trim();
const p=document.getElementById('r-p').value.trim();
const p2=document.getElementById('r-p2').value.trim();
if(!u){sam('❌ Username ထည့်ပါ',false);return;}
if(!/^[a-zA-Z0-9_]+$/.test(u)){sam('❌ Username မှာ English နှင့် number သာ သုံးနိုင်သည်',false);return;}
if(!p||p.length<6){sam('❌ Password အနည်းဆုံး 6 လုံး ထည့်ပါ',false);return;}
if(p!==p2){sam('❌ Password နှစ်ကြောင်း မတူညီပါ',false);return;}
const btn=document.querySelector('#pane-re .bp');
if(btn){btn.disabled=true;btn.textContent='⏳ နေပါ...';}
try{
const r=await fetch('/api/register',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:u,password:p,display_name:nick})});
const d=await r.json();
if(d.ok){
sam('✅ '+d.username+' created!',true);
setTimeout(()=>{sessionStorage.setItem('recap_user',JSON.stringify({u:d.username,coins:d.coins,is_admin:false}));eApp(d.username,d.coins,false);},700);
} else {
sam(d.msg||'❌ Failed',false);
if(btn){btn.disabled=false;btn.textContent='Register';}
}
} catch{
sam('❌ Connection error',false);
if(btn){btn.disabled=false;btn.textContent='Register';}
}
}
async function fetchAndUpdateCoins(){
if(!U||ISADM)return;
try{
const r=await fetch('/api/coins?username='+encodeURIComponent(U)+'&_='+Date.now());
const d=await r.json();
if(d.ok){
if(d.coins!==COINS){
const diff=d.coins-COINS;
updC(d.coins);
// Update sessionStorage so refresh shows correct coins
try{
const s=JSON.parse(sessionStorage.getItem('recap_user')||'{}');
s.coins=d.coins;
sessionStorage.setItem('recap_user',JSON.stringify(s));
}catch(e){}
if(diff>0)toast('🎉 +'+diff+' Coins ရောက်ပြီ! လက်ကျန်: '+d.coins);
}
}
}catch(e){}
}
function startCoinPoll(){
if(COIN_POLL)clearInterval(COIN_POLL);
fetchAndUpdateCoins(); // immediate check on login
COIN_POLL=setInterval(fetchAndUpdateCoins,5000);
}
function stopCoinPoll(){if(COIN_POLL){clearInterval(COIN_POLL);COIN_POLL=null;}}
function eApp(u,coins,isAdm,displayName){
U=u;COINS=coins;ISADM=isAdm;
document.getElementById('login-screen').style.display='none';
document.getElementById('app-screen').style.display='block';
const dn=displayName||u;
updC(coins);
// Drawer header
document.getElementById('dun').textContent=dn;
document.getElementById('drl').textContent=isAdm?'👑 Admin':'Member';
document.getElementById('dav-init').textContent=dn[0].toUpperCase();
document.getElementById('dav-coins').textContent=isAdm?'👑 Unlimited':'🪙 '+coins+' coins';
// Show home grid, hide sections
goHome();
fetch('/api/config').then(r=>r.json()).then(d=>{if(d.admin_tg)window._ADMIN_TG=d.admin_tg;}).catch(()=>{});
if(isAdm){document.getElementById('admp').style.display='block';document.getElementById('adm-dlink').style.display='flex';document.getElementById('cpill').style.display='none';}
else{startCoinPoll();}
// Load profile for nickname + animal emoji
fetch('/api/profile?username='+encodeURIComponent(u)).then(r=>r.json()).then(d=>{
if(d.ok){
document.getElementById('dav-init').textContent = d.animal_emoji || '🐶';
if(d.display_name) document.getElementById('dun').textContent = d.display_name;
}
}).catch(()=>{});
renderV();
window.addEventListener('resize',()=>{const v=document.getElementById('pvid');if(v.src&&v.videoWidth)syncCanvasInner(v);});
fetch('/api/gemini_voices').then(r=>r.ok?r.json():null).then(d=>{if(d?.ok){GV=d.voices;if(document.getElementById('engine').value==='gemini')renderV();}}).catch(()=>{});
initDrag();
}
function doLogout(){
stopCoinPoll();
U='';COINS=0;ISADM=false;
sessionStorage.removeItem('recap_user');
document.getElementById('app-screen').style.display='none';
document.getElementById('login-screen').style.display='flex';
cdw();
}
/* ══ PAYMENT MODAL JS ══ */
let _pkgs=[], _pkgsMmk=[], _pkgsThb=[], _selPkg=null, _slipB64=null, _payInited=false, _selMeth=null, _payInfo={}, _curCurrency='mmk';
async function openPay(tab){
document.getElementById('pov').classList.add('on');
if(!_payInited){ await initPayModal(); _payInited=true; }
if(tab) showPayTab(tab);
}
function closePay(){
document.getElementById('pov').classList.remove('on');
// reset to step 1 for next open
goPayStep(1);
}
function showPayTab(t){
document.getElementById('ptab-buy').classList.toggle('on',t==='buy');
document.getElementById('ptab-his').classList.toggle('on',t==='his');
document.getElementById('ptab-buy-content').style.display=t==='buy'?'':'none';
document.getElementById('ptab-his-content').style.display=t==='his'?'':'none';
if(t==='his') loadPayHistory();
}
async function initPayModal(){
const FB_MMK=[
{coins:10,price:'12,000 MMK',price_thb:100,desc:'Process 10 ကြိမ်'},
{coins:20,price:'24,000 MMK',price_thb:200,desc:'Process 20 ကြိမ်'},
{coins:30,price:'36,000 MMK',price_thb:300,desc:'Process 30 ကြိမ်'},
{coins:60,price:'72,000 MMK',price_thb:600,desc:'Process 60 ကြိမ်'},
];
const FB_THB=[
{coins:10,price:'100 THB',price_thb:100,desc:'Process 10 ကြိမ်'},
{coins:20,price:'200 THB',price_thb:200,desc:'Process 20 ကြိမ်'},
{coins:30,price:'300 THB',price_thb:300,desc:'Process 30 ကြိမ်'},
{coins:60,price:'600 THB',price_thb:600,desc:'Process 60 ကြိမ်'},
];
try{
const r=await fetch('/api/payment/packages').then(r=>r.json());
// Map packages from API — add price_thb field
if(r.packages&&r.packages.length){
_pkgsMmk=r.packages.map(p=>({coins:p.coins,price:p.price,price_thb:p.price_thb||0,desc:p.desc}));
_pkgsThb=r.packages.map(p=>({coins:p.coins,price:(p.price_thb||'—')+' THB',price_thb:p.price_thb||0,desc:p.desc}));
} else {
_pkgsMmk=FB_MMK; _pkgsThb=FB_THB;
}
_payInfo={
kbz_name:r.kbz_name||'—', kbz_number:r.kbz_number||'—',
kbz_qr_url:r.kbz_qr_url||'',
scb_name:r.scb_name||'—', scb_number:r.scb_number||'—',
promptpay:r.promptpay||'—',
truemoney_name:r.truemoney_name||'—', truemoney_number:r.truemoney_number||'—',
truemoney_qr_url:r.truemoney_qr_url||''
};
}catch(e){
_pkgsMmk=FB_MMK; _pkgsThb=FB_THB;
_payInfo={kbz_name:'—',kbz_number:'—',kbz_qr_url:'',scb_name:'—',scb_number:'—',promptpay:'—',truemoney_name:'—',truemoney_number:'—',truemoney_qr_url:''};
}
renderPkgs('mmk');
}
function renderPkgs(currency){
_curCurrency=currency||_curCurrency;
_pkgs=_curCurrency==='thb'?_pkgsThb:_pkgsMmk;
_selPkg=null;
document.getElementById('buy-now-btn').disabled=true;
// update currency tab highlight
const mmkBtn=document.getElementById('ctab-mmk');
const thbBtn=document.getElementById('ctab-thb');
if(mmkBtn&&thbBtn){
const onS='flex:1;padding:10px 8px;border-radius:12px;border:2px solid rgba(234,88,12,.5);background:rgba(194,65,12,.2);color:#fdba74;font-family:var(--F);font-size:.82rem;font-weight:800;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:6px';
const offS='flex:1;padding:10px 8px;border-radius:12px;border:2px solid rgba(255,255,255,.08);background:rgba(255,255,255,.04);color:rgba(255,255,255,.35);font-family:var(--F);font-size:.82rem;font-weight:800;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:6px';
mmkBtn.style.cssText=_curCurrency==='mmk'?onS:offS;
thbBtn.style.cssText=_curCurrency==='thb'?onS:offS;
mmkBtn.innerHTML='<span style="font-size:1.1rem">🇲🇲</span> MMK';
thbBtn.innerHTML='<span style="font-size:1.1rem">🇹🇭</span> THB';
}
const icons=['🥉','🥈','🥇','💎'];
const tiers=['Starter','Basic','Pro','Unlimited'];
const pBg =['rgba(255,255,255,.06)','rgba(234,88,12,.18)','rgba(251,146,60,.12)','rgba(251,191,36,.12)'];
const pClr =['rgba(255,255,255,.75)','var(--muted2)','#fb923c','#fbbf24'];
document.getElementById('ppkgs').innerHTML=_pkgs.map((p,i)=>`
<div class="ppkg${i===1?' pop':''}" id="ppkg${i}" onclick="selPkg(${i})">
<span class="ppkg-icon">${icons[i]||'🪙'}</span>
<div style="font-size:.58rem;font-weight:800;text-transform:uppercase;letter-spacing:.1em;color:rgba(255,255,255,.28);margin-bottom:5px">${tiers[i]}</div>
<div class="ppkg-c">${p.coins}</div>
<div class="ppkg-u">Coins</div>
<div class="ppkg-p" style="background:${pBg[i]};color:${pClr[i]}">${p.price}</div>
<div style="font-size:.6rem;color:rgba(255,255,255,.28);margin-top:5px">${p.desc||''}</div>
</div>`).join('');
}
function selPkg(i){
document.querySelectorAll('.ppkg').forEach(e=>e.classList.remove('sel'));
document.getElementById('ppkg'+i).classList.add('sel');
_selPkg=_pkgs[i];
document.getElementById('buy-now-btn').disabled=false;
}
// Step navigation
function goPayStep(n){
document.querySelectorAll('.pay-step').forEach(e=>e.classList.remove('on'));
document.getElementById('pay-step-'+n).classList.add('on');
}
function goPayStep2(){
if(!_selPkg)return;
_selMeth=null;
document.querySelectorAll('.pmeth').forEach(e=>e.classList.remove('sel'));
document.getElementById('pay-info-box').style.display='none';
goPayStep(2);
}
function goPayStep3(){
if(!_selMeth)return;
_slipB64=null;
// Reset slip UI
document.getElementById('pslip-prev').style.display='none';
document.getElementById('pslip-icon').style.display='block';
document.getElementById('pslip-txt').style.display='block';
document.getElementById('pslip-input').value='';
document.getElementById('psubmit').disabled=true;
goPayStep(3);
}
function selMeth(m){
_selMeth=m;
document.querySelectorAll('.pmeth').forEach(e=>e.classList.remove('sel'));
document.getElementById('pmeth-'+m).classList.add('sel');
// Build info box
let rows='';
if(m==='kbz'){
const mmkAmt=_selPkg?(_selPkg.price||''):'';
const kbzCoins=_selPkg?_selPkg.coins:0;
const kbzQrUrl=`/api/payment/kbz_qr?amount=${kbzCoins*1000}`;
rows=`<div class="pinfo-row"><span class="pinfo-lbl">📱 KBZ Pay</span><span></span></div>
<div class="pinfo-row"><span class="pinfo-lbl">အမည် / Name</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-name">${_payInfo.kbz_name}</span><button class="pcopy" onclick="pcopy2('pi-name')">Copy</button></div></div>
<div class="pinfo-row"><span class="pinfo-lbl">ဖုန်းနံပါတ်</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-num">${_payInfo.kbz_number}</span><button class="pcopy" onclick="pcopy2('pi-num')">Copy</button></div></div>
${_payInfo.kbz_qr_url||kbzQrUrl?`<div style="text-align:center;margin:10px 0"><img src="${_payInfo.kbz_qr_url||kbzQrUrl}" alt="KBZ Pay QR" style="width:180px;height:180px;border-radius:12px;border:2px solid rgba(255,255,255,.15)" onerror="this.style.display='none'"><div style="font-size:.68rem;color:rgba(255,255,255,.4);margin-top:4px">KBZ Pay QR Scan — ${mmkAmt}</div></div>`:''}`;
} else if(m==='wave'){
rows=`<div class="pinfo-row"><span class="pinfo-lbl">🌊 Wave Money</span><span></span></div>
<div class="pinfo-row"><span class="pinfo-lbl">Name</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-name">${_payInfo.kbz_name}</span><button class="pcopy" onclick="pcopy2('pi-name')">Copy</button></div></div>
<div class="pinfo-row"><span class="pinfo-lbl">Phone</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-num">${_payInfo.kbz_number}</span><button class="pcopy" onclick="pcopy2('pi-num')">Copy</button></div></div>`;
} else if(m==='scb'){
rows=`<div class="pinfo-row"><span class="pinfo-lbl">🏦 SCB Bank</span><span></span></div>
<div class="pinfo-row"><span class="pinfo-lbl">ชื่อ / Name</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-name">${_payInfo.scb_name}</span><button class="pcopy" onclick="pcopy2('pi-name')">Copy</button></div></div>
<div class="pinfo-row"><span class="pinfo-lbl">Account No.</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-num">${_payInfo.scb_number}</span><button class="pcopy" onclick="pcopy2('pi-num')">Copy</button></div></div>`;
} else if(m==='prompt'){
const thbAmt=_selPkg?(_selPkg.price_thb||''):'';
const qrUrl=thbAmt?`/api/payment/promptpay_qr?amount=${thbAmt}`:'';
rows=`<div class="pinfo-row"><span class="pinfo-lbl">⚡ PromptPay</span><span></span></div>
<div class="pinfo-row"><span class="pinfo-lbl">เบอร์โทร</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-num">${_payInfo.promptpay}</span><button class="pcopy" onclick="pcopy2('pi-num')">Copy</button></div></div>
${qrUrl?`<div style="text-align:center;margin:10px 0"><img src="${qrUrl}" alt="PromptPay QR" style="width:180px;height:180px;border-radius:12px;border:2px solid rgba(255,255,255,.15)" onerror="this.style.display='none'"><div style="font-size:.68rem;color:rgba(255,255,255,.4);margin-top:4px">QR Scan — ${thbAmt} ฿</div></div>`:''}`;
} else if(m==='truemoney'){
const thbAmtTM=_selPkg?(_selPkg.price_thb||''):'';
const tmQrUrl=thbAmtTM?`/api/payment/truemoney_qr?amount=${thbAmtTM}`:'';
rows=`<div class="pinfo-row"><span class="pinfo-lbl">💛 TrueMoney Wallet</span><span></span></div>
<div class="pinfo-row"><span class="pinfo-lbl">ชื่อ / Name</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-name">${_payInfo.truemoney_name}</span><button class="pcopy" onclick="pcopy2('pi-name')">Copy</button></div></div>
<div class="pinfo-row"><span class="pinfo-lbl">เบอร์โทร</span><div style="display:flex;gap:8px;align-items:center"><span class="pinfo-val" id="pi-num">${_payInfo.truemoney_number}</span><button class="pcopy" onclick="pcopy2('pi-num')">Copy</button></div></div>
${(_payInfo.truemoney_qr_url||tmQrUrl)?`<div style="text-align:center;margin:10px 0"><img src="${_payInfo.truemoney_qr_url||tmQrUrl}" alt="TrueMoney QR" style="width:180px;height:180px;border-radius:12px;border:2px solid rgba(255,255,255,.15)" onerror="this.style.display='none'"><div style="font-size:.68rem;color:rgba(255,255,255,.4);margin-top:4px">TrueMoney QR Scan — ${thbAmtTM} ฿</div></div>`:''}`;
}
// Show selected package price
rows+=`<div class="pinfo-row" style="margin-top:4px"><span class="pinfo-lbl">💰 ชำระ / Amount</span><span class="pinfo-val" style="color:#fbbf24">${_selPkg?_selPkg.price:'—'}</span></div>`;
document.getElementById('pinfo-box-inner').innerHTML=rows;
document.getElementById('pay-info-box').style.display='block';
}
function pcopy2(id){
const el=document.getElementById(id);
if(!el)return;
navigator.clipboard.writeText(el.textContent).then(()=>toast('✅ Copied!'));
}
function handlePSlip(inp){
const f=inp.files[0]; if(!f) return;
if(f.size>5*1024*1024){toast('❌ ပုံဆိုဒ် 5MB မကြီးပါနှင့်');return;}
const rd=new FileReader();
rd.onload=e=>{
_slipB64=e.target.result;
const img=document.getElementById('pslip-prev');
img.src=_slipB64; img.style.display='block';
document.getElementById('pslip-icon').style.display='none';
document.getElementById('pslip-txt').style.display='none';
document.getElementById('psubmit').disabled=false;
};
rd.readAsDataURL(f);
}
function checkPReady(){
const btn=document.getElementById('psubmit');
const ready=_selPkg&&_slipB64;
btn.disabled=!ready;
}
async function submitPay(){
if(!_selPkg||!_slipB64) return;
const btn=document.getElementById('psubmit');
btn.disabled=true; btn.textContent='⏳ တင်နေသည်…';
const methLabel={'kbz':'KBZ Pay','wave':'Wave Money','scb':'SCB Bank','prompt':'PromptPay','truemoney':'TrueMoney Wallet'};
const priceLabel=_selPkg.price + ((_selMeth==='scb'||_selMeth==='prompt')?' (Thai Baht)':'');
try{
const r=await fetch('/api/payment/submit',{
method:'POST',headers:{'Content-Type':'application/json'},
body:JSON.stringify({username:U,coins:_selPkg.coins,price:priceLabel,
method:methLabel[_selMeth]||_selMeth||'—',slip_image:_slipB64,
referral_code:(document.getElementById('pay-ref-input')||{value:''}).value.trim().toUpperCase()})
}).then(r=>r.json());
if(r.ok){
toast('✅ '+r.msg);
setTimeout(()=>{closePay();setTimeout(()=>openPay('his'),300);},1500);
} else { toast('❌ '+(r.msg||'Failed')); btn.disabled=false; btn.textContent='💰 Payment တင်ပေးပါ'; }
}catch(e){ toast('❌ Error: '+e.message); btn.disabled=false; btn.textContent='💰 Payment တင်ပေးပါ'; }
}
async function loadPayHistory(){
const el=document.getElementById('ph-list');
if(!U){el.innerHTML='<div class="ph-empty">⚠️ Login ဦးဝင်ပါ</div>';return;}
el.innerHTML='<div class="ph-empty">⏳ Loading…</div>';
try{
const resp=await fetch(`/api/payment/history?username=${encodeURIComponent(U)}`);
if(!resp.ok){el.innerHTML=`<div class="ph-empty">❌ Server error ${resp.status}</div>`;return;}
const r=await resp.json();
if(!r.ok||!r.payments?.length){
el.innerHTML='<div class="ph-empty">📭 Payment မှတ်တမ်း မရှိသေးပါ</div>'; return;
}
const lbl={pending:'⏳ Pending',approved:'✅ Approved',rejected:'❌ Rejected'};
el.innerHTML=[...r.payments].reverse().map(p=>`
<div class="ph-card">
<div class="ph-top">
<div>
<div class="ph-coins">🪙 ${p.coins} Coins</div>
<div class="ph-meta" style="margin-top:3px">${p.price}</div>
</div>
<span class="ph-badge ${p.status}">${lbl[p.status]||p.status}</span>
</div>
<div class="ph-meta">🆔 ${p.id} &nbsp;·&nbsp; ${p.created_at.slice(0,16).replace('T',' ')}</div>
${p.admin_note?`<div style="margin-top:6px;font-size:.72rem;color:rgba(255,255,255,.35);padding:6px 10px;background:rgba(255,255,255,.04);border-radius:7px">📝 ${p.admin_note}</div>`:''}
</div>`).join('');
}catch(e){ el.innerHTML=`<div class="ph-empty">❌ ${e.message}</div>`; }
}
function pcopy(id){
navigator.clipboard.writeText(document.getElementById(id).textContent)
.then(()=>toast('✅ Copied!'));
}
/* ══ DRAWER ══ */
function odw(){document.getElementById('dov').classList.add('on');}
function cdw(){document.getElementById('dov').classList.remove('on');}
function scrollToAdmin(){document.getElementById('admp').scrollIntoView({behavior:'smooth'});}
function updC(n){if(n===-1||ISADM)return;COINS=n;document.getElementById('hcoins').textContent=n;}
/* ══ URL INPUT — auto preview with debounce ══ */
function onUrl(v){
const b=document.getElementById('ubadge');
b.style.display='none';CACHE_KEY='';
if(!v)return;
const vl=v.toLowerCase();
if(vl.includes('youtube.com')||vl.includes('youtu.be')){b.textContent='YouTube';b.className='ubadge b-yt';b.style.display='';}
else if(vl.includes('tiktok.com')){b.textContent='TikTok';b.className='ubadge b-tt';b.style.display='';}
else if(vl.includes('instagram.com')){b.textContent='Instagram';b.className='ubadge b-ig';b.style.display='';}
else if(vl.includes('facebook.com')||vl.includes('fb.watch')){b.textContent='Facebook';b.className='ubadge b-fb';b.style.display='';}
else if(vl.includes('xiaohongshu.com')||vl.includes('xhslink.com')||vl.includes('xhs.link')){b.textContent='🎵 RedNote → Gemini';b.className='ubadge b-rn';b.style.display='';}
if(URL_DEBOUNCE)clearTimeout(URL_DEBOUNCE);
if(v.startsWith('http')){
URL_DEBOUNCE=setTimeout(()=>autoPreview(v),1200);
}
}
async function autoPreview(url){
const loading=document.getElementById('prev-loading');
loading.classList.add('on');
// Reset both video and thumb
const vid=document.getElementById('pvid');
const thumb=document.getElementById('pthumb');
vid.style.display='none'; vid.src='';
thumb.style.display='none'; thumb.src='';
try{
const r=await fetch('/api/thumb',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url})});
if(!r.ok)throw new Error('Server error '+r.status);
const d=await r.json();
if(d.ok){
thumb.src=d.url;
thumb.style.display='block';
document.getElementById('canvas-ph').style.display='none';
thumb.onload=()=>{};
thumb.onerror=()=>{
// If thumbnail image fails to load, just show placeholder
thumb.style.display='none';
document.getElementById('canvas-ph').style.display='flex';
};
}else{
// No thumbnail available — just hide placeholder with a note
document.getElementById('canvas-ph').innerHTML='<i class="fas fa-check-circle" style="font-size:1.8rem;opacity:.5;color:var(--green)"></i><span>URL ထည့်ပြီးပါပြီ</span>';
}
}catch(e){toast('⚠️ Preview: '+e);}
loading.classList.remove('on');
}
function onFile(inp){const f=inp.files[0];if(!f)return;const n=document.getElementById('upzn');n.textContent=f.name;n.style.display='block';document.getElementById('vurl').value='';document.getElementById('ubadge').style.display='none';CACHE_KEY='';}
function setFN(id,inp){const f=inp.files[0];const el=document.getElementById(id);el.textContent=f?f.name:'';el.style.display=f?'block':'none';}
function hasVid(){return document.getElementById('vurl').value.trim()||(document.getElementById('vfile').files||[]).length>0;}
/* ══ FLIP / COLOR ══ */
function toggleOpt(k){
if(k==='flip'){FLIP_ON=!FLIP_ON;const b=document.getElementById('btn-flip');b.className='icon-toggle'+(FLIP_ON?' on':'');b.innerHTML='<i class="fas fa-arrows-alt-h"></i> '+(FLIP_ON?'On':'Off');}
else{COL_ON=!COL_ON;const b=document.getElementById('btn-col');b.className='icon-toggle'+(COL_ON?' on':'');b.innerHTML='<i class="fas fa-adjust"></i> '+(COL_ON?'On':'Off');}
}
/* ══ BACKGROUND MUSIC ══ */
function toggleBgm(){
BGM_ON=!BGM_ON;
const b=document.getElementById('btn-bgm');
b.className='icon-toggle'+(BGM_ON?' on':'');
b.innerHTML='<i class="fas fa-music"></i> '+(BGM_ON?'On':'Off');
document.getElementById('bgm-wrap').style.display=BGM_ON?'block':'none';
if(!BGM_ON){
document.getElementById('bgm-file').value='';
document.getElementById('bgm-name').textContent='Click to upload MP3 / WAV';
document.getElementById('bgm-name').style.color='rgba(255,255,255,.5)';
}
}
function onBgmFile(input){
const f=input.files[0];
if(!f)return;
document.getElementById('bgm-name').textContent=f.name;
document.getElementById('bgm-name').style.color='var(--muted2)';
}
/* ══ VOICE ══ */
function onLang(){renderVoiceCards();setSpd();}
function onEng(){
// legacy — now handled by pickEngine
renderVoiceCards();
}
function pickAiModel(val,btn){
document.getElementById('aimodel').value=val;
document.querySelectorAll('#aimodel-tabs .model-tab').forEach(b=>b.classList.remove('on'));
btn.classList.add('on');
}
function pickEngine(val,btn){
document.getElementById('engine').value=val;
document.querySelectorAll('#engine-tabs .model-tab').forEach(b=>b.classList.remove('on'));
btn.classList.add('on');
const isGemini=val==='gemini';
const ew=document.getElementById('emotion-wrap');
if(ew)ew.style.display=isGemini?'':'none';
// hide manual preview for Gemini TTS (no preview endpoint)
const pb=document.getElementById('pvbtn');
if(pb)pb.style.display=isGemini?'none':'flex';
renderVoiceCards();
if(isGemini)setSpd();
}
function pickEmo(val,btn){
document.getElementById('tts-emotion').value=val;
document.querySelectorAll('#emotion-grid .emobtn').forEach(b=>b.classList.remove('on'));
btn.classList.add('on');
}
function renderVoiceCards(){
const lang=document.getElementById('vlang').value;
const eng=document.getElementById('engine').value;
const voices=eng==='gemini'?GV:(EV[lang]||EV.my||[]);
const container=document.getElementById('voice-scroll');
if(!container)return;
const curSel=document.getElementById('vsel').value;
container.innerHTML='';
voices.forEach((v,i)=>{
const id=v.id||v;
const name=v.name||id;
const gender=v.gender||(name.toLowerCase().includes('female')?'female':(name.toLowerCase().includes('male')?'male':''));
const genderIcon=gender==='female'?'♀️ female':gender==='male'?'♂️ male':'🎙️';
const displayName=name.replace(/\s*\((Male|Female)\)/i,'').trim();
const isSel=(curSel===id)||(i===0&&!curSel);
if(i===0&&!curSel)document.getElementById('vsel').value=id;
const card=document.createElement('div');
card.className='vc'+(isSel?' sel':'');
card.innerHTML=`
<div class="vc-name" title="${name}">${displayName}</div>
<div class="vc-gender">${genderIcon}</div>
<button class="vc-play" onclick="event.stopPropagation();prevVoiceCard('${id}')" title="Preview">
<i class="fas fa-play"></i>
</button>`;
card.onclick=()=>selectVoiceCard(id,card);
container.appendChild(card);
});
}
function selectVoiceCard(id,el){
document.getElementById('vsel').value=id;
document.querySelectorAll('#voice-scroll .vc').forEach(c=>c.classList.remove('sel'));
el.classList.add('sel');
}
async function prevVoiceCard(id){
const speed=parseInt(document.getElementById('spd').value)||30;
const lang=document.getElementById('vlang').value;
const vo_lang=lang==='my'?'my':lang==='th'?'th':'en';
try{
const r=await fetch('/api/preview_voice',{method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({voice:id,speed,engine:'ms',vo_lang})});
if(!r.ok)return;
const blob=await r.blob();
const url=URL.createObjectURL(blob);
const a=new Audio(url);a.play();
}catch(e){console.warn(e);}
}
function renderV(){renderVoiceCards();} // legacy alias
function setSpd(){const s={my:35,th:20,en:0}[document.getElementById('vlang').value]??35;document.getElementById('spd').value=s;document.getElementById('spdv').textContent=s+'%';}
async function doPrevVoice(){
const voice=document.getElementById('vsel').value,speed=parseInt(document.getElementById('spd').value);
const vo_lang=document.getElementById('vlang').value;
const btn=document.getElementById('pvbtn');btn.innerHTML='<i class="fas fa-spinner sp"></i>';
try{const r=await fetch('/api/preview_voice',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({voice,speed,engine:'ms',vo_lang})});
if(!r.ok)throw new Error();const d=await r.json();
if(d.ok){const a=document.getElementById('pva');a.src=d.url;a.play();}else toast('❌ '+d.msg);}
catch{toast('❌ Preview failed');}
btn.innerHTML='<i class="fas fa-play"></i>';
}
/* ══ OVERLAY TOGGLES ══ */
let BLUR_ON=false, WM2_ON=false, LOGO2_ON=false;
function _ovBtn(id, on, ac, bc){
const b=document.getElementById(id); if(!b)return;
if(on){b.style.background=ac;b.style.borderColor=bc;b.style.color='#fff';b.textContent='On';}
else{b.style.background='';b.style.borderColor='';b.style.color='';b.textContent='Off';}
}
function ovToggle(k){
if(k==='blur'){
BLUR_ON=!BLUR_ON;
_ovBtn('ov-blur',BLUR_ON,'rgba(239,68,68,.28)','#ef4444');
document.getElementById('db-blur').style.display=BLUR_ON?'block':'none';
const bh=document.getElementById('ov-blur-hint');if(bh)bh.style.display=BLUR_ON?'block':'none';
return;
}
if(k==='wm'){
WM2_ON=!WM2_ON;
_ovBtn('ov-wm',WM2_ON,'rgba(234,179,8,.28)','#ca8a04');
document.getElementById('db-wm').style.display=WM2_ON?'block':'none';
document.getElementById('ov-wm-wrap').style.display=WM2_ON?'block':'none';
if(WM2_ON)setTimeout(()=>{const i=document.getElementById('wm-text2');if(i)i.focus();},60);
return;
}
if(k==='logo'){
LOGO2_ON=!LOGO2_ON;
_ovBtn('ov-logo',LOGO2_ON,'rgba(16,185,129,.28)','#10b981');
document.getElementById('db-logo').style.display=LOGO2_ON?'block':'none';
document.getElementById('ov-logo-wrap').style.display=LOGO2_ON?'block':'none';
return;
}
}
function onLogoFile(inp){
const f=inp.files[0]; if(!f)return;
document.getElementById('logo-name').textContent=f.name;
document.getElementById('logo-name').style.color='#6ee7b7';
const r=new FileReader();
r.onload=e=>{
const box=document.getElementById('db-logo');
box.style.backgroundImage='url('+e.target.result+')';
box.style.backgroundSize='contain';
box.style.backgroundRepeat='no-repeat';
box.style.backgroundPosition='center';
const lbl=document.getElementById('db-logo-lbl');
if(lbl)lbl.style.display='none';
};
r.readAsDataURL(f);
}
/* ══ DRAG & RESIZE ══ */
function syncCanvasInner(v){
applyCropPreview(v);
}
function applyCropPreview(v){
const crop=document.getElementById('crop').value;
const bg=document.getElementById('canvas-bg-blur');
const vw=document.getElementById('canvas-video-wrap');
const ci=document.getElementById('canvas-inner');
vw.style.position='';vw.style.left='';vw.style.right='';
vw.style.width='100%';vw.style.margin='';
bg.style.display='none';
if(!v.videoWidth) return;
const RATIOS={'9:16':[9,16],'16:9':[16,9],'1:1':[1,1],'original':null};
const tgt=RATIOS[crop];
if(!tgt) return;
const srcW=v.videoWidth, srcH=v.videoHeight;
const tgtRatio=tgt[0]/tgt[1];
const srcRatio=srcW/srcH;
if(Math.abs(tgtRatio-srcRatio)<0.05) return;
try{
const c=document.createElement('canvas');
c.width=srcW;c.height=srcH;
const ctx=c.getContext('2d');
ctx.drawImage(v,0,0,srcW,srcH);
bg.style.backgroundImage='url('+c.toDataURL('image/jpeg',0.4)+')';
bg.style.display='block';
} catch(e){
bg.style.backgroundImage='none';
bg.style.background='rgba(20,20,20,.9)';
bg.style.display='block';
}
if(srcRatio > tgtRatio){
// Pillarbox: video narrower than canvas → black bars left/right
const pct=(tgtRatio/srcRatio*100).toFixed(2)+'%';
vw.style.position='relative';
vw.style.width=pct;
vw.style.margin='0 auto';
ci.style.left=((100-(tgtRatio/srcRatio*100))/2).toFixed(2)+'%';
ci.style.width=(tgtRatio/srcRatio*100).toFixed(2)+'%';
ci.style.top='0'; ci.style.height='100%';
} else if(srcRatio < tgtRatio - 0.05){
// Letterbox: video shorter than canvas → black bars top/bottom
ci.style.left='0'; ci.style.width='100%';
const hPct=(srcRatio/tgtRatio*100).toFixed(2)+'%';
ci.style.top=((100-(srcRatio/tgtRatio*100))/2).toFixed(2)+'%';
ci.style.height=hPct;
} else {
ci.style.left='0';ci.style.width='100%';
ci.style.top='0'; ci.style.height='100%';
}
}
function initDrag(){
['db-blur','db-wm','db-logo'].forEach(id=>{
const el=document.getElementById(id);
if(el){makeDrag(el);makeResize(el,el.querySelector('.rh'));}
});
}
function makeDrag(el){
let ox,oy,ex,ey;
const down=e=>{if(e.target.classList.contains('rh'))return;e.preventDefault();const t=e.touches?e.touches[0]:e;ox=t.clientX;oy=t.clientY;const r=el.getBoundingClientRect(),pr=el.parentElement.getBoundingClientRect();ex=r.left-pr.left;ey=r.top-pr.top;
const mv=e=>{e.preventDefault();const t=e.touches?e.touches[0]:e;el.style.left=(ex+t.clientX-ox)+'px';el.style.top=(ey+t.clientY-oy)+'px';el.style.bottom='auto';};
const up=()=>{document.removeEventListener('mousemove',mv);document.removeEventListener('mouseup',up);el.removeEventListener('touchmove',mv);el.removeEventListener('touchend',up);};
document.addEventListener('mousemove',mv);document.addEventListener('mouseup',up);el.addEventListener('touchmove',mv,{passive:false});el.addEventListener('touchend',up);
};
el.addEventListener('mousedown',down);el.addEventListener('touchstart',down,{passive:false});
}
function makeResize(el,h){if(!h)return;
const down=e=>{e.stopPropagation();e.preventDefault();const t=e.touches?e.touches[0]:e;const sw=el.offsetWidth,sh=el.offsetHeight,sx=t.clientX,sy=t.clientY;
const mv=e=>{e.preventDefault();const t=e.touches?e.touches[0]:e;el.style.width=Math.max(40,sw+t.clientX-sx)+'px';el.style.height=Math.max(30,sh+t.clientY-sy)+'px';};
const up=()=>{document.removeEventListener('mousemove',mv);document.removeEventListener('mouseup',up);h.removeEventListener('touchmove',mv);h.removeEventListener('touchend',up);};
document.addEventListener('mousemove',mv);document.addEventListener('mouseup',up);h.addEventListener('touchmove',mv,{passive:false});h.addEventListener('touchend',up);
};
h.addEventListener('mousedown',down);h.addEventListener('touchstart',down,{passive:false});
}
// Drag with optional callback fired on every move
function makeDragWithCb(el,cb){
let ox,oy,ex,ey;
const down=e=>{
if(e.target.classList.contains('rh'))return;
e.preventDefault();
const t=e.touches?e.touches[0]:e;
ox=t.clientX;oy=t.clientY;
const r=el.getBoundingClientRect(),pr=el.parentElement.getBoundingClientRect();
ex=r.left-pr.left;ey=r.top-pr.top;
const mv=e=>{
e.preventDefault();
const t=e.touches?e.touches[0]:e;
el.style.left=(ex+t.clientX-ox)+'px';
el.style.top=(ey+t.clientY-oy)+'px';
el.style.bottom='auto';
if(cb)cb();
};
const up=()=>{
document.removeEventListener('mousemove',mv);
document.removeEventListener('mouseup',up);
el.removeEventListener('touchmove',mv);
el.removeEventListener('touchend',up);
if(cb)cb();
};
document.addEventListener('mousemove',mv);
document.addEventListener('mouseup',up);
el.addEventListener('touchmove',mv,{passive:false});
el.addEventListener('touchend',up);
};
el.addEventListener('mousedown',down);
el.addEventListener('touchstart',down,{passive:false});
}
// Resize with optional callback fired on every resize
function makeResizeWithCb(el,h,cb){
if(!h)return;
const down=e=>{
e.stopPropagation();e.preventDefault();
const t=e.touches?e.touches[0]:e;
const sw=el.offsetWidth,sh=el.offsetHeight,sx=t.clientX,sy=t.clientY;
const mv=e=>{
e.preventDefault();
const t=e.touches?e.touches[0]:e;
el.style.width=Math.max(40,sw+t.clientX-sx)+'px';
el.style.height=Math.max(30,sh+t.clientY-sy)+'px';
if(cb)cb();
};
const up=()=>{
document.removeEventListener('mousemove',mv);
document.removeEventListener('mouseup',up);
h.removeEventListener('touchmove',mv);
h.removeEventListener('touchend',up);
if(cb)cb();
};
document.addEventListener('mousemove',mv);
document.addEventListener('mouseup',up);
h.addEventListener('touchmove',mv,{passive:false});
h.addEventListener('touchend',up);
};
h.addEventListener('mousedown',down);
h.addEventListener('touchstart',down,{passive:false});
}
function getBoxPct(id){
const el=document.getElementById(id);
const ci=document.getElementById('canvas-inner');
const video=document.getElementById('pvid');
const crop=document.getElementById('crop').value;
const srcW=video.videoWidth||720, srcH=video.videoHeight||1280;
let tW,tH;
if(crop==='9:16'){tW=720;tH=1280;}
else if(crop==='16:9'){tW=1280;tH=720;}
else if(crop==='1:1'){tW=720;tH=720;}
else{tW=srcW;tH=srcH;}
const ciR=ci.getBoundingClientRect();
const elR=el.getBoundingClientRect();
const sx=tW/ciR.width, sy=tH/ciR.height;
return{
x:Math.max(0,Math.min(1,((elR.left-ciR.left)*sx)/tW)),
y:Math.max(0,Math.min(1,((elR.top-ciR.top)*sy)/tH)),
w:Math.max(0,Math.min(1,(elR.width*sx)/tW)),
h:Math.max(0,Math.min(1,(elR.height*sy)/tH))
};
}
/* ══ FORM DATA ══ */
function bfd(){
const fd=new FormData();
fd.append('username',U);fd.append('video_url',document.getElementById('vurl').value.trim());
fd.append('voice',document.getElementById('vsel').value);fd.append('engine',document.getElementById('engine').value);fd.append('tts_emotion',document.getElementById('tts-emotion')?document.getElementById('tts-emotion').value:'');
fd.append('speed',document.getElementById('spd').value);
// Watermark canvas-positioned
const _wmTxt=WM2_ON?(document.getElementById('wm-text2').value.trim()):'';
fd.append('watermark',_wmTxt);
if(WM2_ON && _wmTxt){
const wp=getBoxPct('db-wm');
fd.append('wmk_xp',wp.x.toFixed(4));
fd.append('wmk_yp',wp.y.toFixed(4));
fd.append('wmk_fontsize','28');
}
// Logo canvas-positioned
const _lf=document.getElementById('logo-file2');
if(LOGO2_ON && _lf && _lf.files[0]){
fd.append('logo_file',_lf.files[0]);
const lp=getBoxPct('db-logo');
fd.append('logo_xp',lp.x.toFixed(4));
fd.append('logo_yp',lp.y.toFixed(4));
fd.append('logo_wp',lp.w.toFixed(4));
}
fd.append('crop',document.getElementById('crop').value);fd.append('flip',FLIP_ON?'1':'0');fd.append('color',COL_ON?'1':'0');
fd.append('content_type',document.getElementById('ctype').value);fd.append('ai_model',document.getElementById('aimodel').value);fd.append('vo_lang',document.getElementById('vlang').value);
if(CACHE_KEY)fd.append('cache_key',CACHE_KEY);
// Blur box
fd.append('blur_enabled',BLUR_ON?'1':'0');
if(BLUR_ON){
const bp=getBoxPct('db-blur');
const vw=document.getElementById('pvid');
const vW=vw.videoWidth||720, vH=vw.videoHeight||1280;
const crop=document.getElementById('crop').value;
let tW=vW,tH=vH;
if(crop==='9:16'){tW=720;tH=1280;}
else if(crop==='16:9'){tW=1280;tH=720;}
else if(crop==='1:1'){tW=720;tH=720;}
fd.append('blur_xp',bp.x.toFixed(4));
fd.append('blur_yp',bp.y.toFixed(4));
fd.append('blur_wp',bp.w.toFixed(4));
fd.append('blur_hp',bp.h.toFixed(4));
}
fd.append('sub_enabled',SUB_ON?'1':'0');
if(SUB_ON){
fd.append('sub_size',document.getElementById('sub-size').value);
fd.append('sub_pos',_getSubPosFromBlur());
fd.append('sub_color',document.getElementById('sub-color').value);
fd.append('sub_style',document.getElementById('sub-style').value);
}
const vf=document.getElementById('vfile');if(vf&&vf.files[0])fd.append('video_file',vf.files[0]);
const mf=document.getElementById('bgm-file');if(BGM_ON&&mf&&mf.files[0])fd.append('music_file',mf.files[0]);
return fd;
}
/* ══ PROGRESS ══ */
function fmt(s){const m=Math.floor(s/60);return m>0?m+'m '+(s%60)+'s':s+'s';}
const SMAP={8:'ps-dl',20:'ps-tr',45:'ps-ai',65:'ps-ts',78:'ps-vd'};
let _waitMsgTimer=null;
function _startWaitMsgs(){
const msgs=['⏳ တန်းစီစောင့်နေသည်…','⏳ Server နဲ့ ချိတ်ဆက်နေသည်…','⏳ Video URL စစ်ဆေးနေသည်…','⏳ ဒေါင်းလုပ်အတွက် ပြင်ဆင်နေသည်…'];
let i=0;
_waitMsgTimer=setInterval(()=>{i=(i+1)%msgs.length;document.getElementById('pmsg').textContent=msgs[i];},2500);
}
function _stopWaitMsgs(){if(_waitMsgTimer){clearInterval(_waitMsgTimer);_waitMsgTimer=null;}}
function showProg(on){document.getElementById('pc').style.display=on?'block':'none';if(on){document.getElementById('pb').style.width='0%';document.getElementById('pmsg').textContent='⏳ တန်းစီစောင့်နေသည်…';document.getElementById('ptmr').textContent='⏱ 0s';Object.values(SMAP).forEach(id=>document.getElementById(id).className='ps');_hideLiveOutputs();}else{_stopWaitMsgs();}}
function updSteps(pct){let hit=false;const e=Object.entries(SMAP);for(let i=0;i<e.length;i++){const[p,id]=e[i],el=document.getElementById(id);if(pct>=parseInt(p)){el.className='ps done';}else if(!hit){el.className='ps active';hit=true;}else el.className='ps';}}
function startTick(){T0=Date.now();if(TICK)clearInterval(TICK);TICK=setInterval(()=>{document.getElementById('ptmr').textContent='⏱ '+fmt(Math.floor((Date.now()-T0)/1000));},1000);}
function stopTick(){if(TICK){clearInterval(TICK);TICK=null;}return Math.floor((Date.now()-T0)/1000);}
function _resetBtn(){const b=document.getElementById('btnauto');b.disabled=false;b.innerHTML='<i class="fas fa-magic"></i> Auto Process <span style="opacity:.7;font-size:.78em;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px">1 Coin</span>';}
function toggleOut(type){const bodyMap={transcript:'out-tr-body',script:'out-sc-body',tts:'out-tts-body'};const chvMap={transcript:'out-tr-chv',script:'out-sc-chv',tts:'out-tts-chv'};const b=document.getElementById(bodyMap[type]);const c=document.getElementById(chvMap[type]);if(!b)return;const open=b.style.display==='block';b.style.display=open?'none':'block';if(c)c.style.transform=open?'':'rotate(180deg)';}
function _showLiveOutput(type,content){const wrapMap={transcript:'out-transcript',script:'out-script',tts:'out-tts'};const w=document.getElementById(wrapMap[type]);if(!w)return;w.style.display='block';document.getElementById('live-outputs').style.display='flex';if(type==='transcript'){document.getElementById('out-tr-text').textContent=content.text||'';if(content.lang)document.getElementById('out-tr-lang').textContent='('+content.lang+')';document.getElementById('out-tr-body').style.display='block';document.getElementById('out-tr-chv').style.transform='rotate(180deg)';}else if(type==='script'){document.getElementById('out-sc-text').textContent=content.text||'';document.getElementById('out-sc-body').style.display='block';document.getElementById('out-sc-chv').style.transform='rotate(180deg)';// Update subtitle preview box label with first sentence
const _firstLine=(content.text||'').trim().split('\n')[0].substring(0,40);const _lbl=document.getElementById('db-sub-label');if(_lbl&&_firstLine)_lbl.textContent=_firstLine;}else if(type==='tts'){const a=document.getElementById('out-tts-audio');a.src=content.url+'?t='+Date.now();document.getElementById('out-tts-body').style.display='block';document.getElementById('out-tts-chv').style.transform='rotate(180deg)';}}
function _hideLiveOutputs(){['out-transcript','out-script','out-tts'].forEach(id=>{const el=document.getElementById(id);if(el)el.style.display='none';});document.getElementById('live-outputs').style.display='none';}
function startSSE(tid){
if(SSE)SSE.close();
let _lastTr=false,_lastSc=false,_lastTts=false;
SSE=new EventSource('/api/progress/'+tid);
SSE.onmessage=e=>{try{
const p=JSON.parse(e.data);
const msg=(p.msg||'').replace(/KEY-\d+\s*·\s*\S+/g,'').trim();
document.getElementById('pb').style.width=(p.pct||0)+'%';
document.getElementById('pmsg').textContent=msg;
updSteps(p.pct||0);
// Show outputs as they arrive
if(p.transcript&&!_lastTr){_lastTr=true;_showLiveOutput('transcript',{text:p.transcript,lang:p.src_lang});}
if(p.script&&!_lastSc){_lastSc=true;_showLiveOutput('script',{text:p.script});}
if(p.tts_url&&!_lastTts){_lastTts=true;_showLiveOutput('tts',{url:p.tts_url});}
if(p.done){SSE.close();SSE=null;const el=stopTick();_resetBtn();if(p.output_url){updC(p.coins!=null?p.coins:0);if(p.tid)RR_TID=p.tid;showRes(p.output_url,p.title,p.hashtags,p.caption,el);}else{showProg(false);toast('❌ output မတွေ့ပါ');}}
else if(p.error){SSE.close();SSE=null;stopTick();showProg(false);_resetBtn();toast(msg||'❌ Process မအောင်မြင်ပါ');}
}catch(ex){}};
}
/* ══ AUTO PROCESS ══ */
async function doAuto(){
if(!hasVid()){toast('❌ Select a video or enter a URL');return;}
const btn=document.getElementById('btnauto');btn.disabled=true;btn.innerHTML='<i class="fas fa-spinner sp"></i> Processing…';
showProg(true);startTick();_startWaitMsgs();
const fd=bfd();
const tid=uid8();fd.append('tid',tid);
try{
const ctrl=new AbortController(),tout=setTimeout(()=>ctrl.abort(),600000);
const r=await fetch('/api/process_all',{method:'POST',body:fd,signal:ctrl.signal});
clearTimeout(tout);
if(!r.ok){_stopWaitMsgs();stopTick();showProg(false);_resetBtn();toast('❌ Server error '+r.status);return;}
const d=await r.json();
if(!d.ok){_stopWaitMsgs();stopTick();showProg(false);_resetBtn();toast(d.msg||'❌ Process မအောင်မြင်ပါ');return;}
// Server confirmed — connect SSE, stop local animation on first real message
_stopWaitMsgs();
startSSE(tid);
}catch(e){
_stopWaitMsgs();stopTick();showProg(false);_resetBtn();
toast(e.name==='AbortError'?'❌ Timeout':'❌ '+e);
}
}
/* ══ RESULT ══ */
function showRes(url,title,tags,cap,el){
showProg(false);OUT_URL=url;OUT_CAP=cap||title;OUT_TAGS=tags;
const rc=document.getElementById('rc');
const rvid=document.getElementById('rvid');
rvid.src='';rc.style.display='block';
if(title){document.getElementById('rtit').textContent=title;document.getElementById('rtit').style.display='block';}
if(tags){document.getElementById('rtag').textContent=tags;document.getElementById('rtag').style.display='block';}
if(el>0){const rt=document.getElementById('rtm');rt.querySelector('span').textContent='Process time: '+fmt(el);rt.style.display='flex';}
rc.scrollIntoView({behavior:'smooth'});
// Reset re-render panel state
document.getElementById('rr-panel').style.display='none';
document.getElementById('rr-chv').style.transform='rotate(0deg)';
document.getElementById('rr-msg').style.display='none';
// Set src immediately so browser can start loading when file appears
setTimeout(()=>{ if(!rvid.src || rvid.src===window.location.href) rvid.src=url; }, 3000);
let tries=0;
const poll=setInterval(async()=>{
tries++;
try{const r=await fetch(url,{method:'HEAD'});if(r.ok){clearInterval(poll);rvid.src=url;toast('✅ Video ပြီးပါပြီ!');return;}}catch(e){}
if(tries>=30){clearInterval(poll);rvid.src=url;toast('✅ Done');}
},1000);
}
function dlVideo(){if(!OUT_URL)return;const a=document.createElement('a');a.href=OUT_URL;a.download='recap.mp4';a.click();}
function copyCap(){const t=[OUT_CAP,OUT_TAGS].filter(Boolean).join('\n\n');if(!t){toast('Nothing to copy');return;}navigator.clipboard.writeText(t).then(()=>toast('✅ Copied!')).catch(()=>toast('❌ Copy failed'));}
/* ══ RE-RENDER ══ */
let RR_TID='';
function toggleRrPanel(){
const p=document.getElementById('rr-panel');
const chv=document.getElementById('rr-chv');
const open=p.style.display==='none';
p.style.display=open?'block':'none';
chv.style.transform=open?'rotate(180deg)':'rotate(0deg)';
}
function rrSetMsg(msg,ok){
const el=document.getElementById('rr-msg');
el.style.display='block';
el.style.background=ok?'rgba(21,128,61,.15)':'rgba(185,28,28,.12)';
el.style.color=ok?'#16a34a':'#ef4444';
el.style.border=ok?'1px solid rgba(21,128,61,.3)':'1px solid rgba(185,28,28,.25)';
el.textContent=msg;
}
async function doRerender(){
if(!RR_TID){rrSetMsg('❌ Result TID မတွေ့ပါ',false);return;}
const btn=document.getElementById('rr-btn');
btn.disabled=true;
btn.innerHTML='<i class="fas fa-spinner fa-spin"></i> Re-render လုပ်နေသည်…';
document.getElementById('rr-msg').style.display='none';
const fd=new FormData();
fd.append('username',U);
fd.append('tid',RR_TID);
fd.append('tts_pad_dur',document.getElementById('rr-pad').value);
fd.append('tts_crossfade',document.getElementById('rr-cf').value);
// pass blur box settings
fd.append('blur_enabled',BLUR_ON?'1':'0');
if(BLUR_ON){
const bp=getBoxPct('db-blur');
fd.append('blur_xp',bp.x.toFixed(4));
fd.append('blur_yp',bp.y.toFixed(4));
fd.append('blur_wp',bp.w.toFixed(4));
fd.append('blur_hp',bp.h.toFixed(4));
}
// pass subtitle settings from original
const sub_on=document.getElementById('btn-sub');
if(sub_on&&sub_on.classList.contains('on')){
fd.append('sub_enabled','1');
fd.append('sub_size',document.getElementById('sub-size').value);
fd.append('sub_pos',_getSubPosFromBlur());
fd.append('sub_color',document.getElementById('sub-color').value);
fd.append('sub_style',document.getElementById('sub-style').value);
}
try{
const r=await fetch('/api/rerender',{method:'POST',body:fd});
const d=await r.json();
if(!d.ok){rrSetMsg(d.msg||'❌ Error',false);btn.disabled=false;btn.innerHTML='<i class="fas fa-redo"></i> ပြန် Render လုပ်မည် (FREE)';return;}
const new_tid=d.tid;
rrSetMsg('⏳ Re-render စတင်ပြီ…',true);
// Poll progress
const sse=new EventSource('/api/progress/'+new_tid);
sse.onmessage=e=>{
const p=JSON.parse(e.data);
btn.innerHTML=`<i class="fas fa-spinner fa-spin"></i> ${p.msg||'Processing…'} ${p.pct||0}%`;
if(p.error){sse.close();rrSetMsg(p.msg||'❌ Error',false);btn.disabled=false;btn.innerHTML='<i class="fas fa-redo"></i> ပြန် Render လုပ်မည် (FREE)';return;}
if(p.done){
sse.close();
rrSetMsg('✅ Re-render ပြီးပါပြီ!',true);
btn.disabled=false;
btn.innerHTML='<i class="fas fa-redo"></i> ပြန် Render လုပ်မည် (FREE)';
RR_TID=new_tid; // allow further re-renders from new result
// Update result video
if(p.output_url){
OUT_URL=p.output_url;
const rvid=document.getElementById('rvid');
rvid.src='';
setTimeout(()=>{rvid.src=p.output_url+'?t='+Date.now();},500);
// hide panel
document.getElementById('rr-panel').style.display='none';
document.getElementById('rr-chv').style.transform='rotate(0deg)';
toast('✅ Re-render ပြီးပြီ!');
}
}
};
sse.onerror=()=>{sse.close();rrSetMsg('❌ SSE ချောင်းပြတ်သွားသည်',false);btn.disabled=false;btn.innerHTML='<i class="fas fa-redo"></i> ပြန် Render လုပ်မည် (FREE)';};
}catch(e){rrSetMsg('❌ '+e.message,false);btn.disabled=false;btn.innerHTML='<i class="fas fa-redo"></i> ပြန် Render လုပ်မည် (FREE)';}
}
/* ══ ADMIN ══ */
async function admCoins(act){const u=document.getElementById('au-'+act).value.trim(),n=parseInt(document.getElementById('an-'+act).value)||0;if(!u){toast('❌ Enter username');return;}const r=await fetch('/api/admin/coins',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u,amount:n,action:act})});const d=await r.json();document.getElementById('admmsg').textContent=d.msg||'';}
async function admCreate(){const u=document.getElementById('au-new').value.trim();const r=await fetch('/api/admin/create_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u,coins:0})});const d=await r.json();document.getElementById('au-res').textContent=d.msg+(d.username?' → '+d.username:'');}
async function admDel(){const u=document.getElementById('au-del').value.trim();if(!u||!confirm('Delete '+u+'?'))return;const r=await fetch('/api/admin/delete_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u})});const d=await r.json();document.getElementById('admmsg').textContent=d.msg;if(d.ok)loadUsers();}
async function loadUsers(){
const r=await fetch('/api/admin/users?caller='+encodeURIComponent(U));
if(!r.ok)return;const d=await r.json();if(!d.ok)return;
const w=document.getElementById('utw');
if(!d.users.length){w.innerHTML='<div style="font-size:.75rem;color:var(--muted);padding:6px">No users</div>';return;}
let h='<table class="ut"><thead><tr><th>User</th><th>🪙</th><th>Vids</th><th>Status</th><th>Actions</th></tr></thead><tbody>';
d.users.forEach(u=>{
const banned=u.banned;
const rowStyle=banned?'opacity:.5;background:rgba(239,68,68,.05)':'';
const banBtn=banned
?`<button class="delbtn" style="color:#10b981" onclick="qBan('${u.username}',false)" title="Unban"><i class="fas fa-unlock"></i></button>`
:`<button class="delbtn" style="color:#f59e0b" onclick="qBan('${u.username}',true)" title="Ban"><i class="fas fa-ban"></i></button>`;
h+=`<tr style="${rowStyle}"><td style="max-width:100px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${u.username}</td><td>${u.coins}</td><td>${u.videos}</td><td>${banned?'<span style="color:#ef4444;font-size:.7rem">🚫 Banned</span>':'<span style="color:#10b981;font-size:.7rem">✅ Active</span>'}</td><td style="display:flex;gap:3px">${banBtn}<button class="delbtn" onclick="qDel('${u.username}')"><i class="fas fa-trash"></i></button></td></tr>`;
});
w.innerHTML=h+'</tbody></table>';
}
async function qDel(u){if(!confirm('Delete '+u+'?'))return;const r=await fetch('/api/admin/delete_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u})});const d=await r.json();toast(d.msg);if(d.ok)loadUsers();}
async function qBan(u,ban){const label=ban?'Ban':'Unban';if(!confirm(label+' '+u+'?'))return;const r=await fetch('/api/admin/ban_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u,ban})});const d=await r.json();toast(d.msg);if(d.ok)loadUsers();}
/* ══ PENDING PAYMENTS ══ */
function openBroadcast(){
const m=document.getElementById('bc-modal');
m.style.display='flex';
document.getElementById('bc-msg').focus();
document.getElementById('bc-res').textContent='';
document.getElementById('bc-msg').oninput=function(){
document.getElementById('bc-char').textContent=this.value.length+' / 4096';
};
}
function closeBroadcast(){
document.getElementById('bc-modal').style.display='none';
document.getElementById('bc-msg').value='';
document.getElementById('bc-char').textContent='0 / 4096';
}
async function sendBroadcast(){
const msg=document.getElementById('bc-msg').value.trim();
const res=document.getElementById('bc-res');
const btn=document.getElementById('bc-send-btn');
if(!msg){res.style.color='#ef4444';res.textContent='❌ Message ထည့်ပါ';return;}
btn.disabled=true;btn.innerHTML='<i class="fas fa-spinner fa-spin"></i> ပို့နေသည်…';
res.style.color='rgba(255,255,255,.4)';res.textContent='';
try{
const r=await fetch('/api/admin/broadcast',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,message:msg})});
const d=await r.json();
if(d.ok){
res.style.color='#4ade80';res.textContent=d.msg;
document.getElementById('bc-msg').value='';
document.getElementById('bc-char').textContent='0 / 4096';
setTimeout(closeBroadcast,2000);
}else{res.style.color='#ef4444';res.textContent=d.msg||'❌ Error';}
}catch(e){res.style.color='#ef4444';res.textContent='❌ Network error';}
btn.disabled=false;btn.innerHTML='<i class="fas fa-paper-plane"></i> ပို့မည်';
}
async function loadPendingPayments(){
const wrap=document.getElementById('adm-pending-wrap');
const list=document.getElementById('adm-pending-list');
const cnt=document.getElementById('adm-pending-count');
list.innerHTML='<div style="font-size:.75rem;color:var(--muted);padding:8px">⏳ Loading…</div>';
wrap.style.display='block';
try{
const r=await fetch('/api/admin/payments?caller='+encodeURIComponent(U)+'&status=pending');
let d;
try{ d=await r.json(); }
catch(je){ list.innerHTML='<div style="color:var(--red);font-size:.75rem">❌ Server error (not JSON) — HTTP '+r.status+'</div>'; return; }
if(!d.ok){list.innerHTML='<div style="color:var(--red);font-size:.75rem">❌ '+(d.msg||'Error')+'</div>';return;}
const pays=d.payments||[];
cnt.textContent=pays.length;
cnt.style.display=pays.length?'':'none';
if(!pays.length){list.innerHTML='<div style="font-size:.78rem;color:var(--muted);padding:10px;text-align:center">✅ Pending payment မရှိပါ</div>';return;}
list.innerHTML=pays.map(p=>{
const dt=p.created_at?p.created_at.replace('T',' ').substring(0,16):'';
return `<div class="adm-pay-card" id="paycard-${p.id}">
<div class="adm-pay-card-top">
<span class="adm-pay-card-user">👤 ${p.username}</span>
<span class="adm-pay-card-coins">🪙 ${p.coins} Coins</span>
</div>
<div class="adm-pay-card-info">
💵 ${p.price} MMK &nbsp;·&nbsp; 🆔 <code style="background:var(--bg3);padding:2px 5px;border-radius:4px;font-size:.7rem">${p.id}</code><br>
${dt}
</div>
${p.slip_image?`<img class="adm-slip-img" id="slip-${p.id}" src="${p.slip_image}" onclick="this.style.display=this.style.display==='none'?'block':'none'">` :''}
<div class="adm-pay-card-btns">
${p.slip_image?`<button class="adm-pay-slip-btn" onclick="toggleSlip('${p.id}')"><i class="fas fa-image"></i> Slip</button>`:''}
<button class="adm-pay-approve" onclick="admPayAction('approve','${p.id}','${p.username}',${p.coins},this)">✅ Approve +${p.coins}</button>
<button class="adm-pay-reject" onclick="admPayAction('reject','${p.id}','${p.username}',0,this)">❌ Reject</button>
</div>
</div>`;
}).join('');
}catch(e){list.innerHTML='<div style="color:var(--red);font-size:.75rem">❌ '+e+'</div>';}
}
function toggleSlip(pid){
const img=document.getElementById('slip-'+pid);
if(img) img.style.display=img.style.display==='block'?'none':'block';
}
async function admPayAction(action,pid,username,coins,btn){
if(action==='reject'&&!confirm('Reject payment from '+username+'?'))return;
// Disable button to prevent double-click freeze
if(btn){btn.disabled=true;btn.style.opacity='0.5';}
const ep=action==='approve'?'/api/admin/payment/approve':'/api/admin/payment/reject';
const body={caller:U,payment_id:pid,username,coins};
try{
const r=await fetch(ep,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)});
const d=await r.json();
if(d.ok){
toast(action==='approve'?'✅ Approved! +'+coins+' coins → '+username:'❌ Rejected');
const card=document.getElementById('paycard-'+pid);
if(card)card.remove();
const remaining=document.querySelectorAll('[id^="paycard-"]').length;
const cnt=document.getElementById('adm-pending-count');
if(cnt){cnt.textContent=remaining;cnt.style.display=remaining?'':'none';}
}else{
toast('❌ '+(d.msg||'Error'));
if(btn){btn.disabled=false;btn.style.opacity='';}
}
}catch(e){
toast('❌ Network error: '+e.message);
if(btn){btn.disabled=false;btn.style.opacity='';}
}
}
/* ══ UTILS ══ */
function toast(m){const e=document.getElementById('toast');e.textContent=m;e.classList.add('show');setTimeout(()=>e.classList.remove('show'),2800);}
function uid8(){return([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,c=>(c^crypto.getRandomValues(new Uint8Array(1))[0]&15>>c/4).toString(16)).replace(/-/g,'').substring(0,8);}
async function doPaste(){try{const t=await navigator.clipboard.readText();if(t){const el=document.getElementById('vurl');el.value=t;onUrl(t);toast('✅ Pasted!');}else toast('❌ Clipboard empty');}catch(e){toast('❌ Clipboard access denied');}}
document.addEventListener('keydown',e=>{if(e.key==='Enter'&&document.getElementById('login-screen').style.display!=='none'){if(document.getElementById('pane-li').style.display!=='none')doLogin();else doReg();}});
/* ══ MODE SWITCH ══ */
function switchMode(m){ goSection(m); }
function goSection(m,ct){
document.getElementById('section-home').style.display='none';
document.getElementById('section-recap').style.display=m==='recap'?'':'none';
document.getElementById('section-srt').style.display=m==='srt'?'':'none';
document.getElementById('section-dubbing').style.display=m==='dubbing'?'':'none';
if(m==='recap' && ct){
const csel=document.getElementById('ctype');
if(csel) csel.value=ct;
}
window.scrollTo(0,0);
}
function goHome(){
document.getElementById('section-home').style.display='';
document.getElementById('section-recap').style.display='none';
document.getElementById('section-srt').style.display='none';
window.scrollTo(0,0);
}
/* ══ TRANSLATE SRT ══ */
/* ══════════════ AI DUBBING MODE ══════════════ */
let DUB_VOUT='', DUB_SSE=null, DUB_TICK=null, DUB_T0=0, DUB_URL_DEB=null;
function onDubUrl(v){
const b=document.getElementById('dub-ubadge');
b.style.display='none';
if(!v) return;
const vl=v.toLowerCase();
if(vl.includes('youtube.com')||vl.includes('youtu.be')){b.textContent='YouTube';b.className='ubadge b-yt';b.style.display='';}
else if(vl.includes('tiktok.com')){b.textContent='TikTok';b.className='ubadge b-tt';b.style.display='';}
else if(vl.includes('facebook.com')||vl.includes('fb.watch')){b.textContent='Facebook';b.className='ubadge b-fb';b.style.display='';}
else if(vl.includes('xiaohongshu.com')||vl.includes('xhslink.com')){b.textContent='RedNote';b.className='ubadge b-tt';b.style.display='';}
else if(vl.includes('douyin.com')){b.textContent='Douyin';b.className='ubadge b-tt';b.style.display='';}
else if(vl.includes('bilibili.com')){b.textContent='Bilibili';b.className='ubadge b-tt';b.style.display='';}
}
async function dubPaste(){
try{
const t=await navigator.clipboard.readText();
if(t){document.getElementById('dub-vurl').value=t;onDubUrl(t);toast('✅ Pasted!');}
else toast('❌ Clipboard empty');
}catch(e){toast('❌ Clipboard access denied');}
}
function onDubVFile(inp){
const f=inp.files[0]; if(!f) return;
document.getElementById('dub-upzn').textContent=f.name;
document.getElementById('dub-upzn').style.display='block';
document.getElementById('dub-vurl').value='';
document.getElementById('dub-ubadge').style.display='none';
}
function hasDubVid(){
return !!(document.getElementById('dub-vurl').value.trim() || document.getElementById('dub-vfile').files[0]);
}
function dubResetBtn(){
const b=document.getElementById('dub-gen-btn');
if(b){b.disabled=false;b.innerHTML='<i class="fas fa-microphone"></i> AI Dubbing စတင်ပါ <span style="opacity:.7;font-size:.78em;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px">1 Coin</span>';}
}
async function doDubProcess(){
if(!hasDubVid()){toast('❌ Video URL သို့ file ထည့်ပါ');return;}
if(!U){toast('❌ Login ဦးဝင်ပါ');return;}
const btn=document.getElementById('dub-gen-btn');
btn.disabled=true;
btn.innerHTML='<i class="fas fa-spinner sp"></i> Processing…';
document.getElementById('dub-pc').style.display='block';
document.getElementById('dub-rc').style.display='none';
DUB_T0=Date.now();
if(DUB_TICK) clearInterval(DUB_TICK);
DUB_TICK=setInterval(()=>{
const el=document.getElementById('dub-ptmr');
if(el) el.textContent='⏱ '+Math.floor((Date.now()-DUB_T0)/1000)+'s';
},1000);
const fd=new FormData();
fd.append('username',U);
const vurl=document.getElementById('dub-vurl').value.trim();
const vf=document.getElementById('dub-vfile').files[0];
if(vf) fd.append('video_file',vf);
else fd.append('video_url',vurl);
fd.append('voice','my-MM-ThihaNeural');
fd.append('vo_lang','my');
const tid=uid8(); fd.append('tid',tid);
try{
const ctrl=new AbortController(),tout=setTimeout(()=>ctrl.abort(),1200000);
const r=await fetch('/api/dub_process',{method:'POST',body:fd,signal:ctrl.signal});
clearTimeout(tout);
if(!r.ok){_dubFail('❌ Server error '+r.status);return;}
const d=await r.json();
if(!d.ok){_dubFail(d.msg||'❌ Failed');return;}
_dubSSE(tid);
}catch(e){
_dubFail(e.name==='AbortError'?'❌ Timeout':'❌ '+e);
}
}
function _dubFail(msg){
clearInterval(DUB_TICK); DUB_TICK=null;
document.getElementById('dub-pc').style.display='none';
dubResetBtn(); toast(msg);
}
function _dubSSE(tid){
if(DUB_SSE) DUB_SSE.close();
DUB_SSE=new EventSource('/api/progress/'+tid);
DUB_SSE.onmessage=e=>{
try{
const p=JSON.parse(e.data);
document.getElementById('dub-pb').style.width=(p.pct||0)+'%';
document.getElementById('dub-pmsg').textContent=(p.msg||'').trim();
const pct=p.pct||0;
if(pct>=15) document.getElementById('dub-ps-dl').classList.add('ps-done');
if(pct>=55) document.getElementById('dub-ps-tr').classList.add('ps-done');
if(pct>=80) document.getElementById('dub-ps-tts').classList.add('ps-done');
if(pct>=100) document.getElementById('dub-ps-render').classList.add('ps-done');
if(p.done){
DUB_SSE.close(); DUB_SSE=null; clearInterval(DUB_TICK); DUB_TICK=null;
document.getElementById('dub-pc').style.display='none';
dubResetBtn();
if(p.coins!=null&&p.coins!==-1) updC(p.coins);
DUB_VOUT=p.output_url||'';
document.getElementById('dub-rvid').src=DUB_VOUT;
document.getElementById('dub-rc').style.display='block';
document.getElementById('dub-rc').scrollIntoView({behavior:'smooth'});
toast('✅ AI Dubbing ပြီးပါပြီ!');
} else if(p.error){
DUB_SSE.close(); DUB_SSE=null; _dubFail((p.msg||'').trim()||'❌ Failed');
}
}catch(ex){}
};
}
function dubDlVideo(){
if(!DUB_VOUT) return;
const a=document.createElement('a'); a.href=DUB_VOUT; a.download='ai_dubbed_video.mp4'; a.click();
}
function dubReset(){
document.getElementById('dub-vurl').value='';
document.getElementById('dub-vfile').value='';
document.getElementById('dub-upzn').style.display='none';
document.getElementById('dub-ubadge').style.display='none';
document.getElementById('dub-rc').style.display='none';
document.getElementById('dub-pc').style.display='none';
DUB_VOUT='';
dubResetBtn();
}
let SRT_VOUT='', SRT_CACHE_KEY='';
let SRT_TEXT='', SRT_VPATH_KEY='';
let SRT_FLIP=false, SRT_COL=false;
let SRT_ZOOM=false, SRT_AUDIO=false;
let SRT_BLUR_ON=false, SRT_WM_ON=false, SRT_LOGO_ON=false;
let SRT_SSE=null, SRT_TICK=null, SRT_T0=0;
let SRT_URL_DEB=null;
let SRT_REGEN_COUNT=0;
/* ── Video source handlers ── */
function onSrtUrl(v){
const b=document.getElementById('srt-ubadge');
b.style.display='none'; SRT_CACHE_KEY=''; SRT_REGEN_COUNT=0;
if(!v) return;
const vl=v.toLowerCase();
if(vl.includes('youtube.com')||vl.includes('youtu.be')){b.textContent='YouTube';b.className='ubadge b-yt';b.style.display='';}
else if(vl.includes('tiktok.com')){b.textContent='TikTok';b.className='ubadge b-tt';b.style.display='';}
else if(vl.includes('instagram.com')){b.textContent='Instagram';b.className='ubadge b-ig';b.style.display='';}
else if(vl.includes('facebook.com')||vl.includes('fb.watch')){b.textContent='Facebook';b.className='ubadge b-fb';b.style.display='';}
if(SRT_URL_DEB) clearTimeout(SRT_URL_DEB);
if(v.startsWith('http')){
SRT_URL_DEB=setTimeout(()=>srtAutoThumb(v),1200);
}
}
async function srtAutoThumb(url){
const loading=document.getElementById('srt-prev-loading');
loading.classList.add('on');
try{
const r=await fetch('/api/thumb',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url})});
const d=await r.json();
if(d.ok){
const th=document.getElementById('srt-pthumb');
th.src=d.url; th.style.display='block';
document.getElementById('srt-pvid').style.display='none';
document.getElementById('srt-canvas-ph').style.display='none';
th.onload=()=>{applySrtCropPreview();syncSrtSubPreview();};
}
}catch(e){}
loading.classList.remove('on');
}
function onSrtVFile(inp){
const f=inp.files[0]; if(!f) return;
document.getElementById('srt-upzn').textContent=f.name;
document.getElementById('srt-upzn').style.display='block';
document.getElementById('srt-vurl').value='';
document.getElementById('srt-ubadge').style.display='none';
SRT_CACHE_KEY=''; SRT_REGEN_COUNT=0;
const url=URL.createObjectURL(f);
const v=document.getElementById('srt-pvid');
v.src=url; v.style.display='block';
document.getElementById('srt-pthumb').style.display='none';
document.getElementById('srt-canvas-ph').style.display='none';
v.onloadedmetadata=()=>{applySrtCropPreview();syncSrtSubPreview();};
}
function onSrtLogoFile(inp){
const f=inp.files[0]; if(!f) return;
document.getElementById('srt-logo-name').textContent=f.name;
document.getElementById('srt-logo-name').style.color='#6ee7b7';
const r=new FileReader();
r.onload=e=>{
const box=document.getElementById('srt-db-logo');
box.style.backgroundImage='url('+e.target.result+')';
box.style.backgroundSize='contain';
box.style.backgroundRepeat='no-repeat';
box.style.backgroundPosition='center';
const lbl=document.getElementById('srt-db-logo-lbl');
if(lbl) lbl.style.display='none';
};
r.readAsDataURL(f);
}
async function srtPaste(){
try{
const t=await navigator.clipboard.readText();
if(t){document.getElementById('srt-vurl').value=t;onSrtUrl(t);toast('✅ Pasted!');}
else toast('❌ Clipboard empty');
}catch(e){toast('❌ Clipboard access denied');}
}
/* ── Overlay toggle (movie recap style) ── */
function _srtOvBtn(id, on, ac, bc){
const b=document.getElementById(id); if(!b) return;
if(on){b.style.background=ac;b.style.borderColor=bc;b.style.color='#fff';b.textContent='On';}
else{b.style.background='';b.style.borderColor='';b.style.color='';b.textContent='Off';}
}
function srtOvToggle(k){
if(k==='blur'){
SRT_BLUR_ON=!SRT_BLUR_ON;
_srtOvBtn('srt-ov-blur',SRT_BLUR_ON,'rgba(239,68,68,.28)','#ef4444');
document.getElementById('srt-db-blur').style.display=SRT_BLUR_ON?'block':'none';
document.getElementById('srt-ov-blur-hint').style.display=SRT_BLUR_ON?'block':'none';
if(SRT_BLUR_ON) initSrtDrag();
return;
}
if(k==='wm'){
SRT_WM_ON=!SRT_WM_ON;
_srtOvBtn('srt-ov-wm',SRT_WM_ON,'rgba(234,179,8,.28)','#ca8a04');
document.getElementById('srt-db-wm').style.display=SRT_WM_ON?'block':'none';
document.getElementById('srt-ov-wm-wrap').style.display=SRT_WM_ON?'block':'none';
if(SRT_WM_ON){initSrtDrag();setTimeout(()=>{const i=document.getElementById('srt-wm-text');if(i)i.focus();},60);}
return;
}
if(k==='logo'){
SRT_LOGO_ON=!SRT_LOGO_ON;
_srtOvBtn('srt-ov-logo',SRT_LOGO_ON,'rgba(16,185,129,.28)','#10b981');
document.getElementById('srt-db-logo').style.display=SRT_LOGO_ON?'block':'none';
document.getElementById('srt-ov-logo-wrap').style.display=SRT_LOGO_ON?'block':'none';
if(SRT_LOGO_ON) initSrtDrag();
return;
}
if(k==='zoom'){
SRT_ZOOM=!SRT_ZOOM;
_srtOvBtn('srt-ov-zoom',SRT_ZOOM,'rgba(234,88,12,.28)','var(--purple)');
_srtApplyZoomPreview();
return;
}
if(k==='audio'){
SRT_AUDIO=!SRT_AUDIO;
_srtOvBtn('srt-ov-audio',SRT_AUDIO,'rgba(59,130,246,.28)','#2563eb');
return;
}
}
/* ── Flip / Color toggles ── */
function srtToggleOpt(k){
if(k==='flip'){
SRT_FLIP=!SRT_FLIP;
const b=document.getElementById('srt-btn-flip');
b.style.background=SRT_FLIP?'rgba(56,189,248,.18)':'rgba(255,255,255,.05)';
b.style.borderColor=SRT_FLIP?'#38bdf8':'rgba(255,255,255,.12)';
b.style.color=SRT_FLIP?'#38bdf8':'rgba(255,255,255,.55)';
b.innerHTML='<i class="fas fa-arrows-alt-h"></i> Flip: '+(SRT_FLIP?'On':'Off');
} else if(k==='col'){
SRT_COL=!SRT_COL;
const b=document.getElementById('srt-btn-col');
b.style.background=SRT_COL?'rgba(251,191,36,.18)':'rgba(255,255,255,.05)';
b.style.borderColor=SRT_COL?'#fbbf24':'rgba(255,255,255,.12)';
b.style.color=SRT_COL?'#fbbf24':'rgba(255,255,255,.55)';
b.innerHTML='<i class="fas fa-adjust"></i> Color: '+(SRT_COL?'On':'Off');
}
}
function _srtApplyZoomPreview(){
const thumb=document.getElementById('srt-pthumb');
const vid=document.getElementById('srt-pvid');
const zv=document.getElementById('srt-zoom-factor');
const scale=SRT_ZOOM&&zv?parseFloat('1.0'+(''+zv.value).slice(1)):1;
if(thumb) thumb.style.transform=scale>1?`scale(${scale})`:'';
if(vid) vid.style.transform=scale>1?`scale(${scale})`:'';
}
function _subSizeOptions(crop){
// XSmall/Small/Medium/Large only — Small default
if(crop==='9:16')
return '<option value="0.0469" selected>Small</option>';
if(crop==='1:1')
return '<option value="0.0469" selected>Small</option><option value="0.0625">Medium</option>';
// 16:9 and original
return '<option value="0.0350">XSmall</option><option value="0.0469" selected>Small</option><option value="0.0625">Medium</option><option value="0.0781">Large</option>';
}
function onSrtCropChange(){
const crop=document.getElementById('srt-crop').value;
const sel=document.getElementById('srt-sub-size');
if(!sel) return;
sel.innerHTML=_subSizeOptions(crop);
applySrtCropPreview();
syncSrtSubPreview();
}
function applySrtCropPreview(){
const crop=(document.getElementById('srt-crop')||{value:'original'}).value;
const bg=document.getElementById('srt-canvas-bg-blur');
const vw=document.getElementById('srt-canvas-video-wrap');
const ci=document.getElementById('srt-canvas-inner');
const thumb=document.getElementById('srt-pthumb');
const vid=document.getElementById('srt-pvid');
if(!vw||!ci) return;
// Reset
vw.style.width='100%'; vw.style.margin='';
ci.style.left='0'; ci.style.width='100%';
if(bg) bg.style.display='none';
const RATIOS={'9:16':[9,16],'16:9':[16,9],'1:1':[1,1]};
const tgt=RATIOS[crop];
if(!tgt) return; // original — no reshape
const tgtRatio=tgt[0]/tgt[1];
let srcW=0,srcH=0;
if(vid&&vid.style.display!=='none'&&vid.videoWidth>0){
srcW=vid.videoWidth; srcH=vid.videoHeight;
} else if(thumb&&thumb.naturalWidth>0){
srcW=thumb.naturalWidth; srcH=thumb.naturalHeight;
}
if(!srcW||!srcH) return;
const srcRatio=srcW/srcH;
if(Math.abs(tgtRatio-srcRatio)<0.05) return;
// Blurred background
if(bg){
try{
const c=document.createElement('canvas');
c.width=srcW; c.height=srcH;
const ctx=c.getContext('2d');
if(vid&&vid.style.display!=='none'&&vid.videoWidth>0) ctx.drawImage(vid,0,0,srcW,srcH);
else if(thumb&&thumb.naturalWidth>0) ctx.drawImage(thumb,0,0,srcW,srcH);
bg.style.backgroundImage='url('+c.toDataURL('image/jpeg',0.4)+')';
bg.style.display='block';
} catch(e){
bg.style.background='rgba(20,20,20,.9)';
bg.style.display='block';
}
}
// Narrow wrap width to match crop ratio (same as movie recap applyCropPreview)
if(srcRatio > tgtRatio){
const pct=(tgtRatio/srcRatio*100).toFixed(2)+'%';
vw.style.width=pct;
vw.style.margin='0 auto';
const off=((100-(tgtRatio/srcRatio*100))/2).toFixed(2)+'%';
ci.style.left=off;
ci.style.width=(tgtRatio/srcRatio*100).toFixed(2)+'%';
}
}
function _filterSubSize(){
// Movie Recap mode — filter #sub-size based on #crop
const crop=(document.getElementById('crop')||{value:'original'}).value;
const sel=document.getElementById('sub-size');
if(!sel) return;
const cur=sel.value;
if(crop==='9:16'){
sel.innerHTML='<option value="0.0469" selected>Small</option>';
} else if(crop==='1:1')
sel.innerHTML='<option value="0.0469" selected>Small</option><option value="0.0625">Medium</option>';
else
sel.innerHTML='<option value="0.0350">XSmall</option><option value="0.0469" selected>Small</option><option value="0.0625">Medium</option><option value="0.0781">Large</option>';
// Try to keep previous selection if still valid
const opt=[...sel.options].find(o=>o.value===cur);
if(opt) sel.value=cur; else sel.selectedIndex=sel.options.length>1?1:0;
}
function syncSrtSubPreview(){
const overlay=document.getElementById('srt-sub-overlay');
if(!overlay) return;
const thumb=document.getElementById('srt-pthumb');
const vid=document.getElementById('srt-pvid');
const hasMedia=(thumb&&thumb.style.display!=='none'&&thumb.src)||
(vid&&vid.style.display!=='none'&&vid.src);
if(!hasMedia){overlay.style.display='none';return;}
const posVal=parseInt((document.getElementById('srt-sub-pos')||{value:85}).value)||85;
// Use canvas-inner bounding rect — same logic as blur/wm/logo getBoxPct()
const srtCi=document.getElementById('srt-canvas-inner');
if(!srtCi){overlay.style.display='none';return;}
const ciR=srtCi.getBoundingClientRect();
if(!ciR.height){overlay.style.display='none';return;}
overlay.style.top=(ciR.height*(posVal/100))+'px';
overlay.style.transform='translateY(-50%)';
overlay.style.display='block';
}
/* ── Drag/Resize for SRT canvas (same logic as movie recap initDrag) ── */
function initSrtDrag(){
['srt-db-blur','srt-db-wm','srt-db-logo'].forEach(id=>{
const el=document.getElementById(id);
if(el){srtMakeDrag(el);srtMakeResize(el,el.querySelector('.rh'));}
});
}
function srtMakeDrag(el){
if(el._srtDragDone) return;
el._srtDragDone=true;
let ox,oy,ex,ey;
const down=e=>{
if(e.target.classList.contains('rh'))return;
e.preventDefault();
const t=e.touches?e.touches[0]:e;
const pr=document.getElementById('srt-canvas-inner');
const r=el.getBoundingClientRect(),pR=pr.getBoundingClientRect();
ox=t.clientX;oy=t.clientY;
ex=r.left-pR.left;ey=r.top-pR.top;
const mv=e=>{
e.preventDefault();
const t=e.touches?e.touches[0]:e;
el.style.left=(ex+t.clientX-ox)+'px';
el.style.top=(ey+t.clientY-oy)+'px';
el.style.bottom='auto';
};
const up=()=>{
document.removeEventListener('mousemove',mv);
document.removeEventListener('mouseup',up);
document.removeEventListener('touchmove',mv);
document.removeEventListener('touchend',up);
};
document.addEventListener('mousemove',mv);
document.addEventListener('mouseup',up);
document.addEventListener('touchmove',mv,{passive:false});
document.addEventListener('touchend',up);
};
el.addEventListener('mousedown',down);
el.addEventListener('touchstart',down,{passive:false});
}
function srtMakeResize(el,h){
if(!h||h._srtResizeDone) return;
h._srtResizeDone=true;
const down=e=>{
e.stopPropagation();e.preventDefault();
const t=e.touches?e.touches[0]:e;
const sw=el.offsetWidth,sh=el.offsetHeight,sx=t.clientX,sy=t.clientY;
const mv=e=>{
e.preventDefault();
const t=e.touches?e.touches[0]:e;
el.style.width=Math.max(40,sw+t.clientX-sx)+'px';
el.style.height=Math.max(30,sh+t.clientY-sy)+'px';
};
const up=()=>{
document.removeEventListener('mousemove',mv);
document.removeEventListener('mouseup',up);
document.removeEventListener('touchmove',mv);
document.removeEventListener('touchend',up);
};
document.addEventListener('mousemove',mv);
document.addEventListener('mouseup',up);
document.addEventListener('touchmove',mv,{passive:false});
document.addEventListener('touchend',up);
};
h.addEventListener('mousedown',down);
h.addEventListener('touchstart',down,{passive:false});
}
function getSrtBoxPct(id){
const el=document.getElementById(id);
const ci=document.getElementById('srt-canvas-inner');
const video=document.getElementById('srt-pvid');
const crop=document.getElementById('srt-crop').value;
const srcW=video.videoWidth||720, srcH=video.videoHeight||1280;
let tW,tH;
if(crop==='9:16'){tW=720;tH=1280;}
else if(crop==='16:9'){tW=1280;tH=720;}
else if(crop==='1:1'){tW=720;tH=720;}
else{tW=srcW;tH=srcH;}
const ciR=ci.getBoundingClientRect();
const elR=el.getBoundingClientRect();
const sx=tW/ciR.width, sy=tH/ciR.height;
return{
x:Math.max(0,Math.min(1,((elR.left-ciR.left)*sx)/tW)),
y:Math.max(0,Math.min(1,((elR.top-ciR.top)*sy)/tH)),
w:Math.max(0,Math.min(1,(elR.width*sx)/tW)),
h:Math.max(0,Math.min(1,(elR.height*sy)/tH))
};
}
function hasSrtVid(){
return document.getElementById('srt-vurl').value.trim()||
(document.getElementById('srt-vfile').files||[]).length>0;
}
/* ── Progress helpers ── */
function srtShowProg(on){
document.getElementById('srt-pc').style.display=on?'block':'none';
if(on){
document.getElementById('srt-pb').style.width='0%';
document.getElementById('srt-pmsg').textContent='⏳ တန်းစီစောင့်နေသည်…';
document.getElementById('srt-ptmr').textContent='⏱ 0s';
['srt-ps-dl','srt-ps-ai','srt-ps-burn'].forEach(id=>{document.getElementById(id).className='ps';});
}
}
function srtUpdSteps(pct){
const MAP={8:'srt-ps-dl',50:'srt-ps-ai',75:'srt-ps-burn'};
let hit=false;
Object.entries(MAP).forEach(([p,id])=>{
const el=document.getElementById(id);
if(pct>=parseInt(p)){el.className='ps done';}
else if(!hit){el.className='ps active';hit=true;}
else el.className='ps';
});
}
function srtStartTick(){SRT_T0=Date.now();if(SRT_TICK)clearInterval(SRT_TICK);SRT_TICK=setInterval(()=>{document.getElementById('srt-ptmr').textContent='⏱ '+fmt(Math.floor((Date.now()-SRT_T0)/1000));},1000);}
function srtStopTick(){if(SRT_TICK){clearInterval(SRT_TICK);SRT_TICK=null;}}
function srtResetBtn(){
const b=document.getElementById('srt-gen-btn');
if(b){b.disabled=false;b.innerHTML='<i class="fas fa-robot"></i> Generate Myanmar SRT <span style="opacity:.7;font-size:.78em;background:rgba(255,255,255,.2);padding:2px 8px;border-radius:10px">1 Coin</span>';}
const b2=document.getElementById('srt-burn-btn');
if(b2){b2.disabled=false;b2.innerHTML='<i class="fas fa-film"></i> Render Video';}
_updateRegenBtn();
}
/* ── STEP 1: Generate SRT ── */
async function doGenerateSrt(){
if(!hasSrtVid()){toast('❌ Video URL သို့ file ထည့်ပါ');return;}
if(!U){toast('❌ Login ဦးဝင်ပါ');return;}
const btn=document.getElementById('srt-gen-btn');
btn.disabled=true;
btn.innerHTML='<i class="fas fa-spinner sp"></i> Generating…';
const pc=document.getElementById('srt-gen-pc');
pc.style.display='block';
document.getElementById('srt-step2-wrap').style.display='none';
document.getElementById('srt-rc').style.display='none';
// Start timer
SRT_T0=Date.now();
if(SRT_TICK) clearInterval(SRT_TICK);
SRT_TICK=setInterval(()=>{
const el=document.getElementById('srt-gen-ptmr');
if(el) el.textContent='⏱ '+Math.floor((Date.now()-SRT_T0)/1000)+'s';
},1000);
const fd=new FormData();
fd.append('username',U);
const vurl=document.getElementById('srt-vurl').value.trim();
const vf=document.getElementById('srt-vfile').files[0];
if(vf) fd.append('video_file',vf);
else fd.append('video_url',vurl);
if(SRT_CACHE_KEY) fd.append('cache_key',SRT_CACHE_KEY);
const tid=uid8(); fd.append('tid',tid);
try{
const ctrl=new AbortController(),tout=setTimeout(()=>ctrl.abort(),1200000);
const r=await fetch('/api/generate_srt',{method:'POST',body:fd,signal:ctrl.signal});
clearTimeout(tout);
if(!r.ok){_srtGenFail('❌ Server error '+r.status);return;}
const d=await r.json();
if(!d.ok){_srtGenFail(d.msg||'❌ Failed');return;}
_srtGenSSE(tid);
}catch(e){
_srtGenFail(e.name==='AbortError'?'❌ Timeout':'❌ '+e);
}
}
function _srtGenFail(msg){
clearInterval(SRT_TICK); SRT_TICK=null;
document.getElementById('srt-gen-pc').style.display='none';
srtResetBtn(); toast(msg);
}
function _srtGenSSE(tid){
const sse=new EventSource('/api/progress/'+tid);
sse.onmessage=e=>{
try{
const p=JSON.parse(e.data);
document.getElementById('srt-gen-pb').style.width=(p.pct||0)+'%';
document.getElementById('srt-gen-pmsg').textContent=(p.msg||'').trim();
// Steps
if((p.pct||0)>=8) document.getElementById('srt-ps-dl').classList.add('ps-done');
if((p.pct||0)>=50) document.getElementById('srt-ps-ai').classList.add('ps-done');
if(p.done){
sse.close(); clearInterval(SRT_TICK); SRT_TICK=null;
document.getElementById('srt-gen-pc').style.display='none';
srtResetBtn();
if(p.coins!=null&&p.coins!==-1) updC(p.coins);
SRT_TEXT=p.srt||'';
SRT_VPATH_KEY=p.vpath_key||tid;
SRT_REGEN_COUNT++;
_updateRegenBtn();
_srtShowStep2(p);
toast('✅ SRT ပြီးပါပြီ!');
} else if(p.error){
sse.close(); _srtGenFail((p.msg||'').trim()||'❌ Failed');
}
}catch(ex){}
};
}
function _srtShowStep2(p){
// Show preview box
const box=document.getElementById('srt-preview-box');
box.textContent=SRT_TEXT;
// Block count badge
const cnt=document.getElementById('srt-block-count');
if(cnt) cnt.textContent=(p.total||0)+' lines';
// First subtitle on thumbnail
const blocks=SRT_TEXT.trim().split(/\n\s*\n/);
let firstTxt='';
for(const blk of blocks){
const lines=blk.trim().split('\n');
for(let i=0;i<lines.length;i++){
if(lines[i].includes('-->')){
firstTxt=lines.slice(i+1).join(' ').trim();
break;
}
}
if(firstTxt) break;
}
const fsw=document.getElementById('srt-first-sub-wrap');
const fst=document.getElementById('srt-first-sub-txt');
if(firstTxt && fsw && fst){
fst.textContent=firstTxt;
fsw.style.display='block';
// Show on thumbnail overlay
const span=document.getElementById('srt-sub-preview-span');
if(span) span.textContent=firstTxt;
syncSrtSubPreview();
}
document.getElementById('srt-step2-wrap').style.display='block';
document.getElementById('srt-step2-wrap').scrollIntoView({behavior:'smooth'});
}
/* ── Regen button lock state ── */
function _updateRegenBtn(){
const btn=document.querySelector('[onclick="doRegenSrt()"]');
if(!btn) return;
if(SRT_REGEN_COUNT>=2){
btn.disabled=true;
btn.style.opacity='0.4';
btn.style.cursor='not-allowed';
btn.innerHTML='<i class="fas fa-lock"></i> Regen (၂/၂ ကုန်ပြီ)';
} else {
btn.disabled=false;
btn.style.opacity='';
btn.style.cursor='';
btn.innerHTML='<i class="fas fa-redo"></i> Regenerate ('+(2-SRT_REGEN_COUNT)+' ကြိမ် ကျန်)';
}
}
/* ── Regenerate SRT (Step 1 again, same video) ── */
async function doRegenSrt(){
if(!SRT_VPATH_KEY && !hasSrtVid()){toast('❌ Video မရှိပါ');return;}
if(!U){toast('❌ Login ဦးဝင်ပါ');return;}
if(SRT_REGEN_COUNT >= 2){toast('❌ Regenerate ၂ ခါ ကုန်ပြီ — Video အသစ်တင်ပါ');return;}
document.getElementById('srt-step2-wrap').style.display='none';
SRT_TEXT=''; SRT_VPATH_KEY='';
const fd=new FormData();
fd.append('username',U);
const vurl=document.getElementById('srt-vurl').value.trim();
const vf=document.getElementById('srt-vfile').files[0];
if(vf) fd.append('video_file',vf);
else fd.append('video_url',vurl);
if(SRT_CACHE_KEY) fd.append('cache_key',SRT_CACHE_KEY);
fd.append('free_regen','1');
const tid=uid8(); fd.append('tid',tid);
const btn=document.querySelector('[onclick="doRegenSrt()"]');
if(btn){btn.disabled=true;btn.innerHTML='<i class="fas fa-spinner sp"></i> Regenerating…';}
const pc=document.getElementById('srt-gen-pc');
pc.style.display='block';
SRT_T0=Date.now();
if(SRT_TICK) clearInterval(SRT_TICK);
SRT_TICK=setInterval(()=>{
const el=document.getElementById('srt-gen-ptmr');
if(el) el.textContent='⏱ '+Math.floor((Date.now()-SRT_T0)/1000)+'s';
},1000);
try{
const ctrl=new AbortController(),tout=setTimeout(()=>ctrl.abort(),600000);
const r=await fetch('/api/generate_srt',{method:'POST',body:fd,signal:ctrl.signal});
clearTimeout(tout);
const d=await r.json();
if(!d.ok){pc.style.display='none';clearInterval(SRT_TICK);_updateRegenBtn();toast(d.msg||'❌ Failed');return;}
_srtGenSSE(d.tid||tid);
}catch(e){
pc.style.display='none'; clearInterval(SRT_TICK);
_updateRegenBtn();
toast('❌ '+e);
}
}
/* ── STEP 2: Burn/Process SRT ── */
async function doProcessSrt(){
if(!SRT_TEXT){toast('❌ SRT မရှိပါ — Generate ဦးလုပ်ပါ');return;}
if(!U){toast('❌ Login ဦးဝင်ပါ');return;}
const btn=document.getElementById('srt-burn-btn');
btn.disabled=true;
btn.innerHTML='<i class="fas fa-spinner sp"></i> Rendering…';
document.getElementById('srt-pc').style.display='block';
document.getElementById('srt-rc').style.display='none';
SRT_T0=Date.now();
if(SRT_TICK) clearInterval(SRT_TICK);
SRT_TICK=setInterval(()=>{
const el=document.getElementById('srt-ptmr');
if(el) el.textContent='⏱ '+Math.floor((Date.now()-SRT_T0)/1000)+'s';
},1000);
const fd=new FormData();
fd.append('username',U);
fd.append('srt_text',SRT_TEXT);
fd.append('vpath_key',SRT_VPATH_KEY);
// Video source fallback
const vurl=document.getElementById('srt-vurl').value.trim();
const vf=document.getElementById('srt-vfile').files[0];
if(vf) fd.append('video_file',vf);
else if(vurl) fd.append('video_url',vurl);
if(SRT_CACHE_KEY) fd.append('cache_key',SRT_CACHE_KEY);
// Subtitle settings
fd.append('sub_pos',document.getElementById('srt-sub-pos').value);
fd.append('sub_size',document.getElementById('srt-sub-size').value);
fd.append('sub_color',document.getElementById('srt-sub-color').value);
fd.append('sub_style',document.getElementById('srt-sub-style').value);
// Video settings
fd.append('crop',document.getElementById('srt-crop').value);
fd.append('flip',SRT_FLIP?'1':'0');
fd.append('color',SRT_COL?'1':'0');
fd.append('zoom_enabled',SRT_ZOOM?'1':'0');
if(SRT_ZOOM){
const zvEl=document.getElementById('srt-zoom-factor');
const zv=zvEl?zvEl.value:'105';
fd.append('zoom_factor',(+zv/100).toFixed(2));
}
fd.append('audio_boost',SRT_AUDIO?'1':'0');
// Blur
fd.append('blur_enabled',SRT_BLUR_ON?'1':'0');
if(SRT_BLUR_ON){
const bp=getSrtBoxPct('srt-db-blur');
fd.append('blur_xp',bp.x.toFixed(4));fd.append('blur_yp',bp.y.toFixed(4));
fd.append('blur_wp',bp.w.toFixed(4));fd.append('blur_hp',bp.h.toFixed(4));
}
// Watermark
const wmkTxt=SRT_WM_ON?(document.getElementById('srt-wm-text').value.trim()):'';
fd.append('watermark',wmkTxt);
if(SRT_WM_ON&&wmkTxt){
const wp=getSrtBoxPct('srt-db-wm');
fd.append('wmk_xp',wp.x.toFixed(4));fd.append('wmk_yp',wp.y.toFixed(4));
fd.append('wmk_fontsize','28');
}
// Logo
const lf=document.getElementById('srt-logo-file');
if(SRT_LOGO_ON&&lf&&lf.files[0]){
fd.append('logo_file',lf.files[0]);
const lp=getSrtBoxPct('srt-db-logo');
fd.append('logo_xp',lp.x.toFixed(4));fd.append('logo_yp',lp.y.toFixed(4));
fd.append('logo_wp',lp.w.toFixed(4));
}
const tid=uid8(); fd.append('tid',tid);
try{
const ctrl=new AbortController(),tout=setTimeout(()=>ctrl.abort(),600000);
const r=await fetch('/api/burn_srt',{method:'POST',body:fd,signal:ctrl.signal});
clearTimeout(tout);
if(!r.ok){_srtBurnFail('❌ Server error '+r.status);return;}
const d=await r.json();
if(!d.ok){_srtBurnFail(d.msg||'❌ Failed');return;}
_srtBurnSSE(tid);
}catch(e){
_srtBurnFail(e.name==='AbortError'?'❌ Timeout':'❌ '+e);
}
}
function _srtBurnFail(msg){
clearInterval(SRT_TICK); SRT_TICK=null;
document.getElementById('srt-pc').style.display='none';
srtResetBtn(); toast(msg);
}
function _srtBurnSSE(tid){
if(SRT_SSE) SRT_SSE.close();
SRT_SSE=new EventSource('/api/progress/'+tid);
SRT_SSE.onmessage=e=>{
try{
const p=JSON.parse(e.data);
document.getElementById('srt-pb').style.width=(p.pct||0)+'%';
document.getElementById('srt-pmsg').textContent=(p.msg||'').trim();
if((p.pct||0)>=75) document.getElementById('srt-ps-burn').classList.add('ps-done');
if(p.done){
SRT_SSE.close(); SRT_SSE=null; clearInterval(SRT_TICK); SRT_TICK=null;
document.getElementById('srt-pc').style.display='none';
srtResetBtn();
if(p.coins!=null&&p.coins!==-1) updC(p.coins);
SRT_VOUT=p.output_url||'';
document.getElementById('srt-rvid').src=SRT_VOUT;
document.getElementById('srt-rc').style.display='block';
document.getElementById('srt-rc').scrollIntoView({behavior:'smooth'});
toast('✅ Video ပြီးပါပြီ!');
} else if(p.error){
SRT_SSE.close(); SRT_SSE=null; _srtBurnFail((p.msg||'').trim()||'❌ Failed');
}
}catch(ex){}
};
}
function srtDlVideo(){
if(!SRT_VOUT) return;
const a=document.createElement('a'); a.href=SRT_VOUT; a.download='myanmar_subtitle_video.mp4'; a.click();
}
function srtReset(){
if(SRT_SSE){SRT_SSE.close();SRT_SSE=null;}
srtStopTick(); srtShowProg(false);
SRT_VOUT=''; SRT_CACHE_KEY=''; SRT_TEXT=''; SRT_VPATH_KEY=''; SRT_REGEN_COUNT=0;
SRT_FLIP=false; SRT_COL=false; SRT_ZOOM=false; SRT_AUDIO=false;
SRT_BLUR_ON=false; SRT_WM_ON=false; SRT_LOGO_ON=false;
document.getElementById('srt-vurl').value='';
try{document.getElementById('srt-vfile').value='';}catch(e){}
document.getElementById('srt-upzn').style.display='none';
document.getElementById('srt-ubadge').style.display='none';
document.getElementById('srt-pvid').style.display='none';
document.getElementById('srt-pvid').style.transform='';
document.getElementById('srt-pthumb').style.display='none';
document.getElementById('srt-pthumb').style.transform='';
document.getElementById('srt-canvas-ph').style.display='flex';
const sov=document.getElementById('srt-sub-overlay');if(sov)sov.style.display='none';
document.getElementById('srt-rc').style.display='none';
document.getElementById('srt-step2-wrap').style.display='none';
document.getElementById('srt-gen-pc').style.display='none';
const pb=document.getElementById('srt-preview-box');if(pb)pb.textContent='';
const fsw=document.getElementById('srt-first-sub-wrap');if(fsw)fsw.style.display='none';
const bflip=document.getElementById('srt-btn-flip');
bflip.style.background='rgba(255,255,255,.05)';bflip.style.borderColor='rgba(255,255,255,.12)';bflip.style.color='rgba(255,255,255,.55)';
bflip.innerHTML='<i class="fas fa-arrows-alt-h"></i> Flip: Off';
const bcol=document.getElementById('srt-btn-col');
bcol.style.background='rgba(255,255,255,.05)';bcol.style.borderColor='rgba(255,255,255,.12)';bcol.style.color='rgba(255,255,255,.55)';
bcol.innerHTML='<i class="fas fa-adjust"></i> Color: Off';
['srt-ov-blur','srt-ov-wm','srt-ov-logo','srt-ov-zoom','srt-ov-audio'].forEach(id=>{
const b=document.getElementById(id); if(b){b.style.background='';b.style.borderColor='';b.style.color='';b.textContent='Off';}
});
['srt-db-blur','srt-db-wm','srt-db-logo'].forEach(id=>{
const el=document.getElementById(id);
if(el){el.style.display='none';el._srtDragDone=false;const rh=el.querySelector('.rh');if(rh)rh._srtResizeDone=false;}
});
['srt-ov-wm-wrap','srt-ov-logo-wrap','srt-ov-blur-hint'].forEach(id=>{const el=document.getElementById(id);if(el)el.style.display='none';});
const lbl=document.getElementById('srt-db-logo-lbl'); if(lbl)lbl.style.display='flex';
const ln=document.getElementById('srt-logo-name'); if(ln){ln.textContent='Click to upload PNG / JPG';ln.style.color='';}
const db=document.getElementById('srt-db-logo'); if(db){db.style.backgroundImage='';}
// Reset canvas crop reshape
const vw2=document.getElementById('srt-canvas-video-wrap');
const ci2=document.getElementById('srt-canvas-inner');
const bg2=document.getElementById('srt-canvas-bg-blur');
if(vw2){vw2.style.width='100%';vw2.style.margin='';}
if(ci2){ci2.style.left='0';ci2.style.width='100%';}
if(bg2){bg2.style.display='none';}
srtResetBtn();
}
</script>
<!-- ══ PAYMENT MODAL ══ -->
<div class="pov" id="pov" onclick="if(event.target===this)closePay()">
<div class="paysheet">
<!-- Header -->
<div class="paysheet-hdr">
<h2><span>🪙</span> Buy Credits</h2>
<button class="pclose" onclick="closePay()"><i class="fas fa-times"></i></button>
</div>
<!-- Tabs -->
<div class="tab2">
<button id="ptab-buy" class="on" onclick="showPayTab('buy')">🛒 ဝယ်ရန်</button>
<button id="ptab-his" onclick="showPayTab('his')">📋 မှတ်တမ်း</button>
</div>
<!-- BUY TAB -->
<div id="ptab-buy-content">
<!-- STEP 1: Package selection -->
<div class="pay-step on" id="pay-step-1">
<div class="pstep-lbl"><span class="pstep-num">1</span> Package ရွေးပါ</div>
<div style="margin:8px 22px 0;padding:8px 12px;background:rgba(234,88,12,.08);border:1px solid rgba(234,88,12,.15);border-radius:9px;font-size:.72rem;color:rgba(255,255,255,.6);line-height:1.7">
💡 Coin တစ်ခု = Video တစ်ခု ထုတ်နိုင်သည် · Package ကြီးလေ တစ်ခုဈေးနည်းလေ
</div>
<!-- Currency tabs -->
<div style="display:flex;gap:8px;padding:10px 22px 0">
<button id="ctab-mmk" onclick="renderPkgs('mmk')" style="flex:1;padding:10px 8px;border-radius:12px;border:2px solid rgba(234,88,12,.5);background:rgba(194,65,12,.2);color:#fdba74;font-family:var(--F);font-size:.82rem;font-weight:800;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:6px"><span style="font-size:1.1rem">🇲🇲</span> MMK</button>
<button id="ctab-thb" onclick="renderPkgs('thb')" style="flex:1;padding:10px 8px;border-radius:12px;border:2px solid rgba(255,255,255,.08);background:rgba(255,255,255,.04);color:rgba(255,255,255,.35);font-family:var(--F);font-size:.82rem;font-weight:800;cursor:pointer;transition:.2s;display:flex;align-items:center;justify-content:center;gap:6px"><span style="font-size:1.1rem">🇹🇭</span> THB</button>
</div>
<div class="ppkgs" id="ppkgs" style="display:grid;grid-template-columns:1fr 1fr;gap:10px;padding:14px 22px 4px"></div>
<button class="buy-now-btn" id="buy-now-btn" onclick="goPayStep2()" disabled style="margin:0 22px 4px">
ဝယ်ရန် →
</button>
</div>
<!-- STEP 2: Payment method -->
<div class="pay-step" id="pay-step-2">
<button class="pback-btn" onclick="goPayStep(1)"><i class="fas fa-arrow-left"></i> ပြန်သွား</button>
<div class="pstep-lbl" style="margin-top:6px"><span class="pstep-num">2</span> ငွေပေးချေနည်း ရွေးပါ</div>
<div style="margin:6px 22px 0;padding:8px 12px;background:rgba(234,88,12,.08);border:1px solid rgba(234,88,12,.15);border-radius:9px;font-size:.72rem;color:rgba(255,255,255,.6);line-height:1.7">
💡 မြန်မာကျပ် = KBZ Pay · ထိုင်းဘတ် = SCB / PromptPay / TrueMoney
</div>
<div class="pmeth-grid">
<div class="pmeth" id="pmeth-kbz" onclick="selMeth('kbz')">
<img class="pmeth-icon" src="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/kbz.png" alt="KBZ Pay">
<div class="pmeth-name">KBZ Pay</div>
</div>
<div class="pmeth" id="pmeth-wave" style="opacity:.4;pointer-events:none;position:relative">
<img class="pmeth-icon" src="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/wave.jpeg" alt="Wave Money">
<div class="pmeth-name">Wave Money</div>
<div class="pmeth-sub" style="color:#ef4444;font-size:.6rem">ခဏပိတ်ထားသည်</div>
</div>
<div class="pmeth" id="pmeth-scb" onclick="selMeth('scb')">
<img class="pmeth-icon" src="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/scb.jpeg" alt="SCB">
<div class="pmeth-name">SCB Bank</div>
<div class="pmeth-sub">ไทยบาท</div>
</div>
<div class="pmeth" id="pmeth-prompt" onclick="selMeth('prompt')">
<img class="pmeth-icon" src="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/prompt.png" alt="PromptPay">
<div class="pmeth-name">PromptPay</div>
<div class="pmeth-sub">ไทยบาท</div>
</div>
<div class="pmeth" id="pmeth-truemoney" onclick="selMeth('truemoney')">
<img class="pmeth-icon" src="https://raw.githubusercontent.com/Shangyi69/psonlineshop/main/true.png" alt="TrueMoney">
<div class="pmeth-name">TrueMoney</div>
<div class="pmeth-sub">ไทยบาท</div>
</div>
</div>
<!-- Payment info box (shown after method select) -->
<div id="pay-info-box" style="display:none">
<div class="pinfo-box" id="pinfo-box-inner"></div>
<button class="buy-now-btn" onclick="goPayStep3()">
Slip တင်မည် →
</button>
</div>
</div>
<!-- STEP 3: Slip upload + submit -->
<div class="pay-step" id="pay-step-3">
<button class="pback-btn" onclick="goPayStep(2)"><i class="fas fa-arrow-left"></i> ပြန်သွား</button>
<div class="pstep-lbl" style="margin-top:6px"><span class="pstep-num">3</span> Slip တင်ပေးပါ</div>
<div style="margin:6px 22px 0;padding:8px 12px;background:rgba(234,88,12,.08);border:1px solid rgba(234,88,12,.15);border-radius:9px;font-size:.72rem;color:rgba(255,255,255,.6);line-height:1.7">
⚠️ ငွေပေးပြီးနောက် Slip ပုံ ထည့်ပြီး Submit နှိပ်ပါ · Admin စစ်ဆေးပြီးမှ Coin ရောက်မည် (၁-၂ နာရီ)
</div>
<div class="pslip-drop" style="margin-top:10px" id="pslip-drop">
<input type="file" accept="image/*" id="pslip-input" onchange="handlePSlip(this)">
<div class="pi" id="pslip-icon">📎</div>
<div class="pt" id="pslip-txt">Slip ပုံကို ဒီနေရာ ဖိဆွဲချပါ<br><span style="color:rgba(255,255,255,.2);font-size:.7rem">သို့မဟုတ် နှိပ်ပြီး ရွေးပါ</span></div>
<img id="pslip-prev" class="pslip-preview">
</div>
<button class="psubmit on" id="psubmit" onclick="submitPay()" disabled>
<i class="fas fa-paper-plane" style="margin-right:8px"></i>Payment တင်ပေးပါ
</button>
</div>
</div>
<!-- HISTORY TAB -->
<div id="ptab-his-content" style="display:none">
<div class="ph-list-wrap">
<div id="ph-list"><div class="ph-empty">⏳ Loading…</div></div>
</div>
</div>
</div>
</div>
<!-- ══ VIDEO HISTORY MODAL ══ -->
<!-- Broadcast Modal -->
<div id="bc-modal" style="display:none;position:fixed;inset:0;z-index:3000;align-items:center;justify-content:center;padding:16px;box-sizing:border-box" onclick="if(event.target===this)closeBroadcast()">
<div style="position:absolute;inset:0;background:rgba(0,0,0,.6);backdrop-filter:blur(6px)"></div>
<div style="position:relative;width:100%;max-width:420px;background:linear-gradient(135deg,#1a1a2e 0%,#16213e 100%);border:1px solid rgba(99,102,241,.3);border-radius:20px;padding:24px;box-shadow:0 20px 60px rgba(0,0,0,.5)">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
<div style="display:flex;align-items:center;gap:10px">
<div style="width:36px;height:36px;border-radius:10px;background:rgba(99,102,241,.2);border:1px solid rgba(99,102,241,.4);display:flex;align-items:center;justify-content:center;color:#6366f1;font-size:.95rem"><i class="fas fa-bullhorn"></i></div>
<div>
<div style="font-weight:800;font-size:1rem;color:#fff">Broadcast</div>
<div style="font-size:.7rem;color:rgba(255,255,255,.4)">Users အားလုံးထံ ပို့မည်</div>
</div>
</div>
<button onclick="closeBroadcast()" style="background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.12);border-radius:8px;width:30px;height:30px;color:rgba(255,255,255,.5);cursor:pointer;font-size:.8rem;display:flex;align-items:center;justify-content:center"><i class="fas fa-times"></i></button>
</div>
<textarea id="bc-msg" placeholder="ကြေငြာချက် ရေးပါ…&#10;&#10;Markdown ပံ့ပိုးသည် — *bold* _italic_" style="width:100%;box-sizing:border-box;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.1);border-radius:12px;color:#fff;padding:14px;font-size:.85rem;font-family:var(--F);resize:none;min-height:120px;outline:none;line-height:1.6;transition:.2s" onfocus="this.style.borderColor='rgba(99,102,241,.5)'" onblur="this.style.borderColor='rgba(255,255,255,.1)'"></textarea>
<div id="bc-char" style="font-size:.68rem;color:rgba(255,255,255,.3);text-align:right;margin-top:4px;margin-bottom:12px">0 / 4096</div>
<div style="display:flex;gap:8px">
<button onclick="closeBroadcast()" style="flex:1;padding:12px;border-radius:10px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.06);color:rgba(255,255,255,.6);cursor:pointer;font-family:var(--F);font-size:.83rem;font-weight:600">မပို့တော့ပါ</button>
<button id="bc-send-btn" onclick="sendBroadcast()" style="flex:2;padding:12px;border-radius:10px;border:none;background:linear-gradient(135deg,#6366f1,#8b5cf6);color:#fff;cursor:pointer;font-family:var(--F);font-size:.83rem;font-weight:700;display:flex;align-items:center;justify-content:center;gap:7px"><i class="fas fa-paper-plane"></i> ပို့မည်</button>
</div>
<div id="bc-res" style="font-size:.78rem;margin-top:10px;text-align:center;font-weight:600;min-height:18px"></div>
</div>
</div>
<div id="vh-overlay" style="display:none;position:fixed;inset:0;z-index:2000;background:rgba(0,0,0,.7);backdrop-filter:blur(4px);overflow-y:auto;padding:20px 12px 40px">
<div style="max-width:600px;margin:0 auto">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px">
<h2 style="color:#fff;font-size:1.2rem;margin:0"><i class="fas fa-film" style="color:#a855f7;margin-right:8px"></i>Video History</h2>
<button onclick="closeVideoHistory()" style="background:rgba(255,255,255,.1);border:none;color:#fff;width:36px;height:36px;border-radius:50%;font-size:1.1rem;cursor:pointer"><i class="fas fa-times"></i></button>
</div>
<p style="color:#888;font-size:.82rem;margin:0 0 16px">Videos are kept for 24 hours after creation.</p>
<div id="vh-list"></div>
</div>
</div>
<style>
.vh-card{background:#1a1a2e;border:1px solid rgba(168,85,247,.2);border-radius:12px;overflow:hidden;margin-bottom:14px}
.vh-thumb-wrap{position:relative;width:100%;aspect-ratio:16/9;background:#0d0d1a;cursor:pointer}
.vh-thumb-wrap video{width:100%;height:100%;object-fit:contain;display:block}
.vh-thumb-overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;background:rgba(0,0,0,.3);transition:opacity .2s}
.vh-thumb-overlay:hover{background:rgba(0,0,0,.1)}
.vh-play-ic{width:52px;height:52px;border-radius:50%;background:rgba(168,85,247,.85);display:flex;align-items:center;justify-content:center;color:#fff;font-size:1.3rem;pointer-events:none}
.vh-info{padding:12px 14px}
.vh-title{color:#e0d7ff;font-size:.95rem;font-weight:600;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.vh-meta{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:10px}
.vh-time{color:#888;font-size:.78rem}<br>.vh-url{color:#888;font-size:.75rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:280px}
.vh-ttl{color:#a855f7;font-size:.75rem;background:rgba(168,85,247,.12);padding:2px 8px;border-radius:10px}
.vh-dl-btn{display:inline-flex;align-items:center;gap:6px;padding:7px 16px;background:linear-gradient(135deg,var(--purple),#a855f7);border:none;border-radius:8px;color:#fff;font-size:.82rem;cursor:pointer;font-weight:600;transition:opacity .2s}
.vh-dl-btn:hover{opacity:.85}
.vh-empty{text-align:center;color:#666;padding:40px 0;font-size:.9rem}
</style>
<script>
function fmtExpire(secs){
if(secs<=0)return'Expired';
const h=Math.floor(secs/3600),m=Math.floor((secs%3600)/60);
return h>0?`${h}h ${m}m left`:`${m}m left`;
}
async function openVideoHistory(){
document.getElementById('vh-overlay').style.display='block';
document.body.style.overflow='hidden';
const list=document.getElementById('vh-list');
list.innerHTML='<div class="vh-empty"><i class="fas fa-spinner" style="animation:spin 1s linear infinite"></i> Loading…</div>';
try{
const r=await fetch(`/api/video_history?username=${encodeURIComponent(U)}`);
const d=await r.json();
if(!d.ok||!d.history||d.history.length===0){
list.innerHTML='<div class="vh-empty"><i class="fas fa-film" style="font-size:2rem;opacity:.3;display:block;margin-bottom:10px"></i>No video history yet.<br>Process a video to see it here.</div>';
return;
}
list.innerHTML=d.history.map(h=>{
const src=h.output_url;
const srcUrl=h.source_url?`<span class="vh-url" title="${h.source_url}"><i class="fas fa-link" style="margin-right:3px"></i>${h.source_url}</span>`:'';
return `<div class="vh-card">
<div class="vh-thumb-wrap" onclick="this.querySelector('video').paused?this.querySelector('video').play():this.querySelector('video').pause()">
<video src="${src}" preload="metadata" playsinline></video>
<div class="vh-thumb-overlay" id="vhov_${h.tid}">
<div class="vh-play-ic"><i class="fas fa-play" style="margin-left:3px"></i></div>
</div>
</div>
<div class="vh-info">
<div class="vh-title">${h.title||'(no title)'}</div>
<div class="vh-meta">
<span class="vh-time"><i class="fas fa-clock" style="margin-right:3px"></i>${h.created_at||''}</span>
<span class="vh-ttl">${fmtExpire(h.expires_in||0)}</span>
${srcUrl}
</div>
<button class="vh-dl-btn" onclick="vhDl('${src}','${h.tid}')"><i class="fas fa-download"></i>Download</button>
</div>
</div>`;
}).join('');
// Hide overlay when video plays
list.querySelectorAll('video').forEach(v=>{
v.addEventListener('play',()=>{const ov=v.closest('.vh-thumb-wrap').querySelector('.vh-thumb-overlay');if(ov)ov.style.opacity='0';});
v.addEventListener('pause',()=>{const ov=v.closest('.vh-thumb-wrap').querySelector('.vh-thumb-overlay');if(ov)ov.style.opacity='1';});
});
}catch(e){list.innerHTML='<div class="vh-empty">❌ Failed to load history</div>';}
}
function closeVideoHistory(){
document.getElementById('vh-overlay').style.display='none';
document.body.style.overflow='';
// Stop all playing videos
document.querySelectorAll('#vh-list video').forEach(v=>v.pause());
}
function vhDl(url,tid){
const a=document.createElement('a');a.href=url;a.download=`recap_${tid}.mp4`;a.click();
}
document.getElementById('vh-overlay').addEventListener('click',function(e){if(e.target===this)closeVideoHistory();});
</script>
<script>
if("serviceWorker" in navigator){
window.addEventListener("load",()=>{
navigator.serviceWorker.register("/sw.js")
.then(()=>console.log("[PWA] SW registered"))
.catch(e=>console.warn("[PWA] SW failed:",e));
});
}
</script>
<script>
// Panda eye cover — triggers on any password field focus
(function(){
const panda = document.querySelector('.panda');
if(!panda) return;
const pwFields = ['l-p','r-p'];
const allFields = ['l-u','r-u','l-p','r-p'];
function coverEyes(){
panda.classList.add('peek-off');
}
function uncoverEyes(){
panda.classList.remove('peek-off');
}
pwFields.forEach(id=>{
const el = document.getElementById(id);
if(el){
el.addEventListener('focus', coverEyes);
el.addEventListener('blur', uncoverEyes);
}
});
// Username fields — uncover (in case switching back)
['l-u','r-u'].forEach(id=>{
const el = document.getElementById(id);
if(el){
el.addEventListener('focus', uncoverEyes);
}
});
})();
</script>
</body>
</html>
</body>
</html>
<!-- ══ PROFILE & SETTINGS MODAL ══ -->
<style>
.ps-warn{background:var(--amber);border:1px solid rgba(180,83,9,.25);border-radius:8px;padding:9px 12px;font-size:.74rem;color:var(--gold);margin-bottom:11px}
</style>
<div class="pov2" id="pov2" onclick="if(event.target===this)closeProfile()">
<div class="ps-sheet">
<!-- HEADER -->
<div class="ps-hdr">
<div class="ps-hdr-top">
<h3>⚙️ My Account</h3>
<button class="ps-close" onclick="closeProfile()"><i class="fas fa-times"></i></button>
</div>
<div class="ps-av-row">
<div class="ps-av" id="ps-av">🐶</div>
<div>
<div class="ps-dname" id="ps-dname"></div>
<div class="ps-role" id="ps-role">Member</div>
<div class="ps-coins" id="ps-coins">🪙 0 coins</div>
</div>
</div>
<!-- TABS -->
<div class="ps-tabs">
<button class="ps-tab on" id="pstab-info" onclick="psTab('info')">Profile</button>
<button class="ps-tab" id="pstab-sec" onclick="psTab('sec')">Security</button>
<button class="ps-tab" id="pstab-bill" onclick="psTab('bill')">Billing</button>
</div>
</div>
<!-- BODY -->
<div class="ps-body">
<div id="ps-loading" style="text-align:center;padding:28px;color:var(--muted)"><i class="fas fa-spinner fa-spin"></i></div>
<!-- TAB: PROFILE INFO -->
<div id="psp-info" style="display:none">
<div class="ps-card">
<div class="ps-label"><i class="fas fa-user-edit" style="margin-right:5px"></i>Personal Info</div>
<div class="ps-field"><label>Nickname</label><input class="ps-inp" id="ps-nick" placeholder="Your nickname"></div>
<div class="ps-field"><label>Bio</label><input class="ps-inp" id="ps-bio" placeholder="Short bio…"></div>
<div class="ps-field">
<label>Telegram ID
<a id="ps-tg-link" href="#" target="_blank" style="display:none;font-size:.68rem;color:var(--orange);margin-left:6px">🔗 Open</a>
</label>
<input class="ps-inp" id="ps-tgid" placeholder="@yourusername" oninput="psTgLink(this.value)">
</div>
</div>
<div id="ps-info-msg" class="ps-msg"></div>
<button class="ps-btn" onclick="psSaveInfo()"><i class="fas fa-save" style="margin-right:6px"></i>Save</button>
</div>
<!-- TAB: SECURITY -->
<div id="psp-sec" style="display:none">
<div class="ps-stat" style="grid-template-columns:1fr 1fr">
<div class="ps-stat-box"><div class="ps-stat-v" id="pss-vids">0</div><div class="ps-stat-l">🎬 Videos</div></div>
<div class="ps-stat-box"><div class="ps-stat-v" id="pss-trans">0</div><div class="ps-stat-l">📝 Transcripts</div></div>
</div>
<div class="ps-card">
<div class="ps-label"><i class="fas fa-key" style="margin-right:5px"></i>Password</div>
<div id="ps-no-pw" class="ps-warn" style="display:none"><i class="fas fa-exclamation-triangle" style="margin-right:5px"></i>Password မသတ်မှတ်ရသေး</div>
<div id="ps-cur-wrap" class="ps-field"><label>လက်ရှိ Password</label><input class="ps-inp" id="ps-cur-pw" type="password" placeholder="Current password"></div>
<div class="ps-field"><label>Password အသစ်</label><input class="ps-inp" id="ps-new-pw" type="password" placeholder="အနည်းဆုံး 6 လုံး"></div>
<div class="ps-field"><label>ထပ်ထည့်</label><input class="ps-inp" id="ps-confirm-pw" type="password" placeholder="Confirm"></div>
<div id="ps-pw-msg" class="ps-msg"></div>
<button class="ps-btn" onclick="psChangePw()"><i class="fas fa-lock" style="margin-right:6px"></i>Password သိမ်း</button>
</div>
<div class="ps-card">
<div class="ps-label"><i class="fas fa-shield-alt" style="margin-right:5px"></i>2FA</div>
<div style="display:flex;justify-content:space-between;align-items:center">
<span style="font-size:.82rem;color:var(--text)">Two-Factor Auth</span>
<span style="font-size:.7rem;background:var(--bg3);color:var(--muted2);padding:3px 10px;border-radius:10px;font-weight:600">Coming Soon</span>
</div>
</div>
</div>
<!-- TAB: BILLING -->
<div id="psp-bill" style="display:none">
<div class="ps-stat">
<div class="ps-stat-box"><div class="ps-stat-v" id="psb-coins">0</div><div class="ps-stat-l">🪙 Coins</div></div>
<div class="ps-stat-box"><div class="ps-stat-v" id="psb-vids">0</div><div class="ps-stat-l">🎬 Videos</div></div>
<div class="ps-stat-box"><div class="ps-stat-v" id="psb-trans">0</div><div class="ps-stat-l">📝 Transcripts</div></div>
</div>
<div class="ps-card">
<div class="ps-label" style="display:flex;align-items:center;justify-content:space-between">
<span><i class="fas fa-history" style="margin-right:5px"></i>Coin History</span>
<button onclick="closeProfile();openPay('his')" style="background:none;border:none;color:var(--orange);font-size:.72rem;cursor:pointer;font-weight:600">Order History →</button>
</div>
<div id="psb-tx"></div>
</div>
<button class="ps-btn" onclick="closeProfile();openPay()"><i class="fas fa-coins" style="margin-right:6px"></i>Coins ဝယ်မည်</button>
</div>
</div><!-- /body -->
</div>
</div>
<script>
let _PS_HAS_PW = false;
function psTab(t){
['info','sec','bill'].forEach(id=>{
document.getElementById('pstab-'+id).classList.toggle('on',id===t);
document.getElementById('psp-'+id).style.display=id===t?'':'none';
});
}
async function openProfile(){
document.getElementById('pov2').classList.add('on');
document.getElementById('ps-loading').style.display='';
['info','sec','bill'].forEach(id=>document.getElementById('psp-'+id).style.display='none');
psTab('info');
['ps-cur-pw','ps-new-pw','ps-confirm-pw'].forEach(id=>document.getElementById(id).value='');
['ps-info-msg','ps-pw-msg'].forEach(id=>document.getElementById(id).style.display='none');
try{
const d = await fetch('/api/profile?username='+encodeURIComponent(U)).then(r=>r.json());
if(!d.ok) return;
_PS_HAS_PW = d.has_password;
document.getElementById('ps-loading').style.display='none';
// Header
const nick = d.display_name || '(nickname မသတ်မှတ်ရသေး)';
document.getElementById('ps-av').textContent = d.animal_emoji || '🐶';
document.getElementById('ps-dname').textContent = nick;
document.getElementById('ps-role').textContent = d.is_admin ? '👑 Admin' : 'Member';
document.getElementById('ps-coins').textContent = d.is_admin ? '🪙 Unlimited' : '🪙 '+d.coins+' coins';
// Profile tab
document.getElementById('ps-nick').value = d.display_name || '';
document.getElementById('ps-bio').value = d.bio || '';
document.getElementById('ps-tgid').value = d.telegram_id || '';
psTgLink(d.telegram_id || '');
// Security tab
document.getElementById('pss-vids').textContent = d.videos;
document.getElementById('pss-trans').textContent = d.transcripts;
document.getElementById('ps-no-pw').style.display = _PS_HAS_PW ? 'none' : '';
document.getElementById('ps-cur-wrap').style.display = _PS_HAS_PW ? '' : 'none';
// Billing tab
document.getElementById('psb-coins').textContent = d.is_admin ? '∞' : d.coins;
document.getElementById('psb-vids').textContent = d.videos;
document.getElementById('psb-trans').textContent = d.transcripts;
const txEl = document.getElementById('psb-tx');
txEl.innerHTML = (d.coin_history||[]).length
? (d.coin_history).map(tx=>`<div class="ps-tx"><div><div style="color:var(--text)">${tx.desc||'—'}</div><div style="color:var(--muted2);font-size:.68rem">${(tx.ts||'').slice(0,16).replace('T',' ')}</div></div><div style="font-weight:700;color:var(--green)">+${tx.delta}🪙</div></div>`).join('')
: '<div style="text-align:center;color:var(--muted2);padding:12px;font-size:.8rem">မှတ်တမ်းမရှိသေး</div>';
} catch(e){ console.error(e); }
}
function closeProfile(){ document.getElementById('pov2').classList.remove('on'); }
function psTgLink(v){
const a=document.getElementById('ps-tg-link'), u=v.trim().replace(/^@/,'');
if(u){ a.href='https://t.me/'+u; a.style.display=''; } else { a.style.display='none'; }
}
async function psSaveInfo(){
const msg=document.getElementById('ps-info-msg');
const body={username:U, display_name:document.getElementById('ps-nick').value.trim(),
bio:document.getElementById('ps-bio').value.trim(),
telegram_id:document.getElementById('ps-tgid').value.trim()};
try{
const d=await fetch('/api/profile',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}).then(r=>r.json());
msg.style.display=''; msg.style.background=d.ok?'#dcfce7':'#fee2e2'; msg.style.color=d.ok?'#166534':'#991b1b'; msg.textContent=d.msg;
if(d.ok){
const nick=body.display_name||'(nickname မသတ်မှတ်ရသေး)';
document.getElementById('ps-dname').textContent=nick;
document.getElementById('dun').textContent=body.display_name||U;
}
}catch(e){msg.style.display='';msg.style.background='#fee2e2';msg.style.color='#991b1b';msg.textContent='❌ '+e.message;}
}
async function psChangePw(){
const newPw=document.getElementById('ps-new-pw').value.trim();
const confirmPw=document.getElementById('ps-confirm-pw').value.trim();
const curPw=document.getElementById('ps-cur-pw').value.trim();
const msg=document.getElementById('ps-pw-msg');
if(newPw.length<6){msg.style.display='';msg.style.background='#fee2e2';msg.style.color='#991b1b';msg.textContent='❌ Password အနည်းဆုံး 6 လုံး';return;}
if(newPw!==confirmPw){msg.style.display='';msg.style.background='#fee2e2';msg.style.color='#991b1b';msg.textContent='❌ Password မတူ';return;}
const ep=_PS_HAS_PW?'/api/change_password':'/api/set_password';
const body=_PS_HAS_PW?{username:U,old_password:curPw,new_password:newPw}:{username:U,password:newPw};
try{
const d=await fetch(ep,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(body)}).then(r=>r.json());
msg.style.display=''; msg.style.background=d.ok?'#dcfce7':'#fee2e2'; msg.style.color=d.ok?'#166534':'#991b1b'; msg.textContent=d.msg;
if(d.ok){_PS_HAS_PW=true;window._HAS_PASSWORD=true;document.getElementById('ps-no-pw').style.display='none';document.getElementById('ps-cur-wrap').style.display='';['ps-cur-pw','ps-new-pw','ps-confirm-pw'].forEach(id=>document.getElementById(id).value='');}
}catch(e){msg.style.display='';msg.style.background='#fee2e2';msg.style.color='#991b1b';msg.textContent='❌ '+e.message;}
}
</script>
</body>
</html>