<!-- ===== SENTENCE PICTURE GAME v2 — paste this whole thing into a Squarespace Code Block ===== -->
<link href="https://fonts.googleapis.com/css2?family=Shantell+Sans:wght@500;700;800&family=Nunito:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
#spg-root{
  --table:#2F4A3E; --paper:#FDFBF2; --paper-shade:#F1ECDC;
  --ink:#26324B; --ink-soft:#5A6480;
  --marker:#6C4AB0; --marker-deep:#57399A;
  --hi:#FFD64D; --redpen:#DE5B6D; --line:#D8D2BE; --radius:14px;
}
#spg-root, #spg-root *{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
#spg-root{
  border-radius:16px;
  font-family:'Nunito',system-ui,sans-serif;color:var(--ink);
  background:radial-gradient(1200px 700px at 50% -10%, rgba(255,255,255,.07), transparent 60%),var(--table);
  min-height:100%;display:flex;flex-direction:column;align-items:center;padding:22px 14px 60px;
}
#spg-root h1,#spg-root h2,#spg-root h3{font-family:'Shantell Sans','Comic Sans MS',cursive}
#spg-root button{font-family:inherit;cursor:pointer;border:none}
#spg-root input,#spg-root textarea{font-family:inherit}
#spg-root .wrap{width:100%;max-width:560px}
#spg-root .wrap.wide{max-width:760px}
#spg-root .brand{text-align:center;color:var(--paper);margin-bottom:18px;user-select:none}
#spg-root .brand h1{font-size:clamp(26px,6vw,38px);font-weight:800;line-height:1.1}
#spg-root .brand h1 .w1{color:var(--hi)}
#spg-root .brand .sub{font-size:14px;opacity:.75;margin-top:4px;font-weight:600}
#spg-root .card{
  background:var(--paper);border-radius:var(--radius);
  box-shadow:0 14px 34px rgba(0,0,0,.34), 0 2px 0 rgba(255,255,255,.35) inset;
  padding:24px 22px 26px;position:relative;
}
#spg-root .card + .card{margin-top:16px}
#spg-root .card::before{content:"";position:absolute;left:0;top:14px;bottom:14px;width:3px;background:var(--redpen);opacity:.28;border-radius:2px}
#spg-root .card h2{font-size:22px;font-weight:800;margin-bottom:6px}
#spg-root .card .hint{color:var(--ink-soft);font-size:14px;line-height:1.5;margin-bottom:14px}
#spg-root .field{margin-bottom:14px}
#spg-root .field label{display:block;font-size:12px;font-weight:800;letter-spacing:1px;text-transform:uppercase;color:var(--ink-soft);margin-bottom:6px}
#spg-root .field input{width:100%;padding:12px 14px;font-size:17px;font-weight:700;color:var(--ink);background:#fff;border:2px solid var(--line);border-radius:10px;outline:none}
#spg-root .field input:focus{border-color:var(--marker)}
#spg-root .btn{display:block;width:100%;padding:14px;border-radius:12px;font-size:17px;font-weight:800;background:var(--marker);color:#fff;box-shadow:0 4px 0 var(--marker-deep);transition:transform .06s,box-shadow .06s}
#spg-root .btn:active{transform:translateY(3px);box-shadow:0 1px 0 var(--marker-deep)}
#spg-root .btn.alt{background:var(--paper-shade);color:var(--ink);box-shadow:0 4px 0 #d9d2ba}
#spg-root .btn.gold{background:var(--hi);color:var(--ink);box-shadow:0 4px 0 #d9b32e}
#spg-root .btn.small{width:auto;padding:9px 16px;font-size:14px;display:inline-block}
#spg-root .btn:disabled{opacity:.45;cursor:default;transform:none}
#spg-root .btn + .btn{margin-top:10px}
#spg-root .divider{display:flex;align-items:center;gap:12px;margin:18px 0;color:var(--ink-soft);font-weight:800;font-size:12px;letter-spacing:2px}
#spg-root .divider::before,#spg-root .divider::after{content:"";flex:1;height:2px;background:var(--line);border-radius:2px}
#spg-root .errmsg{color:var(--redpen);font-weight:700;font-size:14px;margin-top:10px;min-height:18px}
#spg-root .prompt-label{font-size:12px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--marker);margin-bottom:8px}
#spg-root .round-pill{float:right;background:var(--ink);color:var(--paper);border-radius:999px;padding:3px 12px;font-size:12px;font-weight:800}
#spg-root .prev-entry{background:#fff;border:2px dashed var(--line);border-radius:12px;padding:14px;margin-bottom:16px}
#spg-root .prev-entry .who{font-size:12px;font-weight:800;color:var(--ink-soft);margin-bottom:6px}
#spg-root .prev-entry .sentence{font-family:'Shantell Sans',cursive;font-size:20px;font-weight:700;line-height:1.35}
#spg-root .prev-entry canvas{width:100%;border-radius:8px;display:block;background:#fff}
#spg-root textarea.write{
  width:100%;min-height:96px;resize:vertical;
  background:repeating-linear-gradient(transparent,transparent 31px,rgba(38,50,75,.14) 31px,rgba(38,50,75,.14) 32px);
  border:2px solid var(--line);border-radius:10px;padding:8px 14px;
  font-family:'Shantell Sans',cursive;font-size:19px;font-weight:600;line-height:32px;color:var(--ink);outline:none;
}
#spg-root textarea.write:focus{border-color:var(--marker)}
#spg-root textarea.paste{
  width:100%;min-height:110px;resize:vertical;border:2px solid var(--line);border-radius:10px;
  padding:10px 12px;font-size:13px;font-weight:600;color:var(--ink);outline:none;word-break:break-all;
}
#spg-root textarea.paste:focus{border-color:var(--marker)}
#spg-root .charcount{text-align:right;font-size:12px;color:var(--ink-soft);font-weight:700;margin:4px 2px 12px}
#spg-root .toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:10px}
#spg-root .swatch{width:32px;height:32px;border-radius:50%;border:3px solid transparent;box-shadow:0 1px 3px rgba(0,0,0,.25)}
#spg-root .swatch.sel{border-color:var(--ink);transform:scale(1.12)}
#spg-root .sizebtn{width:36px;height:32px;border-radius:8px;background:#fff;border:2px solid var(--line);display:flex;align-items:center;justify-content:center}
#spg-root .sizebtn.sel{border-color:var(--marker);background:#F2ECFC}
#spg-root .sizebtn span{border-radius:50%;background:var(--ink);display:block}
#spg-root .tool{height:32px;padding:0 12px;border-radius:8px;background:#fff;border:2px solid var(--line);font-weight:800;font-size:13px;color:var(--ink)}
#spg-root .tool.sel{border-color:var(--marker);background:#F2ECFC}
#spg-root .canvas-holder{border:2px solid var(--line);border-radius:12px;overflow:hidden;background:#fff;touch-action:none}
#spg-root canvas#pad{display:block;width:100%;height:auto;touch-action:none}
#spg-root .passbox{background:#fff;border:2px solid var(--line);border-radius:12px;padding:12px;margin-bottom:14px;max-height:150px;overflow:auto;font-size:12px;font-weight:600;word-break:break-all;color:var(--ink-soft)}
#spg-root .bigcheck{text-align:center;font-size:52px;margin:4px 0 10px}
#spg-root .tabsrow{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:16px}
#spg-root .strip{perspective:1200px}
#spg-root .panel{background:var(--paper);padding:16px 18px;border-bottom:2px dashed rgba(38,50,75,.22);transform-origin:top center;animation:unfold .55s cubic-bezier(.34,1.3,.5,1) both}
#spg-root .panel:first-child{border-radius:var(--radius) var(--radius) 0 0}
#spg-root .panel .who{font-size:12px;font-weight:800;letter-spacing:1px;color:var(--marker);text-transform:uppercase;margin-bottom:6px}
#spg-root .panel .sentence{font-family:'Shantell Sans',cursive;font-size:20px;font-weight:700;line-height:1.35}
#spg-root .panel canvas{width:100%;border-radius:8px;display:block;background:#fff}
@keyframes unfold{from{transform:rotateX(-88deg);opacity:0;box-shadow:0 30px 40px rgba(0,0,0,.4)}to{transform:rotateX(0);opacity:1;box-shadow:none}}
@media (prefers-reduced-motion: reduce){.panel{animation:none}}
#spg-root .foldbtn{width:100%;padding:15px;border-radius:0 0 var(--radius) var(--radius);background:var(--hi);color:var(--ink);font-family:'Shantell Sans',cursive;font-size:17px;font-weight:800;box-shadow:0 10px 24px rgba(0,0,0,.3)}
#spg-root .strip-shadowbox{border-radius:var(--radius);box-shadow:0 14px 34px rgba(0,0,0,.34);overflow:hidden}
#spg-root .reveal-actions{margin-top:18px}
#spg-root footer{margin-top:26px;color:rgba(255,255,255,.45);font-size:12px;font-weight:700;text-align:center;max-width:560px}
#spg-root .hidden{display:none !important}
</style>
<div id="spg-root">
  <div class="brand">
    <h1><span class="w1">Sentence</span> ✦ Picture</h1>
    <div class="sub">write it · draw it · pass it · giggle</div>
  </div>
  <div class="wrap" id="app"></div>
  <footer>Pass-It-On Edition — the whole game travels inside the link you pass along, just like the folded paper.</footer>
</div>
<script>
/* =====================================================
   Sentence Picture Game — RELAY EDITION
   No storage, no server. Game state is compressed into
   a code that players pass along via text message.
===================================================== */
const $ = s => document.querySelector(s);
const app = $('#app');
const W = 1000, H = 750;              // drawing coordinate space
const COLORS = ['#26324B','#6C4AB0','#DE5B6D','#2E8B57','#E8862E','#2B7BC4','#C9A227','#8B5A3C','#EC7FB4','#2AA9A0'];
const SIZES = [2,5,10,20];

const S = { screen:'home', state:null, myName:'', err:'', revealShown:1 };

/* ---------- pack / unpack ---------- */
function b64url(bytes){
  let bin=''; for(let i=0;i<bytes.length;i++) bin += String.fromCharCode(bytes[i]);
  return btoa(bin).replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,'');
}
function unb64url(str){
  str = str.replace(/-/g,'+').replace(/_/g,'/');
  while(str.length % 4) str += '=';
  const bin = atob(str);
  const bytes = new Uint8Array(bin.length);
  for(let i=0;i<bin.length;i++) bytes[i]=bin.charCodeAt(i);
  return bytes;
}
async function packState(state){
  const bytes = new TextEncoder().encode(JSON.stringify(state));
  if(typeof CompressionStream !== 'undefined'){
    try{
      const buf = await new Response(new Blob([bytes]).stream().pipeThrough(new CompressionStream('deflate-raw'))).arrayBuffer();
      return 'SPG1.' + b64url(new Uint8Array(buf));
    }catch(e){}
  }
  return 'SPG0.' + b64url(bytes);
}
async function unpackState(text){
  text = text || '';
  const candidates = [];
  const strict = text.match(/SPG([01])\.([A-Za-z0-9_\-]+)/);
  if(strict) candidates.push([strict[1], strict[2]]);
  // fallback: some apps wrap long messages with line breaks mid-code —
  // take everything after the marker and strip whitespace
  const loose = text.match(/SPG([01])\.([\s\S]+)$/);
  if(loose) candidates.push([loose[1], loose[2].replace(/[^A-Za-z0-9_\-]/g,'')]);
  for(const [ver, body] of candidates){
    try{
      const bytes = unb64url(body);
      let json;
      if(ver==='1'){
        const buf = await new Response(new Blob([bytes]).stream().pipeThrough(new DecompressionStream('deflate-raw'))).arrayBuffer();
        json = new TextDecoder().decode(buf);
      } else {
        json = new TextDecoder().decode(bytes);
      }
      const st = JSON.parse(json);
      if(st && Array.isArray(st.entries)) return st;
    }catch(e){}
  }
  return null;
}

/* ---------- helpers ---------- */
function esc(str){ const d=document.createElement('div'); d.textContent=str; return d.innerHTML; }
function safeImg(src){ return (typeof src==='string' && src.startsWith('data:image/')) ? src : ''; }

/* ---------- cloud pass storage (JSONBlob) ----------
   Shrinks pass-along texts to one short link. Blobs are
   unlisted (random id) and auto-delete after 75 idle days. */
const BLOB_API = 'https://jsonblob.com/api/jsonBlob';
async function storeState(state){
  try{
    const resp = await fetch(BLOB_API, {
      method:'POST',
      headers:{'Content-Type':'application/json','Accept':'application/json'},
      body: JSON.stringify(state)
    });
    if(!resp.ok) return null;
    const loc = resp.headers.get('Location') || resp.headers.get('location');
    if(!loc) return null;
    const id = loc.split('/').pop();
    return id && id.length > 5 ? id : null;
  }catch(e){ return null; }
}
async function fetchState(id){
  try{
    const resp = await fetch(BLOB_API + '/' + encodeURIComponent(id), {headers:{'Accept':'application/json'}});
    if(!resp.ok) return null;
    const st = await resp.json();
    return (st && Array.isArray(st.entries)) ? st : null;
  }catch(e){ return null; }
}
/* Accepts: full pass message, SPG code, short link with #g=ID, or bare blob id */
async function resolveInput(text){
  text = (text||'').trim();
  const inline = await unpackState(text);
  if(inline) return inline;
  const g = text.match(/[#&?]g=([A-Za-z0-9\-]+)(?:&(r)=1)?/);
  if(g){
    const st = await fetchState(g[1]);
    if(st){ if(g[2]) st.done = true; return st; }
    return 'fetchfail';
  }
  return null;
}
function lastEntry(){ return S.state.entries[S.state.entries.length-1]; }
function nextIsDrawing(){ return lastEntry().t === 's'; }
function foldNum(){ return S.state.entries.length + 1; }

/* Render stored strokes onto a canvas element */
function paintStrokes(canvas, strokes){
  canvas.width = W; canvas.height = H;
  const ctx = canvas.getContext('2d');
  ctx.fillStyle='#fff'; ctx.fillRect(0,0,W,H);
  ctx.lineCap='round'; ctx.lineJoin='round';
  for(const s of strokes){
    ctx.globalAlpha = s.h ? 0.35 : 1;
    ctx.strokeStyle = s.e ? '#fff' : (COLORS[s.c]||COLORS[0]);
    const base = SIZES[s.w]||5;
    ctx.lineWidth = s.e ? base*3 : (s.h ? base*2.5 : base);
    ctx.beginPath();
    const p = s.p;
    for(let i=0;i<p.length;i+=2){
      if(i===0) ctx.moveTo(p[0],p[1]); else ctx.lineTo(p[i],p[i+1]);
    }
    if(p.length===2) ctx.lineTo(p[0]+.1,p[1]+.1);
    ctx.stroke();
  }
  ctx.globalAlpha = 1;
}
function drawingHtml(entry){
  if(entry.c && entry.c.img) return `<img src="${safeImg(entry.c.img)}" alt="drawing" style="width:100%;border-radius:8px;display:block;background:#fff">`;
  return `<canvas></canvas>`;
}
function hydrateDrawing(container, entry){
  const cv = container.querySelector('canvas');
  if(cv) paintStrokes(cv, (entry.c && entry.c.s) || []);
}
function renderPrevEntry(container){
  const prev = lastEntry();
  if(prev.t==='s'){
    container.innerHTML = `<div class="who">${esc(prev.a)} wrote:</div><div class="sentence">“${esc(prev.c)}”</div>`;
  } else {
    container.innerHTML = `<div class="who">${esc(prev.a)} drew:</div>` + drawingHtml(prev);
    hydrateDrawing(container, prev);
  }
}

/* =====================================================
   SCREENS
===================================================== */
function render(){
  app.classList.toggle('wide', S.screen==='draw' || S.screen==='reveal');
  ({home:renderHome, write:renderWrite, draw:renderDraw, pass:renderPass, reveal:renderReveal})[S.screen]();
  window.scrollTo({top:0});
}

/* ---------- HOME ---------- */
function renderHome(){
  app.innerHTML = `
  <div class="card">
    <h2>Got a pass-along message?</h2>
    <p class="hint">Paste the whole text (or just the game code) below to take your turn or unfold a finished game.</p>
    <div class="field">
      <textarea class="paste" id="codeIn" placeholder="Paste it all right here…"></textarea>
    </div>
    <button class="btn" id="continueBtn">Take my turn ➜</button>
    <div class="divider">OR</div>
    <h2>Start a new game</h2>
    <p class="hint">You write the first sentence, then pass the paper on. It becomes a drawing, then a sentence, then a drawing…</p>
    <div class="field">
      <label for="nameNew">Your name</label>
      <input id="nameNew" maxlength="16" placeholder="e.g. Robert" autocomplete="off">
    </div>
    <button class="btn alt" id="startBtn">Write the first sentence ➜</button>
    <div class="errmsg">${esc(S.err)}</div>
  </div>`;
  $('#continueBtn').onclick = ()=> loadFromInput($('#codeIn').value);
  $('#startBtn').onclick = ()=>{
    const name = $('#nameNew').value.trim();
    if(!name){ S.err='Give us a name first!'; render(); return; }
    S.err=''; S.myName=name; S.state={v:1, entries:[]};
    if(/^https?:$/.test(location.protocol)) S.state.u = location.href.split('#')[0];
    S.screen='write'; render();
  };
  // auto-load if a game rode along in the link (short g= link or full SPG code)
  let hash = location.hash || '';
  try{ if(!/SPG|g=/.test(hash) && window.top !== window) hash = window.top.location.hash || hash; }catch(e){}
  if(/SPG|g=/.test(hash)){
    resolveInput(decodeURIComponent(hash)).then(st=>{
      if(st && st!=='fetchfail'){
        S.state=st; S.screen = st.done ? 'reveal' : (nextIsDrawing()?'draw':'write'); S.revealShown=1; render();
      } else if(st==='fetchfail'){
        S.err='This link\u2019s fold couldn\u2019t be loaded \u2014 check your connection and refresh, or ask the sender for the backup full-text code.';
        render();
      }
    });
  }
}

/* ---------- name field (shared by write & draw) ---------- */
function nameFieldHtml(){
  return `<div class="field">
    <label for="myName">Your name</label>
    <input id="myName" maxlength="16" placeholder="Who's holding the paper?" autocomplete="off" value="${esc(S.myName)}">
  </div>`;
}
function grabName(){
  const el = $('#myName');
  if(el) S.myName = el.value.trim();
  return S.myName;
}

/* ---------- WRITE ---------- */
function renderWrite(){
  const first = S.state.entries.length===0;
  app.innerHTML = `
  <div class="card">
    <span class="round-pill">fold ${foldNum()}</span>
    <div class="prompt-label">${first ? 'Start the strip' : 'What is going on in this picture?'}</div>
    ${first
      ? `<p class="hint">Write any sentence — the weirder, the better. The next person has to draw it.</p>`
      : `<div class="prev-entry" id="prev"></div>
         <p class="hint">Describe it in one sentence. Only the last fold is shown — no peeking further back!</p>`}
    <textarea class="write" id="sentence" maxlength="140" placeholder="${first?'Once upon a Tuesday, a llama learned to parallel park…':'I see…'}"></textarea>
    <div class="charcount"><span id="cc">0</span>/140</div>
    ${first ? '' : nameFieldHtml()}
    <button class="btn" id="passBtn">Fold it ➜</button>
    <div class="errmsg">${esc(S.err)}</div>
  </div>`;
  if(!first) renderPrevEntry($('#prev'));
  const ta = $('#sentence');
  ta.addEventListener('input', ()=> $('#cc').textContent = ta.value.length);
  $('#passBtn').onclick = async ()=>{
    const text = ta.value.trim();
    const name = S.state.entries.length===0 ? S.myName : grabName();
    if(!name){ S.err='Add your name so the family knows who to blame.'; render(); return; }
    if(!text){ S.err='Write something first — anything!'; render(); return; }
    S.err='';
    S.state.entries.push({t:'s', a:name, c:text});
    await gotoPass();
  };
}

/* ---------- DRAW ---------- */
function renderDraw(){
  app.innerHTML = `
  <div class="card">
    <span class="round-pill">fold ${foldNum()}</span>
    <div class="prompt-label">Draw this sentence</div>
    <div class="prev-entry" id="prev"></div>
    <div class="toolbar" id="tools"></div>
    <div class="canvas-holder"><canvas id="pad" width="${W}" height="${H}"></canvas></div>
    <div style="height:12px"></div>
    ${nameFieldHtml()}
    <button class="btn" id="passBtn">Fold it ➜</button>
    <div class="errmsg">${esc(S.err)}</div>
  </div>`;
  renderPrevEntry($('#prev'));
  const pad = makePad($('#pad'), $('#tools'));
  $('#passBtn').onclick = async ()=>{
    const name = grabName();
    if(!name){ S.err='Add your name so the family knows who to blame.'; render(); return; }
    if(pad.isBlank()){ S.err='A blank page? Give us at least a squiggle!'; render(); return; }
    S.err='';
    S.state.entries.push({t:'d', a:name, c: pad.exportContent()});
    await gotoPass();
  };
}

function makePad(canvas, toolsEl){
  const ctx = canvas.getContext('2d');
  ctx.fillStyle='#fff'; ctx.fillRect(0,0,W,H);
  ctx.lineCap='round'; ctx.lineJoin='round';
  let colorIdx=0, sizeIdx=1, erasing=false, hiliting=false;
  let strokes=[], current=null, bgImg=null;

  const fileInput = document.createElement('input');
  fileInput.type='file'; fileInput.accept='image/*'; fileInput.style.display='none';
  canvas.parentNode.appendChild(fileInput);
  fileInput.addEventListener('change', ()=>{
    const f = fileInput.files && fileInput.files[0];
    if(!f) return;
    const img = new Image();
    img.onload = ()=>{ bgImg = img; redraw(); buildTools(); };
    img.src = URL.createObjectURL(f);
    fileInput.value='';
  });

  function buildTools(){
    toolsEl.innerHTML = COLORS.map((c,i)=>
      `<button class="swatch ${i===colorIdx&&!erasing&&!hiliting?'sel':''}" data-i="${i}" style="background:${c}" aria-label="color"></button>`).join('')
      + SIZES.map((s,i)=>
      `<button class="sizebtn ${i===sizeIdx?'sel':''}" data-i="${i}" aria-label="brush size"><span style="width:${Math.min(s+3,20)}px;height:${Math.min(s+3,20)}px"></span></button>`).join('')
      + `<button class="tool ${hiliting?'sel':''}" id="hilite">Hi-liter</button>
         <button class="tool ${erasing?'sel':''}" id="eraser">Eraser</button>
         <button class="tool" id="undo">Undo</button>
         <button class="tool" id="clear">Clear</button>
         <button class="tool" id="addphoto">${bgImg?'📷 Swap photo':'📷 Add photo'}</button>`;
    toolsEl.querySelectorAll('.swatch').forEach(b=>b.onclick=()=>{colorIdx=+b.dataset.i;erasing=false;buildTools();});
    toolsEl.querySelectorAll('.sizebtn').forEach(b=>b.onclick=()=>{sizeIdx=+b.dataset.i;buildTools();});
    $('#hilite').onclick=()=>{hiliting=!hiliting;erasing=false;buildTools();};
    $('#eraser').onclick=()=>{erasing=!erasing;hiliting=false;buildTools();};
    $('#undo').onclick=()=>{strokes.pop();redraw();};
    $('#clear').onclick=()=>{strokes=[];bgImg=null;redraw();buildTools();};
    $('#addphoto').onclick=()=>fileInput.click();
  }
  buildTools();

  function pos(ev){
    const r = canvas.getBoundingClientRect();
    return { x:(ev.clientX-r.left)*W/r.width, y:(ev.clientY-r.top)*H/r.height };
  }
  function drawBg(){
    ctx.fillStyle='#fff'; ctx.fillRect(0,0,W,H);
    if(bgImg){
      const sc = Math.min(W/bgImg.width, H/bgImg.height);
      const dw = bgImg.width*sc, dh = bgImg.height*sc;
      ctx.drawImage(bgImg, (W-dw)/2, (H-dh)/2, dw, dh);
    }
  }
  function redraw(){
    drawBg();
    for(const s of strokes) paintLive(s);
  }
  function paintLive(s){
    ctx.globalAlpha = s.h ? 0.35 : 1;
    ctx.strokeStyle = s.e ? '#fff' : COLORS[s.c];
    const base = SIZES[s.w];
    ctx.lineWidth = s.e ? base*3 : (s.h ? base*2.5 : base);
    ctx.beginPath();
    s.pts.forEach((p,i)=> i?ctx.lineTo(p.x,p.y):ctx.moveTo(p.x,p.y));
    if(s.pts.length===1) ctx.lineTo(s.pts[0].x+.1,s.pts[0].y+.1);
    ctx.stroke();
    ctx.globalAlpha = 1;
  }
  canvas.addEventListener('pointerdown', ev=>{
    canvas.setPointerCapture(ev.pointerId);
    current={c:colorIdx,w:sizeIdx,e:erasing?1:0,h:hiliting?1:0,pts:[pos(ev)]};
    strokes.push(current); paintLive(current);
  });
  canvas.addEventListener('pointermove', ev=>{
    if(!current) return;
    const p = pos(ev);
    const lp = current.pts[current.pts.length-1];
    if(Math.hypot(p.x-lp.x, p.y-lp.y) >= 2) { current.pts.push(p); redraw(); }
  });
  const up=()=>{ current=null; };
  canvas.addEventListener('pointerup',up);
  canvas.addEventListener('pointercancel',up);

  return {
    isBlank: ()=> strokes.length===0 && !bgImg,
    exportContent: ()=>{
      if(bgImg){
        redraw(); // ensure photo + ink are painted
        return { img: canvas.toDataURL('image/jpeg', 0.55) };
      }
      return { s: strokes.map(s=>({
        c:s.c, w:s.w, e:s.e, h:s.h,
        p: thin(s.pts).flatMap(p=>[Math.round(p.x), Math.round(p.y)])
      })) };
    },
  };
  /* drop points closer than 2.5px to keep codes small */
  function thin(pts){
    if(pts.length<3) return pts;
    const out=[pts[0]];
    for(let i=1;i<pts.length-1;i++){
      const l=out[out.length-1];
      if(Math.hypot(pts[i].x-l.x, pts[i].y-l.y) >= 2.5) out.push(pts[i]);
    }
    out.push(pts[pts.length-1]);
    return out;
  }
}

/* ---------- PASS ---------- */
let passCode='', revealCode='', blobId=null;
async function gotoPass(){
  S.screen='pass'; S.passReady=false; render();
  blobId = await storeState(S.state);           // short-link storage
  passCode = await packState(S.state);          // inline fallback
  revealCode = await packState({...S.state, done:true});
  S.passReady=true; render();
}
function gameLink(tail){
  if(!S.state.u) return '';
  return S.state.u.split('#')[0] + '#' + tail;
}
function passMessage(forceLong){
  const n = S.state.entries.length;
  if(blobId && S.state.u && !forceLong){
    return `\u{1F3A8} Sentence Picture Game \u2014 fold ${n} is done and it\u2019s YOUR turn! Tap here:\n${gameLink('g='+blobId)}`;
  }
  const link = gameLink(passCode);
  if(link && !forceLong){
    return `\u{1F3A8} Sentence Picture Game \u2014 fold ${n} is done and it\u2019s YOUR turn! Tap here:\n${link}\n\n(If your turn doesn\u2019t load automatically, copy this whole message, open the game, and paste it in the box.)`;
  }
  return `\u{1F3A8} Sentence Picture Game \u2014 fold ${n} is done and it\u2019s YOUR turn!\n`
    + `1. Open the game (same link we\u2019ve been using)\n`
    + `2. Copy this WHOLE message\n`
    + `3. Paste it in the box and tap \u201CTake my turn\u201D\n\n`
    + passCode;
}
function revealMessage(forceLong){
  if(blobId && S.state.u && !forceLong){
    return `\u{1F4DC} Sentence Picture Game \u2014 the paper is FULL! Tap to unfold everything:\n${gameLink('g='+blobId+'&r=1')}`;
  }
  const link = gameLink(revealCode);
  if(link && !forceLong){
    return `\u{1F4DC} Sentence Picture Game \u2014 the paper is FULL! Tap to unfold everything:\n${link}\n\n(If it doesn\u2019t unfold automatically, copy this whole message, open the game, and paste it in the box.)`;
  }
  return `\u{1F4DC} Sentence Picture Game \u2014 the paper is FULL! Open the game, paste this whole message, and unfold everything:\n\n`
    + revealCode;
}
async function shareText(text, btn, doneLabel){
  if(navigator.share){
    try{ await navigator.share({text}); return; }
    catch(e){ if(e && e.name==='AbortError') return; }
  }
  try{
    await navigator.clipboard.writeText(text);
    const old = btn.textContent;
    btn.textContent = doneLabel;
    setTimeout(()=>{ btn.textContent = old; }, 2500);
  }catch(e){
    S.err='Couldn\u2019t open the share sheet — long-press the code box to copy it manually.';
    render();
  }
}
function renderPass(){
  const n = S.state.entries.length;
  const nextTask = nextIsDrawing() ? 'draw your sentence' : 'caption your drawing';
  if(!S.passReady){
    app.innerHTML = `<div class="card"><div class="bigcheck">📬</div>
      <h2 style="text-align:center">Folding it up…</h2>
      <p class="hint" style="text-align:center;margin:0">Packing fold ${n} into a nice short link.</p></div>`;
    return;
  }
  app.innerHTML = `
  <div class="card">
    <div class="bigcheck">📬</div>
    <h2 style="text-align:center">Fold ${n} is in!</h2>
    <p class="hint" style="text-align:center">Now pass the paper: send this to the next player, and they'll ${nextTask}. ${n>=2?'Or if the paper feels full, reveal it instead.':''}</p>
    <button class="btn" id="shareTurn">📨 Send to the next player</button>
    ${n>=2 ? `<button class="btn gold" id="shareReveal">📜 We're done — send the big reveal to everyone</button>
    <button class="btn alt" id="revealNow">👀 Unfold it right here</button>`:''}
    ${blobId ? '' : `<p class="hint" style="margin-top:10px">⚠️ Couldn't reach the short-link service, so the message contains the full game code — longer, but it works the same.</p>`}
    <div class="divider">THE MESSAGE</div>
    <p class="hint">If sharing misbehaves, long-press below, Select All, copy, and text it yourself:</p>
    <div class="passbox" id="rawmsg"></div>
    ${blobId ? `<button class="btn small alt" id="longCode">Send as full-text code instead (backup)</button>`:''}
    <div class="divider">GOT THE NEXT FOLD ALREADY?</div>
    <p class="hint">If someone passed the paper back to you, paste their message or link here:</p>
    <div class="field"><textarea class="paste" id="nextIn" placeholder="Paste the pass-along message…"></textarea></div>
    <button class="btn alt" id="takeNext">Take my turn ➜</button>
    <div class="errmsg">${esc(S.err)}</div>
  </div>`;
  $('#rawmsg').textContent = passMessage();
  $('#shareTurn').onclick = e => shareText(passMessage(), e.target, '✅ Copied — paste it in a text');
  if($('#shareReveal')) $('#shareReveal').onclick = e => shareText(revealMessage(), e.target, '✅ Copied — paste it in the group text');
  if($('#revealNow')) $('#revealNow').onclick = ()=>{ S.state.done=true; S.screen='reveal'; S.revealShown=1; render(); };
  if($('#longCode')) $('#longCode').onclick = e => shareText(passMessage(true), e.target, '✅ Copied full code');
  $('#takeNext').onclick = ()=> loadFromInput($('#nextIn').value);
}
async function loadFromInput(text){
  const st = await resolveInput(text);
  if(st==='fetchfail'){ S.err='Found the link but couldn\u2019t load the fold — check your connection, or ask the sender to use the backup full-text code.'; render(); return; }
  if(!st){ S.err='Hmm, that doesn\u2019t look like a game message. Paste the whole thing.'; render(); return; }
  S.err=''; S.state = st;
  S.screen = st.done ? 'reveal' : (nextIsDrawing() ? 'draw' : 'write');
  S.revealShown = 1;
  render();
}

/* ---------- REVEAL ---------- */
function renderReveal(){
  const entries = S.state.entries;
  const n = entries.length;
  let panels='';
  for(let i=0;i<Math.min(S.revealShown,n);i++){
    const e = entries[i];
    panels += `<div class="panel" data-p="${i}">
      <div class="who">${esc(e.a)} ${e.t==='s'?'wrote':'drew'}</div>
      ${e.t==='s' ? `<div class="sentence">“${esc(e.c)}”</div>` : drawingHtml(e)}
    </div>`;
  }
  const done = S.revealShown >= n;
  app.innerHTML = `
  <div class="strip-shadowbox"><div class="strip">${panels}
    ${done?'':`<button class="foldbtn" id="unfoldBtn">Unfold the next one 👇</button>`}
  </div></div>
  <div class="reveal-actions">
    ${done ? `<button class="btn gold" id="shareReveal2">📜 Send this reveal to the family</button>
    <button class="btn alt" id="againBtn">Start a new game</button>`:''}
  </div>`;
  app.querySelectorAll('.panel[data-p]').forEach(pn=>{
    const e = entries[+pn.dataset.p];
    if(e.t==='d') hydrateDrawing(pn, e);
  });
  if($('#unfoldBtn')) $('#unfoldBtn').onclick = ()=>{ S.revealShown++; render(); };
  if($('#shareReveal2')) $('#shareReveal2').onclick = async e=>{
    if(!blobId) blobId = await storeState({...S.state, done:true});
    if(blobId && S.state.u){
      shareText(`\u{1F4DC} Sentence Picture Game \u2014 the paper is FULL! Tap to unfold everything:\n${gameLink('g='+blobId+'&r=1')}`, e.target, '✅ Copied — paste it in the group text');
    } else {
      revealCode = revealCode || await packState({...S.state, done:true});
      shareText(revealMessage(), e.target, '✅ Copied — paste it in the group text');
    }
  };
  if($('#againBtn')) $('#againBtn').onclick = ()=>{ S.state=null; S.screen='home'; S.err=''; blobId=null; render(); };
}

/* ---------- boot ---------- */
render();
</script>