Mini Apps and Mini Games

Class Treasure Hunt Expense Splitter

Complete the expense splitter in the classroom treasure hunt scene: includes real content, interactive controls, clear state feedback, and responsive layouts across sizes.

Mini Apps and Mini GamesExpense SplitterHTMLCSSJavaScript
With JavaScript enabled, you can edit, run, and save this example. The fixed source is as follows:
<!doctype html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Class Treasure Hunt Expense Splitter</title>
  <style>
    :root { --ink:#252525; --paper:#f7f2e8; --accent:#247ba0; --secondary:#f4b942; --line:color-mix(in srgb, var(--ink) 18%, transparent); --shadow:0 24px 60px color-mix(in srgb, var(--ink) 16%, transparent); color-scheme:light; }
    * { box-sizing:border-box; }
    html { min-width:320px; background:var(--paper); }
    body { min-height:100vh; margin:0; overflow-x:hidden; color:var(--ink); font-family:Avenir,"PingFang SC",sans-serif; background:var(--paper); }
    button,input,select,textarea { color:inherit; font:inherit; }
    button,[role="button"],input,select,textarea { accent-color:var(--accent); }
    button { cursor:pointer; }
    button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }
    [hidden] { display:none !important; }
    @media (max-width:700px) { .mast h1 { line-height:1.08 !important; letter-spacing:-.035em !important; overflow-wrap:anywhere; } }
    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { scroll-behavior:auto !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; } }
    .page{width:min(1320px,calc(100% - 56px));margin:auto;padding:10vh 0}.mast{display:grid;grid-template-columns:minmax(0,1fr) 160px;gap:10vw;margin-block:6vh;align-items:start;margin-bottom:10vh}.mast h1{font-family:Avenir,"PingFang SC",sans-serif;font-weight:500;font-size:clamp(38px,8vw,88px);letter-spacing:-.055em;margin:0;line-height:.96}.eyebrow{display:block;margin-bottom:24px;font:600 10px/1 ui-monospace,monospace;letter-spacing:.22em}.intro{max-width:52ch;margin-top:28px;line-height:1.8}.scenario{font-size:13px;text-align:right}.demo{border-radius:1px;border-color:color-mix(in srgb,var(--ink) 35%,transparent);box-shadow:none;position:relative;min-height:420px;padding:clamp(28px,5vw,70px);background:transparent}@media(max-width:700px){.page{width:calc(100% - 24px);padding:36px 0}.mast{grid-template-columns:1fr;margin-bottom:30px}.scenario{text-align:left}.demo{padding:18px}}
    .panel{padding:16px;border:3px double var(--accent);background:var(--paper)}.stack{display:grid;gap:14px}.row{display:grid;grid-auto-flow:column;grid-auto-columns:max-content;gap:10px;overflow:auto}.action{padding:10px 15px;border:1px solid var(--accent);background:transparent;font-family:Didot,serif;letter-spacing:.06em}.action.primary,.action.is-active{color:var(--paper);background:var(--ink)}.metric{font-family:Didot,serif;font-size:clamp(36px,8vw,74px);letter-spacing:.04em}.status{min-height:24px;padding:9px;border-inline:1px solid var(--accent);text-align:center}.muted{line-height:1.8}.chip{padding:5px 14px;border-inline:1px solid var(--accent);letter-spacing:.1em}.meter{height:5px;background:var(--line)}.meter>i{display:block;height:100%;background:linear-gradient(90deg,var(--accent),var(--secondary))}
    .composition-studio{display:grid;gap:14px}.studio-ruler{display:flex;justify-content:space-between;padding:0 4px;color:color-mix(in srgb,var(--ink) 55%,transparent);font:700 11px/1 ui-monospace,monospace;letter-spacing:.14em}.studio-ruler::before{content:"01 / WORKING PROTOTYPE"}.studio-ruler::after{content:"360 · 768 · 1440"}.composition-studio .demo::after{content:"";position:absolute;right:18px;bottom:18px;width:24px;height:24px;border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);pointer-events:none}
    .split-bill-studio{display:grid;grid-template-columns:repeat(2,1fr);gap:16px;max-width:720px;margin:auto;padding:clamp(24px,5vw,48px);border:1px solid var(--line);border-radius:24px;background:var(--paper)}.split-bill-studio h2,.split-bill-studio .eyebrow,.split-bill-studio output,.split-bill-studio .row,.split-bill-studio small{grid-column:1/-1}.split-bill-studio label{display:grid;gap:8px}.split-bill-studio input{width:100%;padding:12px;border:1px solid var(--line);border-radius:9px}.split-bill-studio .row{display:flex;gap:8px;flex-wrap:wrap}.split-bill-studio .row button{padding:9px 13px;border:1px solid var(--line);border-radius:999px;background:transparent}.split-bill-studio .row button[aria-pressed="true"]{color:var(--paper);background:var(--ink)}.split-bill-studio output{padding-top:18px;border-top:1px solid var(--line)}@media(max-width:520px){.split-bill-studio{grid-template-columns:1fr}.split-bill-studio>*{grid-column:auto}.split-bill-studio .row,.split-bill-studio output,.split-bill-studio small{grid-column:auto}}.workflow-guide{display:grid;grid-template-columns:190px minmax(0,1fr);grid-template-areas:"rail core" "rail evidence";gap:14px 18px}.guide-rail{grid-area:rail;display:grid;align-content:start;gap:15px;padding:18px;border-right:1px solid var(--line)}.guide-rail ol{display:grid;gap:8px;padding:0;margin:0;list-style:none}.guide-rail li{display:grid;grid-template-columns:30px 1fr;gap:8px;align-items:center;padding:9px;opacity:.5}.guide-rail li[aria-current="step"]{opacity:1;color:var(--paper);background:var(--ink)}.guide-rail li.is-complete{opacity:1;color:var(--accent)}.guide-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px}.guide-actions .action{padding-inline:8px}#workflowGuideProgress{height:6px;background:var(--line)}#workflowGuideProgress i{display:block;width:0;height:100%;background:var(--accent)}.guide-core{grid-area:core;min-width:0;padding:16px;border:1px solid var(--line)}.guide-core>p{margin:0 0 14px;padding:10px;border-left:4px solid var(--accent);background:color-mix(in srgb,var(--secondary) 12%,transparent)}.guide-core[data-guide-step="1"]{border-radius:28px}.guide-core[data-guide-step="2"]{box-shadow:inset 0 0 0 4px color-mix(in srgb,var(--accent) 35%,transparent)}.guide-evidence{grid-area:evidence;display:grid;grid-template-columns:1fr 1fr auto;gap:12px;align-items:start}.guide-evidence details,.guide-evidence form{padding:12px;border:1px solid var(--line)}.guide-evidence label{display:grid;gap:7px}.guide-evidence textarea{width:100%;padding:9px;border:1px solid var(--line);background:var(--paper)}@media(max-width:900px){.workflow-guide{grid-template-columns:1fr;grid-template-areas:"core" "rail" "evidence"}.guide-rail{border-right:0;border-bottom:1px solid var(--line)}.guide-rail ol{grid-template-columns:repeat(3,1fr)}.guide-evidence{grid-template-columns:1fr}}
  </style>
</head>
<body data-aesthetic="minimal" data-composition="studio">
  <main class="page">
    <header class="mast"><div><span class="eyebrow">minimal / Expense Splitter / BEGINNER</span><h1>Class Treasure Hunt Expense Splitter</h1><p class="intro">Complete the expense splitter in the classroom treasure hunt scene: includes real content, interactive controls, clear state feedback, and responsive layouts across sizes.</p></div><span class="scenario">Classroom Treasure Hunt</span></header>
    <div class="composition-studio"><div class="studio-ruler" aria-hidden="true"></div><section class="demo" aria-label="Class treasure hunt expense splitter interaction area"><div class="workflow-guide"><nav class="guide-rail" aria-label="Classroom Treasure Hunt Guide"><span class="eyebrow">Class Treasure Hunt GUIDE</span><ol><li data-workflow-guide-step="0" aria-current="step"><b>1</b><span>Class treasure hunt round started</span></li><li data-workflow-guide-step="1"><b>2</b><span>Classroom treasure hunt midway adjustment</span></li><li data-workflow-guide-step="2"><b>3</b><span>Review of Class Treasure Hunt Wrap-Up</span></li></ol><div class="guide-actions"><button id="workflowGuideBack" class="action" type="button" disabled>Previous</button><button id="workflowGuideNext" class="action primary" type="button">Complete this step</button></div><div id="workflowGuideProgress" role="progressbar" aria-label="Class Quest completion progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><i></i></div></nav><section id="workflowCore" class="workflow-core guide-core" data-guide-step="0" aria-describedby="workflowGuideInstruction"><p id="workflowGuideInstruction">Please complete the actions related to “Class Treasure Hunt Round Start” in the main example.</p><!-- 11DZ_CORE_START:mini-apps-games-expense-split --><div class="mini split-bill-studio"><span class="eyebrow">EXPENSE SPLIT</span><h2>Expense Splitter</h2><label>Total amount <input id="billTotal" type="number" min="0" value="268"></label><label>Number of Participants <input id="billPeople" type="number" min="1" max="20" value="4"></label><label>Service Ratio <input id="billTip" type="range" min="0" max="20" value="5" data-core-bridge="mini-apps-games-expense-split"></label><div class="row"><button type="button" data-bill-mode="0" aria-pressed="true">Split Equally</button><button type="button" data-bill-mode="1" aria-pressed="false">AA upward</button><button type="button" data-bill-mode="2" aria-pressed="false">host subsidy</button></div><output id="billResult" class="metric">¥70.35 / person</output><small id="billNote">Currently calculated by equal split.</small></div><!-- 11DZ_CORE_END --></section><aside class="guide-evidence"><details id="workflowGuideDetails"><summary>View acceptance requirements</summary><ul><li>The classroom treasure hunt begins; the turn requires a visible state change</li><li>During a classroom treasure hunt, an in-progress adjustment needs one visible status change</li><li>A class treasure hunt review requires a visible state change.</li></ul></details><form id="workflowGuideEvidenceForm"><label>This step evidence<textarea id="workflowGuideEvidence" rows="3" placeholder="Record the observed state"></textarea></label><input class="action" type="submit" value="Save evidence"></form><output id="workflowGuideSummary">0 / 3 Steps Complete</output></aside></div><p id="status" class="status" role="status" aria-live="polite"></p></section></div>
  </main>
  <script>
    'use strict';
    const statusOutput = document.querySelector('#status');
    const announce = message => { statusOutput.textContent = message; };
    /* 11DZ_CORE_SCRIPT_START:mini-apps-games-expense-split */
const billInputs=[...document.querySelectorAll('.split-bill-studio input')];let billMode=0;function splitBill(){const total=Number(document.querySelector('#billTotal').value)||0;const people=Math.max(1,Number(document.querySelector('#billPeople').value)||1);const tip=Number(document.querySelector('#billTip').value)||0;const factor=billMode===1?1.03:billMode===2?.92:1;const result=total*(1+tip/100)*factor/people;document.querySelector('#billResult').textContent='¥'+result.toFixed(2)+' / person';document.querySelector('#billNote').textContent=billMode===1?'Currently calculated by rounding up to the nearest whole.':billMode===2?'Currently includes a sponsor subsidy.':'Currently calculated by equal split.';announce('Per person '+result.toFixed(2)+' yuan');}billInputs.forEach(input=>input.addEventListener('input',splitBill));document.querySelectorAll('[data-bill-mode]').forEach(button=>button.addEventListener('click',()=>{billMode=Number(button.dataset.billMode);document.querySelectorAll('[data-bill-mode]').forEach(item=>item.setAttribute('aria-pressed',String(item===button)));splitBill();}));splitBill();
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"mini-apps-games-expense-split","selector":"[data-core-bridge=\"mini-apps-games-expense-split\"]","mode":"range","key":"ArrowRight"};const workflowBridgeCore=document.querySelector('#workflowCore');const workflowBridgeControl=workflowBridgeCore.querySelector(workflowBridgeSpec.selector);if(!workflowBridgeControl)throw new Error('Missing core bridge: '+workflowBridgeSpec.name);const workflowBridgeControlledId=workflowBridgeControl.getAttribute('aria-controls');const workflowBridgeControlled=workflowBridgeControlledId?document.getElementById(workflowBridgeControlledId):null;workflowBridgeCore.dataset.workflowBridge=workflowBridgeSpec.name;workflowBridgeCore.dataset.workflowVersion='0';function workflowBridgeSerialize(){const visualNode=workflowBridgeCore.firstElementChild||workflowBridgeCore;const visual=getComputedStyle(visualNode);const outputs=[...workflowBridgeCore.querySelectorAll('output,[role="status"],[aria-live],meter,progress')].map(node=>node.textContent.trim()+'|'+node.getAttribute('aria-valuenow')+'|'+node.getAttribute('value'));const canvas=[...workflowBridgeCore.querySelectorAll('canvas')].map(node=>{try{return node.toDataURL().slice(-160);}catch{return 'canvas-unavailable';}});return JSON.stringify({html:workflowBridgeCore.innerHTML,status:statusOutput.textContent,outputs,canvas,visual:[visual.display,visual.visibility,visual.opacity,visual.transform,visual.filter,visual.backgroundColor,visual.width,visual.height],scroll:workflowBridgeSpec.mode==='scroll'?workflowBridgeControl.scrollTop:null});}let workflowBridgeLastEffect=workflowBridgeSerialize();function workflowBridgeSummary(){const label=(workflowBridgeControl.getAttribute('aria-label')||workflowBridgeControl.textContent||workflowBridgeControl.value||workflowBridgeSpec.name).trim().replace(/\s+/g,' ').slice(0,72);return label+' · Core Version '+workflowBridgeCore.dataset.workflowVersion;}function workflowBridgeCommit(){const effect=workflowBridgeSerialize();if(effect===workflowBridgeLastEffect)return {changed:false,summary:workflowBridgeSummary()};workflowBridgeLastEffect=effect;workflowBridgeCore.dataset.workflowVersion=String(Number(workflowBridgeCore.dataset.workflowVersion||0)+1);return {changed:true,summary:workflowBridgeSummary()};}function workflowBridgeScheduleCommit(){queueMicrotask(workflowBridgeCommit);setTimeout(workflowBridgeCommit,0);}workflowBridgeControl.addEventListener("input",workflowBridgeScheduleCommit);workflowBridgeControl.addEventListener('change',workflowBridgeScheduleCommit);const workflowBridgeStateTargets=new Set(workflowBridgeCore.querySelectorAll('dialog'));if(workflowBridgeControlled&&workflowBridgeCore.contains(workflowBridgeControlled))workflowBridgeStateTargets.add(workflowBridgeControlled);workflowBridgeStateTargets.forEach(target=>['close','cancel','toggle'].forEach(eventName=>target.addEventListener(eventName,workflowBridgeScheduleCommit)));function workflowBridgeActivate(){workflowBridgeControl.focus();const step=Number(workflowBridgeControl.step)||1;const min=workflowBridgeControl.min===''?-Infinity:Number(workflowBridgeControl.min);const max=workflowBridgeControl.max===''?Infinity:Number(workflowBridgeControl.max);let next=Math.min(max,Math.max(min,(Number(workflowBridgeControl.value)||0)+step));if(next===Number(workflowBridgeControl.value))next=Math.max(min,Number(workflowBridgeControl.value)-step);workflowBridgeControl.value=String(next);workflowBridgeControl.dispatchEvent(new Event('input',{bubbles:true}));workflowBridgeControl.dispatchEvent(new Event('change',{bubbles:true}));const result=workflowBridgeCommit();setTimeout(workflowBridgeCommit,0);return result;}function workflowBridgeReset(){workflowBridgeCore.dataset.workflowVersion='0';workflowBridgeLastEffect=workflowBridgeSerialize();}
const workflowGuideCore=document.querySelector('#workflowCore');const workflowGuideStages=["Class treasure hunt round started","Classroom treasure hunt midway adjustment","Review of Class Treasure Hunt Wrap-Up"];const workflowGuideState={step:0,completed:new Set(),evidence:new Map(),consumedVersion:0};function workflowGuideDrive(){const step=workflowGuideState.step;workflowGuideCore.dataset.guideStep=String(step);document.querySelector('#workflowGuideInstruction').textContent='Please complete the main example ‘'+workflowGuideStages[step]+'Related actions.”';document.querySelectorAll('[data-workflow-guide-step]').forEach((item,index)=>{item.classList.toggle('is-complete',workflowGuideState.completed.has(index));if(index===step)item.setAttribute('aria-current','step');else item.removeAttribute('aria-current');});document.querySelector('#workflowGuideBack').disabled=step===0;document.querySelector('#workflowGuideNext').textContent=step===workflowGuideStages.length-1?'Record Result':'Complete this step';const percent=Math.round(workflowGuideState.completed.size/workflowGuideStages.length*100);const progress=document.querySelector('#workflowGuideProgress');progress.setAttribute('aria-valuenow',String(percent));progress.querySelector('i').style.width=percent+'%';document.querySelector('#workflowGuideSummary').textContent=workflowGuideState.completed.size+' / '+workflowGuideStages.length+' Step complete · '+workflowBridgeSummary();announce('Current step in Classroom Treasure Hunt:'+workflowGuideStages[step]);}function workflowGuideAdvance(direction){if(direction>0){const bridge=workflowBridgeActivate();const version=Number(workflowGuideCore.dataset.workflowVersion||0);if(version<=workflowGuideState.consumedVersion){announce('Please complete the visible state change in the main example first');return;}workflowGuideState.consumedVersion=version;workflowGuideState.completed.add(workflowGuideState.step);announce('Main case changes recorded · '+bridge.summary);}workflowGuideState.step=Math.max(0,Math.min(workflowGuideStages.length-1,workflowGuideState.step+direction));workflowGuideDrive();}document.querySelector('#workflowGuideBack').addEventListener('click',()=>workflowGuideAdvance(-1));document.querySelector('#workflowGuideNext').addEventListener('click',()=>workflowGuideAdvance(1));document.querySelector('#workflowGuideEvidenceForm').addEventListener('submit',event=>{event.preventDefault();const version=Number(workflowGuideCore.dataset.workflowVersion||0);if(version<=workflowGuideState.consumedVersion){announce('Evidence not saved: the main example has no new changes yet');return;}const text=document.querySelector('#workflowGuideEvidence').value.trim();workflowGuideState.evidence.set(workflowGuideState.step,text||'Visible status check completed');workflowGuideState.completed.add(workflowGuideState.step);workflowGuideState.consumedVersion=version;workflowGuideDrive();announce('Evidence for this step has been saved · '+workflowBridgeSummary());});document.querySelector('#workflowGuideDetails').addEventListener('toggle',event=>announce(event.currentTarget.open?'Acceptance requirements expanded':'Acceptance requirements collapsed'));workflowGuideDrive();
workflowBridgeReset();
  </script>
</body>
</html>
Page feedbackFound an issue or have suggestions for improvement?
Feedback features need to be used in the online version

Please enable JavaScript in the online version before submitting; local features of the current tool or example are not affected.

Go to the online version for feedback