Mini-exhibition • project and evidence studio — Plan a multi-session learner project with distinct benchmark artifacts, individual contribution evidence and an audience rehearsal,…

HTML for this example

Select the code and use your copy shortcut. Changes in this preview are temporary.

<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Mini-exhibition • project and evidence studio</title><style>*{box-sizing:border-box}body{margin:0;background:var(--bg,#f3f7fa);color:var(--ink,#203342);font:16px/1.55 system-ui,Segoe UI,sans-serif}main{max-width:1100px;margin:auto;padding:28px 30px 50px}h1{font-size:clamp(27px,3.5vw,40px);line-height:1.18;letter-spacing:-.035em;margin:8px 0 12px}h2{font-size:21px;line-height:1.35;margin:0 0 16px}h3{font-size:18px}.eyebrow{color:var(--accent,#176783);font-size:12px;letter-spacing:.12em;font-weight:800;text-transform:uppercase}.intro,.muted,small{color:#516272}.intro{margin:0 0 24px}.panel{padding:24px;border:1px solid var(--line,#d6e0e7);border-radius:12px;background:white;margin:18px 0}.grid{display:grid;grid-template-columns:1fr 1fr;gap:22px}.grid>*{min-width:0}.controls{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin:16px 0}button,input,textarea,select{font:inherit}button{border:1px solid var(--accent,#176783);background:var(--accent,#176783);color:white;padding:10px 16px;min-height:44px;border-radius:7px;font-weight:700;cursor:pointer}button.secondary{background:white;color:var(--accent,#176783)}button[aria-pressed=true]{background:var(--tint,#e3f2f8);color:var(--ink,#203342);box-shadow:inset 0 0 0 2px var(--accent,#176783)}button:hover{filter:brightness(.96)}:focus-visible{outline:3px solid #d56b00;outline-offset:3px}label{display:block;margin:12px 0 5px;font-size:14px;font-weight:650}input:not([type=checkbox]),select,textarea{width:100%;padding:10px 12px;min-height:44px;border:1px solid #94a5b2;background:white;color:inherit;border-radius:7px}textarea{resize:vertical;min-height:120px}input[type=checkbox]{width:20px;height:20px;margin-right:9px}label.inline{display:flex;align-items:center;font-weight:500;gap:7px}.result{padding:24px;background:var(--tint,#e3f2f8);border:1px solid var(--line,#c8dce7);border-radius:12px}.big{font-size:clamp(30px,5vw,48px);font-weight:780;line-height:1.25;letter-spacing:-.035em;margin:10px 0}.trace{font:15px/1.7 ui-monospace,Consolas,monospace;white-space:pre-wrap;overflow-wrap:anywhere}.error{color:#a12820;font-weight:650;min-height:24px}.table-wrap{overflow-x:auto}table{border-collapse:collapse;width:100%;font-size:15px}th,td{text-align:left;border-bottom:1px solid var(--line,#d6e0e7);padding:12px 9px;vertical-align:top}th{font-size:12px;text-transform:uppercase;letter-spacing:.03em;color:#516272}code,pre,.code{font:14px/1.65 ui-monospace,Consolas,monospace}pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--tint,#eef3f7);padding:16px;border-radius:6px}details{border-top:1px solid var(--line,#d6e0e7);margin:24px 0;padding-top:16px}summary{cursor:pointer;font-weight:700;min-height:44px}footer{border-top:1px solid var(--line,#d6e0e7);margin-top:26px;padding-top:16px;font-size:13px;color:#516272}.bar{height:16px;background:#dce4ea;border-radius:20px;overflow:hidden;margin:12px 0}.bar span{display:block;height:100%;background:var(--accent,#176783)}[hidden]{display:none!important}@media(max-width:720px){main{padding:20px}.grid{grid-template-columns:1fr;gap:12px}.panel,.result{padding:20px}}@media(max-width:400px){main{padding:16px}.panel,.result{padding:16px}button{padding:10px 13px}} .metrics{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin:20px 0}.metric{padding:20px;background:white;border:1px solid var(--line,#d6e0e7);border-radius:9px}.metric h2{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#516272;margin:0}.metric .big{font-size:clamp(25px,4vw,39px);margin:8px 0}.metric small{font-size:12px;display:block}.badge{display:inline-block;padding:4px 10px;background:var(--tint,#e3f2f8);border-radius:20px;font-size:13px;font-weight:700}.paper{background:white;padding:26px;border:1px solid var(--line,#d6e0e7)}.feedback{padding:18px;background:var(--tint,#e3f2f8);border-left:4px solid var(--accent,#176783)}.preview{white-space:pre-wrap;overflow-wrap:anywhere}.fact-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}.fact-grid article{padding:20px;background:white;border:1px solid var(--line,#d6e0e7)}.record-row{display:grid;grid-template-columns:70px 1fr 1fr 1fr;gap:12px;align-items:start;padding:16px 0;border-bottom:1px solid var(--line,#d6e0e7)}.record-row small{display:block}.record-row b{display:block}.export textarea{min-height:170px}@media(max-width:720px){.metrics{grid-template-columns:1fr 1fr}.fact-grid{grid-template-columns:1fr}.record-row{grid-template-columns:55px 1fr 1fr}.record-row .row-extra{grid-column:2/4}}@media(max-width:400px){.metrics{gap:10px}.metric{padding:14px}.metric .big{font-size:29px}.metric h2{font-size:11px}.paper{padding:18px}.record-row{gap:9px;font-size:14px}}
body{--accent:#4b6d62;--bg:#f5f6f0;--ink:#2d4038;--tint:#e8eee4;--line:#d2ddcd}.object-records{display:grid;grid-template-columns:1fr 1fr;gap:20px}.object-records article{padding:22px;background:white;border:1px solid #d2ddcd}.object-records h2{font:25px Georgia,serif;margin:16px 0 8px}.object-sketch{height:95px;display:flex;align-items:center;justify-content:center;max-width:240px;background:#dfc995;border:2px solid #ad9665;position:relative}.object-sketch.folder:before{content:'';position:absolute;width:65px;height:12px;top:-12px;left:0;background:#dfc995;border:2px solid #ad9665;border-bottom:0}.object-sketch.card{max-width:140px;background:#f0ece2;border:1px solid #c6c0af}.object-sketch span{background:#fffdf5;padding:4px 12px;color:#675539;font:18px Georgia,serif}.record-note{font-size:13px;color:#586451}.benchmark-strip{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin:22px 0}.benchmark-strip div{padding:15px;background:#e5ece1;border-top:3px solid #4b6d62}.benchmark-strip b,.benchmark-strip span{display:block}.benchmark-strip span{font-size:13px;margin-top:8px}.project-status{display:flex;gap:12px;flex-wrap:wrap;font-size:14px;align-items:center}.session{margin:24px 0;border-top:4px solid #8d9f79;padding-top:18px}.pbl-time{display:grid;grid-template-columns:1fr 70px 90px;gap:12px;align-items:center;border-bottom:1px solid #d2ddcd;padding:12px 0}.pbl-time label{margin-top:0}.panel{border-radius:5px}.paper h2{font:26px Georgia,serif}@media(max-width:720px){.benchmark-strip{grid-template-columns:1fr}.benchmark-strip div{padding:12px}.benchmark-strip span{margin:4px 0 0}.object-records article{padding:16px}.object-records h2{font-size:21px}.object-records p{font-size:14px}}@media(max-width:400px){.object-records{gap:10px}.object-sketch{height:75px}.object-sketch span{padding:4px 8px;font-size:16px}.pbl-time{grid-template-columns:1fr 55px 65px;gap:9px;font-size:14px}}</style></head><body><main>
<header><span class="eyebrow">Classroom mini-exhibition / original three-session project</span><h1>Show what the record supports.</h1><p class="intro">Create an exhibit label that separates supplied object details from what remains to ask.</p></header>
<section class="object-records"><article><div class="object-sketch folder" aria-hidden="true"><span>Archive</span></div><h2>O1 · Paper folder</h2><p><b>20 cm wide</b> · printed label “Archive”</p><small>Maker, date, and use: not supplied.</small></article><article><div class="object-sketch card" aria-hidden="true"><span>Notes</span></div><h2>O2 · Card</h2><p><b>10 cm wide</b> · label “Notes”</p><small>Maker, date, and use: not supplied.</small></article></section>
<p class="record-note">Fictional descriptive records; schematics are not measured objects or historical provenance.</p>
<section class="benchmark-strip"><div><b>1 · Source/question log</b><span>Known detail + further question</span></div><div><b>2 · Draft and critique</b><span>Retain exact original wording</span></div><div><b>3 · Revision and rehearsal</b><span>Explain evidence and uncertainty</span></div></section>
<div class="project-status"><span class="badge" id="project-total">135 in-class minutes</span><b id="team-status">Team product: no learner draft supplied</b><span id="individual-status">Individual evidence: not supplied</span></div>
<nav class="controls" aria-label="Project surface"><button type="button" id="materials" class="secondary">Learner materials</button><button type="button" id="teacher" class="secondary">Teacher plan & illustration</button></nav>
<section id="learner-materials"><section class="panel"><h2>1. Link a detail to its record</h2><div class="controls"><button type="button" id="record-o1" class="secondary">O1</button><button type="button" id="record-o2" class="secondary">O2</button></div><p id="source-summary"></p><label for="fact">Choose the supplied detail to describe</label><select id="fact"><option value="">Choose a detail</option><option value="material">Material</option><option value="width">Width</option><option value="label">Printed label</option></select><label for="question">A question needing additional evidence</label><input id="question" type="text" value="" ><div class="controls"><button type="button" id="prepare-source">Prepare source/question log</button></div><p id="source-log" class="feedback" aria-live="polite">No source/question draft prepared.</p><p id="source-error" class="error" role="alert"></p></section>
<section class="panel"><h2>2. Retain the draft and exact peer question</h2><label for="draft">Original learner label — blank until supplied</label><textarea id="draft" rows="3"></textarea><div class="controls"><button type="button" id="keep-draft">Keep original for this review</button><button type="button" id="reset-record" class="secondary">Reset this record’s draft</button></div><label for="original">Retained original — not overwritten by revision</label><textarea id="original" rows="4" readonly></textarea><label for="peer">Exact peer question about a specific statement</label><textarea id="peer" rows="3"></textarea><p id="draft-error" class="error" role="alert"></p></section>
<section class="paper"><h2>3. Revise and explain</h2><label for="decision">Revision decision: what changed and why</label><textarea id="decision" rows="3"></textarea><label for="revised">Revised label — blank until supplied</label><textarea id="revised" rows="3"></textarea><label for="rehearsal">Audience rehearsal plan: one supported detail and one uncertainty</label><textarea id="rehearsal" rows="3"></textarea><div class="controls"><button type="button" id="build-packet">Prepare revision packet</button><button type="button" id="select-packet" class="secondary">Select packet text</button></div><p id="packet-error" class="error" role="alert"></p><label for="packet">Exact team draft packet — manual copying</label><textarea id="packet" rows="10" readonly></textarea><small>A document state is not a grade. Review source claims with the teacher; free-text labels are not machine checked.</small></section>
<section class="panel"><h2>Individual contribution evidence</h2><div class="grid"><div><label for="learner-name">Actual learner name — blank until supplied</label><input id="learner-name" type="text" value="" ><label for="contribution">Record ID and exact statement you contributed or checked</label><textarea id="contribution" rows="3"></textarea></div><div><label for="evidence">Supporting evidence or remaining unknown</label><textarea id="evidence" rows="3"></textarea><label for="feedback-reason">Which feedback affected the revision, and why?</label><textarea id="feedback-reason" rows="3"></textarea></div></div><div class="controls"><button type="button" id="prepare-individual">Prepare individual note</button><button type="button" id="select-individual" class="secondary">Select note text</button></div><p id="individual-error" class="error" role="alert"></p><label for="individual-note">Exact supplied individual note</label><textarea id="individual-note" rows="5" readonly></textarea></section></section>
<section id="teacher-plan" hidden><section class="panel"><h2>Three sessions, three concrete benchmarks</h2><p>Each original session is 45 minutes. Keep the source log, original draft, exact peer question, revision decision, revised label, and individual explanation together.</p>
<article class="session"><h3>Session 1</h3><label for="budget-1">Available minutes</label><input id="budget-1" type="number" value="45" ><p id="session-status-1" class="badge"></p><div class="pbl-time"><b>Launch</b><span id="s1-range-0"></span><div><label for="s1-p0">Minutes</label><input id="s1-p0" type="number" value="5"></div></div><div class="pbl-time"><b>Inspect records</b><span id="s1-range-1"></span><div><label for="s1-p1">Minutes</label><input id="s1-p1" type="number" value="10"></div></div><div class="pbl-time"><b>Question log</b><span id="s1-range-2"></span><div><label for="s1-p2">Minutes</label><input id="s1-p2" type="number" value="15"></div></div><div class="pbl-time"><b>Label outline</b><span id="s1-range-3"></span><div><label for="s1-p3">Minutes</label><input id="s1-p3" type="number" value="10"></div></div><div class="pbl-time"><b>Exit</b><span id="s1-range-4"></span><div><label for="s1-p4">Minutes</label><input id="s1-p4" type="number" value="5"></div></div></article><article class="session"><h3>Session 2</h3><label for="budget-2">Available minutes</label><input id="budget-2" type="number" value="45" ><p id="session-status-2" class="badge"></p><div class="pbl-time"><b>Recap</b><span id="s2-range-0"></span><div><label for="s2-p0">Minutes</label><input id="s2-p0" type="number" value="5"></div></div><div class="pbl-time"><b>Draft</b><span id="s2-range-1"></span><div><label for="s2-p1">Minutes</label><input id="s2-p1" type="number" value="15"></div></div><div class="pbl-time"><b>Peer critique</b><span id="s2-range-2"></span><div><label for="s2-p2">Minutes</label><input id="s2-p2" type="number" value="10"></div></div><div class="pbl-time"><b>Revision plan</b><span id="s2-range-3"></span><div><label for="s2-p3">Minutes</label><input id="s2-p3" type="number" value="10"></div></div><div class="pbl-time"><b>Individual note</b><span id="s2-range-4"></span><div><label for="s2-p4">Minutes</label><input id="s2-p4" type="number" value="5"></div></div></article><article class="session"><h3>Session 3</h3><label for="budget-3">Available minutes</label><input id="budget-3" type="number" value="45" ><p id="session-status-3" class="badge"></p><div class="pbl-time"><b>Setup</b><span id="s3-range-0"></span><div><label for="s3-p0">Minutes</label><input id="s3-p0" type="number" value="5"></div></div><div class="pbl-time"><b>Revise</b><span id="s3-range-1"></span><div><label for="s3-p1">Minutes</label><input id="s3-p1" type="number" value="15"></div></div><div class="pbl-time"><b>Audience rehearsal</b><span id="s3-range-2"></span><div><label for="s3-p2">Minutes</label><input id="s3-p2" type="number" value="10"></div></div><div class="pbl-time"><b>Individual explanation</b><span id="s3-range-3"></span><div><label for="s3-p3">Minutes</label><input id="s3-p3" type="number" value="10"></div></div><div class="pbl-time"><b>Reflection</b><span id="s3-range-4"></span><div><label for="s3-p4">Minutes</label><input id="s3-p4" type="number" value="5"></div></div></article><p id="schedule-error" class="error" role="alert"></p></section>
<section class="panel"><h2>Plan role rotation; record actual work separately</h2><div class="table-wrap"><table><thead><tr><th>Planned slot</th><th>Session 1</th><th>Session 2</th><th>Session 3</th></tr></thead><tbody><tr><td>A</td><td>Evidence checker</td><td>Label writer</td><td>Presenter</td></tr><tr><td>B</td><td>Label writer</td><td>Presenter</td><td>Evidence checker</td></tr><tr><td>C</td><td>Presenter</td><td>Evidence checker</td><td>Label writer</td></tr></tbody></table></div><p>Actual names, role agreements, access supports, and contributions must be supplied. Rotation does not prove equal understanding.</p><label for="arrangements">Audience location, access, invitation and presentation arrangements — to confirm</label><textarea id="arrangements" rows="3"></textarea></section>
<details><summary>Separate hypothetical O1 critique and model</summary><p><b>Hypothetical draft:</b> “An old school folder used in 1950.”</p><p><b>Peer question:</b> “Where did the year and school use come from?”</p><p><b>Revision decision:</b> Remove unsupported age, school-use, and year claims. Do not substitute another invented date.</p><p><b>Model label:</b> O1: Paper folder, 20 cm wide, with the printed label “Archive.” The supplied record does not establish its maker, date or use. What additional evidence would establish when it was made or how it was used?</p><p>This illustration is not actual learner work and is excluded from learner-generated packets.</p></details><section class="panel export"><h2>Teacher project plan</h2><div class="controls"><button type="button" id="prepare">Prepare text</button><button type="button" id="select-text" class="secondary">Select text</button></div><p id="export-error" class="error" role="alert"></p><label for="export-text">Exact generated plain text — manual copying</label><textarea id="export-text" rows="10" readonly></textarea><small>Select text, then copy it manually into your maintained document. Nothing is saved or sent.</small></section></section>
<footer>Local HTML plan-and-material companion. Team and individual fields start blank. No automatic grading, learning-gain claim, saved learner record, invitation, publication, or completed audience event. Keep actual work and official school formats in the approved workflow.</footer>
</main><script>const $=id=>document.getElementById(id);const on=(id,e,fn)=>$(id).addEventListener(e,fn);const txt=(id,v)=>$(id).textContent=v;const esc=s=>String(s).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));const positive=x=>String(x).trim()!==''&&Number.isFinite(Number(x))&&Number(x)>0;const num=x=>Number(x.toPrecision(10)).toString();function enter(id,fn){on(id,'keydown',e=>{if(e.key==='Enter'&&!e.isComposing&&e.keyCode!==229){e.preventDefault();fn()}})}function selectText(id){$(id).focus();$(id).select()}
function clockMinute(s){if(!/^(?:[01]\d|2[0-3]):[0-5]\d$/.test(s))throw Error('Use a valid 24-hour time as HH:MM.');const [h,m]=s.split(':').map(Number);return h*60+m}
function whole(s,label){if(!/^\d+$/.test(String(s))||!Number.isSafeInteger(Number(s)))throw Error(label+' must be a nonnegative whole number.');return Number(s)}
function isoDay(s){if(!/^\d{4}-\d{2}-\d{2}$/.test(s))throw Error('Use a real calendar date as YYYY-MM-DD.');const d=new Date(s+'T00:00:00Z');if(!Number.isFinite(d.getTime())||d.toISOString().slice(0,10)!==s)throw Error('Use a real calendar date as YYYY-MM-DD.');return d.getTime()/86400000}

const sessions=[[["Launch", 5], ["Inspect records", 10], ["Question log", 15], ["Label outline", 10], ["Exit", 5]], [["Recap", 5], ["Draft", 15], ["Peer critique", 10], ["Revision plan", 10], ["Individual note", 5]], [["Setup", 5], ["Revise", 15], ["Audience rehearsal", 10], ["Individual explanation", 10], ["Reflection", 5]]];

const objects={o1:{id:'O1',material:'Paper folder',width:'20 cm wide',label:'Printed label “Archive”'},o2:{id:'O2',material:'Card',width:'10 cm wide',label:'Label “Notes”'}};let object='o1',sourceLog=null,retained=null,scheduleValid=false,sessionRanges=[];
function sourceView(){const r=objects[object];txt('source-summary',r.id+' · '+r.material+' · '+r.width+' · '+r.label+'. Maker, date, and use are not supplied.');for(const key of ['o1','o2'])$('record-'+key).setAttribute('aria-pressed',String(object===key))}
function clearPacket(){ $('packet').value='';txt('team-status',retained?'Team product: original draft retained; revision pending':'Team product: no learner draft supplied');txt('packet-error','')}
function resetRecord(){sourceLog=null;retained=null;for(const n of ['question','draft','original','peer','decision','revised','rehearsal'])$(n).value='';$('fact').value='';txt('source-log','No source/question draft prepared.');txt('source-error','');txt('draft-error','');clearPacket()}
for(const key of ['o1','o2'])on('record-'+key,'click',()=>{object=key;resetRecord();sourceView()});
for(const n of ['fact','question']){on(n,'input',()=>{sourceLog=null;txt('source-log','Source inputs changed. Prepare the current log.');clearPacket()});on(n,'change',()=>{sourceLog=null;txt('source-log','Source inputs changed. Prepare the current log.');clearPacket()})}
on('prepare-source','click',()=>{const r=objects[object],f=$('fact').value,q=$('question').value.trim();if(!Object.hasOwn(r,f)||!q){sourceLog=null;txt('source-error','Choose a supplied detail and write a question needing more evidence.');txt('source-log','No current source/question draft.');return}sourceLog=r.id+' supplied detail: '+r[f]+'.\nMaker, date, use: unknown from this record.\nQuestion: '+q;txt('source-log',sourceLog);txt('source-error','')});
on('keep-draft','click',()=>{if(!sourceLog){txt('draft-error','Prepare the source/question log first.');return}if(retained){txt('draft-error','The original is retained. Use the revised-label field; reset this record only to begin a new draft.');return}if(!$('draft').value.trim()){txt('draft-error','Supply an original label before retaining it.');return}retained={object,text:$('draft').value,sourceLog};$('original').value=retained.text;txt('draft-error','Original retained locally for this review. It is not saved between visits.');clearPacket()});
on('reset-record','click',resetRecord);for(const n of ['draft','peer','decision','revised','rehearsal'])on(n,'input',clearPacket);
on('build-packet','click',()=>{try{if(!sourceLog||!retained||retained.object!==object)throw Error('Keep a matching source log and original draft first.');for(const n of ['peer','decision','revised','rehearsal'])if(!$(n).value.trim())throw Error('Supply the exact peer question, revision decision, revised label, and rehearsal explanation.');$('packet').value='TEAM REVISION DRAFT — FOR TEACHER REVIEW\n'+sourceLog+'\n\nOriginal source log (retained): '+retained.sourceLog+'\n\nOriginal draft (retained): '+retained.text+'\nExact peer question: '+$('peer').value+'\nRevision decision: '+$('decision').value+'\nRevised label: '+$('revised').value+'\nRehearsal: '+$('rehearsal').value+'\n\nFree-text source claims require teacher review. This document does not establish every member’s contribution or understanding.';txt('team-status','Team product: revision draft prepared for review');txt('packet-error','')}catch(e){$('packet').value='';txt('packet-error',e.message)}});on('select-packet','click',()=>selectText('packet'));
for(const n of ['learner-name','contribution','evidence','feedback-reason'])on(n,'input',()=>{$('individual-note').value='';txt('individual-status','Individual evidence: current note not prepared');txt('individual-error','')});
on('prepare-individual','click',()=>{const values=['learner-name','contribution','evidence','feedback-reason'].map(n=>$(n).value.trim());if(values.some(v=>!v)){$('individual-note').value='';txt('individual-error','Supply the actual name, exact contributed statement/record, evidence, and revision reason.');return}$('individual-note').value='INDIVIDUAL NOTE — SUPPLIED TEXT, NOT AUTOMATICALLY GRADED\nLearner: '+values[0]+'\nExact contribution / record: '+values[1]+'\nEvidence / unknown: '+values[2]+'\nFeedback and revision reason: '+values[3];txt('individual-status','Individual evidence: supplied note prepared for teacher review');txt('individual-error','')});on('select-individual','click',()=>selectText('individual-note'));
function projectSchedule(values,budgets){let total=0;const states=values.map((row,s)=>{if(!/^[1-9]\d*$/.test(budgets[s])||Number(budgets[s])>480)throw Error('Each session budget needs 1–480 whole minutes.');let t=0;const ranges=row.map(v=>{if(!/^[1-9]\d*$/.test(v)||Number(v)>180)throw Error('Each phase needs 1–180 whole minutes.');const start=t;t+=Number(v);return start+'–'+t});total+=t;return {total:t,ranges,valid:t===Number(budgets[s])}});return {total,states,valid:states.every(x=>x.valid)}}
function updateSchedule(){try{const state=projectSchedule(sessions.map((row,s)=>row.map((_,i)=>$('s'+(s+1)+'-p'+i).value)),sessions.map((_,s)=>$('budget-'+(s+1)).value));scheduleValid=state.valid;sessionRanges=state.states.map(s=>s.ranges);txt('project-total',state.total+' in-class minutes');state.states.forEach((r,s)=>{txt('session-status-'+(s+1),r.valid?r.total+'-minute session ready':r.total+' scheduled / '+$('budget-'+(s+1)).value+' available');r.ranges.forEach((v,i)=>txt('s'+(s+1)+'-range-'+i,v))});txt('schedule-error',state.valid?'':'Reconcile each session against its own budget.')}catch(e){scheduleValid=false;sessionRanges=[];txt('project-total','Project timing needs input');for(let s=1;s<=3;s++){txt('session-status-'+s,'Needs input');for(let i=0;i<5;i++)txt('s'+s+'-range-'+i,'—')}txt('schedule-error',e.message)}$('export-text').value=''}
sessions.forEach((row,s)=>{on('budget-'+(s+1),'input',updateSchedule);row.forEach((_,i)=>on('s'+(s+1)+'-p'+i,'input',updateSchedule))});on('arrangements','input',()=>{$('export-text').value=''});
function view(teacher){$('teacher-plan').hidden=!teacher;$('learner-materials').hidden=teacher;$('teacher').setAttribute('aria-pressed',String(teacher));$('materials').setAttribute('aria-pressed',String(!teacher))}
on('materials','click',()=>view(false));on('teacher','click',()=>view(true));on('prepare','click',()=>{if(!scheduleValid){$('export-text').value='';txt('export-error','Resolve each session timetable before preparing the plan.');return}$('export-text').value='MINI-EXHIBITION PROJECT — TEACHER PLAN\nDriving question: How can we create an exhibit label that helps visitors separate what an object record shows from what remains to ask?\nFictional records: O1 paper folder, 20 cm wide, printed Archive label; O2 card, 10 cm wide, Notes label. Maker/date/use not supplied.\nBenchmarks: source/question log; retained draft and exact peer question; revision and presentation plan.\n\n'+sessions.map((row,s)=>'SESSION '+(s+1)+'\n'+row.map((p,i)=>sessionRanges[s][i]+' min · '+p[0]).join('\n')).join('\n\n')+'\n\nRotate evidence checker / label writer / presenter. Actual assignments and contributions: NOT SUPPLIED.\nAudience arrangements: '+($('arrangements').value||'TO CONFIRM')+'\nActual audience event: NOT PERFORMED BY THIS REVIEW.\nTeam completion does not establish each learner’s understanding.';txt('export-error','')});on('select-text','click',()=>selectText('export-text'));sourceView();updateSchedule();view(false);
</script></body></html>