<div class="stage"><div class="phone"><div class="notch"></div><div class="screen" id="screen">
<div class="acbg"><div class="bar w80"></div><div class="bar w60"></div><div class="bar w70"></div><div class="bar w50"></div></div>
<div class="acshade" id="acshade"></div>
<div class="accard" id="accard">
<button class="acclose" id="acclose">✕</button>
<div class="acicon" id="acicon"></div>
<div class="actxt"><div class="acname">Cafe Lumen</div><div class="acdesc">Order & pay — no install</div></div>
<button class="acopen" id="acopen">Open</button>
</div></div><div class="home"></div></div></div>
.stage{position:absolute;inset:0;display:grid;place-items:center;overflow:hidden}
.phone{position:relative;height:90vmin;max-height:640px;aspect-ratio:9/19.5;background:#08080c;
border-radius:20%/8.6%;box-shadow:0 0 0 2px rgba(255,255,255,.08) inset,0 12px 30px rgba(0,0,0,.35)}
.phone .notch{position:absolute;left:50%;top:0;transform:translateX(-50%);width:38%;height:5.6%;
background:#08080c;border-radius:0 0 46% 46%;z-index:80}
.phone .screen{position:absolute;top:7.6%;left:3%;right:3%;bottom:3%;border-radius:11%/4.6%;overflow:hidden;
background:var(--surface);color:var(--fg)}
.phone .home{position:absolute;left:50%;bottom:1.1%;transform:translateX(-50%);width:32%;height:3px;
border-radius:2px;background:rgba(255,255,255,.45);z-index:80}
.pfx{position:absolute;left:0;top:0;width:16px;height:16px;margin:-8px 0 0 -8px;border-radius:50%;
background:color-mix(in srgb,var(--accent) 55%,transparent);
box-shadow:0 0 0 6px color-mix(in srgb,var(--accent) 15%,transparent);pointer-events:none;z-index:999;
transition:opacity .2s}
.pfx.hold{width:30px;height:30px;margin:-15px 0 0 -15px;
box-shadow:0 0 0 9px color-mix(in srgb,var(--accent) 20%,transparent);
transition:width .5s linear,height .5s linear,margin .5s linear,box-shadow .5s linear,opacity .2s}
.acbg{position:absolute;inset:0;padding:16% 8% 0;display:grid;grid-auto-rows:clamp(3px,2.6vmin,7px);gap:8%;filter:blur(1.4px);opacity:.7}
.bar{border-radius:3px;background:var(--line)}
.w80{width:80%}.w60{width:60%}.w70{width:70%}.w50{width:50%}
.acshade{position:absolute;inset:0;background:#000;opacity:0;transition:opacity .3s;z-index:10;pointer-events:none}
.acshade.show{opacity:.22}
.accard{position:absolute;left:4%;right:4%;bottom:4%;background:var(--surface);border-radius:16px;
box-shadow:0 -6px 20px rgba(0,0,0,.22);padding:8% 7%;display:grid;grid-template-columns:auto 1fr;
align-items:center;gap:5%;transform:translateY(140%);transition:transform .35s cubic-bezier(.2,.8,.2,1);z-index:20}
.accard.show{transform:translateY(0)}
.acclose{position:absolute;top:6%;right:5%;border:none;background:none;color:var(--muted);font-size:clamp(6px,2vmin,8px)}
.acicon{width:clamp(20px,13vmin,34px);height:clamp(20px,13vmin,34px);border-radius:24%;background:var(--accent);transition:transform .2s}
.acicon.pulse{transform:scale(1.15)}
.actxt{min-width:0}
.acname{font-weight:800;font-size:clamp(6.5px,2.4vmin,9px);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.acdesc{font-size:clamp(5.5px,1.9vmin,7.5px);color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.acopen{grid-column:1/3;margin-top:4%;border:none;border-radius:999px;background:var(--accent);color:#fff;
font-weight:800;font-size:clamp(6.5px,2.4vmin,9px);padding:4% 0}
const pfx=document.createElement('div');pfx.className='pfx';document.body.appendChild(pfx);
const screenEl=document.getElementById('screen');
let pfxAuto=true;
function pfxHide(){pfx.style.opacity='0';}
addEventListener('pointerdown',()=>{pfxAuto=false;pfxHide();},{capture:true});
function pfxAt(fx,fy){
const r=screenEl.getBoundingClientRect();
const x=r.left+r.width*fx, y=r.top+r.height*fy;
pfx.style.transform='translate('+x+'px,'+y+'px)';
return {x,y};
}
function pfxWalk(x0,y0,x1,y1,ms){
return new Promise(res=>{
const start=performance.now();
function step(now){
if(!pfxAuto) return res();
const p=Math.min(1,(now-start)/ms), e=1-Math.pow(1-p,3);
pfxAt(x0+(x1-x0)*e, y0+(y1-y0)*e);
if(p<1) requestAnimationFrame(step); else res();
}
requestAnimationFrame(step);
});
}
function pfxWait(ms){
return new Promise(res=>{
const start=performance.now();
function step(now){ if(!pfxAuto) return res(); if(now-start<ms) requestAnimationFrame(step); else res(); }
requestAnimationFrame(step);
});
}
const shade=document.getElementById('acshade'), card=document.getElementById('accard'), icon=document.getElementById('acicon'),
openBtn=document.getElementById('acopen'), closeBtn=document.getElementById('acclose');
function open(){ shade.classList.add('show'); card.classList.add('show'); }
function close(){ shade.classList.remove('show'); card.classList.remove('show'); }
closeBtn.addEventListener('pointerdown',()=>{ pfxAuto=false; pfxHide(); close(); });
shade.addEventListener('pointerdown',close);
function launch(){
icon.classList.add('pulse'); openBtn.textContent='Opening...';
setTimeout(()=>{ icon.classList.remove('pulse'); openBtn.textContent='Open'; close(); },650);
}
openBtn.addEventListener('pointerdown',()=>{ pfxAuto=false; pfxHide(); launch(); });
function fracOf(el){ const r=el.getBoundingClientRect(), sr=screenEl.getBoundingClientRect();
return {x:(r.left+r.width/2-sr.left)/sr.width,y:(r.top+r.height/2-sr.top)/sr.height}; }
async function autoSeq(){
while(pfxAuto){
close();
await pfxWalk(0.5,0.9,0.5,0.9,350); if(!pfxAuto)break;
open();
await pfxWait(700); if(!pfxAuto)break;
const f=fracOf(openBtn);
await pfxWalk(0.5,0.9,f.x,f.y,300); if(!pfxAuto)break;
launch();
await pfxWait(1000);
}
}
autoSeq();