PageSourceSearch

https://pinin.ai/assets/PhotoRestoration-BNLYNh_T.js

js pinin.ai collected 2026-10-05 12:24:58 UTC 78,194 bytes, 152 lines download raw bytes

1import{T as B,E as W,F as H,h as ve,l as It,u as ye,d as $,e as T,A as F,D as Ne,n as ke,o as Ce,p as Ie,f as St,_ as Ve,G as _t}from"./index-BxPM34rs.js";import{r as l,j as e,u as b}from"./vendor-ui-CyX5KghO.js";import{b as Se,L as be}from"./vendor-router-BkOfq-NB.js";import{B as Pt}from"./badge-By8xe4hx.js";import{a as _e,bu as Rt,aH as at,bv as Lt,az as ot,X as Ut,bw as Mt,au as Et,e as $t,a5 as Pe,bx as Ye,f as At,al as Tt,ag as Ft,D as we,by as Dt,S as nt,aq as zt,ap as Ot,A as pe,O as je,w as it,bz as qt,bA as Bt,a6 as Wt,W as ge,a8 as Ge,b6 as Ht,Z as Vt,c as Ze,bB as Yt,aP as fe,bq as Xe,ax as Gt,aF as Zt,aA as Xt,am as Jt}from"./vendor-icons-BDZUQ1og.js";import{B as w,S as Kt,a as Qt,b as er,d as tr,e as rr,f as Je,H as sr,F as ar}from"./Footer-Dhel5crY.js";import{C as V}from"./card-BeQFBJ7R.js";import{u as or}from"./useAuthDialog-DOsK39nU.js";import{a as nr,g as Ke,f as Qe,u as ir}from"./imageUrls-CDTmcJj8.js";import{S as Z}from"./SafeImage-CY3ECsxP.js";import{S as lr}from"./ScrambleText-CvesROPc.js";import{A as cr}from"./AuthDialog-DNpkW53V.js";import{C as dr}from"./checkbox-CJKyGvBm.js";import{O as mr}from"./OrderProductsButton-D_qDhsfU.js";import{M as ee}from"./MotionText-DEYNa0bY.js";import{T as ur}from"./textarea-C1Z50uXK.js";import{R as hr}from"./RelatedServices-ih2Gd-8m.js";import{S as xr}from"./SEOHead-BQTjRJJ_.js";import{g as pr}from"./seoConfig-2jHAa8Ba.js";import{s as gr,f as fr}from"./seoData-DAptt2vQ.js";import"./vendor-utils-DeRmtv56.js";import"./vendor-state-DibS_CIo.js";import"./vendor-data-BqycYhy-.js";import"./vendor-realtime-CfEct8BT.js";import"./onboardingConfig-CmrN-lh4.js";import"./vendor-fx-B5JVzsfH.js";import"./vendor-anim-CCekb2R6.js";const br=[{id:"all-in-one",label:"All-in-one",tooltip:"Complete restoration: fixes scratches, enhances colors, sharpens details, and upscales resolution all at once. Best for most photos.",recommended:!0,Icon:_e},{id:"dust-scratch",label:"Dust & scratch removal",tooltip:"Removes dust particles, scratches, and surface damage while preserving the original image quality and colors.",Icon:Rt},{id:"colorize",label:"Colorization",tooltip:"Adds realistic colors to black & white or faded photos. Brings monochrome memories to life with natural color tones.",Icon:at},{id:"deblur-upscale",label:"Deblur + upscale",tooltip:"Sharpens blurry images and increases resolution. Ideal for out-of-focus or motion-blurred photos.",Icon:Lt},{id:"upscale-only",label:"Resolution upscale",tooltip:"Increases image resolution without altering colors or content. Perfect for enlarging small or low-res images for printing.",Icon:ot}];function et({selectedMode:n,onSelectMode:c}){const[p,d]=l.useState(!0);return e.jsxs("div",{className:"space-y-4",children:[e.jsx("p",{className:"text-sm font-semibold text-foreground text-center tracking-wide uppercase",children:"Choose restoration mode"}),e.jsx("div",{className:"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3 max-w-3xl mx-auto",children:br.map(x=>{const f=n===x.id;return e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsxs("button",{onClick:()=>c(x.id),className:`group relative flex flex-col items-center gap-2 px-3 py-4 rounded-2xl border-2 transition-all duration-300 cursor-pointer ${f?"border-primary bg-primary/10 text-primary shadow-lg shadow-primary/10 scale-[1.03]":"border-border bg-card text-muted-foreground hover:border-primary/50 hover:bg-primary/5 hover:shadow-md hover:scale-[1.02]"}`,children:[x.recommended&&e.jsx(Pt,{className:"absolute -top-2.5 left-1/2 -translate-x-1/2 bg-primary text-primary-foreground text-[10px] px-2.5 py-0.5 whitespace-nowrap rounded-full shadow-sm",children:"Recommended"}),e.jsx("span",{className:`transition-colors duration-200 ${f?"text-primary":"text-muted-foreground group-hover:text-primary"}`,children:e.jsx(x.Icon,{className:"w-7 h-7 transition-transform duration-500 ease-out group-hover:scale-110 group-hover:rotate-[8deg]",size:28})}),e.jsx("span",{className:"text-[11px] font-medium leading-tight text-center",children:x.label}),f&&e.jsx("span",{className:"absolute -bottom-1 left-1/2 -translate-x-1/2 w-6 h-1 bg-primary rounded-full"})]})}),e.jsx(H,{side:"bottom",className:"max-w-[240px] text-center rounded-xl",children:e.jsx("p",{className:"text-sm leading-relaxed",children:x.tooltip})})]},x.id)})}),p&&e.jsxs("div",{className:"relative max-w-3xl mx-auto rounded-xl border border-primary/30 bg-gradient-to-r from-primary/10 to-primary/5 px-4 py-3 pr-9",children:[e.jsx("button",{onClick:()=>d(!1),"aria-label":"Dismiss tip",className:"absolute top-2 right-2 text-muted-foreground hover:text-foreground transition-colors",children:e.jsx(Ut,{className:"w-4 h-4"})}),e.jsxs("div",{className:"flex items-start gap-2.5",children:[e.jsx(Mt,{className:"w-4 h-4 text-primary flex-shrink-0 mt-0.5"}),e.jsxs("p",{className:"text-xs sm:text-sm text-foreground leading-relaxed",children:[e.jsx("span",{className:"font-semibold",children:"Pro tip:"})," mix & match modes for the best results. Try running ",e.jsx("span",{className:"font-medium text-primary",children:"Colorization"})," first, then restore the same photo again with ",e.jsx("span",{className:"font-medium text-primary",children:"All-in-one"})," to sharpen and polish. Layering modes often beats a single pass."]})]})]})]})}const wr=It("relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",{variants:{variant:{default:"bg-background text-foreground",destructive:"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"}},defaultVariants:{variant:"default"}}),oe=l.forwardRef(({className:n,variant:c,...p},d)=>e.jsx("div",{ref:d,role:"alert",className:ve(wr({variant:c}),n),...p}));oe.displayName="Alert";const jr=l.forwardRef(({className:n,...c},p)=>e.jsx("h5",{ref:p,className:ve("mb-1 font-medium leading-none tracking-tight",n),...c}));jr.displayName="AlertTitle";const ne=l.forwardRef(({className:n,...c},p)=>e.jsx("div",{ref:p,className:ve("text-sm [&_p]:leading-relaxed",n),...c}));
1ne.displayName="AlertDescription";const vr=()=>{const n=Se(),{user:c}=ye(),[p,d]=l.useState([]),[x,f]=l.useState(!0);l.useEffect(()=>{if(!c){d([]),f(!1);return}f(!0),y()},[c]);const y=async()=>{if(c)try{const{data:g,error:M}=await $.from("image_restorations").select("id, order_number, original_image_path, restored_image_path, created_at, status, storage_provider").eq("user_id",c.id).eq("status","completed").order("created_at",{ascending:!1}).limit(6);if(M){console.error("Error fetching restorations:",M);return}const k=(g||[]).map(I=>({...I,status:I.status})),S=new Map,z=[],E=[];if(k.forEach(I=>{const r=I.restored_image_path||I.original_image_path;r&&(I.storage_provider==="r2"?E.push(r):z.push(r))}),z.length>0){const{data:I}=await $.storage.from("pinin").createSignedUrls(z,3600);I?.forEach(r=>{r.path&&r.signedUrl&&S.set(r.path,r.signedUrl)})}E.length>0&&(await nr(E,3600)).forEach((r,R)=>S.set(R,r)),k.forEach(I=>{const r=I.restored_image_path||I.original_image_path;I.signedUrl=r&&S.get(r)||void 0}),d(k)}catch(g){console.error("Error fetching restorations:",g)}finally{f(!1)}};return x?e.jsx("section",{className:"px-4 py-16 bg-muted/30",children:e.jsxs("div",{className:"container mx-auto max-w-6xl",children:[e.jsx("div",{className:"text-center mb-12",children:e.jsx("h2",{className:"text-2xl md:text-3xl lg:text-4xl font-bold text-foreground mb-4",children:"Recent photo restorations"})}),e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4",children:[...Array(6)].map((g,M)=>e.jsx(V,{className:"aspect-square bg-muted animate-pulse"},M))})]})}):p.length===0?null:e.jsx("section",{className:"px-4 py-16 bg-muted/30",children:e.jsxs("div",{className:"container mx-auto max-w-6xl",children:[e.jsx("div",{className:"text-center mb-12",children:e.jsxs("h2",{className:"text-2xl md:text-3xl lg:text-4xl font-bold text-foreground mb-4",children:["Recent ",e.jsx(lr,{text:"photo restorations",className:"text-primary",speed:10})]})}),e.jsx("div",{className:"grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4 mb-8",children:p.map(g=>e.jsx(V,{className:"overflow-hidden hover:shadow-lg transition-shadow",children:e.jsx("div",{className:"aspect-square",children:e.jsx(Z,{src:g.signedUrl||"",alt:`Restoration ${g.order_number}`,className:"w-full h-full object-cover object-center",fallbackMessage:"Image preview expired",srOnlyFallback:!0})})},g.id))}),e.jsx("div",{className:"text-center",children:e.jsxs(w,{onClick:()=>n("/history"),variant:"outline",size:"lg",className:"font-semibold",children:[e.jsx(Et,{className:"w-4 h-4 mr-2"}),"View full restoration history"]})})]})})},yr=({className:n})=>e.jsx("svg",{className:n,viewBox:"0 0 24 24",fill:"currentColor",children:e.jsx("path",{d:"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"})}),Nr=({className:n})=>e.jsx("svg",{className:n,viewBox:"0 0 24 24",fill:"currentColor",children:e.jsx("path",{d:"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413Z"})}),kr=({className:n})=>
1e.jsx("svg",{className:n,viewBox:"0 0 24 24",fill:"currentColor",children:e.jsx("path",{d:"M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"})}),Cr=({isOpen:n,onClose:c,imageUrl:p,imageName:d,restorationId:x})=>{const[f,y]=l.useState(!1),[g,M]=l.useState(null),[k,S]=l.useState(!1),[z,E]=l.useState(!1);l.useEffect(()=>{n&&(y(!1),M(null),E(!1))},[n,p]);const I=l.useCallback(async()=>{if(!f){b.error("Please confirm the privacy notice first.");return}if(!x){b.error("This restoration can't be shared yet.");return}S(!0);try{const{data:{session:N}}=await $.auth.getSession();if(!N?.access_token){b.error("Please sign in to share your restoration.");return}const{data:D,error:U}=await $.functions.invoke("r2-images",{body:{action:"create-share",restorationId:x},headers:{Authorization:`Bearer ${N.access_token}`}});if(U)throw U;if(!D?.shareUrl)throw new Error("No share URL returned");M(D.shareUrl),T(F.ReferralShared,{channel:"link_created",restoration_id:x,share_token:D.shareToken})}catch(N){console.error("Share creation failed:",N),b.error("Couldn't create a share link. Please try again.")}finally{S(!1)}},[f,x]),r=async()=>{try{const N=await fetch(p);if(!N.ok)throw new Error("Failed to fetch image");const D=await N.blob(),U=URL.createObjectURL(D),m=document.createElement("a");m.href=U,m.download=`restored_${d}`,document.body.appendChild(m),m.click(),document.body.removeChild(m),URL.revokeObjectURL(U),b.success("Image downloaded successfully!")}catch(N){console.error("Download error:",N),b.error("Failed to download image. Please try again.")}},R=async()=>{if(g)try{await navigator.clipboard.writeText(g),E(!0),T(F.ReferralShared,{channel:"copy_link",restoration_id:x,share_token:g.split("/").pop()}),setTimeout(()=>E(!1),2e3),b.success("Share link copied!")}catch(N){console.error("Copy error:",N),b.error("Failed to copy link. Please try again.")}},C=N=>{if(!g)return;const D="I restored an old photo with Pinin AI ✨";let U="";N==="x"?U=`https://twitter.com/intent/tweet?text=${encodeURIComponent(D)}&url=${encodeURIComponent(g)}`:N==="whatsapp"?U=`https://wa.me/?text=${encodeURIComponent(`${D} ${g}`)}`:U=`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(g)}`,window.open(U,"_blank","width=600,height=500"),T(F.ReferralShared,{channel:N,restoration_id:x,share_token:g.split("/").pop()})};return e.jsx(Ne,{open:n,onOpenChange:c,children:e.jsxs(ke,{className:"sm:max-w-md overflow-x-hidden grid-cols-[minmax(0,1fr)]",children:[e.jsx(Ce,{children:e.jsx(Ie,{className:"text-center",children:"Share your restoration"})}),e.jsxs("div",{className:"space-y-5",children:[e.jsx("div",{className:"text-center",children:e.jsx("img",{src:p,alt:"Restored",className:"w-full max-w-xs mx-auto rounded-lg shadow-lg"})}),e.jsxs("div",{className:"rounded-xl border border-border bg-muted/40 p-5",children:[e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx(dr,{id:"share-consent",checked:f,onCheckedChange:N=>y(!!N),className:"mt-0.5"}),e.jsxs("label",{htmlFor:"share-consent",className:"text-sm text-foreground/80 leading-relaxed cursor-pointer",children:[e.jsx("span",{className:"font-semibold text-foreground",children:"I understand and agree"})," that my restored photo will be ",e.jsx("span",{className:"font-semibold",children:"publicly visible"})," on a shareable Pinin page."]})]}),e.jsxs("p",{className:"text-xs text-foreground/50 mt-4 leading-relaxed flex items-start gap-1.5",children:[e.jsx($t,{className:"w-3.5 h-3.5 mt-0.5 shrink-0"}),e.jsxs("span",{children:["Privacy note: only this restored photo is shared — never your account details, other photos, or original uploads. The share link expires automatically after ",e.jsx("span",{className:"font-semibold",children:"90 days"}),".",e.jsx("span",{className:"block mt-1",children:"You can delete the share anytime from your history."})]})]})]}),g?e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"flex items-center gap-2 rounded-xl border border-border bg-muted/40 p-2 pl-3 min-w-0 max-w-full overflow-hidden",children:[e.jsx(Ye,{className:"w-4 h-4 text-primary shrink-0"}
1),e.jsx("span",{className:"text-xs text-foreground/70 flex-1 min-w-0 truncate",children:g}),e.jsxs(w,{onClick:R,variant:"outline",size:"sm",className:"shrink-0",children:[z?e.jsx(At,{className:"w-4 h-4"}):e.jsx(Tt,{className:"w-4 h-4"}),z?"Copied":"Copy"]})]}),e.jsxs("div",{className:"grid grid-cols-3 gap-2",children:[e.jsxs(w,{onClick:()=>C("x"),variant:"outline",className:"flex items-center justify-center gap-2 bg-black text-white hover:bg-gray-800 border-black min-w-0",children:[e.jsx(yr,{className:"w-4 h-4 shrink-0"})," ",e.jsx("span",{className:"truncate",children:"X"})]}),e.jsxs(w,{onClick:()=>C("whatsapp"),variant:"outline",className:"flex items-center justify-center gap-2 bg-[#25D366] text-white hover:bg-[#1DA851] border-[#25D366] min-w-0",children:[e.jsx(Nr,{className:"w-4 h-4 shrink-0"})," ",e.jsx("span",{className:"truncate",children:"WhatsApp"})]}),e.jsxs(w,{onClick:()=>C("facebook"),variant:"outline",className:"flex items-center justify-center gap-2 bg-[#1877F2] text-white hover:bg-[#145DBF] border-[#1877F2] min-w-0",children:[e.jsx(kr,{className:"w-4 h-4 shrink-0"})," ",e.jsx("span",{className:"truncate",children:"Facebook"})]})]}),e.jsxs("div",{className:"flex items-center justify-center gap-1 text-xs text-foreground/50",children:[e.jsx(Ft,{className:"w-3 h-3"}),"Anyone with the link can view this page for 90 days."]})]}):e.jsx(w,{onClick:I,disabled:!f||k,className:"w-full",children:k?e.jsxs(e.Fragment,{children:[e.jsx(Pe,{className:"w-4 h-4 mr-2 animate-spin"})," Creating share link…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Ye,{className:"w-4 h-4 mr-2"})," Create share link"]})}),e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs(w,{onClick:r,variant:"outline",className:"flex items-center gap-2 min-w-0",children:[e.jsx(we,{className:"w-4 h-4 shrink-0"}),e.jsx("span",{className:"truncate",children:"Download"})]}),e.jsxs(w,{onClick:()=>{navigator.clipboard.writeText(p).then(()=>b.success("Image link copied!"))},variant:"outline",className:"flex items-center gap-2 min-w-0",children:[e.jsx(Dt,{className:"w-4 h-4 shrink-0"}),e.jsx("span",{className:"truncate",children:"Instagram"})]})]})]})]})})},Ir=({value:n,onChange:c,className:p=""})=>{const[d,x]=l.useState(0),f=d||n;return e.jsx("div",{className:`flex items-center justify-center gap-2 ${p}`,role:"radiogroup","aria-label":"Star rating",children:[1,2,3,4,5].map(y=>{const g=y<=f;return e.jsx("button",{type:"button",role:"radio","aria-checked":n===y,"aria-label":`${y} star${y>1?"s":""}`,onMouseEnter:()=>x(y),onMouseLeave:()=>x(0),onFocus:()=>x(y),onBlur:()=>x(0),onClick:()=>c(y),className:"p-1 transition-transform duration-300 ease-in-out hover:scale-125 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-400 rounded-full",children:e.jsx(nt,{className:"w-8 h-8 transition-colors duration-200",style:{color:g?"#f59e0b":"#d1d5db",fill:g?"#f59e0b":"transparent"}})},y)})})},Sr=[{value:"quality",label:"Poor restoration quality"},{value:"slow",label:"Processing was too slow"},{value:"failed",label:"Restoration failed completely"},{value:"artifacts",label:"Unwanted artifacts in result"},{value:"colors",label:"Colors look unnatural"},{value:"other",label:"Other issue"}],_r=[{label:"Review on Trustpilot",url:"https://www.trustpilot.com/evaluate/pinin.ai"},{label:"Review on Capterra",url:"https://reviews.capterra.com/products/new/30fd1f2b-3827-4920-ad31-fe39f7fc0f06/"},{label:"Review on G2",url:"https://www.g2.com/products/pinin/reviews/start"}],lt=({restorationId:n,onShare:c,onRated:p})=>{const[d,x]=l.useState(null),[f,y]=l.useState(0),[g,M]=l.useState(""),k=Se(),S=async r=>{if(n)try{await $.rpc("set_restoration_rating",{p_restoration_id:n,p_rating:r.rating??null,p_reason:r.reason??null,p_stars:r.stars??null})}catch(R){console.error("Failed to record rating:",R)}},z=r=>{x(r),r==="positive"&&M(""),S({rating:r}),p?.(r)},E=r=>{y(r),S({stars:r})},I=r=>{M(r),S({rating:"negative",reason:r})};return e.jsxs(e.Fragment,{children:[e.jsx("style",{children:`
2        @keyframes thumbAltPulse {
3          0%, 100% { transform: scale(1); }
4          7% { transform: scale(1.16); }
5          15% { transform: scale(1); }
6        }
7        .thumb-pulse-up { animation: thumbAltPulse 5s ease-in-out infinite; }
8        .thumb-pulse-down { animation: thumbAltPulse 5s ease-in-out infinite 2.5s; }
9      `}),e.jsxs("div",{className:"text-center",children:[e.jsx("h3",{className:"text-lg font-semibold mb-2",children:"How did it go? Happy with the final result?"}),e.jsx("p",{className:"text-sm text-muted-foreground mb-6",children:"Tell us about your experience with Pinin!"}),e.jsxs("div",{className:"flex items-center justify-center gap-8 mb-6",children:[e.jsx("button",{onClick:()=>z("negative"),className:`w-16 h-16 rounded-full flex items-center justify-center icon-fx transition-all duration-200 ${d==="negative"?"bg-red-500 text-white shadow-lg":"bg-red-500/10 text-red-500 hover:bg-red-500/20 thumb-pulse-down"}`,children:e.jsx(zt,{className:"w-6 h-6"})}),e.jsx("button",{onClick:()=>z("positive"),className:`w-16 h-16 rounded-full flex items-center justify-center icon-fx transition-all duration-200 ${d==="positive"?"text-white shadow-lg":"text-[#00A859] thumb-pulse-up"}`,style:{backgroundColor:d==="positive"?"#00A859":"rgba(0, 168, 89, 0.1
9)"},children:e.jsx(Ot,{className:"w-6 h-6"})})]}),d&&e.jsxs("div",{className:"mb-6 animate-fade-in",children:[e.jsx("p",{className:"text-sm font-medium mb-3",children:"How many stars would you give this restoration?"}),e.jsx(Ir,{value:f,onChange:E})]}),f===5&&e.jsxs("div",{className:"max-w-md mx-auto space-y-4 text-left animate-fade-in",children:[e.jsxs("div",{className:"relative overflow-hidden bg-gradient-to-br from-primary via-primary/90 to-primary/70 text-primary-foreground rounded-2xl p-6 text-center",children:[e.jsx("div",{className:"absolute -top-1/2 -right-1/2 w-32 h-32 bg-white/10 rounded-full blur-2xl animate-pulse"}),e.jsxs("div",{className:"relative z-10",children:[e.jsx("div",{className:"flex justify-center gap-1 mb-3",children:[...Array(5)].map((r,R)=>e.jsx(nt,{className:"w-5 h-5",style:{color:"#FBBF24",fill:"#FBBF24"}},R))}),e.jsx("h3",{className:"text-xl font-bold mb-2",children:"You just made our day! ✨"}),e.jsx("p",{className:"text-primary-foreground/90 text-sm mb-5",children:"Reviews mean the world to a small team like ours. Would you take a moment to share your experience? It only takes a minute and helps others discover Pinin."}),e.jsx("div",{className:"flex flex-col gap-2",children:_r.map(r=>e.jsx(w,{asChild:!0,className:"bg-white text-primary hover:bg-white/90 font-semibold",children:e.jsxs("a",{href:r.url,target:"_blank",rel:"noopener noreferrer",children:[r.label," ",e.jsx(pe,{className:"w-4 h-4 ml-2"})]})},r.url))})]})]}),c&&e.jsx("div",{className:"text-center",children:e.jsxs(w,{onClick:c,variant:"outline",className:"border-primary text-primary hover:bg-primary hover:text-primary-foreground",children:[e.jsx(je,{className:"w-4 h-4 mr-2"}),"Share your restoration"]})})]}),f===4&&e.jsxs("div",{className:"max-w-md mx-auto space-y-4 text-left animate-fade-in",children:[e.jsxs("div",{className:"relative overflow-hidden bg-gradient-to-br from-primary via-primary/90 to-primary/70 text-primary-foreground rounded-2xl p-6 text-center",children:[e.jsx("div",{className:"absolute -top-1/2 -right-1/2 w-32 h-32 bg-white/10 rounded-full blur-2xl animate-pulse"}),e.jsxs("div",{className:"relative z-10",children:[e.jsx(it,{className:"w-10 h-10 mx-auto mb-3"}),e.jsx("h3",{className:"text-xl font-bold mb-2",children:"Love Pinin? Share it!"}),e.jsx("p",{className:"text-primary-foreground/90 text-sm mb-4",children:"Join our referral program and earn 5 credits for every friend who becomes a paying customer."}),e.jsxs(w,{onClick:()=>k("/referrals"),className:"bg-white text-primary hover:bg-white/90 font-semibold",children:["Join referral program ",e.jsx(pe,{className:"w-4 h-4 ml-2"})]})]})]}),c&&e.jsx("div",{className:"text-center",children:e.jsxs(w,{onClick:c,variant:"outline",className:"border-primary text-primary hover:bg-primary hover:text-primary-foreground",children:[e.jsx(je,{className:"w-4 h-4 mr-2"}),"Share your restoration"]})})]}),f===3&&e.jsxs("div",{className:"max-w-md mx-auto space-y-4 text-left animate-fade-in",children:[e.jsxs("div",{className:"rounded-2xl border border-border bg-muted/40 p-5 text-center",children:[e.jsx("h4",{className:"font-semibold text-foreground mb-1",children:"Thanks for the honest rating"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"What would have made this a 5-star result? Let us know so we can keep improving."})]}),e.jsx("div",{className:"text-center",children:e.jsx(w,{onClick:()=>k("/support"),className:"font-semibold",style:{backgroundColor:"#FA7921",color:"white"},children:"Contact the support team"})})]}),f>0&&f<=2&&e.jsxs("div",{className:"max-w-md mx-auto space-y-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"What went wrong?"}),e.jsxs(Kt,{value:g,onValueChange:I,children:[e.jsx(Qt,{children:e.jsx(er,{placeholder:"Select an issue"})}),e.jsx(tr,{children:Sr.map(r=>e.jsx(rr,{value:r.value,children:r.label},r.value))})]})]}),g&&e.jsxs("div",{className:"space-y-5 text-left",children:[e.jsxs("div",{className:"relative overflow-hidden rounded-2xl border border-primary/30 bg-gradient-to-br from-primary/10 via-primary/5 to-transparent p-5",children:[e.jsx("div",{className:"absolute -top-8 -right-8 w-28 h-28 bg-primary/10 rounded-full blur-2xl"}),e.jsxs("div",{className:"relative z-10 flex items-start gap-3",children:[e.jsx("div",{className:"flex-shrink-0 w-10 h-10 rounded-xl bg-primary/15 flex items-center justify-center",children:e.jsx(qt,{className:"w-5 h-5 text-primary"})}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("h4",{className:"font-semibold text-foreground flex items-center gap-1.5",children:["Some damage needs a human touch",e.jsx(_e,{className:"w-4 h-4 text-primary"})]}),e.jsxs("p",{className:"text-sm text-muted-foreground mt-1",children:["Severe tears, missing pieces or heavy fading can be tricky for automatic AI. Our expert restorers handcraft your photo with our manual restoration service, starting from just ",e.jsx("span",{className:"font-semibold text-foreground",children:"$20"}),"."]}),e.jsxs(w,{onClick:()=>k("/manual-restoration"),className:"mt-3 font-semibold",children:["Explore manual restoration",e.jsx(pe,{className:"w-4 h-4 ml-2"})]})]})]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("span",{className:"flex-1 border-t border-dashed border-border"}),e.jsx("span",{className:"text-xs font-medium text-muted-foreground uppercase tracking-wide",children:"or"}),e.jsx("span",{className:"flex-1 border-t border-dashed border-border"})]}),e.jsx("div",{className:"text-center",children:e.jsx(w,{onClick:()=>k("/support"),className:"font-semibold",style:{backgroundColor:"#FA7921",color:"white"},children:"Contact the support team"})})]})]})]})]})},Pr=({isVisible:n,restorationId:c,onShare:p})=>n?e.jsx("div",{className:"mt-8",children:e.jsx(lt,{restorationId:c,onShare:p})}):null,Rr=({open:n,onOpenChange:c,restorationId:p,onShare:d})=>e.jsx(Ne,{open:n,onOpenChange:c,children:e.jsxs(ke,{className:"sm:max-w-md",children:[e.jsx(Ce,{children:e.jsx(Ie,{className:"sr-only",children:"Share your feedback"})}),e.jsx(lt,{restorationId:p,onShare:d})]})}),Lr=({text:n,className:c="",duration:p=2.4,stagger:d=.09})=>{const x=Array.from(n);return e.jsxs(e.Fragment,{children:[e.jsx("style",{children:`
10        @keyframes rainbowLetterLoop {
11          0%   { color: #ffffff; }
12          12%  { color: #ff004c; }
13          24%  { color: #ff8a00; }
14          36%  { color: #ffe600; }
15          48%  { color: #00c853; }
16          60%  { color: #00b8d4; }
17          72%  { color: #2979ff; }
18          84%  { color: #d500f9; }
19          100% { color: #ffffff; }
20        }
21        .rainbow-loop-letter {
22          display: inline-block;
23          color: #ffffff;
24          animation: rainbowLetterLoop var(--rainbow-loop-duration, 2.4s) ease-in-out infinite;
25          will-change: color;
26        }
27      `}),e.jsx("span",{className:`rainbow-loop-text ${c}`,"aria-label":n,style:{"--rainbow-loop-duration":`${p}s`},children:x.map((f,y)=>e.jsx("span",{"aria-hidden":"true",className:"rainbow-loop-letter",style:{animationDelay:`${y*d}s`},children:f===" "?" ":f},`${f}-${y}`))})]})},Ur=n=>St(n,{width:600,quality:75,format:"auto"}),Mr=Ur("Circle%20green_extra_small.png"),Er=()=>{const{user:n,profile:c}=ye(),[p,d]=l.useState(!1),[x,f]=l.useState(""),[y,g]=l.useState(!1),M=async()=>{const k=x.trim();if(!k){b.error("Please write a message first.");return}if(n){g(!0);try{const{error:S}=await $.from("user_feedback").insert({user_id:n.id,email:c?.email??n.email??null,message:k});if(S)throw S;b.success("Thank you! Your message reached Umberto."),f(""),d(!1)}catch(S){console.error("Failed to send feedback:",S),b.error("Could not send your message. Please try again.")}finally{g(!1)}}};return e.jsxs(e.Fragment,{children:[e.jsx("style",{children:`
28        .founder-avatar {
29          transition: transform 0.4s ease-in-out;
30        }
31        .founder-avatar:hover {
32          transform: scale(1.12) rotate(8deg);
33        }
34      `}),e.jsxs(w,{onClick:()=>d(!0),size:"lg",className:"fixed bottom-4 left-4 sm:bottom-6 sm:left-6 z-50 rounded-full shadow-lg font-semibold animate-fade-in",children:[e.jsx(Bt,{className:"w-5 h-5 mr-2"}),"Send feedback"]}),e.jsx(Ne,{open:p,onOpenChange:d,children:e.jsxs(ke,{className:"sm:max-w-md",children:[e.jsx(Ce,{children:e.jsx(Ie,{className:"text-xl",children:"Let me know what's on your mind!"})}),e.jsx("p",{className:"text-sm text-muted-foreground leading-relaxed",children:"You can tell me anything: what you love, what feels off, or what would make Pinin better. I read every single reply. Thank you for using Pinin."}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("img",{src:Mr,alt:"Umberto, founder of Pinin",width:40,height:40,loading:"lazy",className:"founder-avatar w-10 h-10 rounded-full object-cover flex-shrink-0"}),e.jsxs("span",{className:"text-sm font-medium text-foreground",children:["— ",e.jsx("strong",{className:"font-semibold",children:"Umberto"}),", founder of Pinin"]})]}),e.jsx(ur,{value:x,onChange:k=>f(k.target.value),placeholder:"Type your message…",rows:5,maxLength:2e3,className:"resize-none"}),e.jsx(w,{onClick:M,disabled:y,className:"w-full font-semibold",children:y?e.jsxs(e.Fragment,{children:[e.jsx(Pe,{className:"w-4 h-4 mr-2 animate-spin"}),"Sending…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Wt,{className:"w-4 h-4 mr-2"}),"Send feedback"]})}),e.jsxs("p",{className:"text-xs text-muted-foreground text-center leading-relaxed",children:["This form isn't for support requests. If you need help, please visit our"," ",e.jsx(be,{to:"/support",className:"text-primary hover:underline font-medium",children:"support page"}),"."]})]})})]})},tt=.92;function $r(n){return new Promise((c,p)=>{const d=URL.createObjectURL(n),x=new Image;x.onload=()=>{URL.revokeObjectURL(d),c(x)},x.onerror=()=>{URL.revokeObjectURL(d),p(new Error("Failed to load image for compression"))},x.src=d})}function rt(n,c,p){return new Promise(d=>{n.toBlob(x=>d(x),c,p)})}async function Ar(n){if(!n.type.startsWith("image/")||n.type==="image/gif")return n;try{const c=await $r(n),p=document.createElement("canvas");p.width=c.naturalWidth,p.height=c.naturalHeight;const d=p.getContext("2d");if(!d)return n;d.drawImage(c,0,0);const x=n.type==="image/png"||n.type==="image/webp",f=x?"image/webp":"image/jpeg",y=x?"webp":"jpg";let g=await rt(p,f,tt);if(!g&&f==="image/webp"&&(g=await rt(p,"image/jpeg",tt)),!g||g.size>=n.size)return n;const M=n.name.replace(/\.[^.]+$/,""),k=g.type||f,S=k==="image/jpeg"?"jpg":y;return new File([g],`${M}.${S}`,{type:k,lastModified:Date.now()})}catch{return n}}const st=["🪄","👽","🛸","🌌","☄️","🌠","⭐","✨"];function ms(){const n=Se(),{user:c,profile:p,subscription:d}=ye(),{isAuthDialogOpen:x,authDialogMode:f,openAuthDialog:y,closeAuthDialog:g}=or(),[M,k]=l.useState(null),[S,z]=l.useState(!document.hidden),[E,I]=l.useState(!1),[r,R]=l.useState([]),[C,N]=l.useState("select"),D=l.useRef(null),U=l.useRef(!1),[m,ie]=l.useState(0),[Re,ct]=l.useState(0),[dt,Le]=l.useState([]),[le,J]=l.useState(50),[mt,ce]=l.useState(!1),[Y,te]=l.useState(!1),[ut,re]=l.useState(!1),[de,me]=l.useState(0),[G,Ue]=l.useState("all-in-one"),[ht,se]=l.useState(!1),[Me,Ee]=l.useState(!1),[$e,Ae]=l.useState(null),[Te,Fe]=l.useState(!1),K=l.useRef(null),ae=l.useRef(!1);l.useEffect(()=>{let t=null,s=null;const a=()=>{z(!document.hidden),document.hidden&&E?(console.log("Page hidden - maintaining background processing"),t=setInterval(()=>
34{console.log("Background processing heartbeat")},3e4)):t&&(clearInterval(t),t=null)},o=async()=>{if("wakeLock"in navigator&&E&&!document.hidden)try{s=await navigator.wakeLock.request("screen"),k(s),console.log("Wake lock acquired"),s.addEventListener("release",()=>{console.log("Wake lock released"),k(null)})}catch(i){document.visibilityState==="visible"&&console.warn("Wake lock request failed:",i)}};return document.addEventListener("visibilitychange",a),E&&o(),()=>{document.removeEventListener("visibilitychange",a),t&&clearInterval(t),s&&s.release().catch(()=>{})}},[E]),l.useEffect(()=>{c&&X()},[c]);const Q=r.filter(t=>t.status==="completed").length;l.useEffect(()=>{(async()=>{const s=r.filter(a=>a.status==="completed"&&a.restorationId&&!a.originalUrl);if(s.length>0){const a=await Promise.all(s.map(async o=>{const i=await xt(o.restorationId);return i?{...o,originalUrl:i}:o}));R(o=>o.map(i=>a.find(j=>j.id===i.id)||i))}})()},[Q]);const X=async()=>{try{const{data:t,error:s}=await $.from("subscribers").select("credits").eq("user_id",c?.id).maybeSingle();if(s)return console.error("Error fetching credits:",s),b.error("Failed to load your credit balance"),0;const a=t?.credits||0;return ct(a),a}catch(t){return console.error("Error fetching credits:",t),b.error("Failed to load your credit balance"),0}},xt=async t=>{try{const{data:s,error:a}=await $.from("image_restorations").select("original_image_url, original_image_path, storage_provider").eq("id",t).single();if(a)return console.error("Error fetching original image URL:",a),null;if(s?.storage_provider==="r2"&&s?.original_image_path){const o=await Ke(s.original_image_path);if(o)return o}return s?.original_image_url||null}catch(s){return console.error("Error fetching original image URL:",s),null}};d&&d.subscription_tier;const ue=c&&Re>0,De=t=>{ie(t),J(50),setTimeout(()=>{J(51),setTimeout(()=>J(50),50)},100)};l.useEffect(()=>{if(C==="processing"){const t=setInterval(()=>{Le(s=>{const a=s.map(o=>({...o,x:o.x+o.direction.x*o.speed,y:o.y+o.direction.y*o.speed,rotation:o.rotation+2})).filter(o=>o.x>-100&&o.x<window.innerWidth+100&&o.y>-100&&o.y<window.innerHeight+100);if(Math.random()<.3&&a.length<15){const o=Math.floor(Math.random()*4);let i,u,j,h;switch(o){case 0:i=Math.random()*window.innerWidth,u=-50,j=(Math.random()-.5)*2,h=Math.random()+.5;break;case 1:i=window.innerWidth+50,u=Math.random()*window.innerHeight,j=-(Math.random()+.5),h=(Math.random()-.5)*2;break;case 2:i=Math.random()*window.innerWidth,u=window.innerHeight+50,j=(Math.random()-.5)*2,h=-(Math.random()+.5);break;default:i=-50,u=Math.random()*window.innerHeight,j=Math.random()+.5,h=(Math.random()-.5)*2}a.push({id:Math.random().toString(),emoji:st[Math.floor(Math.random()*st.length)],x:i,y:u,size:Math.random()*20+20,rotation:0,speed:Math.random()*2+1,direction:{x:j,y:h}})}return a})},100);return()=>clearInterval(t)}else Le([])},[C]),l.useEffect(()=>{C!=="complete"&&(U.current=!1)},[C]),l.useEffect(()=>{if(C!=="complete"||r[m]?.status!=="completed"||Y)return;const s=window.setTimeout(()=>{U.current||(U.current=!0,Je(D.current))},700);return()=>window.clearTimeout(s)},[C,m,Y,Q,r]);const ze=()=>{if(!d)return 20;switch(d.subscription_tier){case"giotto":return 30;case"botticelli":return 50;case"da_vinci":return 150;default:return 20}},he=l.useCallback(async t=>{const s=Array.from(t),a=ze();if(s.length>a){const h=d?.subscription_tier||"free",_=h==="free"?"Free":h==="giotto"?"Giotto":h==="botticelli"?"Botticelli":"Da Vinci";b.error(`Your ${_} plan allows uploading up to ${a} images at once`);return}const o=[],i=[];if((await Promise.all(s.map(async h=>{const _=await Oe(h);return{file:h,validationError:_}}))).forEach(({file:h,validationError:_})=>{_?i.push(`${h.name}: ${_}`):o.push(h)}),i.length>0){const h=i.length===1?i[0]:`${i.length} files were rejected:
35${i.slice(0,3).join(`
36`)}${i.length>3?`
37...`:""}`;b.error(h)}if(o.length===0)return;const j=o.map(h=>({id:Math.random().toString(),file:h,preview:URL.createObjectURL(h),status:"pending"}));R(j),N("preview"),T(F.ImageUploaded,{image_count:j.length}),o.length!==s.length&&b.success(`${o.length} valid images selected for processing`)},[d?.subscription_tier]),pt=l.useCallback(t=>{t.preventDefault(),ce(!1);const s=t.dataTransfer.files;s.length>0&&he(s)}
37,[he]),gt=l.useCallback(t=>{t.preventDefault(),ce(!0)},[]),ft=l.useCallback(t=>{t.preventDefault(),ce(!1)},[]),Oe=async t=>{const{validateImageFile:s}=await Ve(async()=>{const{validateImageFile:o}=await import("./fileValidation-q1IXChml.js");return{validateImageFile:o}},[]),a=await s(t);return a.valid?null:a.error||"Invalid file"},bt=async t=>{if(!c?.id)throw new Error("User not authenticated");const s=await Oe(t);if(s)throw new Error(s);const a=await Ar(t);console.log("Uploading to R2:",a.name,"Original:",t.size,"Compressed:",a.size,"Type:",a.type);let o=0;const i=3;for(;o<i;)try{const{key:u}=await ir(a),j=await Ke(u,7200);if(!j)throw new Error("Failed to generate signed URL for uploaded image");return console.log("R2 upload successful:",u),{signedUrl:j,path:u}}catch(u){if(o++,console.error(`Upload attempt ${o} failed:`,u),o>=i)throw new Error(`Failed to upload image after ${i} attempts: ${u instanceof Error?u.message:"Unknown error"}`);await new Promise(j=>setTimeout(j,1e3*o))}throw new Error("Failed to upload image")},wt=async(t,s)=>{if(!c?.id)throw new Error("User not authenticated");const a=jt(),{data:o,error:i}=await $.from("image_restorations").insert({user_id:c.id,order_number:a,original_image_url:t,original_image_path:s,storage_provider:"r2",status:"pending"}).select().single();if(i)throw console.error("Database insert error:",i),new Error(`Failed to create restoration record: ${i.message}`);return o},jt=()=>{const t=new Date().toISOString().slice(0,10).replace(/-/g,""),s=crypto.randomUUID().replace(/-/g,"").slice(0,10).toUpperCase();return`ORD-${t}-${s}`},qe=async(t,s=5)=>{let a=0,o=t.originalUrl,i=t.restorationId,u=null;for(;a<s;)try{if(console.log(`Processing attempt ${a+1}/${s} for:`,t.file.name),!o||!i){const v=await bt(t.file);o=v.signedUrl;const L=v.path;console.log("Image uploaded successfully:",L),u=await wt(o,L),i=u.id,console.log("Restoration record created:",u.id),R(O=>O.map(q=>q.id===t.id?{...q,status:"processing",restorationId:u.id,originalUrl:o}:q))}else{const{data:v}=await $.from("image_restorations").select("*").eq("id",i).single();u=v}if(!u?.id)throw new Error("Restoration record was not created");try{const v=await $.functions.invoke("process-image-restoration",{body:{imageRestorationId:u.id,imageUrl:o,restorationMode:G}});console.log("Edge function response:",v),v.error&&console.error("Edge function returned an error:",v.error)}catch(v){console.log("Function invoke error (will continue polling):",v)}const j=18e4,h=3e3,_=Date.now();let P=0;const A=15;for(;Date.now()-_<j;)try{const{data:v,error:L}=await $.from("image_restorations").select("*").eq("id",u.id).single();if(L){if(console.error("Status check error:",L),P++,P>=A)throw new Error("Failed to check processing status after multiple attempts");await new Promise(O=>setTimeout(O,h));continue}if(P=0,v?.status==="completed"&&v?.restored_image_url){R(O=>O.map(q=>q.id===t.id?{...q,status:"completed",restoredUrl:v.restored_image_url,originalUrl:v.original_image_url||q.originalUrl}:q)),await X(),T(F.RestoreCompleted,{restoration_mode:G,attempts:a+1}),b.success(`Image "${t.file.name}" restored successfully!`);return}else if(v?.status==="failed")throw new Error(v?.error_message||"Processing failed");await new Promise(O=>setTimeout(O,h))}catch(v){if(console.error("Polling error:",v),v?.message?.includes("peer closed connection")||v?.message?.includes("complete message body")||v?.message?.includes("timeout")||v?.message?.includes("network")){console.log("Connection interrupted, retrying..."),P++;const L=Math.min(h*Math.pow(1.5,P),15e3);await new Promise(O=>setTimeout(O,L))}else P++,await new Promise(L=>setTimeout(L,h));if(P>=A)throw v}throw new Error("Processing attempt timed out")}catch(j){if(a++,console.error(`Processing attempt ${a}/${s} failed:`,j.message),a>=s){const _=`Failed to process "${t.file.name}" after ${s} attempts. Please try again.`;R(P=>P.map(A=>A.id===t.id?{...A,status:"failed",errorMessage:_}:A)),T(F.RestoreFailed,{restoration_mode:G,attempts:a,error:String(j?.message??j).slice(0,200)}),b.error(_);return}const h=Math.min(12e3*Math.pow(1.5,a-1),6e4);console.log(`Retrying in ${h/1e3}s...`),await new Promise(_=>setTimeout(_,h))}},vt=async()=>
37{if(!c){b.error("Please log in to process images",{action:{label:"Sign in",onClick:()=>y()},actionButtonStyle:{backgroundColor:"white",color:"black"}});return}const t=await X();if(t<r.length){b.error(`You need ${r.length} credits to process these images. You currently have ${t} credits. Please purchase more credits.`);return}if(!Y){te(!0),N("processing"),me(0),T(F.RestoreStarted,{image_count:r.length,restoration_mode:G,subscription_tier:d?.subscription_tier??"free"}),I(!0),r.length>1&&b.info("Processing in background - you can safely switch tabs or minimize the window",{duration:5e3});try{if(r.length===1){const s=setInterval(()=>{me(a=>a>=100?(clearInterval(s),100):a+.5)},100);await qe(r[0]),clearInterval(s),me(100)}else{const a=Math.min((()=>{if(!d||d.subscription_tier==="free")return 1;switch(d.subscription_tier){case"giotto":return 5;case"botticelli":return 25;case"da_vinci":return 75;default:return 1}})(),r.length,150),o=r.length;console.log(`Processing ${o} images with concurrency of ${a}`);let i=0,u=0;const j=async _=>{for(;;){const P=i;if(P>=o)break;i+=1;const A=r[P],v=3;for(let L=1;L<=v;L++)try{await qe(A);break}catch(O){if(console.error(`Worker ${_} failed on ${A.file.name} (attempt ${L}/${v}):`,O),L<v){const q=Math.min(1e3*Math.pow(2,L-1),8e3);await new Promise(Ct=>setTimeout(Ct,q))}}u+=1,console.log(`Progress: ${u}/${o} images processed`)}},h=Array.from({length:a},async(_,P)=>(P>0&&await new Promise(A=>setTimeout(A,P*120)),j(P+1)));await Promise.allSettled(h)}N("complete")}catch(s){console.error("Batch processing error:",s),b.error("Some images failed to process. Please try again.")}finally{if(te(!1),I(!1),!S){const s=r.filter(i=>i.status==="completed").length,a=r.filter(i=>i.status==="failed").length;let o=`Processing completed! ${s} images restored`;a>0&&(o+=`, ${a} failed`),b.success(o,{duration:1e4})}}}},Be=l.useCallback(async()=>{if(ae.current)return;ae.current=!0,Fe(!0);const t=r.filter(s=>s.status==="processing"&&s.restorationId);await Promise.all(t.map(async s=>{try{const{error:a}=await $.functions.invoke("refund-restoration-credit",{body:{restorationId:s.restorationId}});a&&console.error("Auto-refund failed for",s.restorationId,a)}catch(a){console.error("Auto-refund exception for",s.restorationId,a)}})),R(s=>s.map(a=>a.status==="processing"?{...a,status:"failed",errorMessage:"Restoration timed out after 5 minutes. Your credit has been refunded."}:a)),I(!1),await X(),T(F.RestoreFailed,{restoration_mode:G,reason:"client_timeout_5min",refunded_count:t.length})},[r,X]);l.useEffect(()=>{if(C!=="processing")return;K.current===null&&(K.current=Date.now(),ae.current=!1);const t=K.current+5*60*1e3,s=Math.max(0,t-Date.now()),a=window.setTimeout(()=>{Be()},s);return()=>window.clearTimeout(a)},[C,Be]),l.useEffect(()=>{C!=="processing"&&(K.current=null)},[C]);const yt=async()=>{const t=r[m];if(!t?.restorationId||t.status!=="completed"){b.error("This photo isn't ready to upscale yet.");return}Ae(t.id),T(F.OrderUpscaleClicked,{restoration_id:t.restorationId});try{const{data:s,error:a}=await $.functions.invoke("upscale-restoration",{body:{restorationId:t.restorationId}}),o=s?.restoredImageUrl;if(a||!o){const i=a?.message||s?.error||"Upscaling failed. Please try again.";b.error(i);return}R(i=>i.map(u=>u.id===t.id?{...u,restoredUrl:o,isUpscaled:!0}:u)),X(),b.success("Your photo was upscaled — it now prints sharper.")}catch{b.error("Upscaling failed. Please try again.")}finally{Ae(null)}},Nt=async(t,s)=>{try{T(F.RestoredImageDownloaded,{image_name:s,source:"single_download"});const a=await Qe(t),o=URL.createObjectURL(a),i=s.replace(/\.[^/.]+$/,""),u=s.split(".").pop()||"jpg",j=`${i}_restored.${u}`,h=document.createElement("a");h.href=o,h.download=j,document.body.appendChild(h),h.click(),document.body.removeChild(h),URL.revokeObjectURL(o),b.success("Image downloaded successfully!")}catch(a){console.error("Download error:",a),b.error("Failed to download image. Please try again.")}},kt=async()=>{const{default:t}=await Ve(async()=>{const{default:a}=await import("./vendor-zip-FMNDhfof.js").then(o=>o.j);return{default:a}},[]),s=r.filter(a=>a.status==="completed"&&a.restoredUrl);if(s.length===0){b.error("No completed images to download");return}b.info("Preparing ZIP file with your restored photos...",{duration:4e3,position:"bottom-right"});try{const a=new t;for(let j=0;j<s.length;j++){const h=s[j];try{const _=await Qe(h.restoredUrl),P=h.file.name,A=P.replace(/\.[^/.]+$/,""),v=P.split(".").pop()||"jpg",L=`${A}_restored.${v}`;a.file(L,_)}catch(_){console.error("Failed to add image to zip",h.file.name,_)}}const o=await a.generateAsync({type:"blob"}),i=URL.createObjectURL(o),u=document.createElement("a");u.href=i,u.download=`restored_images_${new Date().toISOString().split("T")[0]}.zip`,document.body.appendChild(u),u.click(),document.body.removeChild(u),URL.revokeObjectURL(i),b.success(`Downloaded ${s.length} images in a ZIP file!`),T(F.RestoredImageDownloaded,{image_count:s.length,source:"batch_download"})}catch(a){console.error("Download all error:",a),b.error("Failed to download images. Please try again.")}},We=()=>{R(t=>t.map(s=>({...s,status:"pending",errorMessage:void 0,restoredUrl:void 0,originalUrl:s.originalUrl||s.preview}))),N("preview"),te(!1),Fe(!1),K.current=null,ae.current=!1},xe=()=>{r.forEach(t=>{t.preview&&t.preview.startsWith("blob:")&&URL.revokeObjectURL(t.preview)}),R([]),N("select"),ie(0),te(!1),se(!1),Ee(!1)};l.useEffect(()=>{if(C==="complete"&&Q>0&&!Me){const t=setTimeout(()=>{se(!0),Ee(!0)},3e4);return()=>clearTimeout(t)}},[C,Q,Me]),l.useEffect(()=>()=>{r.forEach(t=>{t.preview&&t.preview.startsWith("blob:")&&URL.revokeObjectURL(t.preview)})},[r]);const He=[{question:"How do I restore an old photo with Pinin?",answer:"Upload a scan or photo of your old print, choose a restoration mode, and Pinin's AI repairs damage, sharpens detail, and can colorize it in seconds. Your first restoration is free — no account or credit card required to try it."},{question:"Is the first photo restoration really free?",answer:"Yes. Your first photo restoration is completely free, with no watermark and no credit card required. After that, one credit restores one photo."},{question:"What kinds of damage can AI photo restoration fix?",answer:"Pinin repairs scratches, tears, creases, fading, discoloration, water and mold stains, blur, and low resolution. It can also colorize black-and-white photos and upscale small or grainy scans to a sharp, print-ready result."},{question:"What image formats and sizes are supported?",answer:"You can upload JPEG, PNG, and most common image formats. For best results, scan prints at 600 DPI or higher and keep the file lossless so the AI has real detail to reconstruct."},{question:"Are my uploaded photos kept private and secure?",answer:"Yes. Every upload is encrypted in transit and during processing, your original is never altered, and images are not shared with third parties. See our Privacy Policy for full details."},{question:"What if my photo is too damaged for automatic restoration?",answer:"For severely damaged or antique photos where large areas are missing, we offer a manual restoration service where our expert artists rebuild the image by hand."}];return e.jsxs(_t,{children:[e.jsx(xr,{...pr("/photo-restoration"),jsonLd:[gr("AI Photo Restoration","Restore, enhance, and colorize old, damaged, or blurry photos with Pinin's AI-powered photo restoration.","https://pinin.ai/photo-restoration"),fr(He)]}),e.jsxs("div",{className:"min-h-screen bg-background text-foreground overflow-x-hidden",children:[e.jsx(sr,{}),e.jsx("style",{children:`
38        @keyframes liquidFill {
39          0% { 
40            width: 0%; 
41            background: linear-gradient(to right, #00A859, #00C769);
42          }
43          100% { 
44            width: 100%; 
45            background: linear-gradient(to right, #00A859, #00C769);
46          }
47        }
48        
49        @keyframes tada {
50          0% { transform: scale(1) rotate(0deg); }
51          15% { transform: scale(0.9) rotate(-3deg); }
52          30% { transform: scale(1.1) rotate(3deg); }
53          45% { transform: scale(1.1) rotate(-3deg); }
54          60% { transform: scale(1.1) rotate(3deg); }
55          75% { transform: scale(1.05) rotate(-1deg); }
56          100% { transform: scale(1) rotate(0deg); }
57        }
58        
59        .lock-animation {
60          animation: tada 6s ease-in-out infinite;
61        }
62        
63        @keyframes gradientShift {
64          0% { background-position: 200% 0; }
65          100% { background-position: -200% 0; }
66        }
67        
68        .gradient-animation {
69          background: linear-gradient(
70            90deg,
71            #00A859,
72            #00C769,
73            #00E67A,
74            #00C769,
75            #00A859
76          );
77          background-size: 400% 100%;
78          animation: gradientShift 2s ease-in-out infinite;
79        }
80        
81        @keyframes magicWandTada {
82          0% { transform: scale(1) rotate(0deg); }
83          10% { transform: scale(0.9) rotate(-2deg); }
84          20% { transform: scale(1.05) rotate(2deg); }
85          30% { transform: scale(1.05) rotate(-2deg); }
86          40% { transform: scale(1.05) rotate(2deg); }
87          50% { transform: scale(1.02) rotate(-1deg); }
88          60% { transform: scale(1.02) rotate(1deg); }
89          70% { transform: scale(1.01) rotate(-0.5deg); }
90          80% { transform: scale(1.01) rotate(0.5deg); }
91          90% { transform: scale(1.005) rotate(-0.25deg); }
92          100% { transform: scale(1) rotate(0deg); }
93        }
94        
95        .magic-wand-tada {
96          animation: magicWandTada 2s ease-in-out infinite;
97          display: inline-block;
98          color: #00A859;
99        }
100      `}
100),e.jsxs("main",{id:"main-content",tabIndex:-1,className:"pt-0",children:[E&&e.jsx("div",{className:"fixed bottom-4 right-4 sm:bottom-6 sm:right-6 md:bottom-8 md:right-8 z-50 bg-primary/90 backdrop-blur-md text-white px-4 py-2 rounded-lg shadow-lg border border-white/20",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"w-2 h-2 bg-white rounded-full animate-pulse"}),e.jsxs("span",{className:"text-sm font-medium",children:["Processing in background ",!S&&"(tab inactive)"]})]})}),e.jsxs("section",{className:"relative px-4 py-20 overflow-hidden",style:{background:"linear-gradient(135deg, hsl(var(--background)) 0%, #00A859 100%)"},children:[e.jsx("div",{className:"absolute bottom-0 left-1/2 transform -translate-x-1/2 z-0 pointer-events-none opacity-20",children:[...Array(5)].map((t,s)=>e.jsx("div",{className:`absolute rounded-t-full left-1/2 transform -translate-x-1/2 bottom-0 hero-circle-pulse-${s+1}`,style:{width:`${1200-s*200}px`,height:`${600-s*100}px`,background:"rgba(255, 255, 255, 0.1)",border:"1px solid rgba(255, 255, 255, 0.2)",borderBottom:"none"}},s))}),e.jsxs("div",{className:"container mx-auto max-w-6xl text-center space-y-8 relative z-20",children:[e.jsxs("div",{className:"inline-flex items-center gap-2 bg-white/10 backdrop-blur-md text-white px-6 py-3 rounded-full text-sm font-medium border border-white/20 shadow-lg",children:[e.jsx(ge,{className:"w-4 h-4"}),"Automatic AI photo restoration"]}),e.jsxs("h1",{className:"text-3xl md:text-4xl lg:text-5xl font-bold font-dm drop-shadow-lg text-white leading-tight [text-wrap:balance] max-w-[18ch] sm:max-w-2xl mx-auto",children:[e.jsx(ee,{text:"The first AI photo restoration"})," ",e.jsx(ee,{text:"that actually works",delay:320})]}),e.jsxs("p",{className:"text-base md:text-lg text-white/95 max-w-3xl mx-auto leading-relaxed drop-shadow-md",children:["Upload up to"," ",e.jsxs(B,{children:[e.jsx(W,{className:"underline decoration-white/50 underline-offset-2 hover:
100decoration-white/80 transition-colors",children:"100 images"}),e.jsx(H,{className:"max-w-xs",children:e.jsxs("p",{className:"text-sm",children:["Upload limits by plan:",e.jsx("br",{}),"• Free: 20 images",e.jsx("br",{}),"• Giotto: 30 images",e.jsx("br",{}),"• Botticelli: 50 images",e.jsx("br",{}),"• Da Vinci: 100 images"]})})]})," ","at the same time, Pinin will restore them automatically. Each photo restoration takes approximately 12 seconds and costs only one credit."]})]})]}),!c&&e.jsx("section",{className:"px-4 py-6",children:e.jsx("div",{className:"container mx-auto max-w-4xl",children:e.jsx(V,{className:"p-6 border-primary/20 bg-primary/5",children:e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4",children:[e.jsxs("div",{className:"flex items-center gap-4 text-center sm:text-left",children:[e.jsx("div",{className:"w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center icon-fx flex-shrink-0",children:e.jsx(it,{className:"w-6 h-6 text-primary"})}),e.jsxs("div",{children:[e.jsx("h3",{className:"text-lg font-semibold text-foreground mb-1",children:"Try Pinin for free"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"Experience our AI-powered image restoration with your first photo completely free. No payment required."})]})]}),e.jsx(w,{onClick:()=>y(),size:"lg",className:"whitespace-nowrap",children:"Claim your free photo restoration"})]})})})}),c&&!ue&&e.jsx("section",{className:"px-4 py-3 bg-primary",children:e.jsx("div",{className:"container mx-auto max-w-6xl",children:e.jsxs("div",{className:"flex flex-col sm:flex-row items-center justify-between gap-4 text-white",children:[e.jsxs("div",{className:"text-center sm:text-left",children:[e.jsx("p",{className:"font-semibold",children:"You need credits to restore images"}),e.jsx("p",{className:"text-white/90 text-sm",children:"Get credits now and start restoring your precious memories"})]}),e.jsxs(w,{onClick:()=>n("/pricing"),variant:"secondary",className:"bg-white text-primary hover:bg-white/90 font-semibold",children:[e.jsx(Ge,{className:"w-4 h-4 mr-2"}),"Get Credits"]})]})})}),e.jsx("section",{className:"px-4 py-16",children:e.jsxs("div",{className:"container mx-auto max-w-4xl",children:[(!c||!ue)&&e.jsxs(V,{className:"relative overflow-visible mt-14",children:[e.jsx("div",{className:"absolute inset-0 bg-background/50 backdrop-blur-sm z-10 flex items-center justify-center px-4",children:e.jsxs("div",{className:"text-center space-y-6 w-full",children:[e.jsx("div",{className:"w-24 h-24 mx-auto -mt-28 bg-muted rounded-full flex items-center justify-center icon-fx lock-animation shadow-xl ring-4 ring-background relative z-20",children:e.jsx(Ht,{className:"w-12 h-12 text-muted-foreground"})}),c?e.jsxs(e.Fragment,{children:[e.jsx("h2",{className:"text-2xl font-semibold",children:"Credits required"}),e.jsxs("p",{className:"text-muted-foreground max-w-md mx-auto",children:["Each restoration costs one credit. You can buy more credits on the"," ",e.jsx("button",{onClick:()=>n("/pricing"),className:"text-primary hover:underline font-medium inline",children:"pricing page"}),"."]}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-3 justify-center",children:[e.jsxs(w,{onClick:()=>n("/pricing"),size:"lg",children:[e.jsx(Ge,{className:"w-4 h-4 mr-2"}),"Get credits"]}),e.jsxs(w,{onClick:()=>n("/pricing"),size:"lg",variant:"outline",className:"animate-pulse",children:[e.jsx(Vt,{className:"w-4 h-4 mr-2"}),"Quick recharge (5 Credits)"]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("h2",{className:"text-2xl font-semibold",children:"Login required"}),e.jsx("p",{className:"text-muted-foreground max-w-md mx-auto mb-4",children:"Please log in to use our automatic image restoration service."}),e.jsxs("div",{className:"flex flex-col gap-2 w-[85%] mx-auto",children:[e.jsx(w,{onClick:()=>y("login"),style:{backgroundColor:"#00A859",color:"white"},className:"w-full hover:bg-primary/90",children:"Sign in"}),e.jsx(w,{onClick:()=>y("register"),variant:"outline",style:{backgroundColor:"white",color:"black"},className:"w-full border-gray-300 hover:bg-gray-50",children:"Sign Up"})]})]})]})}),e.jsx("div",{className:"p-8 opacity-30",children:e.jsx("div",{className:"border-2 border-dashed border-border rounded-lg h-64 flex items-center justify-center",children:e.jsxs("div",{className:"text-center",children:[e.jsx(Ze,{className:"w-12 h-12 mx-auto mb-4 text-muted-foreground"}),e.jsx("p",{className:"text-lg font-medium",children:"Drag & drop up to 20 images"}),e.jsx("p",{className:"text-muted-foreground",children:"or click to browse"})]})})})]}),c&&ue&&C==="select"&&e.jsxs(V,{className:"p-8",children:[e.jsxs("div",{className:"mb-6 text-center",children:[e.jsxs("div",{className:"flex items-center justify-center gap-2 mb-2",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"Your current subscription:"}),e.jsxs(B,{children:[e.jsx(W,{children:e.jsx(Yt,{className:"w-4 h-4 text-muted-foreground hover:text-foreground transition-colors"})}),e.jsx(H,{className:"max-w-xs",children:e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"font-medium",children:"Bulk upload limits:"}),e.jsxs("div",{className:"text-sm space-y-1",children:[e.jsx("p",{children:"• Free: 20 images"}),e.jsx("p",{children:"• Giotto: 30 images"}),e.jsx("p",{children:"• Botticelli: 50 images"}),e.jsx("p",{children:"• Da Vinci: 100 images"})]})]})})]})]}),e.jsx("div",{className:`inline-flex items-center px-4 py-2 rounded-full text-sm font-medium ${!d||d.subscription_tier==="free"?"bg-gray-100 text-gray-800 border border-gray-200":d.subscription_tier==="giotto"?"bg-blue-100 text-blue-800 border border-blue-200":d.subscription_tier==="botticelli"?"bg-purple-100 text-purple-800 border border-purple-200":"bg-amber-100 text-amber-800 border border-amber-200"}`,children:!d||d.subscription_tier==="free"?"Free":d.subscription_tier==="giotto"?"Giotto":d.subscription_tier==="botticelli"?"Botticelli":"Da Vinci"})]}),e.jsx("div",{className:"mb-6",children:e.jsx(et,{selectedMode:G,onSelectMode:t=>{Ue(t),T(F.RestorationModeSelected,{mode:t})}})}),e.jsx("div",{className:`border-2 border-dashed rounded-lg h-64 flex items-center justify-center transition-colors ${mt?"border-primary bg-primary/5":"border-border"}`,onDrop:pt,onDragOver:gt,onDragLeave:ft,children:e.jsxs("div",{className:"text-center",children:[e.jsx(Ze,{className:"w-12 h-12 mx-auto mb-4 text-muted-foreground"}),e.jsxs("p",{className:"text-lg font-medium mb-2",children:["Drag & drop up to ",ze()," images"]}),e.jsx("p",{className:"text-muted-foreground mb-4",children:"or click to browse"}),e.jsx("input",{type:"file",accept:"image/*",multiple:!0,className:"hidden",id:"file-input",onChange:t=>t.target.files&&he(t.target.files)}),e.jsx(w,{asChild:!0,children:e.jsx("label",{htmlFor:"file-input",className:"cursor-pointer",children:"Choose images"})}),e.jsx("p",{className:"text-xs text-muted-foreground mt-4 max-w-xs mx-auto",children:"Supports JPG, PNG and other common image types. Click the button above to upload your image(s)"})]})}),e.jsxs("div",{className:"mt-6 text-center",children:[e.jsxs("p",{className:"text-sm text-muted-foreground flex items-center justify-center gap-2",children:["Credits available:",e.jsx("span",{className:"inline-flex items-center justify-center min-w-[2rem] px-2 py-0.5 rounded-md font-semibold text-black",style:{backgroundColor:"rgba(155, 157, 154, 0.5)"},children:Re})]}),e.jsxs("p",{className:"text-xs text-muted-foreground mt-1",children:["Low on credits?"," ",e.jsx(be,{to:"/credits",className:"text-primary hover:underline",children:"Visit the credits page"})," ","to reload."]})]})]}),C==="preview"&&e.jsxs(V,{className:"p-8",children:[e.jsx("h2",{className:"text-2xl font-semibold text-center mb-8",children:e.jsx(ee,{text:"Ready to restore"})}),e.jsx("div",{className:"grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2 mb-8 max-h-48 overflow-y-auto",children:r.map((t,s)=>e.jsx("div",{className:`relative aspect-square rounded-lg overflow-hidden cursor-pointer border-2 ${s===m?"border-primary":"border-border"} flex-shrink-0`,onClick:()=>De(s),children:e.jsx(Z,{src:t.originalUrl||t.preview,alt:`Preview ${s+1}`,className:"w-full h-full object-cover",fallbackMessage:"Image not available"})},t.id))}),e.jsx("div",{className:"mb-8",children:e.jsx(et,{selectedMode:G,onSelectMode:t=>{Ue(t),T(F.RestorationModeSelected,{mode:t})}})}),r[m]&&e.jsxs("div",{className:"text-center mb-8",children:[e.jsx("div",{className:"max-w-md mx-auto mb-6",children:e.jsx(Z,{src:r[m].preview,alt:"Selected preview",className:"w-full rounded-lg shadow-lg",fallbackMessage:"Image not available"})}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-4 justify-center",children:[e.jsxs(w,{onClick:vt,size:"lg",className:"group",disabled:Y,children:[e.jsx(ge,{className:`w-4 h-4 mr-2 ${Y?"animate-spin":""}`}),"Let the magic begin"]}),e.jsxs(w,{onClick:xe,variant:"outline",size:"lg",disabled:Y,children:[e.jsx(fe,{className:"w-4 h-4 mr-2"}),"Choose different images"]})]})]}),e.jsx("div",{className:"text-center text-sm text-muted-foreground",children:e.jsxs("p",{children:["Processing ",r.length," image",r.length!==1?"s":""," •",` ${r.length} credit${r.length!==1?"s":""} will be used`]})})]}),C==="processing"&&Te&&e.jsx(V,{className:"p-8",children:e.jsxs("div",{className:"text-center max-w-2xl mx-auto",children:[e.jsx("h2",{className:"text-2xl font-semibold mb-4",children:"We’re sorry for the inconvenience."}),e.jsx("p",{className:"text-muted-foreground mb-8",children:"Your image restoration request could not be completed. Please try again using a different image, select a different restoration mode or simply try again later. The good news: your credit has been refunded automatically."}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-3 justify-center",children:[e.jsxs(w,{onClick:We,variant:"default",size:"lg",children:[e.jsx(Xe,{className:"w-4 h-4 mr-2"}),"Retry"]}),e.jsxs(w,{onClick:xe,variant:"outline",size:"lg",children:[e.jsx(fe,{className:"w-4 h-4 mr-2"}),"Restore another image"]})]})]})}),C==="processing"&&!Te&&e.jsxs("div",{className:"relative overflow-hidden",children:[dt.map(t=>e.jsx("div",{className:"absolute pointer-events-none select-none",style:{left:t.x,top:t.y,fontSize:t.size,transform:`rotate(${t.rotation}deg)`,zIndex:1},children:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"w-6 h-6 text-primary animate-tada",children:[e.jsx("path",{d:"M14.828 14.828a4 4 0 0 1-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("path",{d:"M12 6l2 2-2 2-2-2 2-2Z",fill:"currentColor"})]})},t.id)),e.jsxs(V,{className:"p-8 relative z-10",children:[e.jsx(oe,{className:"mb-6 bg-red-500/10 border-red-500/20",children:e.jsx(ne,{className:"text-center font-medium text-red-500",children:"⚠️ Please do not refresh or close this page while images are being processed."})}),de>=100&&r.some(t=>t.status==="processing")&&e.jsx(oe,{className:"mb-6 bg-red-500/10 border-red-500/20",children:e.jsx(ne,{className:"text-center font-medium text-white",children:"This is taking a while! Please hold on, this might take a few minutes."})}),e.jsxs("div",{className:"text-center",children:[e.jsx("h2",{className:"text-2xl font-semibold mb-8",children:e.jsx(Lr,{text:"Doing our magic..."})}),e.jsxs("div",{className:"mb-8",children:[e.jsx("div",{className:"flex justify-center mb-4",children:e.jsx("div",{className:"w-16 h-16 flex items-center justify-center",children:e.jsxs("svg",{className:"w-12 h-12 magic-wand-tada",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:[e.jsx("path",{d:"M3 3L5 5M5 3L3 5M21 21L19 19M19 21L21 19M12 2L11.5 3.5L10 4L11.5 4.5L12 6L12.5 4.5L14 4L12.5 3.5L12 2Z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-primary"}),e.jsx("path",{d:"M9 11L3 17L7 21L13 15",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-foreground"}),e.jsx("path",{d:"M11 9L17 3L21 7L15 13",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:"text-foreground"})]})})}),e.jsx("p",{className:"text-muted-foreground mb-6",children:"Pinin is carefully analyzing and restoring your image(s). Please hold on."}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex justify-between text-sm",children:[e.jsx("span",{children:"Progress"}),e.jsx("span",{children:r.length===1?`${Math.round(de)}%`:`${r.filter(t=>t.status==="completed").length} of ${r.length} completed`})]}),e.jsx("div",{className:"w-full bg-gray-200 rounded-full h-4 overflow-hidden",children:e.jsx("div",{className:"h-full gradient-animation rounded-full transition-all duration-100 ease-linear",style:{width:r.length===1?`${de}%`:`${r.filter(t=>t.status==="completed").length/r.length*100}%`}})})]})]}),e.jsx("div",{className:"mt-8 grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-2 max-h-48 overflow-y-auto",children:r.map((t,s)=>e.jsxs("div",{className:`relative rounded-lg overflow-hidden cursor-pointer border-2 ${s===m?"border-primary":"border-border"} aspect-square flex-shrink-0`,onClick:()=>De(s),children:[e.jsx(Z,{src:t.originalUrl||t.preview,alt:`Processing ${s+1}`,className:`w-full h-full object-cover transition-opacity ${t.status==="completed"?"opacity-100":"opacity-50"}`,fallbackMessage:"Image not available"}),e.jsxs("div",{className:"absolute inset-0 flex items-center justify-center",children:[t.status==="processing"&&e.jsx("div",{className:"w-8 h-8 border-2 border-primary border-t-transparent roun
100ded-full animate-spin"}),t.status==="completed"&&e.jsx("div",{className:"w-8 h-8 bg-green-500 rounded-full flex items-center justify-center icon-fx",children:e.jsx("span",{className:"text-white text-lg",children:"✓"})}),t.status==="failed"&&e.jsx("div",{className:"w-8 h-8 bg-red-500 rounded-full flex items-center justify-center icon-fx",children:e.jsx("span",{className:"text-white text-lg",children:"✗"})})]})]},t.id))})]})]})]}),C==="complete"&&e.jsxs(V,{className:"p-8",children:[e.jsx("h2",{className:"text-2xl font-semibold text-center mb-8",children:e.jsx(ee,{text:"Restoration complete!",speed:10})}),e.jsx("div",{className:"grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-4 mb-8",children:r.map((t,s)=>e.jsxs("div",{className:`relative aspect-square rounded-lg overflow-hidden cursor-pointer border-2 ${s===m?"border-primary":"border-border"}`,onClick:()=>ie(s),children:[e.jsx(Z,{src:t.status==="completed"?t.restoredUrl||t.originalUrl||t.preview:t.originalUrl||t.preview,alt:`Result ${s+1}`,className:"w-full h-full object-cover",fallbackMessage:"Loading..."}),t.status==="failed"&&e.jsx("div",{className:"absolute inset-0 bg-red-500/20 flex items-center justify-center",children:e.jsx("span",{className:"text-red-500 text-xl",children:"✗"})})]},t.id))}),r[m]?.status==="completed"&&!Y&&e.jsx("div",{className:"mb-8",children:e.jsxs("div",{ref:D,className:"relative max-w-2xl mx-auto",children:[e.jsxs("div",{className:"relative overflow-hidden rounded-lg aspect-video cursor-ew-resize select-none",onMouseDown:t=>{t.preventDefault();const s=t.currentTarget.getBoundingClientRect(),a=i=>{i.preventDefault();const u=i.clientX-s.left,j=Math.max(0,Math.min(100,u/s.width*100));J(j)},o=i=>{i.preventDefault(),document.removeEventListener("mousemove",a),document.removeEventListener("mouseup",o)};document.addEventListener("mousemove",a),document.addEventListener("mouseup",o)},onTouchStart:t=>{t.preventDefault();const s=t.currentTarget.getBoundingClientRect(),a=i=>{i.preventDefault();const j=i.touches[0].clientX-s.left,h=Math.max(0,Math.min(100,j/s.width*100));J(h)},o=i=>{i.preventDefault(),document.removeEventListener("touchmove",a),document.removeEventListener("touchend",o)};document.addEventListener("touchmove",a,{passive:!1}),document.addEventListener("touchend",o)},children:[e.jsx(Z,{src:r[m].originalUrl||r[m].preview,alt:"Before restoration",className:"absolute inset-0 w-full h-full object-cover",fallbackMessage:"Loading original image..."},`before-${m}-${r[m]?.id}`),e.jsx("div",{className:"absolute inset-0 overflow-hidden",style:{clipPath:`inset(0 0 0 ${le}%)`},children:e.jsx(Z,{src:r[m].restoredUrl||"",alt:"After restoration",className:"w-full h-full object-cover",fallbackMessage:"Image not available",onLoad:()=>{U.current||(U.current=!0,requestAnimationFrame(()=>Je(D.current)))}},`after-${m}-${r[m]?.id}`)}),e.jsx("div",{className:"absolute top-0 bottom-0 w-0.5 bg-white shadow-lg pointer-events-none z-10",style:{left:`${le}%`}}),e.jsx("div",{className:"absolute top-1/2 transform -translate-y-1/2 w-8 h-8 bg-white rounded-full shadow-lg border-2 border-primary cursor-ew-resize flex items-center justify-center pointer-events-none z-10",style:{left:`calc(${le}% - 16px)`},children:e.jsx("div",{className:"w-1 h-4 bg-primary rounded-full"})})]}),e.jsxs("div",{className:"flex justify-between mt-4 text-sm text-muted-foreground",children:[e.jsx("span",{children:"Before (original)"}),e.jsx("span",{children:"After (restored)"})]})]})}),r[m]?.status==="failed"&&e.jsxs("div",{className:"mb-6 p-4 bg-red-50 border border-red-200 rounded-lg",children:[e.jsx("p",{className:"text-red-700 font-medium",children:"Processing failed"}),e.jsx("p",{className:"text-red-600 text-sm mt-1",children:r[m].errorMessage||"Unknown error occurred"})]}),e.jsxs("div",{className:"space-y-4 mb-8",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row gap-4 justify-center",children:[r[m]?.status==="completed"&&e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(w,{onClick:()=>Nt(r[m].restoredUrl,r[m].file.name),variant:"outline",size:"lg",children:[e.jsx(we,{className:"w-4 h-4 mr-2"}),"Download"]})}),e.jsx(H,{children:"Save the restored photo to your device"})]}),r[m]?.status==="completed"&&r[m]?.restorationId&&!r[m]?.isUpscaled&&e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsx(w,{onClick:yt,disabled:$e===r[m].id,variant:"outline",size:"lg",children:$e===r[m].id?e.jsxs(e.Fragment,{children:[e.jsx(Pe,{className:"w-4 h-4 mr-2 animate-spin"}),"Upscaling…"]}):e.jsxs(e.Fragment,{children:[e.jsx(ge,{className:"w-4 h-4 mr-2"}),"Upscale to HD"]})})}),e.jsx(H,{children:"Increase resolution and sharpness for large, print-ready prints"})]}),r.filter(t=>t.status==="completed").length>1&&e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(w,{onClick:kt,variant:"outline",size:"lg",children:[e.jsx(we,{className:"w-4 h-4 mr-2"}),"Download All (",r.filter(t=>t.status==="completed").length,")"]})}),e.jsx(H,{children:"Download every restored photo at once"})]}),e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(w,{onClick:We,variant:"outline",size:"lg",children:[e.jsx(Xe,{className:"w-4 h-4 mr-2"}),"Retry"]})}),e.jsx(H,{children:"Run the restoration again on this photo"})]}),e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(w,{onClick:xe,variant:"outline",size:"lg",children:[e.jsx(fe,{className:"w-4 h-4 mr-2"}),"Restore another image"]})}),e.jsx(H,{children:"Start over and upload new photos to restore"})]})]}),r[m]?.status==="completed"&&r[m]?.restorationId&&e.jsx("div",{className:"mt-4",children:e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsx("div",{children:e.jsx(mr,{restorationId:r[m].restorationId,imageUrl:r[m].restoredUrl,label:"Print in one-click with Zazzle.com",iconUrl:"https://assets.pinin.ai/zazzle_logo.png",variant:"default",size:"lg",className:"w-full font-bold bg-white text-black hover:bg-white/90 shadow-lg border-2 border-black/10 shadow-black/20 whitespace-normal h-auto min-h-11 py-2.5 px-3 leading-snug text-center text-sm sm:text-base"})})}
100),e.jsx(H,{children:"Order prints, framed art and gifts with your restored photo"})]})}),r[m]?.status==="completed"&&e.jsx("div",{className:"flex justify-center mt-4",children:e.jsxs(B,{children:[e.jsx(W,{asChild:!0,children:e.jsxs(w,{onClick:()=>re(!0),variant:"outline",size:"lg",className:"w-full border-primary text-primary hover:bg-primary hover:text-primary-foreground",children:[e.jsx(je,{className:"w-4 h-4 mr-2"}),"Share"]})}),e.jsx(H,{children:"Share your before/after result with friends and family"})]})})]}),e.jsx(Pr,{isVisible:r[m]?.status==="completed",restorationId:r[m]?.restorationId,onShare:()=>re(!0)})]}),e.jsx(oe,{className:"mt-6",children:e.jsxs(ne,{children:["Please note: heavily damaged, antique and certain other images may not be successfully restored by our automatic AI image restoration tool. In those cases, we recommend using our"," ",e.jsx("button",{onClick:()=>n("/manual-restoration"),className:"text-primary hover:underline font-medium",children:"manual image restoration service"}),". All uploaded images are processed according to our"," ",e.jsx(be,{to:"/privacy-policy",className:"text-primary hover:underline font-medium",children:"Privacy Policy"}),", ensuring your photos are handled securely and with complete confidentiality."]})})]})}),e.jsx("section",{className:"px-4 py-10",children:e.jsx("div",{className:"container mx-auto max-w-5xl",children:e.jsxs("div",{className:"relative overflow-hidden rounded-3xl border border-border/60 bg-gradient-to-br from-primary/[0.07] via-card to-accent/[0.06] shadow-sm",children:[e.jsx("div",{className:"pointer-events-none absolute -top-24 -right-24 h-64 w-64 rounded-full bg-primary/10 blur-3xl","aria-hidden":"true"}),e.jsx("div",{className:"pointer-events-none absolute -bottom-24 -left-24 h-64 w-64 rounded-full bg-accent/10 blur-3xl","aria-hidden":"true"}),e.jsxs("div",{className:"relative p-6 sm:p-10",children:[e.jsxs("div",{className:"mx-auto mb-8 max-w-2xl text-center",children:[e.jsxs("span",{className:"inline-flex items-center gap-2 rounded-full border border-primary/20 bg-primary/10 px-3.5 py-1.5 text-xs font-semibold uppercase tracking-wide text-primary",children:[e.jsx(_e,{className:"h-3.5 w-3.5"}),"Pro tips"]}),e.jsx("h3",{className:"mt-4 text-2xl font-bold tracking-tight sm:text-3xl",children:e.jsx(ee,{text:"How to get the best results when restoring photos"})}),e.jsx("p",{className:"mt-3 text-sm text-muted-foreground sm:text-base",children:"A few quick habits before you upload make a big difference in how sharp, clean and lifelike your restored photos turn out."})]}),e.jsx("div",{className:"grid gap-4 sm:grid-cols-2 lg:grid-cols-3",children:[{icon:Gt,title:"Scan it flat",desc:"Lay photos completely flat on the glass — no wrinkles, folds or curled corners."},{icon:Zt,title:"Clean the surface",desc:"Wipe your scanner glass or camera lens so no dust or smudges get baked in."},{icon:ot,title:"Go high resolution",desc:"Scan at 600 DPI or higher so the AI has real detail to work with."},{icon:at,title:"Even lighting",desc:"Use bright, consistent light and avoid harsh shadows, glare or reflections."},{icon:Xt,title:"Remove dust first",desc:"Gently brush the print with a soft cloth to clear loose particles before scanning."},{icon:Jt,title:"Keep it lossless",desc:"Save as PNG or TIFF when you can to preserve the maximum amount of detail."}].map(({icon:t,title:s,desc:a})=>e.jsxs("div",{className:"group relative flex flex-col gap-3 rounded-2xl border border-border/60 bg-card/70 p-5 transition-all duration-200 hover:-translate-y-1 hover:border-primary/40 hover:shadow-md",children:[e.jsx("span",{className:"flex h-11 w-11 items-center justify-center rounded-xl bg-primary/10 text-primary transition-colors duration-200 group-hover:bg-primary group-hover:text-primary-foreground",children:e.jsx(t,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx("h4",{className:"text-sm font-semibold text-foreground",children:s}),e.jsx("p",{className:"mt-1 text-sm leading-relaxed text-muted-foreground",children:a})]})]},s))})]})]})})}),e.jsx("section",{className:"px-4 py-10",children:e.jsxs("div",{className:"container mx-auto max-w-3xl",children:[e.jsxs("div",{className:"mb-8 text-center",children:[e.jsx("h2",{className:"text-2xl font-bold tracking-tight sm:text-3xl",children:"Photo restoration — frequently asked questions"}),e.jsx("p",{className:"mt-3 text-sm text-muted-foreground sm:text-base",children:"Everything you need to know about restoring your old and damaged photos with Pinin."})]}),e.jsx("div",{className:"space-y-4",children:He.map(t=>e.jsxs("div",{className:"rounded-2xl border border-border/60 bg-card/70 p-5 sm:p-6",children:[e.jsx("h3",{className:"text-base font-semibold text-foreground sm:text-lg",children:t.question}),e.jsx("p",{className:"mt-2 text-sm leading-relaxed text-muted-foreground",children:t.answer})]},t.question))})]})}),e.jsx(hr,{group:"restoration"}),e.jsx(vr,{})]}),e.jsx(ar,{}),e.jsx("style",{children:`
101        @keyframes tada {
102          0% { transform: scale(1) rotate(0deg); }
103          10%, 20% { transform: scale(0.9) rotate(-3deg); }
104          30%, 50%, 70%, 90% { transform: scale(1.1) rotate(3deg); }
105          40%, 60%, 80% { transform: scale(1.1) rotate(-3deg); }
106          100% { transform: scale(1) rotate(0deg); }
107        }
108          30%, 50%, 70%, 90% { transform: scale(1.1) rotate(3deg); }
109          40%, 60%, 80% { transform: scale(1.1) rotate(-3deg); }
110          100% { transform: scale(1) rotate(0deg); }
111        }
112        .hero-circle-pulse-1 {
113          animation: hero-circle-pulse 8s ease-in-out infinite;
114        }
115        
116        .hero-circle-pulse-2 {
117          animation: hero-circle-pulse 6s ease-in-out infinite 0.5s;
118        }
119        
120        .hero-circle-pulse-3 {
121          animation: hero-circle-pulse 4s ease-in-out infinite 1s;
122        }
123        
124        .hero-circle-pulse-4 {
125          animation: hero-circle-pulse 7s ease-in-out infinite 1.5s;
126        }
127        
128        .hero-circle-pulse-5 {
129          animation: hero-circle-pulse 5s ease-in-out infinite 2s;
130        }
131        
132        @keyframes hero-circle-pulse {
133          0%, 100% {
134            transform: scale(1);
135            opacity: 0.3;
136          }
137          50% {
138            transform: scale(1.05);
139            opacity: 0.6;
140          }
141        }
142        
143        @keyframes liquidFill {
144          0% { width: 0%; }
145          100% { width: 100%; }
146        }
147        
148        @keyframes wave {
149          0%, 100% { transform: translateX(-100%); }
150          50% { transform: translateX(100%); }
151        }
152      `}),e.jsx(cr,{open:x,onOpenChange:g,initialMode:f}),e.jsx(Cr,{isOpen:ut,onClose:()=>re(!1),imageUrl:r[m]?.restoredUrl||"",imageName:r[m]?.file.name||"",restorationId:r[m]?.restorationId||""}),e.jsx(Rr,{open:ht,onOpenChange:se,restorationId:r[m]?.restorationId,onShare:()=>{se(!1),re(!0)}}),c&&C==="complete"&&Q>0&&e.jsx(Er,{})]})]})}export{ms as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.