Este es un ejemplo que funciona a la perfeccion para gestionar gastos en un viaje:

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0"><title>Gestion de viajes</title><style>body,html{margin:0;padding:0;display:flex;flex-direction:column;justify-content:center;align-items:center;height:100vh;position:relative;background:linear-gradient(135deg,#e25baa,#45bb9e);background-size:200% 200%;animation:gs 15s ease-in-out infinite;font-family:-apple-system;touch-action:none}@keyframes gs{0%{background-position:0% 50%}50%{background-position:100% 50%}100%{background-position:0% 50%}}.phone{width:100vw;height:87vh;background:linear-gradient(to top,#f5f5f5,rgba(255,255,255,0.6),rgba(255,255,255,0.8));position:absolute;top:0;overflow:hidden;box-shadow:inset 0 2px 6px rgba(0,0,0,0.3),0 0 30px rgba(255,255,255,1),0 0 60px rgba(255,255,255,0.9),0 0 90px rgba(255,255,255,0.8);background-clip:padding-box}.logo{position:absolute;bottom:15px;width:auto;height:7vh;left:50%;transform:translateX(-50%)}#sec{width:100vw;height:87vh;position:absolute;top:0;overflow-y:auto;overflow-x:hidden}div,dialog{padding:5px}input,select,button{margin:8px;font-size:28px;padding:12px;border:none;outline:none;border-radius:15px}input{width:50vw;height:4vh}dialog{border:none;border-radius:10px;background:#fff;padding:20px;width:80%;max-width:400px;box-shadow:0 2px 10px rgba(0,0,0,0.3)}dialog::backdrop{background:rgba(0,0,0,0.5)}</style></head><body><a href="https://iacutstore.com" target="_blank" class="button"><img src="https://assets.zyrosite.com/AGBGKEDqpZHD6qRQ/logo-bueno-mnl3pJJ39oCgZGZV.png" alt="Logo" class="logo"></a><div class="phone"><div id="sec"><div id="t"><button id="nt">Nuevo Viaje</button><select id="ts"></select><button id="dt">Borrar Viaje</button></div><div id="p"><input id="pn" placeholder="Añadir Persona"><button id="ap">+</button><span id="pl"></span></div><div id="x"><input id="cx" placeholder="Concepto"><input id="am" type="number" placeholder="€" step="0.01"><select id="py"></select><input id="tk" type="file" accept="image/*"><button id="ae">Añadir Ticket</button></div><div id="cl"></div><button id="sh">Compartir</button><dialog id="dg"><p>¿Seguro?</p><button id="sy">ok</button><button id="no">cancelar</button></dialog><dialog id="newTripDialog"><p>Nuevo Viaje</p><input id="newTripInput" placeholder="Nombre"><div><button id="newTripCancel">Cancelar</button><button id="newTripOk">OK</button></div></dialog></div><script>(function(){let db,act,cur;const nt=document.getElementById("nt"),ts=document.getElementById("ts"),dt=document.getElementById("dt"),pn=document.getElementById("pn"),ap=document.getElementById("ap"),pl=document.getElementById("pl"),cx=document.getElementById("cx"),am=document.getElementById("am"),py=document.getElementById("py"),tk=document.getElementById("tk"),ae=document.getElementById("ae"),cl=document.getElementById("cl"),sh=document.getElementById("sh"),dg=document.getElementById("dg"),sy=document.getElementById("sy"),no=document.getElementById("no"),ntd=document.getElementById("newTripDialog"),nti=document.getElementById("newTripInput"),ntc=document.getElementById("newTripCancel"),nto=document.getElementById("newTripOk");const req=indexedDB.open("vdb",1);req.onupgradeneeded=e=>{db=e.target.result;db.createObjectStore("trips",{keyPath:"id",autoIncrement:true})};req.onsuccess=e=>{db=e.target.result;load()};function load(){const os=db.transaction("trips","readonly").objectStore("trips");let arr=[];ts.innerHTML="";os.openCursor().onsuccess=function(e){let curor=e.target.result;curor?(arr.push(curor.value),curor.continue()):(arr.forEach(o=>{let op=document.createElement("option");op.value=o.id;op.textContent=o.n;cur&&cur.id==o.id&&(op.selected=!0);ts.appendChild(op)}),!cur&&arr.length&&(cur=arr[0]),upd())}}function upd(){if(!cur)return document.getElementById("p").style.display="none",document.getElementById("x").style.display="none",sh.style.display="none",ts.style.display="none",dt.style.display="none";document.getElementById("p").style.display="block",document.getElementById("x").style.display="block",sh.style.display="inline-block",ts.style.display="inline-block",dt.style.display="inline-block",pl.innerHTML="",cur.p.forEach(n=>{let b=document.createElement("button");b.textContent=n;pl.appendChild(b)}),py.innerHTML="",cur.p.forEach(n=>{let o=document.createElement("option");o.textContent="Pagado por "+n;o.value=n;py.appendChild(o)}),updTickets()}function updTickets(){cl.innerHTML=tickets();let d=debts();d.length&&d.forEach(t=>{let b=document.createElement("button");b.textContent=t;cl.appendChild(b)})}function tickets(){if(!cur.e||!cur.e.length)return"";let s="";cur.e.forEach((t,i)=>{s+=(i+1)+". "+t.cx+" -> "+t.am.toFixed(2)+" -> Pagado por "+t.py+"<br>"});return s}function debts(){if(!cur.p.length)return[];let tot=0,ns={};cur.p.forEach(n=>ns[n]=0);cur.e.forEach(x=>{tot+=x.am;ns[x.py]+=x.am});let avg=tot/cur.p.length;for(let n in ns)ns[n]-=avg;let cr=[],de=[];for(let n in ns){let v=ns[n];v>0?cr.push({n,v}):v<0&&de.push({n,v:-v})}cr.sort((a,b)=>b.v-a.v);de.sort((a,b)=>b.v-a.v);let res=[];while(cr.length&&de.length){let m=Math.min(cr[0].v,de[0].v);res.push(de[0].n+" -> "+cr[0].n+": "+m.toFixed(2));cr[0].v-=m;de[0].v-=m;0===cr[0].v&&cr.shift();0===de[0].v&&de.shift()}return res}function save(){const tx=db.transaction("trips","readwrite").objectStore("trips").put(cur);tx.onsuccess=load}ap.onclick=function(){pn.value&&cur&&(cur.p.push(pn.value),pn.value="",upd(),save())};ae.onclick=function(){if(cx.value&&am.value&&py.value&&cur){const add=x=>{cur.e.push({cx:cx.value,am:+am.value,py:py.value,tk:x||""});cx.value="";am.value="";tk.value="";save();upd()};const f=tk.files[0];if(f){const fr=new FileReader;fr.onload=function(){add(fr.result)};fr.readAsDataURL(f)}else add()}};nt.onclick=function(){nti.value="",ntd.showModal()};ntc.onclick=function(){ntd.close()};nto.onclick=function(){if(nti.value){let o={n:nti.value,p:[],e:[]},r=db.transaction("trips","readwrite").objectStore("trips").add(o);r.onsuccess=function(e){o.id=e.target.result;cur=o;load();upd();ntd.close()}}};ts.onchange=function(){let id=+this.value,tx=db.transaction("trips","readonly").objectStore("trips").get(id);tx.onsuccess=function(e){cur=e.target.result;upd()}};dt.onclick=function(){ask(()=>{let tx=db.transaction("trips","readwrite").objectStore("trips").delete(cur.id);tx.onsuccess=function(){cur=null;load();pl.innerHTML="";cl.innerHTML=""}})};sh.onclick=function(){if(!cur)return;let s="Viaje: "+cur.n+"\n"+"Personas: "+cur.p.join(", ")+"\n"+"Tickets:\n"+tickets().replace(/<br>/g,"\n")+"Deudas:\n"+debts().join("\n");navigator.share?navigator.share({title:"Viaje Gastos",text:s}).then(()=>console.log("Compartido")).catch(e=>console.error("Error: "+e)):console.log("API Web Share no disponible")};function ask(fn){act=fn;dg.showModal()}sy.onclick=function(){act&&act();dg.close()};no.onclick=function(){dg.close()}})();</script></div></body></html>