memoscan
← all memos

Memo 0xcde4e0f0…053087 on Ethereum

N <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀</title> <link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet" /> <script src="https://arweave.net/S1hqI3tgUg-m_lhtrQX9IalKxMdfGqI3fox04_xMwEI"></script> </head> <script> let isUnlocked = false; window.onload = function () { const infoButtons = document.querySelectorAll(".info"); const submitButton = document.querySelector(".submit"); const submitInfoButton = document.querySelector(".submitInfo"); const viewArtworkInfoButton = document.querySelector(".viewArtworkInfo"); const modalClose = document.querySelector(".modal-close"); const modal = document.querySelector(".modal"); infoButtons.forEach((infoButton) => { infoButton.addEventListener("click", () => { const infoModal = showModal(` <div class="modal-title">Critical text by Primavera De Filippi</div> <div class="modal-subtitle">Artist and Legal Scholar (Harvard / CNRS)</div> <div class="modal-body"> <p class="text-center">In 𝐐𝐔𝐀𝐍𝐓𝐔𝐌 𝐇𝐄𝐗 𝐌𝐀𝐂𝐇𝐈𝐍𝐀, Andrea Chiampo points at the paradoxes of our technological systems — with blockchain as a particularly revealing case, where the promise of cryptographic immortality is perpetually undone by its own impermanence and volatility. A JPEG file is hashed onto the blockchain, before it is corrupted beyond recognition—its bytes scattered like ashes across a monumental print and sealed within an accompanying physical pamphlet.</p> <p class="text-center">This act of deliberate corruption is not an act of destruction but one of transformation. Like a digital phoenix emerging from its own cryptographic hashes, the hashed representation of the JPEG serves as a signature of existence that persists beyond physical transformation. Locked within the immutable ledger of the blockchain, the hash exists as both a challenge and a metaphor, inviting the public to reconstitute the corrupted JPEG, while acknowledging the precarious architecture of our technological tools.</p> <p class="text-center">The collector who purchases the work does not acquire ownership of the NFT, but that of the physical artwork and it paired pamphlet that contains the instruction to recover the original JPEG file in its uncorrupted format. But the retrieval is not guaranteed; it is a gamble, a mathematical puzzle that even a quantum computer would struggle to solve. It is a puzzle that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> <p class="text-center">Chiampo's piece is a manifestation of Machina Hex Machina—a machine that curses as much as it saves. As technology has become our "<b>deus ex machina</b>", our divine intervention, what happens when it falters? What remains of our digital artefacts when the gears of the machine grind to a halt?</p> <p class="text-center">The digital artwork is a puzzle waiting to be solved. It is a challenge that defies solution, yet invites it—a paradox that speaks to the human condition in an age of machines.</p> The answer lies in the act of unravelling itself, the perpetual negotiation between creation and dissolution, where human ingenuity emerges as a recursive algorithm of resistance. Yet, there is a strange beauty in decay, as decay can become a source of reconstruction—reminding us that even as our systems collapse, the human desire to rebuild will come alive, transmuting every act of destruction into a new possibility for reconstruction.</p> <p class="text-center">QUANTUM HEX MACHINA is not merely an artwork; it is a provocation, a mirror held up to the blockchain's contradictions. It is a testament to the fragility of the systems we create and the resilience of the spirit that creates them. In its corrupted bytes and cryptographic riddles, it whispers a truth: that the act of falling apart is not an end, but a beginning—a quiet, insistent call to reimagine what lies beyond the ruins.</p> </div> <div class="modal-footer text-center"> <p style="font-size:1dvmin;line-height:initial"><i>*** Smart contract by Nahiko ***</i></p> </div> `); infoModal.children[0].style.height = "85dvmin"; }); }); submitButton.addEventListener("click", async () => { if (submitButton.classList.contains("disabled")) { return; // Don't proceed if button is disabled } try { // Get the verification result with hash and dataURI const result = await isFileCorrect(); const { dataURI, submittedFileHash } = result; console.log("Submit handler received:", { dataURI, submittedFileHash }); if (!dataURI || !submittedFileHash) { console.error("Missing dataURI or submittedFileHash"); return; // Don't proceed if verification failed } // For transactions, we need a wallet signer, not just any provider let provider; if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); } catch (err) { console.error("User rejected wallet connection:", err); showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Connection Required:</b> To submit your solution, you need to connect your Ethereum wallet.</div>` ); return; } } else { showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;"><b>Wallet Not Found:</b> To submit your solution, you need an Ethereum wallet like MetaMask installed.</div>` ); return; } // Get signer const signer = await provider.getSigner(); // Create contract instance with signer to allow transactions const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, signer); console.log("Submitting file hash:", submittedFileHash); // Let the wallet handle the transaction UI const tx = await vaultContract.unlockNFT(submittedFileHash); // Wait for transaction to be mined const receipt = await tx.wait(); if (receipt.status === 1) { // Transaction successful - show success modal const successModal = showModal(` <div class="modal-title title">CONGRATULATIONS, YOU HAVE FINALLY SOLVED THE PUZZLE!</div> <div class="modal-body"> <div class="text-center"> <p>~</p> <p>“An eternal tunnel of static — an infinite absence of signal. A loop of technological answers birthing only more questions — drifting further from the real ones ”</p> <p>~</p> <p>Thanks to your hardwork the original image has been restored.</p> <p>You can now decide how the NFT will be experienced. Follow the instructions in the physical dossier and smart contract to upload the artwork. metadata with the recovered artwork.</p> </div> </div> `); successModal.children[0].style.padding = "8dvmin 3dvmin"; successModal.classList.add("Ihatecss"); } } catch (error) { console.error("Error in transaction:", error); // Let the wallet handle error cases - don't show our own modal } }); submitInfoButton.addEventListener("click", () => { const submitInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">While anyone may interact with this interface and attempt to submit a solution, only the wallet address registered on-chain at the time of acquisition holds the exclusive right to advance to the next phase:<br> to unlock the NFT, validate the reconstruction, and update its metadata with the recovered artwork.</div>` ); submitInfoModal.children[0].style.height = "auto"; submitInfoModal.children[0].style.width = "80dvmin"; }); viewArtworkInfoButton.addEventListener("click", () => { const viewArtworkInfoModal = showModal( `<div style="text-align:left;font-size:1.5dvmin;line-height:initial;padding: 2dvmin 4dvmin;">The Physical Collector may or may not choose to make the artwork available for display</div>` ); viewArtworkInfoModal.children[0].style.height = "auto"; viewArtworkInfoModal.children[0].style.width = "80dvmin"; }); document.addEventListener("keydown", (e) => { if (e.key === "Escape") { const modal = document.querySelector(".modal"); if (modal) closeModal(modal); } }); const collectorElements = document.querySelectorAll(".collector"); collectorElements.forEach((element) => { console.log(element.textContent); element.addEventListener("click", function () { window.open("https://etherscan.io/address/" + element.textContent, "_blank"); }); }); const timer = document.querySelector(".timer"); const targetDate = new Date("April 3, 2025 13:00:00 EDT"); const timerInterval = setInterval(() => { const now = new Date(); const timeZoneDiff = now.getTimezoneOffset() * 60000; const nowUTC = new Date(now.getTime() + timeZoneDiff); const nyTimeOffset = -4 * 60 * 60000; const nowNY = new Date(nowUTC.getTime() + nyTimeOffset); const difference = targetDate - nowNY; const years = Math.floor(Math.abs(difference) / (1000 * 60 * 60 * 24 * 365.25)); const days = Math.abs( Math.floor((difference % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24)) ); const hours = Math.abs(Math.floor((difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))); const minutes = Math.abs(Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60))); const seconds = Math.abs(Math.floor((difference % (1000 * 60)) / 1000)); if (difference <= 0) { timer.textContent = "ENTER"; timer.classList.add("button"); timer.addEventListener("click", enterGame); const chronometer = document.querySelector(".chronometer"); chronometer.textContent = `${padZero(years)}y:${padZero(days)}:${padZero( hours )}:${padZero(minutes)}:${padZero(seconds)}`; return; } timer.textContent = `${padZero(days)}:${padZero(hours)}:${padZero(minutes)}:${padZero( seconds )}`; }, 500); setTimeout(function () { timer.style.opacity = 1; }, 500); }; function padZero(num) { return num.toString().padStart(2, "0"); } // Simplified enterGame function let isGameEntered = false; async function enterGame() { if (isGameEntered) return; try { const provider = await getProvider(); proceedToEnterGame(provider); } catch (error) { console.error("Failed to initialize provider:", error); } } // Helper function to actually enter the game once we have a provider async function proceedToEnterGame(provider) { // Call getContractData when needed await getContractData(); document.querySelector(".background").style.opacity = 1; isGameEntered = true; const cover = document.querySelector(".cover"); const game = document.querySelector(".game"); const ending = document.querySelector(".ending"); // Target element based on the unlocked status const targetElement = isUnlocked ? ending : game; cover.style.opacity = "0"; setTimeout(() => { cover.style.display = "none"; targetElement.style.display = "flex"; targetElement.style.transition = "opacity 1s ease-in"; setTimeout(() => { targetElement.style.opacity = "1"; console.log(isUnlocked ? "ENDING REACHED" : "WELCOME"); }, 50); }, 1000); } function showModal(content) { const existingModal = document.querySelector(".modal"); if (existingModal) { existingModal.remove(); } const modal = document.createElement("div"); modal.className = "modal"; modal.innerHTML = ` <div class="modal-content"> <span class="close">&times;</span> ${content} </div> `; document.body.appendChild(modal); modal.offsetHeight; modal.style.display = "flex"; setTimeout(() => { modal.style.opacity = "1"; }, 10); const closeBtn = modal.querySelector(".close"); closeBtn.onclick = () => closeModal(modal); window.onclick = (e) => { if (e.target === modal) closeModal(modal); }; return modal; } function closeModal(modal) { modal.style.opacity = "0"; setTimeout(() => { modal.remove(); }, 300); } async function isFileCorrect() { try { const fileInput = document.querySelector("textarea"); let inputText = fileInput.value.trim(); const verificationString = document.querySelector(".verificationString"); if (!inputText) { verificationString.innerHTML = ""; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } if (inputText.startsWith("0x")) { inputText = inputText.substring(2); } if (!/^[0-9a-fA-F]*$/.test(inputText)) { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } let inputBytes; try { if (inputText.length % 2 !== 0) { inputText = "0" + inputText; } inputBytes = ethers.getBytes("0x" + inputText); } catch (e) { console.error("Error parsing hex input:", e); verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } const base64Content = ethers.encodeBase64(inputBytes); const dataURI = `data:image/jpeg;base64,${base64Content}`; const dataURIBytes = ethers.toUtf8Bytes(dataURI); const submittedFileHash = ethers.keccak256(dataURIBytes); // Store first hash as submittedFileHash const packedFirstHash = ethers.solidityPacked(["bytes32"], [submittedFileHash]); const hashedFileHash = ethers.keccak256(packedFirstHash); console.log("First hash (submittedFileHash):", submittedFileHash); console.log("Final hash (hashedFileHash):", hashedFileHash); const expectedHashedFileHash = "0xb43501f79c29086d44cc94ea56ab6c0901cbc79e113f498a64dbfde145f1fa49"; if (hashedFileHash.toLowerCase() === expectedHashedFileHash.toLowerCase()) { verificationString.innerHTML = "✓ &nbsp;Quantum state observed. Reality collapses into certainty."; document.querySelector(".submit").classList.remove("disabled"); return { dataURI, submittedFileHash }; // Return an object with the values } else { verificationString.innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; document.querySelector(".submit").classList.add("disabled"); return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } catch (error) { console.error("Error in isFileCorrect function:", error); document.querySelector(".verificationString").innerHTML = "✖ &nbsp;Wrong string. Entropy persists."; return { dataURI: "", submittedFileHash: "" }; // Return an object with empty values } } function stringToHexBytes(str) { return Array.from(new TextEncoder().encode(str)) .map((b) => b.toString(16).padStart(2, "0")) .join(""); } document.addEventListener("DOMContentLoaded", function () { const fileInput = document.querySelector("textarea"); const textareaContainer = document.querySelector(".textareaContainer"); let debounceTimer; fileInput.addEventListener("input", function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { isFileCorrect(); }, 300); }); fileInput.addEventListener("paste", function () { setTimeout(isFileCorrect, 50); }); ["dragenter", "dragover", "dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, preventDefaults, false); }); function preventDefaults(e) { e.preventDefault(); e.stopPropagation(); } ["dragenter", "dragover"].forEach((eventName) => { textareaContainer.addEventListener(eventName, highlight, false); }); ["dragleave", "drop"].forEach((eventName) => { textareaContainer.addEventListener(eventName, unhighlight, false); }); function highlight() { textareaContainer.style.backgroundColor = "#e6e3dc"; } function unhighlight() { textareaContainer.style.backgroundColor = "#f7f6f3"; } textareaContainer.addEventListener("drop", handleDrop, false); function handleDrop(e) { const dt = e.dataTransfer; const files = dt.files; if (files.length > 0) { const file = files[0]; readFileAsHex(file); } } function readFileAsHex(file) { const reader = new FileReader(); reader.onload = function (e) { const arrayBuffer = e.target.result; const bytes = new Uint8Array(arrayBuffer); let hexString = ""; for (let i = 0; i < bytes.length; i++) { const hex = bytes[i].toString(16).padStart(2, "0"); hexString += hex; } fileInput.value = hexString; isFileCorrect(); }; reader.readAsArrayBuffer(file); } }); // Add contract details const VAULT_ADDRESS = "0x24e9C8Aa584F7F0338ec617E3F2261F4BdC49708"; const VAULT_ABI = [ "function physicalCollectorAddress() view returns (address)", "function isUnlocked() view returns (bool)", "function unlockAddress() view returns (address)", "function unlockTimestamp() view returns (uint256)", "function owner() view returns (address)", "function fileAddress() view returns (address)", "function isFileCorrect(address potentialFileAddress) view returns (bool, string)", "function unlockNFT(bytes32 submittedFileHash) external", ]; async function getProvider() { let provider; try { provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com"); await provider.getBlockNumber(); // Test the connection console.log("Connected to public RPC provider"); return provider; } catch (error) { console.warn("Public RPC failed:", error); if (window.ethereum) { try { await window.ethereum.request({ method: "eth_requestAccounts" }); provider = new ethers.BrowserProvider(window.ethereum); console.log("Connected using wallet"); return provider; } catch (err) { console.error("User rejected wallet connection:", err); throw new Error("Failed to connect to wallet"); } } throw new Error("No provider available"); } } // Update getContractData to use the centralized provider async function getContractData() { try { const provider = await getProvider(); const vaultContract = new ethers.Contract(VAULT_ADDRESS, VAULT_ABI, provider); const collectorAddress = await vaultContract.physicalCollectorAddress(); console.log("physicalCollectorAddress: " + collectorAddress); // Update first collector address element const collectorElement = document.querySelector(".collector"); if (collectorElement) { collectorElement.textContent = collectorAddress; } // Get vault unlock status isUnlocked = await vaultContract.isUnlocked(); console.log("isUnlocked: " + isUnlocked); // Variables to store file data let fileAddress = null; let jpegDataURI = null; // If the vault is unlocked, get the unlock details from state variables if (isUnlocked) { try { // Get unlock information directly from state variables const unlockAddress = await vaultContract.unlockAddress(); const unlockTimestamp = await vaultContract.unlockTimestamp(); console.log("Unlock address:", unlockAddress); console.log("Unlock timestamp:", unlockTimestamp); if (unlockTimestamp > 0) { // Check if the timestamp is valid // Convert timestamp to date const unlockDate = new Date(Number(unlockTimestamp) * 1000); console.log("Unlock date:", unlockDate.toISOString()); // Update the chronometer with the unlock timestamp const chronometer = document.querySelector(".ending .chronometer"); if (chronometer) { chronometer.textContent = `${unlockDate .getUTCDate() .toString() .padStart(2, "0")}/${(unlockDate.getUTCMonth() + 1) .toString() .padStart(2, "0")}/${unlockDate.getUTCFullYear()}`; } // Update the collector in the ending screen with unlock address const endingCollector = document.querySelector(".ending .collector"); if (endingCollector) { endingCollector.textContent = unlockAddress; } fileAddress = await vaultContract.fileAddress(); console.log("File address:", fileAddress); try { // First check if the file is correct using the Vault contract's isFileCorrect function const [isCorrect, fileContent] = await vaultContract.isFileCorrect(fileAddress); console.log("File correctness check:", isCorrect); if (isCorrect && fileContent) { jpegDataURI = fileContent; console.log("Retrieved verified JPEG data URI successfully"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { viewArtworkButton.addEventListener("click", function () { showModal(` <div style="text-align:center;"> <div class="modal-title">QUANTUM HEX MACHINA</div> <div class="modal-subtitle">THE UNLOCKED ARTWORK</div> <div style="margin-top: 2dvmin;"> <img src="${jpegDataURI}" style="max-width: 90%; max-height: 70dvmin;" alt="Quantum Hex Machina" /> </div> </div> `); }); viewArtworkButton.classList.remove("disabled"); console.log("View Artwork button enabled"); } } else { console.log("File verification failed"); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Simply keep the button disabled by adding the disabled class viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to file verification failure"); } } } catch (error) { console.error("Error verifying file:", error); const viewArtworkButton = document.querySelector(".viewArtwork"); if (viewArtworkButton) { // Also keep the button disabled in case of errors viewArtworkButton.classList.add("disabled"); console.log("View Artwork button disabled due to verification error"); } } } else { console.log("No unlock data found despite unlocked status"); // Set default values for testing if no timestamp const chronometer = document.querySelector(".chronometer"); if (chronometer) { chronometer.textContent = "UNLOCKED"; } } } catch (error) { console.error("Error getting unlock details:", error); } } return { collectorAddress, isUnlocked, unlockAddress: await vaultContract.unlockAddress(), unlockTimestamp: await vaultContract.unlockTimestamp(), fileAddress, jpegDataURI, }; } catch (error) { console.error("Error fetching contract data:", error); } } </script> <style> html { background-color: black; width: 100%; height: 100%; color: #6e6d69; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: "Times New Roman", serif; font-weight: 500; margin: 0; padding: 0; background-color: #ece9e2; background-image: url("https://arweave.net/0MD2DIp1YxwVD1xATJssXH54S9Xjz2lXA583PogfmpY"); background-size: cover; background-position: center; background-repeat: no-repeat; line-height: 1.2dvmin; } body { display: flex; flex-direction: column; width: 100dvmin; height: 100dvmin; align-items: center; justify-content: center; text-align: center; margin: 0; padding: 0; } .background { width: 100%; height: 100%; position: absolute; background-color: #ece9e2; opacity: 0; transition: opacity 1s; } .main { display: flex; flex-direction: column; align-items: center; gap: 1.3dvmin; transition: opacity 1s ease-in-out; margin-bottom: 0.4dvmin; z-index: 10; } .ending { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .game { margin-bottom: 6.5dvmin; display: none; opacity: 0; gap: 4dvmin; } .title { font-size: 2.5dvmin; line-height: 2.5dvmin; letter-spacing: 0.54dvmin; text-indent: 0.54dvmin; } .subtitle { letter-spacing: 0.225dvmin; text-indent: 0.225dvmin; font-size: 1dvmin; line-height: 1dvmin; } .timer { background-color: #3e3e3e; color: #ece9e2; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; font-size: 1.2dvmin; transform: translateY(0.7dvmin); letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; leading-trim: both; opacity: 0; transition: 1.5s opacity; } .Ihatecss { font-family: "Times New Roman", serif !important; } .button { background-color: #3e3e3e; leading-trim: both; color: #ece9e2; font-size: 1.2dvmin; padding: 0.8dvmin 1.5dvmin; border-radius: 2dvmin; cursor: pointer; transition: opacity 1.5s ease-in-out, background-color 0.1s; user-select: none; letter-spacing: 0.24dvmin; text-indent: 0.24dvmin; } .button:hover { background-color: #6e6d69; } .disabled { background-color: #aeaeae; cursor: default; } .disabled:hover { background-color: #aeaeae; } .info { padding: 0.8dvmin 2.4dvmin; margin-top: 2.2dvmin; } .titleContainer { display: flex; flex-direction: column; align-items: center; gap: 1.1dvmin; } .titleContainer > .title { font-size: 1.7dvmin; line-height: 1.7dvmin; } .titleContainer > .subtitle { font-size: 0.7dvmin; line-height: 0.7dvmin; } .inputContainer { display: flex; flex-direction: column; align-items: center; position: relative; } .textareaContainer { width: 48dvmin; display: flex; position: relative; background-color: #f7f6f3; padding: 2dvmin; padding-bottom: 9.5dvmin; align-items: center; justify-content: center; flex-direction: column; } .ending .textareaContainer { height: 48.5dvmin; } .ending .chronometerContainer { position: initial; bottom: initial; padding: 0.8dvmin 3dvmin; } .ending .collectorContainer { align-items: center; } .ending .collector { font-size: 1.2dvmin; } textarea { width: 100%; height: 48.5dvmin; background-color: #f7f6f3; font: inherit; font-size: 1.1dvmin; line-height: 1.1dvmin; color: inherit; vertical-align: top; letter-spacing: 0.18dvmin; text-align: justify; outline: none; border: none; box-shadow: none; -webkit-appearance: none; -moz-appearance: none; appearance: none; resize: none; overflow-y: scroll; scrollbar-gutter: stable; overflow-x: auto; overflow-y: overlay; scrollbar-width: none; font-family: "Calibri", "Open Sans", sans-serif; font-family: monospace; } textarea::placeholder { color: #e0ddd7; } textarea::-webkit-scrollbar-track { background: transparent; } textarea { scrollbar-color: rgba(110, 109, 105, 0.5) transparent; } .chronometerContainer { position: absolute; bottom: 7dvmin; padding: 0.8dvmin 8dvmin; background-color: #e6e3dc; border-radius: 8dvmin; display: flex; flex-direction: column; gap: 0.2dvmin; } .verificationString { position: absolute; bottom: 13.5dvmin; font-size: 1.1dvmin; line-height: 1.1dvmin; font-family: "Calibri", "Open Sans", sans-serif; background-color: #f7f6f3; } .submitInfo { position: absolute; bottom: 3.75dvmin; right: -2.8dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; line-height: 2dvmin; cursor: pointer; } .submitInfo:hover { opacity: 0.75; } .viewArtworkInfo { position: absolute; bottom: 0.5dvmin; right: 11dvmin; line-height: 1.6dvmin; width: 1.6dvmin; height: 1.6dvmin; border-radius: 50%; color: #6f6d69; border: solid 0.15dvmin #6f6d69; font-weight: 200; font-family: sans-serif; font-size: 1.5dvmin; line-height: 1.5dvmin; cursor: pointer; } .viewArtworkInfo:hover { opacity: 0.75; } .collectorContainer { display: flex; flex-direction: column; justify-content: flex-start; width: 100%; align-items: start; margin-top: 1dvmin; margin-left: 0.6dvmin; gap: 0.3dvmin; } .collector { font-weight: bold; text-decoration: underline; letter-spacing: 0.22dvmin; cursor: pointer; } .collector:hover { opacity: 0.6; } .collectorTitle { letter-spacing: 0.08dvmin; font-size: 0.9dvmin; line-height: 0.9dvmin; } .submit { align-self: end; border-radius: 0; } .viewArtwork { border-radius: 0; align-self: center; } .chronometer { font-size: 1.8dvmin; line-height: 1.8dvmin; } .modal { position: fixed; z-index: 100; left: 0; top: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.3); opacity: 0; transition: opacity 0.3s ease-in-out; font-family: "Calibri", "Open Sans", sans-serif; display: flex; justify-content: center; align-items: center; font-size: 1.2dvmin; } .modal-content { background-color: #f7f6f3; padding: 3dvmin; width: 85dvmin; position: relative; border-radius: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.75dvmin; line-height: initial; } .text-center { text-align: center; } .modal-title { font-size: 1.45dvmin; line-height: 1.45dvmin; text-align: center; margin-top: 0; font-weight: 600; color: #3e3e3e; } .modal-subtitle { font-size: 1.27dvmin; line-height: 1.27dvmin; text-align: center; margin-top: 0; margin-bottom: 3dvmin; font-weight: normal; color: #3e3e3e; } .modal-body { line-height: 1.8; color: #3e3e3e; text-align: left; padding: 0 10dvmin; } .close { color: #6e6d69; position: absolute; right: 0.75dvmin; top: 0.25dvmin; font-size: 2dvmin; line-height: 2dvmin; font-weight: bold; cursor: pointer; padding: 0.5dvmin; user-select: none; } .close:hover { opacity: 0.7; } </style> <body> <div class="background"></div> <div class="main cover"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="timer">00:00:00:00</div> </div> <div class="main game"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <textarea type="text" placeholder="Paste correct string here/drag in to upload a file" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" ></textarea> </div> <div class="verificationString"></div> <div class="chronometerContainer"> <div class="subtitle">UNSOLVED SINCE</div> <div class="chronometer title">00:00:00:00</div> </div> <div class="submit button disabled">SUBMIT</div> <div class="submitInfo">i</div> <div class="collectorContainer"> <div class="subtitle collectorTitle"> PHYSICAL ART COLLECTOR / WALLET ALLOWED TO CLAIM </div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> </div> <div class="main ending"> <div class="titleContainer"> <div class="subtitle">ANDREA CHIAMPO PRESENTS</div> <div class="title">QUANTUM HEX MACHINA</div> <div class="info button">INFO</div> </div> <div class="inputContainer"> <div class="textareaContainer"> <div class="chronometerContainer"> <div class="subtitle">THIS ARTWORK HAS BEEN UNLOCKED</div> <div class="chronometer title">00/00/00</div> </div> <div class="collectorContainer"> <div class="subtitle collectorTitle">UNLOCKED BY</div> <div class="subtitle collector">0x0000000000000000000000000000000000000000</div> </div> </div> <div class="viewArtwork button">VIEW UNLOCKED ARTWORK</div> <div class="viewArtworkInfo">i</div> </div> </div> </body> </html>