✅ Your bills are saved automatically on this device as you make changes.
You do not need to press Backup every time. Use this optional backup if you want an extra copy of your bills, or if you want to move them to another device.
⚠️ Restoring a backup will replace the bills currently saved on this device.
(function(){ var STORAGE_KEY = "moneyUntilPaydayBudget"; var backupButton = document.getElementById( "backupBudgetButton" ); var restoreInput = document.getElementById( "restoreBudgetFile" ); var status = document.getElementById( "budgetBackupStatus" ); if( !backupButton || !restoreInput || !status ){ return; } /* ========================= BACKUP ========================= */ backupButton.addEventListener( "click", function(){ var saved = localStorage.getItem( STORAGE_KEY ); if(!saved){ status.textContent = "⚠️ No saved bill data found."; return; } var parsed; try{ parsed = JSON.parse( saved ); } catch(e){ status.textContent = "❌ Could not read the saved bill data."; return; } /* CREATE BACKUP FILE */ var backupData = { type: "DLC_BILL_TRACKER_BACKUP", version: 1, created: new Date() .toISOString(), data: parsed }; var blob = new Blob( [ JSON.stringify( backupData, null, 2 ) ], { type: "application/json" } ); var url = URL.createObjectURL( blob ); var link = document.createElement( "a" ); var today = new Date(); var dateName = today.getFullYear() + "-" + String( today.getMonth()+1 ).padStart(2,"0") + "-" + String( today.getDate() ).padStart(2,"0"); link.href = url; link.download = "dlc-bill-tracker-backup-" + dateName + ".json"; document.body.appendChild( link ); link.click(); document.body.removeChild( link ); URL.revokeObjectURL( url ); status.textContent = "✅ Backup created successfully"; } ); /* ========================= RESTORE ========================= */ restoreInput.addEventListener( "change", function(){ var file = restoreInput.files && restoreInput.files[0]; if(!file){ return; } /* CONFIRM BEFORE REPLACING CURRENT SAVED DATA */ var confirmed = window.confirm( "Restore this backup?\n\n" + "This will replace the bills currently saved on this device." ); if(!confirmed){ restoreInput.value = ""; status.textContent = "Restore cancelled."; return; } var reader = new FileReader(); reader.onload = function(event){ try{ var backup = JSON.parse( event.target.result ); /* CHECK VALID BACKUP */ if( !backup || backup.type !== "DLC_BILL_TRACKER_BACKUP" || !backup.data ){ status.textContent = "❌ This does not look like a valid bill-tracker backup."; restoreInput.value = ""; return; } /* RESTORE DATA */ localStorage.setItem( STORAGE_KEY, JSON.stringify( backup.data ) ); status.textContent = "✅ Backup restored — reloading..."; setTimeout( function(){ window.location.reload(); }, 700 ); } catch(e){ status.textContent = "❌ Could not restore this backup file."; } restoreInput.value = ""; }; reader.readAsText( file ); } ); })();
Income Shortfall Calculator
See how much extra you need to earn to cover the gap.
var DLCTwoSnap = { area:null, status:null, countBox:null, completeBox:null, active:null, dragging:false, offsetX:0, offsetY:0, fittedHead:false, fittedBody:false, headStart:null, bodyStart:null, topLayer:20, start:function() { this.area = document.getElementById( "twoSnapArea" ); this.status = document.getElementById( "twoSnapStatus" ); this.countBox = document.getElementById( "twoSnapCount" ); this.completeBox = document.getElementById( "twoComplete" ); var head = document.getElementById( "twoHeadPiece" ); var body = document.getElementById( "twoBodyPiece" ); if ( !this.area || !head || !body ) { return; } /* Record their real starting positions after Carrd loads. */ this.headStart = { left: head.offsetLeft, top: head.offsetTop }; this.bodyStart = { left: body.offsetLeft, top: body.offsetTop }; head.addEventListener( "pointerdown", this.down.bind(this) ); body.addEventListener( "pointerdown", this.down.bind(this) ); document.addEventListener( "pointermove", this.move.bind(this) ); document.addEventListener( "pointerup", this.up.bind(this) ); document.addEventListener( "pointercancel", this.up.bind(this) ); this.updateCount(); this.status.textContent = "✅ Two-piece test loaded"; }, down:function(event) { event.preventDefault(); this.active = event.currentTarget; this.dragging = true; var name = this.active.getAttribute( "data-piece" ); /* If fitted already, grabbing it removes it from fitted state. */ if ( name === "HEAD" && this.fittedHead ) { this.fittedHead = false; this.active.classList.remove( "twoFitted" ); } if ( name === "BODY" && this.fittedBody ) { this.fittedBody = false; this.active.classList.remove( "twoFitted" ); } this.updateCount(); var rect = this.active .getBoundingClientRect(); this.offsetX = event.clientX - rect.left; this.offsetY = event.clientY - rect.top; this.topLayer++; this.active.style.zIndex = this.topLayer; this.active.style.cursor = "grabbing"; this.status.textContent = "✋ Moving " + name; }, move:function(event) { if ( !this.dragging || !this.active ) { return; } event.preventDefault(); var areaRect = this.area .getBoundingClientRect(); var x = event.clientX - areaRect.left - this.offsetX; var y = event.clientY - areaRect.top - this.offsetY; var maxX = this.area.clientWidth - this.active.offsetWidth; var maxY = this.area.clientHeight - this.active.offsetHeight; if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x > maxX) { x = maxX; } if (y > maxY) { y = maxY; } this.active.style.left = x + "px"; this.active.style.top = y + "px"; this.active.style.right = "auto"; this.active.style.bottom = "auto"; }, up:function() { if ( !this.dragging || !this.active ) { return; } this.dragging = false; var piece = this.active; this.active = null; piece.style.cursor = "grab"; this.checkSnap( piece ); }, checkSnap:function(piece) { var name = piece.getAttribute( "data-piece" ); var target; if ( name === "HEAD" ) { target = document.getElementById( "twoHeadTarget" ); } if ( name === "BODY" ) { target = document.getElementById( "twoBodyTarget" ); } if (!target) { return; } var pieceRect = piece .getBoundingClientRect(); var targetRect = target .getBoundingClientRect(); /* Check whether the middle of the piece has entered the target area. */ var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 20 && centreX < targetRect.right + 20 && centreY > targetRect.top - 20 && centreY < targetRect.bottom + 20; if (!inside) { this.status.textContent = "❌ Not in the slot — try again"; return; } this.snap( piece, target, name ); }, snap:function( piece, target, name ) { var areaRect = this.area .getBoundingClientRect(); var targetRect = target .getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); if ( name === "HEAD" ) { this.fittedHead = true; } if ( name === "BODY" ) { this.fittedBody = true; } this.status.textContent = "🎉 CLICK! " + name + " FITTED!"; this.updateCount(); }, updateCount:function() { var count = 0; if ( this.fittedHead ) { count++; } if ( this.fittedBody ) { count++; } if ( this.countBox ) { this.countBox.textContent = count; } if ( count === 2 ) { this.status.textContent = "🎉 CHARACTER TEST COMPLETE!"; this.completeBox.classList.add( "showTwoComplete" ); this.area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } else { this.completeBox.classList.remove( "showTwoComplete" ); this.area.style.boxShadow = ""; } }, reset:function() { var head = document.getElementById( "twoHeadPiece" ); var body = document.getElementById( "twoBodyPiece" ); this.dragging = false; this.active = null; this.fittedHead = false; this.fittedBody = false; head.classList.remove( "twoFitted" ); body.classList.remove( "twoFitted" ); head.style.right = "auto"; head.style.bottom = "auto"; head.style.left = this.headStart.left + "px"; head.style.top = this.headStart.top + "px"; body.style.right = "auto"; body.style.bottom = "auto"; body.style.left = this.bodyStart.left + "px"; body.style.top = this.bodyStart.top + "px"; this.updateCount(); this.status.textContent = "↺ Test reset"; } }; setTimeout( function() { DLCTwoSnap.start(); var button = document.getElementById( "twoSnapReset" ); if (button) { button.addEventListener( "click", function() { DLCTwoSnap.reset(); } ); } }, 600 );
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var count = document.getElementById( "twoSnapCount" ); var status = document.getElementById( "twoSnapStatus" ); if ( !area || !window.DLCTwoSnap ) { return; } /* CHANGE COUNTER TO /3 */ if (count) { var parent = count.parentElement; if (parent) { parent.innerHTML = '' + '0' + '/3'; } } /* CREATE ARM TARGET */ var target = document.createElement( "div" ); target.id = "twoLeftArmTarget"; target.textContent = "ARM"; area.appendChild( target ); /* CREATE ARM */ var arm = document.createElement( "div" ); arm.id = "twoLeftArmPiece"; arm.setAttribute( "data-piece", "ARM" ); arm.innerHTML = '' + '' + 'LEFT'; area.appendChild( arm ); /* STORE START */ DLCTwoSnap.armStart = { left:arm.offsetLeft, top:arm.offsetTop }; DLCTwoSnap.fittedArm = false; /* CONNECT ARM TO EXISTING DRAG */ arm.addEventListener( "pointerdown", DLCTwoSnap.down.bind( DLCTwoSnap ) ); /* SAVE ORIGINAL CHECK SNAP */ var oldCheckSnap = DLCTwoSnap.checkSnap.bind( DLCTwoSnap ); DLCTwoSnap.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); if ( name !== "ARM" ) { oldCheckSnap( piece ); return; } var armTarget = document.getElementById( "twoLeftArmTarget" ); var pieceRect = piece.getBoundingClientRect(); var targetRect = armTarget.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 20 && centreX < targetRect.right + 20 && centreY > targetRect.top - 20 && centreY < targetRect.bottom + 20; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); DLCTwoSnap.fittedArm = true; status.textContent = "🎉 CLICK! LEFT ARM FITTED!"; updateThreeCount(); }; /* NEW 3 PIECE COUNTER */ function updateThreeCount() { var total = 0; if ( DLCTwoSnap.fittedHead ) { total++; } if ( DLCTwoSnap.fittedBody ) { total++; } if ( DLCTwoSnap.fittedArm ) { total++; } var newCount = document.getElementById( "twoSnapCount" ); if (newCount) { newCount.textContent = total; } if ( total === 3 ) { status.textContent = "🎉 3 PIECES FITTED!"; area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } } /* EXTEND ORIGINAL UPDATE */ var oldUpdate = DLCTwoSnap.updateCount.bind( DLCTwoSnap ); DLCTwoSnap.updateCount = function() { oldUpdate(); updateThreeCount(); }; status.textContent = "✅ LEFT ARM added — try dragging it"; },1000);
setTimeout(function() { if ( !window.DLCTwoSnap ) { return; } var oldReset = DLCTwoSnap.reset.bind( DLCTwoSnap ); DLCTwoSnap.reset = function() { /* First run the ORIGINAL HEAD + BODY reset. */ oldReset(); /* Then reset the LEFT ARM. */ var arm = document.getElementById( "twoLeftArmPiece" ); if ( arm && this.armStart ) { this.fittedArm = false; arm.classList.remove( "twoFitted" ); arm.style.right = "auto"; arm.style.bottom = "auto"; arm.style.left = this.armStart.left + "px"; arm.style.top = this.armStart.top + "px"; arm.style.zIndex = "10"; arm.style.cursor = "grab"; } /* Make sure counter goes back to zero. */ var count = document.getElementById( "twoSnapCount" ); if (count) { count.textContent = "0"; } var status = document.getElementById( "twoSnapStatus" ); if (status) { status.textContent = "↺ Test reset"; } var area = document.getElementById( "twoSnapArea" ); if (area) { area.style.boxShadow = ""; } }; },1400);
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var countBox = document.getElementById( "twoSnapCount" ); var status = document.getElementById( "twoSnapStatus" ); if ( !area || !window.DLCTwoSnap ) { return; } /* ========================= CREATE RIGHT TARGET ========================= */ if ( !document.getElementById( "twoRightArmTarget" ) ) { var target = document.createElement( "div" ); target.id = "twoRightArmTarget"; target.textContent = "ARM"; area.appendChild( target ); } /* ========================= CREATE RIGHT ARM ========================= */ if ( !document.getElementById( "twoRightArmPiece" ) ) { var arm = document.createElement( "div" ); arm.id = "twoRightArmPiece"; arm.setAttribute( "data-piece", "RIGHT ARM" ); arm.textContent = "RIGHT"; area.appendChild( arm ); } var arm = document.getElementById( "twoRightArmPiece" ); var target = document.getElementById( "twoRightArmTarget" ); /* SAVE START POSITION */ DLCTwoSnap.rightArmStart = { left: arm.offsetLeft, top: arm.offsetTop }; DLCTwoSnap.fittedRightArm = false; /* ========================= DRAG RIGHT ARM ========================= */ arm.addEventListener( "pointerdown", DLCTwoSnap.down.bind( DLCTwoSnap ) ); /* ========================= EXTEND SNAP CHECK ========================= */ var oldCheckSnap = DLCTwoSnap.checkSnap.bind( DLCTwoSnap ); DLCTwoSnap.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); if ( name !== "RIGHT ARM" ) { oldCheckSnap( piece ); return; } var pieceRect = piece.getBoundingClientRect(); var targetRect = target.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 20 && centreX < targetRect.right + 20 && centreY > targetRect.top - 20 && centreY < targetRect.bottom + 20; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); this.fittedRightArm = true; status.textContent = "🎉 CLICK! RIGHT ARM FITTED!"; this.updateCount(); }; /* ========================= NEW COUNTER ========================= */ DLCTwoSnap.updateCount = function() { var fittedPieces = area.querySelectorAll( ".twoFitted" ); var count = fittedPieces.length; if (countBox) { countBox.textContent = count; } var progress = countBox ? countBox.parentElement : null; if (progress) { progress.innerHTML = '' + count + '/4'; countBox = document.getElementById( "twoSnapCount" ); } if ( count === 4 ) { status.textContent = "🎉 4 PIECES FITTED!"; area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } else { area.style.boxShadow = ""; } }; /* ========================= EXTEND RESET ========================= */ var oldReset = DLCTwoSnap.reset.bind( DLCTwoSnap ); DLCTwoSnap.reset = function() { oldReset(); this.fittedRightArm = false; arm.classList.remove( "twoFitted" ); arm.style.left = this.rightArmStart.left + "px"; arm.style.top = this.rightArmStart.top + "px"; arm.style.right = "auto"; arm.style.bottom = "auto"; arm.style.zIndex = "10"; this.updateCount(); status.textContent = "↺ Test reset"; }; /* CHANGE DISPLAY TO /4 */ var strong = countBox.parentElement; strong.innerHTML = '0/4'; countBox = document.getElementById( "twoSnapCount" ); status.textContent = "✅ RIGHT ARM added — 4 piece test ready"; },1500);
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var status = document.getElementById( "twoSnapStatus" ); var countBox = document.getElementById( "twoSnapCount" ); if ( !area || !window.DLCTwoSnap ) { return; } /* ========================= FIX ARM GLOW WHEN PICKED UP ========================= */ var oldDown = DLCTwoSnap.down.bind( DLCTwoSnap ); DLCTwoSnap.down = function(event) { var piece = event.currentTarget; var name = piece.getAttribute( "data-piece" ); if ( name === "LEFT ARM" || name === "RIGHT ARM" ) { piece.classList.remove( "twoFitted" ); if ( name === "LEFT ARM" ) { this.fittedLeftArm = false; } if ( name === "RIGHT ARM" ) { this.fittedRightArm = false; } if ( this.updateCount ) { this.updateCount(); } } oldDown( event ); }; /* Reconnect the existing arms to the new pickup behaviour. */ var leftArm = document.getElementById( "twoLeftArmPiece" ); var rightArm = document.getElementById( "twoRightArmPiece" ); if (leftArm) { leftArm.onpointerdown = function(event) { DLCTwoSnap.down( event ); }; } if (rightArm) { rightArm.onpointerdown = function(event) { DLCTwoSnap.down( event ); }; } /* ========================= CREATE LEFT LEG TARGET ========================= */ if ( !document.getElementById( "twoLeftLegTarget" ) ) { var target = document.createElement( "div" ); target.id = "twoLeftLegTarget"; target.textContent = "LEG"; area.appendChild( target ); } /* ========================= CREATE LEFT LEG ========================= */ if ( !document.getElementById( "twoLeftLegPiece" ) ) { var leg = document.createElement( "div" ); leg.id = "twoLeftLegPiece"; leg.setAttribute( "data-piece", "LEFT LEG" ); area.appendChild( leg ); } var leg = document.getElementById( "twoLeftLegPiece" ); var legTarget = document.getElementById( "twoLeftLegTarget" ); DLCTwoSnap.leftLegStart = { left: leg.offsetLeft, top: leg.offsetTop }; DLCTwoSnap.fittedLeftLeg = false; /* ========================= LEFT LEG PICKUP ========================= */ leg.addEventListener( "pointerdown", function(event) { if ( DLCTwoSnap.fittedLeftLeg ) { DLCTwoSnap.fittedLeftLeg = false; leg.classList.remove( "twoFitted" ); if ( DLCTwoSnap.updateCount ) { DLCTwoSnap.updateCount(); } } DLCTwoSnap.down( event ); } ); /* ========================= EXTEND SNAP ========================= */ var previousSnap = DLCTwoSnap.checkSnap.bind( DLCTwoSnap ); DLCTwoSnap.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); if ( name !== "LEFT LEG" ) { previousSnap( piece ); return; } var pieceRect = piece.getBoundingClientRect(); var targetRect = legTarget.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; var inside = centreX > targetRect.left - 22 && centreX < targetRect.right + 22 && centreY > targetRect.top - 22 && centreY < targetRect.bottom + 22; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); this.fittedLeftLeg = true; status.textContent = "🎉 CLICK! LEFT LEG FITTED!"; this.updateCount(); }; /* ========================= COUNTER = /5 ========================= */ DLCTwoSnap.updateCount = function() { var count = area.querySelectorAll( ".twoFitted" ).length; var box = document.getElementById( "twoSnapCount" ); if (box) { box.textContent = count; } var strong = box ? box.parentElement : null; if (strong) { strong.innerHTML = '' + count + '/5'; } if ( count === 5 ) { status.textContent = "🎉 5 PIECES FITTED!"; area.style.boxShadow = "inset 0 0 45px rgba(0,255,145,0.20)"; } else { area.style.boxShadow = ""; } }; /* ========================= EXTEND RESET ========================= */ var oldReset = DLCTwoSnap.reset.bind( DLCTwoSnap ); DLCTwoSnap.reset = function() { oldReset(); this.fittedLeftLeg = false; leg.classList.remove( "twoFitted" ); leg.style.left = this.leftLegStart.left + "px"; leg.style.top = this.leftLegStart.top + "px"; leg.style.right = "auto"; leg.style.bottom = "auto"; leg.style.zIndex = "10"; this.updateCount(); status.textContent = "↺ Test reset"; }; /* SET DISPLAY TO /5 */ var box = document.getElementById( "twoSnapCount" ); if (box) { box.parentElement.innerHTML = '0/5'; } status.textContent = "✅ LEFT LEG added — 5 piece test ready"; },1800);
setTimeout(function() { var game = window.DLCTwoSnap; var area = document.getElementById( "twoSnapArea" ); var status = document.getElementById( "twoSnapStatus" ); if ( !game || !area ) { return; } /* ================================= FIX LEFT ARM GREEN GLOW ================================= */ var leftArm = document.getElementById( "twoLeftArmPiece" ) || area.querySelector( '[data-piece="LEFT ARM"]' ); if ( leftArm && !leftArm.dataset.glowFixAdded ) { leftArm.dataset.glowFixAdded = "yes"; leftArm.addEventListener( "pointerdown", function() { leftArm.classList.remove( "twoFitted" ); game.fittedLeftArm = false; setTimeout( function() { leftArm.classList.remove( "twoFitted" ); if ( game.updateCount ) { game.updateCount(); } }, 10 ); }, true ); } /* ================================= CREATE RIGHT LEG TARGET ================================= */ if ( !document.getElementById( "twoRightLegTarget" ) ) { var target = document.createElement( "div" ); target.id = "twoRightLegTarget"; target.textContent = "LEG"; area.appendChild( target ); } /* ================================= CREATE RIGHT LEG PIECE ================================= */ if ( !document.getElementById( "twoRightLegPiece" ) ) { var leg = document.createElement( "div" ); leg.id = "twoRightLegPiece"; leg.setAttribute( "data-piece", "RIGHT LEG" ); area.appendChild( leg ); } var rightLeg = document.getElementById( "twoRightLegPiece" ); var rightTarget = document.getElementById( "twoRightLegTarget" ); /* ================================= SAVE START POSITION ================================= */ game.rightLegStart = { left: rightLeg.offsetLeft, top: rightLeg.offsetTop }; game.fittedRightLeg = false; /* ================================= RIGHT LEG DRAG ================================= */ rightLeg.addEventListener( "pointerdown", function(event) { /* If already fitted, picking it up removes the green glow. */ if ( game.fittedRightLeg ) { game.fittedRightLeg = false; rightLeg.classList.remove( "twoFitted" ); if ( game.updateCount ) { game.updateCount(); } } /* Use the SAME working drag system as all the other character pieces. */ game.down( event ); } ); /* ================================= EXTEND SNAP SYSTEM ================================= */ var previousCheckSnap = game.checkSnap.bind( game ); game.checkSnap = function(piece) { var name = piece.getAttribute( "data-piece" ); /* All existing pieces still use their existing code. */ if ( name !== "RIGHT LEG" ) { previousCheckSnap( piece ); return; } var pieceRect = piece.getBoundingClientRect(); var targetRect = rightTarget.getBoundingClientRect(); var centreX = pieceRect.left + pieceRect.width / 2; var centreY = pieceRect.top + pieceRect.height / 2; /* Slightly generous target area for phone dragging. */ var inside = centreX > targetRect.left - 22 && centreX < targetRect.right + 22 && centreY > targetRect.top - 22 && centreY < targetRect.bottom + 22; if (!inside) { status.textContent = "❌ Not in the slot — try again"; return; } var areaRect = area.getBoundingClientRect(); var x = targetRect.left - areaRect.left + ( targetRect.width - piece.offsetWidth ) / 2; var y = targetRect.top - areaRect.top + ( targetRect.height - piece.offsetHeight ) / 2; piece.style.left = x + "px"; piece.style.top = y + "px"; piece.style.right = "auto"; piece.style.bottom = "auto"; piece.classList.add( "twoFitted" ); this.fittedRightLeg = true; status.textContent = "🎉 CLICK! RIGHT LEG FITTED!"; this.updateCount(); }; /* ================================= UPDATE COUNTER TO 6 ================================= */ game.updateCount = function() { var fittedPieces = area.querySelectorAll( ".twoFitted" ); var count = fittedPieces.length; var countBox = document.getElementById( "twoSnapCount" ); if ( countBox ) { countBox.textContent = count; if ( countBox.parentElement ) { countBox.parentElement.innerHTML = '' + count + '/6'; } } if ( count === 6 ) { status.textContent = "🎉 DLC DIGITAL CHARACTER COMPLETE!"; area.style.boxShadow = "inset 0 0 55px rgba(0,255,145,0.25)"; var complete = document.getElementById( "twoComplete" ); if ( complete ) { complete.textContent = "🤖 DLC DIGITAL READY!"; complete.classList.add( "showTwoComplete" ); } } else { area.style.boxShadow = ""; var complete = document.getElementById( "twoComplete" ); if ( complete ) { complete.classList.remove( "showTwoComplete" ); } } }; /* ================================= EXTEND RESET ================================= */ var previousReset = game.reset.bind( game ); game.reset = function() { previousReset(); this.fittedRightLeg = false; rightLeg.classList.remove( "twoFitted" ); rightLeg.style.right = "auto"; rightLeg.style.bottom = "auto"; rightLeg.style.left = this.rightLegStart.left + "px"; rightLeg.style.top = this.rightLegStart.top + "px"; rightLeg.style.zIndex = "10"; /* Extra left-arm glow fix during reset too. */ if ( leftArm ) { leftArm.classList.remove( "twoFitted" ); } this.fittedLeftArm = false; this.updateCount(); status.textContent = "↺ Test reset"; }; /* ================================= INITIAL DISPLAY ================================= */ game.updateCount(); status.textContent = "✅ RIGHT LEG added — build all 6 pieces"; },1800);
🎨 Character Colour
Choose your DLC Digital colour
Current colour: Blue
setTimeout(function () { var buttons = document.querySelectorAll( ".dlcColourChoice" ); var status = document.getElementById( "dlcColourStatus" ); function changeCharacter(colour) { var main; var dark; if (colour === "blue") { main = "linear-gradient(145deg,#244dff,#251090)"; dark = "linear-gradient(145deg,#2631c6,#100c50)"; } if (colour === "purple") { main = "linear-gradient(145deg,#9b35ff,#3b087d)"; dark = "linear-gradient(145deg,#6720d8,#21064f)"; } if (colour === "red") { main = "linear-gradient(145deg,#ff3b4d,#8f0714)"; dark = "linear-gradient(145deg,#c52031,#52030b)"; } if (colour === "green") { main = "linear-gradient(145deg,#18c978,#075934)"; dark = "linear-gradient(145deg,#11975a,#033820)"; } if (colour === "gold") { main = "linear-gradient(145deg,#ffd84d,#9b6500)"; dark = "linear-gradient(145deg,#d9aa20,#684900)"; } /* Find ALL robot pieces, including pieces added later. */ var pieces = document.querySelectorAll( "#twoSnapArea [data-piece]" ); for ( var i = 0; i < pieces.length; i++ ) { var piece = pieces[i]; var name = ( piece.getAttribute( "data-piece" ) || "" ).toUpperCase(); /* Arms + legs use darker shade. */ if ( name.indexOf("ARM") !== -1 || name.indexOf("LEG") !== -1 ) { piece.style.background = dark; } else { piece.style.background = main; } } if (status) { var display = colour.charAt(0) .toUpperCase() + colour.slice(1); status.textContent = "🎨 Character changed to " + display; } } for ( var i = 0; i < buttons.length; i++ ) { buttons[i].addEventListener( "click", function () { /* Remove selected outline. */ for ( var x = 0; x < buttons.length; x++ ) { buttons[x] .classList .remove( "activeColour" ); } this.classList.add( "activeColour" ); var colour = this.getAttribute( "data-colour" ); changeCharacter( colour ); } ); } if (status) { status.textContent = "✅ Colour changer loaded"; } }, 900);
setTimeout( function() { function blinkDlcEyes() { /* Look for whichever eye class exists in your current robot. */ var eyes = document.querySelectorAll( ".twoEye, .dlc3Eye, .dlc4Eye, .threeEye" ); if ( !eyes.length ) { return; } for ( var i = 0; i < eyes.length; i++ ) { eyes[i] .classList .remove( "dlcEyeBlink" ); /* Forces browser to restart the animation each time. */ void eyes[i].offsetWidth; eyes[i] .classList .add( "dlcEyeBlink" ); } } /* First blink after 2 seconds */ setTimeout( blinkDlcEyes, 2000 ); /* Then blink every 4 seconds */ setInterval( blinkDlcEyes, 4000 ); }, 1200 );
var music = document.getElementById("dlcMusic"); function headphonesOn() { music.currentTime = 0; music.play(); } function headphonesOff() { music.pause(); music.currentTime = 0; }
setTimeout(function() { var area = document.getElementById( "twoSnapArea" ); var headphones = document.getElementById( "dlcHeadphones" ); var head = document.getElementById( "twoHeadPiece" ); if ( !area || !headphones || !head ) { return; } /* Move headphones into the same game area. */ area.appendChild( headphones ); headphones.style.left = "20px"; headphones.style.top = ( area.clientHeight - 100 ) + "px"; var dragging = false; var offsetX = 0; var offsetY = 0; headphones.addEventListener( "pointerdown", function(event) { event.preventDefault(); dragging = true; var rect = headphones .getBoundingClientRect(); offsetX = event.clientX - rect.left; offsetY = event.clientY - rect.top; headphones.style.cursor = "grabbing"; } ); document.addEventListener( "pointermove", function(event) { if (!dragging) { return; } event.preventDefault(); var areaRect = area.getBoundingClientRect(); var x = event.clientX - areaRect.left - offsetX; var y = event.clientY - areaRect.top - offsetY; var maxX = area.clientWidth - headphones.offsetWidth; var maxY = area.clientHeight - headphones.offsetHeight; if (x < 0) { x = 0; } if (y < 0) { y = 0; } if (x > maxX) { x = maxX; } if (y > maxY) { y = maxY; } headphones.style.left = x + "px"; headphones.style.top = y + "px"; } ); document.addEventListener( "pointerup", function() { if (!dragging) { return; } dragging = false; headphones.style.cursor = "grab"; var headphoneRect = headphones .getBoundingClientRect(); var headRect = head .getBoundingClientRect(); var headphoneX = headphoneRect.left + headphoneRect.width / 2; var headphoneY = headphoneRect.top + headphoneRect.height / 2; var headX = headRect.left + headRect.width / 2; var headY = headRect.top + headRect.height / 2; var dx = Math.abs( headphoneX - headX ); var dy = Math.abs( headphoneY - headY ); /* If headphones are close to the robot head... */ if ( dx < 90 && dy < 80 ) { var areaRect = area.getBoundingClientRect(); headphones.style.left = ( headX - areaRect.left - headphones.offsetWidth / 2 ) + "px"; headphones.style.top = ( headRect.top - areaRect.top + 20 ) - "px"; headphones.classList.add( "headphonesOn" ); } else { headphones.classList.remove( "headphonesOn" ); } } ); }, 1000);
setTimeout( function() { var headphones = document.getElementById( "dlcHeadphones" ); if (!headphones) { return; } /* Add the missing right ear cup only once. */ if ( !headphones.querySelector( ".dlcRightCupVisual" ) ) { var rightCup = document.createElement( "div" ); rightCup.className = "dlcRightCupVisual"; headphones.appendChild( rightCup ); } }, 1200 );
📁 About DLC Digital Folder Your everyday tools, organised in one place. DLC Digital Folder is designed to make everyday organisation simpler. The website brings together useful tools for managing money, bills, receipts, savings, calculations, notes and other everyday tasks — all inside one easy-to-use digital folder. We're continually developing and improving DLC Digital Folder, with new tools and features being added over time. Our aim is simple: create useful tools that are quick, straightforward and easy to access when you need them. Some features may be experimental or updated as we continue to improve the website.🔒 Privacy Your privacy is important to us. DLC Digital Folder aims to collect only the information necessary to operate and improve the website. Some tools may save information locally within your browser or device so that your information can remain available when you return. Where information is stored locally, it may be removed if you clear your browser data, use another device or browser, or reset the relevant tool. We may use website analytics to understand general information such as page visits, popular features, device/browser types and how visitors use the website. This helps us improve DLC Digital Folder. If you contact us, we may receive information that you voluntarily provide, such as your name, email address and message, so that we can respond to your enquiry. We do not intentionally sell your personal information. Third-party services used by the website may operate under their own privacy policies. Important: Please avoid entering highly sensitive information such as passwords, full payment-card details, PIN numbers or online banking login details into notes or other general-purpose fields on the website.📜 Terms of Use By using DLC Digital Folder, you agree to use the website and its tools responsibly. The tools and information provided on this website are intended for general organisational and informational purposes. Although we aim to make our calculators and tools as accurate and useful as possible, we cannot guarantee that every calculation, result or piece of information will always be complete or error-free. You should check important financial calculations and information before making decisions based upon them. Information provided by DLC Digital Folder should not be considered professional financial, tax, legal or investment advice. You remain responsible for decisions you make using information or calculations provided by the website. Features may be changed, improved, replaced or removed as DLC Digital Folder continues to develop. We may also introduce new free or paid features in the future.✉️ Contact Need help, have a question, or found something that isn't working? We'd love to hear from you. You can also contact us if you have an idea for a feature you'd like to see added to DLC Digital Folder. Email: [ADD YOUR CONTACT EMAIL HERE] You can also use the website contact form where available. When reporting a problem, it can be helpful to tell us which device and browser you were using.📢 Advertise With Us Interested in advertising your business or service on DLC Digital Folder? We may offer selected advertising and promotional spaces throughout the website. Advertising opportunities could include business listings, featured placements or promotional areas within relevant sections of DLC Digital Folder. We aim to keep advertising appropriate to the website and useful to our visitors. Interested in advertising? Contact us at: [ADD YOUR ADVERTISING EMAIL HERE] Please include your business name, website or social-media page and a short description of what you would like to advertise. Advertising availability, placement and pricing may vary.🤖 DLC Digital Folder Useful tools. One digital folder. DLC Digital Folder is continually evolving, so check back for new tools, improvements and features.
window.dlcBrainQuestions = [ { category:"LOGIC", q:"Which number comes next? 2, 4, 8, 16, ?", answers:["18","24","32","36"], correct:2 }, { category:"NUMBERS", q:"What is 15% of 200?", answers:["20","25","30","35"], correct:2 }, { category:"PATTERN", q:"What comes next? ▲ ● ▲ ● ▲ ?", answers:["▲","●","■","◆"], correct:1 }, { category:"ATTENTION", q:"How many letters are in the word CONCENTRATION?", answers:["11","12","13","14"], correct:2 }, { category:"REASONING", q:"All Bloops are Razzies. All Razzies are Lazzies. Therefore all Bloops are...", answers:[ "Lazzies", "Not Lazzies", "Both", "Impossible to know" ], correct:0 }, { category:"NUMBERS", q:"Which number is missing? 5, 10, 20, 40, ?", answers:["50","60","70","80"], correct:3 }, { category:"LOGIC", q:"If yesterday was Monday, what day is tomorrow?", answers:[ "Monday", "Tuesday", "Wednesday", "Thursday" ], correct:2 }, { category:"PATTERN", q:"Which number comes next? 1, 4, 9, 16, ?", answers:["20","24","25","32"], correct:2 }, { category:"ATTENTION", q:"Which word is different?", answers:[ "APPLE", "APPLE", "APPEL", "APPLE" ], correct:2 }, { category:"NUMBERS", q:"A £40 item is reduced by £10. What percentage discount is that?", answers:[ "10%", "20%", "25%", "30%" ], correct:2 }, { category:"LOGIC", q:"A farmer has 12 sheep. All but 5 run away. How many remain?", answers:["5","7","12","17"], correct:0 }, { category:"PATTERN", q:"What comes next? 3, 6, 12, 24, ?", answers:["30","36","42","48"], correct:3 }, { category:"REASONING", q:"Which one does not belong?", answers:[ "Car", "Bus", "Train", "Apple" ], correct:3 }, { category:"NUMBERS", q:"What is half of 86?", answers:["41","42","43","44"], correct:2 }, { category:"ATTENTION", q:"How many times does the letter E appear in 'EVERY EVENING'?", answers:["3","4","5","6"], correct:1 }, { category:"LOGIC", q:"If 3 cats catch 3 mice in 3 minutes, how many cats are needed to catch 6 mice in 3 minutes?", answers:["3","4","6","9"], correct:2 }, { category:"PATTERN", q:"Which number comes next? 10, 9, 7, 4, ?", answers:["0","1","2","3"], correct:0 }, { category:"NUMBERS", q:"What is 7 × 8?", answers:["48","54","56","64"], correct:2 }, { category:"REASONING", q:"Book is to reading as fork is to...", answers:[ "Drawing", "Eating", "Walking", "Sleeping" ], correct:1 }, { category:"ATTENTION", q:"Which number appears twice? 17, 28, 39, 46, 28, 51", answers:["17","28","39","51"], correct:1 }, { category:"PATTERN", q:"What comes next? A, C, E, G, ?", answers:["H","I","J","K"], correct:1 }, { category:"NUMBERS", q:"If you save £5 each day for 7 days, how much have you saved?", answers:[ "£25", "£30", "£35", "£40" ], correct:2 }, { category:"LOGIC", q:"Which is heavier: 1kg of steel or 1kg of feathers?", answers:[ "Steel", "Feathers", "They weigh the same", "Cannot know" ], correct:2 }, { category:"ATTENTION", q:"Which spelling is correct?", answers:[ "Definately", "Definitely", "Definatly", "Definetly" ], correct:1 }, { category:"REASONING", q:"If every Zog is blue and this object is a Zog, what colour must it be?", answers:[ "Red", "Green", "Blue", "Unknown" ], correct:2 }, { category:"NUMBERS", q:"What is 144 divided by 12?", answers:["10","11","12","14"], correct:2 }, { category:"PATTERN", q:"Which number comes next? 100, 90, 80, 70, ?", answers:["50","55","60","65"], correct:2 }, { category:"LOGIC", q:"You have three apples and take away two. How many apples do you have?", answers:["1","2","3","5"], correct:1 }, { category:"REASONING", q:"Hand is to glove as foot is to...", answers:[ "Hat", "Sock", "Scarf", "Belt" ], correct:1 }, { category:"ATTENTION", q:"Which symbol appears most? ★ ◆ ★ ● ★ ◆", answers:[ "★", "◆", "●", "All equal" ], correct:0 } ];
(function(){ var attempts = 0; function startBrainGame(){ attempts++; /* WAIT FOR QUESTION BANK */ var questions = window.dlcBrainQuestions || []; /* WAIT FOR HTML */ var startScreen = document.getElementById( "brainStart" ); var gameScreen = document.getElementById( "brainGame" ); var resultScreen = document.getElementById( "brainResults" ); var startButton = document.getElementById( "brainStartButton" ); if( !questions.length || !startScreen || !gameScreen || !resultScreen || !startButton ){ if(attempts < 50){ setTimeout( startBrainGame, 100 ); } return; } /* STOP THIS BLOCK FROM INITIALISING TWICE */ if( startButton.dataset.brainReady === "yes" ){ return; } startButton.dataset.brainReady = "yes"; var questionText = document.getElementById( "brainQuestion" ); var answerArea = document.getElementById( "brainAnswers" ); var categoryText = document.getElementById( "brainCategory" ); var feedback = document.getElementById( "brainFeedback" ); var questionCount = document.getElementById( "brainQuestionCount" ); var liveScore = document.getElementById( "brainLiveScore" ); var progressBar = document.getElementById( "brainProgressBar" ); /* ========================= DATE ========================= */ var today = new Date(); var dateKey = today.getFullYear() + "-" + String( today.getMonth()+1 ).padStart(2,"0") + "-" + String( today.getDate() ).padStart(2,"0"); var dateDisplay = document.getElementById( "brainDate" ); if(dateDisplay){ dateDisplay.textContent = today.toLocaleDateString( "en-GB", { weekday:"long", day:"numeric", month:"long" } ); } /* ========================= DAILY QUESTION SELECTION ========================= */ function dateSeed(){ return ( today.getFullYear() * 10000 + (today.getMonth()+1) * 100 + today.getDate() ); } function seededRandom(seed){ var x = Math.sin(seed) * 10000; return x - Math.floor(x); } function getDailyQuestions(){ var pool = questions.slice(); var selected = []; var seed = dateSeed(); while( selected.length < 5 && pool.length ){ var random = seededRandom( seed + selected.length * 71 ); var index = Math.floor( random * pool.length ); selected.push( pool[index] ); pool.splice( index, 1 ); } return selected; } var dailyQuestions = getDailyQuestions(); /* ========================= STORAGE ========================= */ var storageKey = "dlcBrainScores"; var scores = {}; try{ scores = JSON.parse( localStorage.getItem( storageKey ) ) || {}; } catch(e){ scores = {}; } function saveScores(){ try{ localStorage.setItem( storageKey, JSON.stringify( scores ) ); } catch(e){ } } function getBest(){ var values = Object.values( scores ); if(!values.length){ return 0; } return Math.max.apply( null, values ); } function dayKeyOffset(offset){ var d = new Date(); d.setDate( d.getDate() + offset ); return d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); } function calculateStreak(){ var streak = 0; var offset = 0; if( scores[dateKey] === undefined ){ offset = -1; } while(true){ var key = dayKeyOffset( offset ); if( scores[key] === undefined ){ break; } streak++; offset--; } return streak; } /* ========================= TOP STATS ========================= */ function updateStats(){ var todayScore = scores[dateKey]; document.getElementById( "brainToday" ).textContent = todayScore !== undefined ? todayScore + "/100" : "--"; var best = getBest(); document.getElementById( "brainBest" ).textContent = best ? best + "/100" : "--"; document.getElementById( "brainStreak" ).textContent = calculateStreak() + " 🔥"; } window.dlcBrainScores = scores; window.dlcBrainDateKey = dateKey; window.dlcBrainGetBest = getBest; window.dlcBrainGetStreak = calculateStreak; updateStats(); /* ========================= GAME STATE ========================= */ var current = 0; var correct = 0; var score = 0; var locked = false; /* ALREADY DONE TODAY */ if( scores[dateKey] !== undefined ){ document.getElementById( "brainAlreadyDone" ).textContent = "✅ Today's challenge already completed"; startButton.textContent = "📈 View Today's Result"; } /* ========================= START BUTTON ========================= */ startButton.addEventListener( "click", function(){ /* TODAY ALREADY COMPLETED */ if( scores[dateKey] !== undefined ){ showResultSafely( scores[dateKey], Math.round( scores[dateKey] / 20 ) ); return; } /* START NEW GAME */ current = 0; correct = 0; score = 0; startScreen.style.display = "none"; gameScreen.style.display = "block"; resultScreen.style.display = "none"; showQuestion(); } ); /* ========================= SHOW QUESTION ========================= */ function showQuestion(){ locked = false; var item = dailyQuestions[ current ]; questionCount.textContent = "Question " + (current + 1) + " of 5"; liveScore.textContent = score + " points"; progressBar.style.width = ( (current + 1) * 20 ) + "%"; categoryText.textContent = item.category; questionText.textContent = item.q; feedback.textContent = ""; answerArea.innerHTML = ""; for( var i = 0; i < item.answers.length; i++ ){ var button = document.createElement( "button" ); button.type = "button"; button.className = "brainAnswer"; button.textContent = item.answers[i]; button.dataset.index = i; button.addEventListener( "click", answerQuestion ); answerArea.appendChild( button ); } } /* ========================= ANSWER QUESTION ========================= */ function answerQuestion(){ if(locked){ return; } locked = true; var chosen = parseInt( this.dataset.index ); var item = dailyQuestions[ current ]; var buttons = answerArea.querySelectorAll( ".brainAnswer" ); if( chosen === item.correct ){ correct++; score += 20; this.classList.add( "correct" ); feedback.textContent = "✅ Correct! +20"; } else{ this.classList.add( "wrong" ); buttons[ item.correct ] .classList.add( "correct" ); feedback.textContent = "❌ Not quite"; } liveScore.textContent = score + " points"; setTimeout( function(){ current++; if( current >= 5 ){ scores[ dateKey ] = score; saveScores(); window.dlcBrainScores = scores; updateStats(); showResultSafely( score, correct ); } else{ showQuestion(); } }, 850 ); } /* ========================= WAIT FOR RESULTS BLOCK ========================= */ function showResultSafely( finalScore, correctAnswers ){ var start = document.getElementById( "brainStart" ); var game = document.getElementById( "brainGame" ); var results = document.getElementById( "brainResults" ); if( !start || !game || !results ){ return; } /* OPEN RESULT SCREEN DIRECTLY */ start.style.display = "none"; game.style.display = "none"; results.style.display = "block"; /* SCORE */ var scoreBox = document.getElementById( "brainFinalScore" ); if(scoreBox){ scoreBox.textContent = finalScore; } /* CORRECT ANSWERS */ var correctBox = document.getElementById( "resultCorrect" ); if(correctBox){ correctBox.textContent = correctAnswers + "/5"; } /* BEST SCORE */ var bestBox = document.getElementById( "resultBest" ); if(bestBox){ bestBox.textContent = getBest(); } /* STREAK */ var streakBox = document.getElementById( "resultStreak" ); if(streakBox){ streakBox.textContent = calculateStreak() + " 🔥"; } /* RESULT MESSAGE */ var title = document.getElementById( "brainResultTitle" ); var message = document.getElementById( "brainResultMessage" ); if(finalScore === 100){ if(title){ title.textContent = "Perfect score! 🏆"; } if(message){ message.textContent = "5 out of 5 — excellent work."; } } else if(finalScore >= 80){ if(title){ title.textContent = "Excellent work! ⚡"; } if(message){ message.textContent = "Your brain is definitely switched on."; } } else if(finalScore >= 60){ if(title){ title.textContent = "Nice work! 👏"; } if(message){ message.textContent = "A solid daily brain workout."; } } else{ if(title){ title.textContent = "Brain activated 🧠"; } if(message){ message.textContent = "Come back tomorrow and try again."; } } /* NOW ASK BLOCK 4 TO DRAW THE GRAPH, IF IT IS READY. */ setTimeout( function(){ if( typeof window .dlcBrainDrawGraph === "function" ){ window.dlcBrainDrawGraph(); } }, 150 ); } /* ========================= DONE BUTTON ========================= */ var doneButton = document.getElementById( "brainDoneButton" ); if(doneButton){ doneButton.addEventListener( "click", function(){ resultScreen.style.display = "none"; gameScreen.style.display = "none"; startScreen.style.display = "block"; document.getElementById( "brainAlreadyDone" ).textContent = "✅ Today's challenge completed — come back tomorrow"; startButton.textContent = "📈 View Today's Result"; } ); } /* SUCCESS MESSAGE FOR TESTING — SAFE TO KEEP */ console.log( "DLC Brain Training loaded ✓" ); } /* START, BUT ALLOW CARRD TIME TO LOAD BLOCKS */ setTimeout( startBrainGame, 100 ); })();
(function(){ var STORAGE = "dlcBrainScores"; /* ========================= GET SCORES ========================= */ function getScores(){ try{ return JSON.parse( localStorage.getItem( STORAGE ) ) || {}; } catch(e){ return {}; } } /* ========================= TODAY KEY ========================= */ function getTodayKey(){ var d = new Date(); return d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); } /* ========================= BEST SCORE ========================= */ function getBest(scores){ var values = Object.values( scores ); if(!values.length){ return 0; } return Math.max.apply( null, values ); } /* ========================= STREAK ========================= */ function getStreak(scores){ var streak = 0; var d = new Date(); if( scores[getTodayKey()] === undefined ){ d.setDate( d.getDate()-1 ); } while(true){ var key = d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); if( scores[key] === undefined ){ break; } streak++; d.setDate( d.getDate()-1 ); } return streak; } /* ========================= SHOW RESULT ========================= */ function showResult( score, correct ){ var start = document.getElementById( "brainStart" ); var game = document.getElementById( "brainGame" ); var results = document.getElementById( "brainResults" ); if( !start || !game || !results ){ return; } start.style.display = "none"; game.style.display = "none"; results.style.display = "block"; var finalScore = document.getElementById( "brainFinalScore" ); if(finalScore){ finalScore.textContent = score; } /* RESULT TEXT */ var title = "Brain warmed up!"; var message = "Come back tomorrow and try to beat today's score."; if(score === 100){ title = "Perfect score! 🏆"; message = "5 out of 5 — excellent work."; } else if(score >= 80){ title = "Excellent work! ⚡"; message = "Your brain is definitely switched on."; } else if(score >= 60){ title = "Nice work! 👏"; message = "A solid daily brain workout."; } else if(score >= 40){ title = "Good warm-up 👍"; message = "Tomorrow gives you another chance."; } else{ title = "Brain activated 🧠"; message = "Daily practice is what matters."; } var resultTitle = document.getElementById( "brainResultTitle" ); if(resultTitle){ resultTitle.textContent = title; } var resultMessage = document.getElementById( "brainResultMessage" ); if(resultMessage){ resultMessage.textContent = message; } /* RESULT STATS */ var scores = getScores(); var bestBox = document.getElementById( "resultBest" ); if(bestBox){ bestBox.textContent = getBest( scores ); } var streakBox = document.getElementById( "resultStreak" ); if(streakBox){ streakBox.textContent = getStreak( scores ) + " 🔥"; } var correctBox = document.getElementById( "resultCorrect" ); if(correctBox){ correctBox.textContent = correct + "/5"; } /* WAIT BRIEFLY UNTIL THE RESULT PANEL IS VISIBLE */ setTimeout( drawGraph, 100 ); } /* MAKE RESULT FUNCTION AVAILABLE TO BLOCK 3 */ window.dlcBrainShowResult = showResult; /* ========================= VIEW TODAY'S RESULT BUTTON ========================= */ function connectButton(){ var button = document.getElementById( "brainStartButton" ); if(!button){ setTimeout( connectButton, 150 ); return; } if( button.dataset.resultController === "yes" ){ return; } button.dataset.resultController = "yes"; button.addEventListener( "click", function(event){ var scores = getScores(); var key = getTodayKey(); if( scores[key] === undefined ){ return; } event.preventDefault(); event.stopImmediatePropagation(); var score = scores[key]; showResult( score, Math.round( score / 20 ) ); }, true ); } connectButton(); /* ========================= SIMPLE HTML WEEK GRAPH ========================= */ function drawGraph(){ var chart = document.getElementById( "brainWeekBars" ); if(!chart){ return; } var scores = getScores(); /* CLEAR OLD BARS */ chart.innerHTML = ""; var dayNames = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ]; var completed = []; /* ========================= LAST 7 DAYS ========================= */ for( var offset=-6; offset<=0; offset++ ){ var d = new Date(); /* NOON HELPS AVOID DATE/DST ODDITIES */ d.setHours( 12, 0, 0, 0 ); d.setDate( d.getDate() + offset ); var key = d.getFullYear() + "-" + String( d.getMonth()+1 ).padStart(2,"0") + "-" + String( d.getDate() ).padStart(2,"0"); var storedScore = scores[key]; var hasScore = storedScore !== undefined; var score = hasScore ? storedScore : 0; /* ONE DAY COLUMN */ var day = document.createElement( "div" ); day.className = "brainDayBar"; if(offset === 0){ day.classList.add( "today" ); } if(!hasScore){ day.classList.add( "empty" ); } else{ completed.push( score ); } /* SCORE NUMBER */ var scoreLabel = document.createElement( "div" ); scoreLabel.className = "brainBarScore"; scoreLabel.textContent = hasScore ? score : "--"; /* BAR */ var bar = document.createElement( "div" ); bar.className = "brainBarFill"; bar.style.setProperty( "--brain-score", score ); /* DAY NAME */ var dayLabel = document.createElement( "div" ); dayLabel.className = "brainDayName"; dayLabel.textContent = dayNames[ d.getDay() ]; /* BUILD DAY */ day.appendChild( scoreLabel ); day.appendChild( bar ); day.appendChild( dayLabel ); chart.appendChild( day ); } /* ========================= TREND ========================= */ var trend = document.getElementById( "brainTrend" ); if(!trend){ return; } if( completed.length === 0 ){ trend.textContent = ""; } else if( completed.length === 1 ){ trend.textContent = "Day 1"; } else{ var latest = completed[ completed.length - 1 ]; var previous = completed[ completed.length - 2 ]; var difference = latest - previous; if( difference > 0 ){ trend.textContent = "↑ +" + difference; } else if( difference < 0 ){ trend.textContent = "↓ " + Math.abs( difference ); } else{ trend.textContent = "→ Same"; } } } /* MAKE GRAPH AVAILABLE TO BLOCK 3 */ window.dlcBrainDrawGraph = drawGraph; /* ========================= REDRAW ON RESIZE ========================= */ window.addEventListener( "resize", function(){ var results = document.getElementById( "brainResults" ); if( results && results.style.display !== "none" ){ drawGraph(); } } ); })();