Give the ending a cause

HTML for this example

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

<!doctype html>
<html lang="en-US"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Give the ending a cause</title><style>
:root{color-scheme:light;--accent:#8a472c;--wash:#f9ede1;--ink:#202d3b;--paper:#fffdf9}*{box-sizing:border-box}body{margin:0;color:var(--ink);background:#eeeae2;font:17px/1.65 system-ui,-apple-system,"Segoe UI",sans-serif}main{max-width:980px;margin:auto;padding:28px 24px 40px}header{border-top:6px solid var(--accent);padding:20px 0 24px}.kicker{color:var(--accent);font-weight:750;letter-spacing:.06em;margin:0 0 8px}h1{font:700 clamp(30px,5vw,46px)/1.15 Georgia,serif;margin:0 0 14px;max-width:780px}h2{font-size:23px;line-height:1.3;margin:0 0 14px}h3{font-size:19px;margin:12px 0 8px}p{margin:0 0 16px}button,input,textarea,select{font:inherit}button{background:white;border:1px solid #87949b;color:var(--ink);border-radius:8px;padding:11px 16px;min-height:48px;cursor:pointer;font-weight:650}button:hover{background:var(--wash)}button[aria-pressed=true],button.primary{background:var(--accent);color:white;border-color:var(--accent)}:focus-visible{outline:3px solid #b45a1e;outline-offset:3px}label{display:block;font-weight:650;margin:14px 0 6px}input:not([type=checkbox]):not([type=radio]),textarea,select{display:block;width:100%;min-width:0;max-width:100%;border:1px solid #80909b;border-radius:7px;padding:11px;background:white;color:var(--ink)}input[type=checkbox],input[type=radio]{width:21px;height:21px;accent-color:var(--accent)}textarea{resize:vertical}.panel{background:var(--paper);border:1px solid #ccd2d1;border-radius:12px;padding:24px;margin-bottom:20px}.two{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px}.two>.panel{margin:0}.two{margin-bottom:20px}.actions{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0}.result{padding:18px;background:var(--wash);border-left:5px solid var(--accent);margin-top:18px;white-space:pre-line;overflow-wrap:anywhere}.note{color:#465565;font-size:16px}.strip{padding:18px;background:var(--wash);border-radius:8px;margin-bottom:18px}table{border-collapse:collapse;width:100%;font-size:16px;table-layout:fixed}th,td{text-align:left;padding:10px 8px;border-bottom:1px solid #cbd0d1;overflow-wrap:anywhere;vertical-align:top}th{background:var(--wash)}ol,ul{padding-left:24px}li+li{margin-top:8px}pre{font-size:16px;white-space:pre-wrap;overflow-wrap:anywhere}code{font-size:16px}.grid{display:grid;gap:5px;max-width:440px}.grid button{padding:5px;min-width:0}.grid input{padding:5px!important;text-align:center;font-weight:750}blockquote{font:500 26px/1.5 Georgia,serif;margin:16px 0}footer{font-size:16px;color:#465565;margin-top:22px}[hidden]{display:none!important}svg{display:block;max-width:100%;height:auto}mark{background:#e0efad;color:var(--ink)}@media(max-width:560px){main{padding:18px 12px 28px}.panel{padding:20px 16px}.two{grid-template-columns:minmax(0,1fr)}h1{font-size:32px}.actions button{flex:1 1 135px}th,td{padding:8px 5px}.grid button{min-height:40px}blockquote{font-size:24px}}
</style></head><body><main><header><p class="kicker">STORY WORKSHOP · EVENT CARDS</p><h1>Give the ending a cause</h1><p>Arrange the events, then ask which supplied fact makes the ending possible. All events and permissions are fictional.</p></header><div class="actions"><button type="button" id="base">Base · key supplied</button><button type="button" id="unavailable">Staff unavailable</button><button type="button" id="closed">Desk closed</button></div><section class="panel"><h2>Active event cards</h2><div id="cards" class="result" role="status" aria-live="polite"></div><label for="cardId">Card ID to move</label><input id="cardId" type="text" value="T3"><div class="actions"><button type="button" id="earlier">Move earlier</button><button type="button" id="later">Move later</button></div><div id="moveStatus" class="result" role="status" aria-live="polite">Select a card ID.</div></section><section class="panel"><h2>Test an ending</h2><label for="ending">Proposed ending (room / hallway)</label><input id="ending" type="text" value=""><label for="retelling">Your retelling and cause-and-result explanation</label><textarea id="retelling" rows="4"></textarea><div class="actions"><button type="button" id="check">Check supplied support</button><button type="button" id="reveal">Show teacher example</button><button type="button" id="reset">Reset base story</button></div><div id="feedback" class="result" role="status" aria-live="polite">Choose an ending and explain it.</div><div class="strip" id="key" hidden></div></section><footer>Original fictional example. Changes remain in this open page and are not saved.</footer><noscript>JavaScript is required for the local controls. The accompanying article contains worked examples.</noscript></main><script>
(()=>{'use strict';const $=id=>document.getElementById(id);
const base=[['T1','Lin wants to deliver the club poster before the meeting.'],['T2','The club room is locked.'],['T3','Lin reads: Staff desk holds spare key.'],['T4','Lin asks a staff member for help.'],['T5','The staff member provides the key.']];let branch='base',cards=[];function render(){$('cards').textContent=cards.map((x,i)=>(i+1)+'. '+x[0]+' · '+x[1]).join(' / ');}function set(v){branch=v;cards=base.map(x=>x.slice());if(v==='unavailable')cards=cards.slice(0,3).concat([['T4B','Lin tries to find staff.'],['T5B','Staff is unavailable.'],['T6','Lin asks the organizer about an approved hallway display.']]);if(v==='closed')cards[2]=['T3C','Staff desk closed.'];$('ending').value='';$('retelling').value='';$('key').hidden=true;$('feedback').textContent='Choose an ending and explain it.';$('moveStatus').textContent='Select a card ID.';$('cardId').value=cards[2][0];render();}['base','unavailable','closed'].forEach(id=>$(id).addEventListener('click',()=>set(id)));function move(d){const i=cards.findIndex(x=>x[0]===$('cardId').value.trim().toUpperCase());if(i<0){$('moveStatus').textContent='Enter an active card ID.';return;}if(i+d<0||i+d>=cards.length){$('moveStatus').textContent='Card is already at this edge.';return;}[cards[i],cards[i+d]]=[cards[i+d],cards[i]];render();$('moveStatus').textContent='Moved '+cards[i+d][0]+' to position '+(i+d+1)+'. Presentation order is for teacher review.';$('feedback').textContent='Order changed. Revisit your causal explanation.';} $('earlier').addEventListener('click',()=>move(-1));$('later').addEventListener('click',()=>move(1));['ending','retelling'].forEach(id=>$(id).addEventListener('input',()=>{$('feedback').textContent='Response changed. Check supplied support again.';}));$('check').addEventListener('click',()=>{const e=$('ending').value.trim().toLowerCase();if(!['room','hallway'].includes(e)||!$('retelling').value.trim()){$('feedback').textContent='Enter room or hallway and add a retelling/reason.';return;}$('feedback').textContent=e==='hallway'?'Unsupported: asking the organizer is not an approval event. Add any new fictional event explicitly for teacher review.':branch==='unavailable'?'Unsupported: this branch does not supply the key.':branch==='closed'?'Review needed: the old spare-key clue is removed. T5 still supplies a key, but the retelling must explain the revised attempt.':'Supported by supplied T5: the staff member provides the key. Teacher reviews the retelling and order.';});$('reveal').addEventListener('click',()=>{$('key').hidden=!$('key').hidden;$('key').textContent=branch==='base'?'Sample T1→T2→T3→T4→T5→room ending. T5 changes the locked-room obstacle. Other coherent presentations are possible.':branch==='unavailable'?'T5B removes the successful key result. T6 is a request only; hallway approval is absent.':'T3C replaces T3. Revisit how the revised attempt leads to the still-supplied result.';});$('reset').addEventListener('click',()=>set('base'));set('base');
})();
</script></body></html>