\n \n \x3c!-- 2) then the button --\x3e\n \n \n \n
- | \n | \n `;const n=t.querySelector(".toggle-checkbox");return n.addEventListener("change",(()=>toggleValueTag(n))),t.querySelector("input.image-upload"),t.querySelector(".choose-image-btn").addEventListener("click",(()=>{let e=t.querySelector(".image-preview");e||(e=document.createElement("img"),e.className="image-preview",e.style.display="none",e.style.maxHeight="32px",t.querySelector("td").appendChild(e)),currentPreviewImg=e,openLibrary("custom")})),t.querySelector(".clear-row-btn").addEventListener("click",(()=>{t.querySelector(".instance").value=1,t.querySelector(".value").value=1,t.querySelector("select.tag").disabled||toggleValueTag(t.querySelector(".toggle-checkbox")),t.querySelector(".image-preview")?.remove(),t.querySelector(".edit-image-btn")?.remove();const e=t.querySelector("input.image-upload");e.value="",e.style.display="",e.removeAttribute("data-image-url"),updateProbabilities(),showPreview(),checkForDuplicates()})),t}function limitInstanceValue(e){const t=parseInt(document.getElementById("customSides").value);parseInt(e.value)>t&&(e.value=t)}function toggleValueTag(e){const t=e.closest(".value-tag-container").querySelector(".value-tag-input");let n=t.querySelector("select.tag");n||(n=document.createElement("select"),n.className="tag",n.disabled=!0,n.onchange=()=>checkForDuplicates(n),n.innerHTML='',tags.forEach((e=>{const t=document.createElement("option");t.value=e,t.textContent=e,n.appendChild(t)})),t.appendChild(n)),n.disabled=!n.disabled,e.checked=!n.disabled,n.disabled&&(n.value=""),checkForDuplicates(),showPreview()}function updateProbabilities(){const e=parseInt(document.getElementById("customSides").value,10)||0,t=document.querySelector("#diceTable tbody");let n=Array.from(t.querySelectorAll("tr")),c=n.map((e=>parseInt(e.querySelector(".instance").value,10)||0)),l=c.reduce(((e,t)=>e+t),0);for(;le;){const e=c.lastIndexOf(1);if(-1!==e)t.removeChild(n[e]),n.splice(e,1),c.splice(e,1);else{const e=n.length-1,t=n[e].querySelector(".instance");c[e]--,t.value=c[e]}l=c.reduce(((e,t)=>e+t),0)}n=Array.from(t.querySelectorAll("tr")),n.forEach(((e,t)=>{e.cells[0].textContent=t+1})),c=n.map((e=>parseInt(e.querySelector(".instance").value,10)||0)),l=c.reduce(((e,t)=>e+t),0),n.forEach(((t,n)=>{const l=e?(c[n]/e*100).toFixed(2):"0.00";t.querySelector(".prob").textContent=`${l}%`}))}function showPreview(){console.log("→ showPreview called, faces:",Array.from(document.querySelectorAll("#diceTable tbody tr")).map(((e,t)=>({idx:t+1,url:e.querySelector("input.image-upload").dataset.imageUrl||null,file:!!e.querySelector("input.image-upload").files[0]}))));const e=document.getElementById("dicePreview");e.innerHTML="";const t={};document.querySelectorAll("#diceTable tbody tr").forEach((e=>{const n=e.querySelector(".value-tag-input input, .value-tag-input select")?.value||"-",c=parseInt(e.querySelector("input.value").value,10)||0,l=parseInt(e.querySelector(".instance").value,10)||1,o=e.querySelector("input.image-upload"),i=o.files[0],a=i?URL.createObjectURL(i):o.dataset.imageUrl||null,r=1===l&&"-"===n&&1===c&&!a,s=r?"default":`${n}|${c}|${a||""}|${e.rowIndex}`;t[s]||(t[s]={count:0,label:n,value:c,srcUrl:a,isDefault:r,key:s}),t[s].count+=l})),Object.keys(t).length?Object.values(t).forEach((t=>{const{label:n,value:c,srcUrl:l,count:o,isDefault:i,key:a}=t,r=document.createElement("div");r.className="preview-die",i&&r.classList.add("default"),r.dataset.key=a,Object.assign(r.style,{position:"relative",display:"flex",flexDirection:"column",alignItems:"center"});const s=document.createElement("div");if(s.className="badge",s.textContent=o,Object.assign(s.style,{position:"absolute",top:"4px",right:"6px",background:"#333",color:"#fff",borderRadius:"50%",width:"20px",height:"20px",display:"flex",alignItems:"center",justifyContent:"center",fontSize:"0.75rem"}),r.appendChild(s),l){const e=document.createElement("img");e.src=l,Object.assign(e.style,{maxWidth:"100%",maxHeight:"60px"}),r.appendChild(e)}const d=document.createElement("div");d.className="preview-info",d.textContent=`${n} [${c}]`,Object.assign(d.style,{fontSize:"0.75rem",marginTop:"0.25rem",opacity:"0.8"}),r.appendChild(d),e.appendChild(r)})):e.innerHTML=''}function checkForDuplicates(){const e=Array.from(document.querySelectorAll("#diceTable tbody tr")),t={},n={},c={},l={};e.forEach((e=>{const o=e.querySelector("input.value"),i=e.querySelector("select.tag"),a=e.querySelector("input.image-upload"),r=o.value.trim(),s=!i.disabled&&i.value?i.value:"";let d="";if(a.files[0]?d=a.files[0].name:a.dataset.imageUrl&&(d=a.dataset.imageUrl),r&&s){const e=`${r}|${s}`;t[e]=(t[e]||0)+1}if(r&&d){const e=`${r}|${d}`;n[e]=(n[e]||0)+1}if(s&&d){const e=`${s}|${d}`;c[e]=(c[e]||0)+1}d&&(l[d]=(l[d]||0)+1)})),e.forEach((e=>{const o=e.querySelector("input.value"),i=e.querySelector("select.tag"),a=e.querySelector("input.image-upload"),r=e.querySelector(".image-preview"),s=o.value.trim(),d=!i.disabled&&i.value?i.value:"";let u="";a.files[0]?u=a.files[0].name:a.dataset.imageUrl&&(u=a.dataset.imageUrl);const m=s&&d&&t[`${s}|${d}`]>1,g=s&&u&&n[`${s}|${u}`]>1,p=d&&u&&c[`${d}|${u}`]>1,v=u&&l[u]>1;[o,i,a,r].forEach((e=>{e&&(e.style.border=""),e&&(e.title="")})),m&&(o.style.border=i.style.border="2px solid red",o.title=i.title="Duplicate value & tag"),g&&(o.style.border=a.style.border="2px solid red",o.title=a.title="Duplicate value & image",r&&(r.style.border="2px solid red")),p&&(i.style.border=a.style.border="2px solid red",i.title=a.title="Duplicate tag & image",r&&(r.style.border="2px solid red")),v&&r&&(r.style.border="2px solid red",r.title="This image is already used on another face")}))}!function(){const e="diceSets";let t=[],n=-1,c=null;function l(){localStorage.setItem(e,JSON.stringify(t))}function o(){const e=document.getElementById("diceSetSelect-design");e.innerHTML="",e.prepend(new Option("── Select a Set ──","")),t.forEach(((t,n)=>{e.append(new Option(t.name,n))})),e.append(new Option("+ New Set…","new"))}function i(){const e=n>=0,c=document.getElementById("exportSetBtn-design");if(c.disabled=!e,document.getElementById("editDiceSetNameBtn-design").disabled=!e,document.getElementById("diceCountDisplay-design").textContent=e?t[n].diceCount:1,a(e?t[n].diceCount:1),e){const{diceCount:e,diceConfigs:l}=t[n],o=l.length===e,i=l.every((e=>e.faces.every((e=>!(1===e.instances&&"—"===e.label&&1===e.value&&!e.imageDataUrl)))));c.disabled=!(o&&i)}}function a(e){const l=document.getElementById("diceButtonsContainer-design");if(l.innerHTML="",!(n<0))for(let o=0;o1===e.instances&&!e.label&&1===e.value&&!e.imageDataUrl)).length>0){const t=document.createElement("span");t.className="die-badge",e.appendChild(t)}o===c&&e.classList.add("active"),e.addEventListener("click",(()=>s(o))),l.appendChild(e)}}function r(e){if(n<0)return;const o=t[n],a=o.diceCount,r=Math.max(1,a+e);e<0&&r=r&&(c=null,document.getElementById("customSides").value=0,document.getElementById("diceSelect").value=0,document.querySelector("#diceTable tbody").innerHTML="",document.getElementById("dicePreview").innerHTML='')),o.diceCount=r,l(),i()}function s(e){c=e;const l=t[n].diceConfigs[e];l?(function(e){const{name:t,sides:n,faces:l}=e,o=document.querySelector(`#diceButtonsContainer-design button[data-idx="${c}"]`);o&&(o.textContent=t),document.getElementById("diceNameInput").value=t,document.getElementById("customSides").value=n,generateTable(),document.querySelectorAll("#diceTable tbody tr").forEach(((e,t)=>{const n=l[t]||{};e.querySelector("input.value").value=null!=n.value?n.value:"";const c=e.querySelector("select.tag"),o=e.querySelector(".toggle-checkbox");null!=n.label?(c.disabled&&toggleValueTag(o),c.value=n.label):c.disabled||toggleValueTag(o),e.querySelector(".instance").value=n.instances||1;const i=e.querySelector("input.image-upload");if(n.imageDataUrl?i.dataset.imageUrl=n.imageDataUrl:i.removeAttribute("data-image-url"),e.querySelector(".image-preview")?.remove(),i.style.display="",n.imageDataUrl){const e=document.createElement("img");e.src=n.imageDataUrl,e.className="image-preview",e.style.maxHeight="32px";const t=i.closest("td");e.style.display="",t.appendChild(e),i.style.display="none",i.addEventListener("change",(()=>{const t=i.files[0];t&&(e.src=URL.createObjectURL(t))}))}})),updateProbabilities()}(l),showPreview()):(document.getElementById("customSides").value=0,document.getElementById("diceSelect").value=0,generateTable(),document.getElementById("dicePreview").innerHTML='');const o=l&&l.name||`Die ${c+1}`;nameInput.value=o,a(t[n].diceCount),showPreview(),i()}document.getElementById("saveConfigBtn-design").addEventListener("click",(()=>{!async function(){if(hasDuplicateCombinations())return;if(n<0||null==c)return;const e=t[n].diceConfigs[c],o=e?.faces||[],r=document.getElementById("diceNameInput").value.trim(),s=""!==r?r:`Die ${c+1}`,d=parseInt(document.getElementById("customSides").value,10),u=document.querySelectorAll("#diceTable tbody tr"),m=[],g=[];u.forEach(((e,t)=>{const n=parseInt(e.querySelector("input.value").value,10)||0,c=(()=>{const t=e.querySelector("select.tag");return!t.disabled&&t.value?t.value:null})(),l=parseInt(e.querySelector(".instance").value,10)||0,i=e.querySelector("input.image-upload"),a=i.files[0],r=i.dataset.imageUrl||null,s={index:t+1,value:n,label:c,instances:l,imageDataUrl:o[t]?.imageDataUrl||null};a?g.push(new Promise((e=>{const t=new FileReader;t.onload=()=>{s.imageDataUrl=t.result,e()},t.readAsDataURL(a)}))):r&&(s.imageDataUrl=r),m.push(s)})),await Promise.all(g),t[n].diceConfigs[c]={name:s,sides:d,faces:m},l(),a(t[n].diceCount),i()}(),a(t[n].diceCount)})),document.getElementById("clearConfigBtn-design").addEventListener("click",(()=>{n<0||null==c||(document.getElementById("customSides").value=0,document.getElementById("diceSelect").value=0,document.getElementById("dicePreview").innerHTML='',document.querySelectorAll("#diceTable tbody tr").forEach((e=>{e.querySelector(".value").value="",e.querySelector("select.tag").disabled||toggleValueTag(e.querySelector(".toggle-checkbox")),e.querySelector(".instance").value=1,e.querySelector(".image-upload").value="",e.querySelector("img.image-preview")?.remove()})),updateProbabilities(),delete t[n].diceConfigs[c],l(),a(t[n].diceCount),showPreview(),i())})),document.getElementById("diceSetSelect-design").addEventListener("change",(function(e){const a=e.target.value;if("new"===a){const c=prompt("Name for new set:");if(!c||t.some((e=>e.name===c)))return alert("Invalid or duplicate name"),void(e.target.value="");t.push({name:c,diceCount:1,diceConfigs:[]}),l(),o(),n=t.length-1,e.target.value=n}else n=""===a?-1:parseInt(a,10);c=null,i(),document.getElementById("customSides").value=0,document.getElementById("diceSelect").value=0,document.querySelector("#diceTable tbody").innerHTML="",document.getElementById("dicePreview").innerHTML=''})),document.getElementById("editDiceSetNameBtn-design").addEventListener("click",(()=>{if(n<0)return;const e=t[n].name,c=prompt("Rename set:",e);c&&c!==e&&!t.some((e=>e.name===c))?(t[n].name=c,l(),o(),document.getElementById("diceSetSelect-design").value=n):alert("Invalid or duplicate name")})),document.getElementById("deleteDiceSetBtn-design").addEventListener("click",(()=>{if(n<0)return;const e=t[n].name;confirm(`Delete set "${e}"? This cannot be undone.`)&&(t.splice(n,1),l(),n=-1,c=null,o(),document.getElementById("diceSetSelect-design").value="",i())})),document.getElementById("increaseDiceCountBtn-design").addEventListener("click",(()=>r(1))),document.getElementById("decreaseDiceCountBtn-design").addEventListener("click",(()=>r(-1))),document.getElementById("exportSetBtn-design").addEventListener("click",(()=>{if(n<0)return;const{diceCount:e,diceConfigs:c}=t[n],l=c.length===e,o=c.some((e=>e.faces.some((e=>1===e.instances&&1===e.value&&!e.label&&!e.imageDataUrl))));l&&!o&&(localStorage.setItem("activeSetIndex",n),window.location.href="https://dice.untitledquest.com")})),function(){const n=localStorage.getItem(e);t=n?JSON.parse(n):[]}(),o(),i()}();const nameInput=document.getElementById("diceNameInput");function hasDuplicateCombinations(){const e=Array.from(document.querySelectorAll("#diceTable tbody tr")),t={},n={},c={},l={};e.forEach((e=>{const o=e.querySelector("input.value").value.trim(),i=e.querySelector("select.tag"),a=!i.disabled&&i.value?i.value:"",r=e.querySelector("input.image-upload"),s=r.files[0]?.name||r.dataset.imageUrl||"";o&&a&&(t[`${o}|${a}`]=(t[`${o}|${a}`]||0)+1),o&&s&&(n[`${o}|${s}`]=(n[`${o}|${s}`]||0)+1),a&&s&&(c[`${a}|${s}`]=(c[`${a}|${s}`]||0)+1),s&&(l[s]=(l[s]||0)+1)}));let o=!1;return e.forEach((e=>{const i=e.querySelector("input.value").value.trim(),a=e.querySelector("select.tag"),r=!a.disabled&&a.value?a.value:"",s=e.querySelector("input.image-upload"),d=s.files[0]?.name||s.dataset.imageUrl||"",u=i&&r&&t[`${i}|${r}`]>1,m=i&&d&&n[`${i}|${d}`]>1,g=r&&d&&c[`${r}|${d}`]>1,p=d&&l[d]>1;(u||m||g||p)&&(o=!0,e.classList.add("duplicate-row"),e.addEventListener("animationend",(()=>{e.classList.remove("duplicate-row")}),{once:!0}))})),o}nameInput.addEventListener("blur",(()=>{let e=nameInput.value.trim()||`Die ${currentDieIndex+1}`;if(nameInput.value=e,currentSetIndex>=0&&null!=currentDieIndex){const t=diceSets[currentSetIndex].diceConfigs[currentDieIndex]||{};t.name=e,diceSets[currentSetIndex].diceConfigs[currentDieIndex]=t;const n=document.querySelector(`#diceButtonsContainer-design button[data-idx="${currentDieIndex}"]`);n&&(n.textContent=e),saveDiceSets(),renderDiceButtons(diceSets[currentSetIndex].diceCount)}}));let currentPreviewImg=null;function populateGrid(e){const t=document.getElementById("iconGrid");if(t.innerHTML="","custom"===e){t.innerHTML="";const e=document.createElement("div");e.className="custom-upload-container";const n=document.createElement("input");n.type="file",n.accept="image/*",n.id="modal-upload-file",n.addEventListener("change",(()=>{const e=n.files[0];if(!e)return;const t=URL.createObjectURL(e);currentPreviewImg.src=t,currentPreviewImg.style.display="";const c=Object.values(selectedIcons).some((e=>e>0));document.getElementById("modal-confirm-btn").disabled=!c}));const c=document.createElement("label");return c.htmlFor=n.id,c.className="custom-upload-label",c.textContent="Choose File",e.appendChild(c),e.appendChild(n),void t.appendChild(e)}ICON_TEMPLATES[e].forEach((e=>{const n=document.createElement("img");n.crossOrigin="anonymous",n.src=e,n.addEventListener("click",(()=>{t.querySelectorAll("img").forEach((e=>e.classList.remove("selected"))),n.classList.add("selected"),currentPreviewImg.src=e,currentPreviewImg.style.display="";const c=Object.values(selectedIcons).some((e=>e>0));document.getElementById("modal-confirm-btn").disabled=!c})),t.appendChild(n)}))}function openLibrary(e){resetPreviewSelection(),document.getElementById("imageLibraryModal").classList.remove("hidden"),document.querySelectorAll(".icon-tabs button").forEach((t=>t.classList.toggle("active",t.dataset.cat===e))),populateGrid(e);const t=document.getElementById("modal-confirm-btn"),n=document.getElementById("modal-clear-btn");t.disabled=!0,t.onclick=()=>{const e=currentPreviewImg.closest("td").querySelector("input.image-upload"),t=document.querySelector(".preview-grid");html2canvas(t,{backgroundColor:null,useCORS:!0,allowTaint:!1,onclone:e=>{e.querySelector(".preview-grid").style.padding="0"}}).then((t=>{const n=t.toDataURL("image/png");e.dataset.imageUrl=n,currentPreviewImg.src=n,currentPreviewImg.style.display="",showPreview(),closeLibrary()}))},n.onclick=()=>{const e=currentPreviewImg?.closest("td");e&&(e.querySelector("input.image-upload").removeAttribute("data-image-url"),e.querySelector(".image-preview")?.remove(),e.querySelector(".edit-image-btn")?.remove(),currentPreviewImg=null,t.disabled=!0)},resetPreviewSelection()}function closeLibrary(){document.getElementById("imageLibraryModal").classList.add("hidden"),currentPreviewImg=null}document.addEventListener("click",(e=>{if(e.target.matches(".choose-image-btn")){const t=e.target.closest("td");let n=t.querySelector(".image-preview");n||(n=document.createElement("img"),n.className="image-preview",n.style.display="none",n.style.maxHeight="32px",t.appendChild(n)),currentPreviewImg=n,openLibrary("symbols")}e.target.matches(".icon-tabs button")&&(document.querySelectorAll(".icon-tabs button").forEach((e=>e.classList.remove("active"))),e.target.classList.add("active"),populateGrid(e.target.dataset.cat)),e.target.matches(".modal-backdrop, .modal-close")&&closeLibrary(),showPreview(),checkForDuplicates()}));let selectedIcons={};function updatePreviewGrid(){const e=document.querySelector(".preview-image-modal .preview-grid");if(!e)return;e.innerHTML="";const t=Object.keys(selectedIcons).filter((e=>selectedIcons[e]>0)).length;Object.entries(selectedIcons).forEach((([n,c])=>{if(!(c<=0))if(t>2||c>3){const t=document.createElement("div");t.className="preview-item";const l=document.createElement("img");l.src=n,l.style.minHeight="40px",t.appendChild(l);const o=document.createElement("div");o.className="badge",o.textContent=c,t.appendChild(o),e.appendChild(t)}else for(let t=0;t{document.querySelector(".preview-grid").style.backgroundColor=document.getElementById("modal-bg-color").value})),document.getElementById("iconGrid").addEventListener("click",(e=>{if("IMG"!==e.target.tagName)return;const t=e.target.getAttribute("src"),n=document.getElementById("modal-icon-count");selectedIcons[t]=(selectedIcons[t]||0)+1,n.value=selectedIcons[t],updatePreviewGrid();const c=Object.values(selectedIcons).some((e=>e>0));document.getElementById("modal-confirm-btn").disabled=!c})),document.getElementById("modal-icon-count").addEventListener("input",(e=>{const t=parseInt(e.target.value,10);if(isNaN(t)||t<0)return;const n=Object.keys(selectedIcons),c=n[n.length-1];if(!c)return;selectedIcons[c]=t,updatePreviewGrid();const l=Object.values(selectedIcons).some((e=>e>0));document.getElementById("modal-confirm-btn").disabled=!l})),document.getElementById("iconGrid").addEventListener("change",(e=>{if(e.target.matches('input[type="file"]')){const t=e.target.files[0];if(!t)return;const n=URL.createObjectURL(t),c=document.getElementById("modal-icon-count"),l=Math.max(1,parseInt(c.value,10)||0);selectedIcons[n]=(selectedIcons[n]||0)+l,updatePreviewGrid();const o=Object.values(selectedIcons).some((e=>e>0));document.getElementById("modal-confirm-btn").disabled=!o}})),document.querySelectorAll(".icon-tabs button").forEach((e=>{e.addEventListener("click",resetPreviewSelection)})),document.getElementById("modal-clear-btn").addEventListener("click",(()=>{resetPreviewSelection()}))