{"ok": true, "next": null, "rows": [{"app_id": "01kwjk7289pmy4h2xrkpct13y5", "version": 1, "actor_id": "root", "name": "A Candid World", "description": "", "html": "<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n<meta charset=\"utf-8\">\r\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n<title>A Candid World: The Declaration at 250</title>\r\n<style>\r\n  :root{\r\n    --bg:#FBF7EF; --card:#FFFDF7; --ink:#26251F; --muted:#6E6A5E;\r\n    --navy:#3C3B6E; --red:#B22234; --tabbar:#F1EADB;\r\n    --line:rgba(60,59,110,0.16); --line-strong:rgba(60,59,110,0.25);\r\n    --chip-bg:rgba(60,59,110,0.09); --chip-line:rgba(60,59,110,0.18);\r\n    --serif:Georgia,'Times New Roman',serif;\r\n    --sans:system-ui,'Segoe UI',Helvetica,Arial,sans-serif;\r\n  }\r\n  html,body{margin:0;padding:0;background:var(--bg);}\r\n  *{box-sizing:border-box;}\r\n  body{color:var(--ink);font-family:var(--sans);}\r\n  input,select,button{font:inherit;}\r\n  .paper{position:fixed;inset:0;pointer-events:none;z-index:0;\r\n    background-image:repeating-linear-gradient(0deg, rgba(60,59,110,0.022) 0px, rgba(60,59,110,0.022) 1px, transparent 1px, transparent 4px),\r\n                     repeating-linear-gradient(90deg, rgba(178,34,52,0.012) 0px, rgba(178,34,52,0.012) 1px, transparent 1px, transparent 7px);}\r\n  .shell{position:relative;z-index:1;max-width:820px;margin:0 auto;padding:40px 20px 72px;}\r\n\r\n  header.hd{text-align:center;display:flex;flex-direction:column;align-items:center;gap:14px;margin-bottom:28px;}\r\n  .badge{display:inline-flex;align-items:center;gap:8px;background:var(--navy);color:var(--bg);\r\n    border-radius:999px;padding:6px 16px;font-size:11px;font-weight:600;letter-spacing:.14em;}\r\n  .badge span.st{color:#fff;font-size:10px;}\r\n  h1{margin:0;font-family:var(--serif);font-weight:400;font-size:clamp(36px,7vw,52px);line-height:1.05;color:var(--ink);letter-spacing:-.01em;}\r\n  .gloss{margin:0;max-width:560px;font-family:var(--serif);font-style:italic;font-size:15px;line-height:1.55;color:var(--muted);}\r\n  .gloss b{font-style:normal;font-weight:700;color:var(--navy);}\r\n  .subtitle{margin:0;font-size:14px;color:var(--muted);}\r\n  .rule{display:flex;align-items:center;gap:10px;color:var(--red);font-size:11px;letter-spacing:.4em;margin-top:2px;}\r\n  .tabbar{display:inline-flex;background:var(--tabbar);border:1px solid var(--chip-line);border-radius:999px;padding:4px;gap:4px;margin-top:6px;}\r\n  .tab{border:none;background:transparent;color:var(--navy);border-radius:999px;padding:9px 20px;font-size:14px;font-weight:600;cursor:pointer;}\r\n  .tab:hover{background:rgba(60,59,110,0.08);}\r\n  .tab.active{background:var(--navy);color:var(--bg);}\r\n  .tab.active:hover{background:var(--navy);}\r\n\r\n  .panel{display:none;} .panel.active{display:flex;flex-direction:column;gap:12px;}\r\n  .ctl{display:flex;flex-wrap:wrap;align-items:center;gap:10px;}\r\n  .ctl input[type=search],.ctl select{padding:10px 14px;border:1px solid var(--line-strong);border-radius:8px;background:var(--card);color:var(--ink);font-size:14px;}\r\n  .ctl input[type=search]{flex:1 1 200px;min-width:160px;outline-color:var(--navy);}\r\n  .ctl select{color:var(--navy);font-weight:500;cursor:pointer;padding:10px 12px;}\r\n  .count{font-size:13px;color:var(--muted);margin-left:auto;white-space:nowrap;}\r\n  .plainbtn{display:inline-flex;align-items:center;gap:8px;border:1px solid var(--line-strong);background:var(--card);color:var(--navy);\r\n    border-radius:999px;padding:9px 14px;font-size:13px;font-weight:600;cursor:pointer;}\r\n  .plainbtn:hover{background:rgba(60,59,110,0.06);}\r\n  .plainbtn .dot{width:14px;height:14px;border-radius:50%;border:2px solid rgba(60,59,110,0.4);display:inline-block;}\r\n  .plainbtn.on{border-color:var(--navy);background:var(--navy);color:var(--bg);}\r\n  .plainbtn.on .dot{background:var(--bg);border-color:var(--bg);}\r\n\r\n  .decl{border:1px solid var(--chip-line);border-radius:10px;background:rgba(60,59,110,0.045);overflow:hidden;}\r\n  .decl>button{width:100%;display:flex;align-items:center;justify-content:space-between;gap:10px;border:none;background:transparent;\r\n    padding:13px 16px;cursor:pointer;color:var(--navy);font-size:14px;font-weight:600;text-align:left;}\r\n  .decl .chev{font-size:12px;color:var(--muted);}\r\n  .decl .doc{padding:2px 18px 18px;}\r\n  .decl .doc h4{margin:14px 0 2px;font-family:var(--serif);font-size:14px;color:var(--red);}\r\n  .decl .doc p{margin:0 0 10px;font-family:var(--serif);font-size:15px;line-height:1.7;color:var(--ink);}\r\n\r\n  .card{background:var(--card);border:1px solid var(--line);border-radius:10px;box-shadow:0 1px 2px rgba(60,59,110,0.05);transition:border-color .15s,box-shadow .15s;}\r\n  .card:hover{border-color:rgba(60,59,110,0.4);box-shadow:0 2px 8px rgba(60,59,110,0.10);}\r\n  .chev{font-size:12px;color:var(--muted);}\r\n\r\n  /* grievance */\r\n  .grow{display:flex;align-items:baseline;gap:14px;padding:16px 18px;cursor:pointer;}\r\n  .gnum{font-family:var(--serif);font-size:26px;line-height:1;color:var(--red);min-width:34px;text-align:right;font-variant-numeric:oldstyle-nums;}\r\n  .gmid{flex:1;display:flex;flex-direction:column;gap:5px;min-width:0;}\r\n  .gtop{display:flex;align-items:center;flex-wrap:wrap;gap:8px;}\r\n  .gtitle{margin:0;font-family:var(--serif);font-weight:600;font-size:18px;color:var(--ink);}\r\n  .chip{font-size:10.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--navy);\r\n    background:var(--chip-bg);border:1px solid var(--chip-line);border-radius:999px;padding:3px 9px;}\r\n  .chip.state{color:var(--bg);background:var(--navy);border-color:var(--navy);}\r\n  .preview{margin:0;font-size:13.5px;line-height:1.5;color:var(--muted);overflow:hidden;text-overflow:ellipsis;\r\n    display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;}\r\n  .grow .chev{align-self:center;}\r\n  .gexp{padding:0 18px 18px 66px;display:flex;flex-direction:column;gap:12px;}\r\n  blockquote.orig{margin:0;padding:2px 0 2px 16px;border-left:3px solid var(--red);font-family:var(--serif);font-style:italic;font-size:16px;line-height:1.65;color:var(--ink);}\r\n  .plainbox{background:rgba(60,59,110,0.06);border:1px solid rgba(60,59,110,0.14);border-radius:8px;padding:12px 14px;}\r\n  .plainbox .lbl{font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--navy);margin-bottom:5px;}\r\n  .plainbox p{margin:0;font-size:14.5px;line-height:1.6;color:var(--ink);}\r\n\r\n  /* signer */\r\n  .srow{display:flex;align-items:center;gap:14px;padding:16px 18px;cursor:pointer;}\r\n  .smid{flex:1;display:flex;flex-direction:column;gap:7px;min-width:0;}\r\n  .sname{margin:0;font-family:var(--serif);font-weight:600;font-size:18px;color:var(--ink);}\r\n  .schips{display:flex;align-items:center;flex-wrap:wrap;gap:6px;}\r\n  .agebox{text-align:center;min-width:58px;}\r\n  .agebox .n{font-family:var(--serif);font-size:30px;line-height:1;color:var(--red);font-variant-numeric:oldstyle-nums;}\r\n  .agebox .n.q{font-size:24px;color:rgba(110,106,94,0.5);}\r\n  .agebox .cap{font-size:9.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);margin-top:3px;}\r\n  .sexp{margin:0 18px 18px;border-top:1px solid rgba(60,59,110,0.12);padding-top:14px;\r\n    display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px;}\r\n  .fact .lbl{font-size:10.5px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--navy);margin-bottom:4px;}\r\n  .fact p{margin:0;font-size:14px;line-height:1.5;color:var(--ink);}\r\n\r\n  .empty{text-align:center;padding:56px 20px;display:flex;flex-direction:column;align-items:center;gap:12px;}\r\n  .empty .star{font-size:40px;color:rgba(60,59,110,0.25);letter-spacing:.3em;}\r\n  .empty .big{margin:0;font-family:var(--serif);font-size:19px;color:var(--ink);}\r\n  .empty .sm{margin:0;font-size:14px;color:var(--muted);}\r\n  .clearbtn{margin-top:6px;border:1px solid var(--navy);background:transparent;color:var(--navy);border-radius:8px;padding:9px 18px;font-size:13.5px;font-weight:600;cursor:pointer;}\r\n  .clearbtn:hover{background:var(--navy);color:var(--bg);}\r\n\r\n  footer{margin-top:48px;text-align:center;display:flex;flex-direction:column;gap:8px;}\r\n  footer .rule{justify-content:center;}\r\n  footer p{margin:0;font-size:12px;color:var(--muted);}\r\n  footer .src{max-width:640px;margin:0 auto;font-size:11px;line-height:1.5;color:rgba(110,106,94,0.85);}\r\n</style>\r\n</head>\r\n<body>\r\n<div class=\"paper\"></div>\r\n<div class=\"shell\">\r\n\r\n  <header class=\"hd\">\r\n    <div class=\"badge\"><span class=\"st\">&#9733;</span><span>AMERICA 250</span><span class=\"st\">&#9733;</span></div>\r\n    <h1>A Candid World</h1>\r\n    <p class=\"gloss\">&ldquo;To prove this, let Facts be submitted to a candid world.&rdquo; Here <b>candid</b> means fair-minded and impartial.</p>\r\n    <p class=\"subtitle\">The 27 grievances and the 56 signers of the Declaration of Independence, in one small reference.</p>\r\n    <div class=\"rule\">&#10038; &#10038; &#10038;</div>\r\n    <div class=\"tabbar\">\r\n      <button class=\"tab active\" data-tab=\"grievances\">The 27 Grievances</button>\r\n      <button class=\"tab\" data-tab=\"signers\">The 56 Signers</button>\r\n    </div>\r\n  </header>\r\n\r\n  <!-- GRIEVANCES -->\r\n  <section class=\"panel active\" id=\"panel-grievances\">\r\n    <div class=\"ctl\">\r\n      <input type=\"search\" id=\"gq\" placeholder=\"Search the grievances&hellip;\" autocomplete=\"off\">\r\n      <select id=\"gtheme\"><option value=\"\">All themes</option></select>\r\n      <button class=\"plainbtn\" id=\"gplain\"><span class=\"dot\"></span> Modern English</button>\r\n      <span class=\"count\" id=\"gcount\"></span>\r\n    </div>\r\n    <div class=\"decl\">\r\n      <button id=\"declToggle\"><span>Read the Declaration itself</span><span class=\"chev\" id=\"declChev\">&#9660;</span></button>\r\n      <div class=\"doc\" id=\"sections\" style=\"display:none;\"></div>\r\n    </div>\r\n    <div id=\"glist\"></div>\r\n  </section>\r\n\r\n  <!-- SIGNERS -->\r\n  <section class=\"panel\" id=\"panel-signers\">\r\n    <div class=\"ctl\">\r\n      <input type=\"search\" id=\"sq\" placeholder=\"Search the signers&hellip;\" autocomplete=\"off\">\r\n      <select id=\"sstate\"><option value=\"\">All states</option></select>\r\n      <select id=\"ssort\">\r\n        <option value=\"seq\">Order on the document</option>\r\n        <option value=\"age_desc\">Age: oldest first</option>\r\n        <option value=\"age_asc\">Age: youngest first</option>\r\n        <option value=\"name\">Name (A&ndash;Z)</option>\r\n        <option value=\"state\">By state</option>\r\n      </select>\r\n      <span class=\"count\" id=\"scount\"></span>\r\n    </div>\r\n    <div id=\"slist\"></div>\r\n  </section>\r\n\r\n  <footer>\r\n    <div class=\"rule\">&#10038; &#10038; &#10038;</div>\r\n    <p>In Congress, July 4, 1776. The unanimous Declaration of the thirteen united States of America.</p>\r\n    <p class=\"src\">Built as a Datasette micro-app: one sandboxed HTML file over a governed SQLite layer via <code>datasette.query()</code>. Text: public domain (U.S. National Archives). Signer facts from public biographies; four birth dates are too uncertain to state an exact age. Modern-English restatements are editorial paraphrase.</p>\r\n  </footer>\r\n</div>\r\n\r\n<script>\r\nconst DB = \"declaration250\";\r\nlet GPLAIN=false, GEXP=null, SEXP=null, GROWS=[], SROWS=[];\r\n\r\nasync function q(sql, params){ const r = await datasette.query(DB, sql, params || {}); return r.rows || []; }\r\nfunction esc(s){return (s==null?\"\":String(s)).replace(/[&<>]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;'}[c]));}\r\nfunction ftsQuery(raw){const t=raw.toLowerCase().replace(/[^a-z0-9 ]/g,\" \").split(/\\s+/).filter(Boolean);return t.length?t.map(x=>x+\"*\").join(\" OR \"):null;}\r\n\r\n/* tabs */\r\ndocument.querySelectorAll(\".tab\").forEach(btn=>btn.addEventListener(\"click\",()=>{\r\n  document.querySelectorAll(\".tab\").forEach(b=>b.classList.toggle(\"active\",b===btn));\r\n  const n=btn.dataset.tab;\r\n  document.getElementById(\"panel-grievances\").classList.toggle(\"active\",n===\"grievances\");\r\n  document.getElementById(\"panel-signers\").classList.toggle(\"active\",n===\"signers\");\r\n}));\r\n\r\n/* declaration collapsible */\r\nlet declOpen=false;\r\ndocument.getElementById(\"declToggle\").addEventListener(\"click\",()=>{\r\n  declOpen=!declOpen;\r\n  document.getElementById(\"sections\").style.display=declOpen?\"block\":\"none\";\r\n  document.getElementById(\"declChev\").innerHTML=declOpen?\"&#9650;\":\"&#9660;\";\r\n});\r\n\r\n/* grievances */\r\nasync function loadThemes(){\r\n  const rows=await q(\"select distinct theme from grievances order by theme\",{});\r\n  const sel=document.getElementById(\"gtheme\");\r\n  rows.forEach(r=>{const o=document.createElement(\"option\");o.value=r.theme;o.textContent=r.theme;sel.appendChild(o);});\r\n}\r\nasync function loadSections(){\r\n  const rows=await q(\"select heading, body from sections order by section_order\",{});\r\n  document.getElementById(\"sections\").innerHTML=rows.map(r=>`<h4>${esc(r.heading)}</h4><p>${esc(r.body)}</p>`).join(\"\");\r\n}\r\nasync function fetchGrievances(){\r\n  const fts=ftsQuery(document.getElementById(\"gq\").value.trim());\r\n  const theme=document.getElementById(\"gtheme\").value;\r\n  let sql,params;\r\n  if(fts&&theme){sql=\"select g.num,g.short_title,g.theme,g.text,g.plain_english from grievances_fts f join grievances g on cast(f.num as integer)=g.num where f.grievances_fts match :q and g.theme=:theme order by g.num\";params={q:fts,theme};}\r\n  else if(fts){sql=\"select g.num,g.short_title,g.theme,g.text,g.plain_english from grievances_fts f join grievances g on cast(f.num as integer)=g.num where f.grievances_fts match :q order by g.num\";params={q:fts};}\r\n  else if(theme){sql=\"select num,short_title,theme,text,plain_english from grievances where theme=:theme order by num\";params={theme};}\r\n  else{sql=\"select num,short_title,theme,text,plain_english from grievances order by num\";params={};}\r\n  try{GROWS=await q(sql,params);}catch(e){document.getElementById(\"glist\").innerHTML=`<p class=\"empty sm\">Query error: ${esc(e.message||e)}</p>`;return;}\r\n  renderGrievances();\r\n}\r\nfunction renderGrievances(){\r\n  document.getElementById(\"gcount\").textContent=GROWS.length+(GROWS.length===1?\" grievance\":\" grievances\");\r\n  const list=document.getElementById(\"glist\");\r\n  if(!GROWS.length){\r\n    list.innerHTML=`<div class=\"empty\"><div class=\"star\">&#10038;</div><p class=\"big\">No facts found for a candid world</p><p class=\"sm\">Try a different word, or clear the search and theme filter.</p><button class=\"clearbtn\" data-clear=\"g\">Clear filters</button></div>`;\r\n    return;\r\n  }\r\n  list.style.display=\"flex\";list.style.flexDirection=\"column\";list.style.gap=\"10px\";\r\n  list.innerHTML=GROWS.map(r=>{\r\n    const exp=GEXP===r.num;\r\n    const preview=GPLAIN?r.plain_english:r.text;\r\n    return `<article class=\"card\">\r\n      <div class=\"grow\" data-g=\"${r.num}\">\r\n        <span class=\"gnum\">${r.num}</span>\r\n        <div class=\"gmid\">\r\n          <div class=\"gtop\"><h3 class=\"gtitle\">${esc(r.short_title)}</h3><span class=\"chip\">${esc(r.theme)}</span></div>\r\n          ${exp?\"\":`<p class=\"preview\">${esc(preview)}</p>`}\r\n        </div>\r\n        <span class=\"chev\">${exp?\"&#9650;\":\"&#9660;\"}</span>\r\n      </div>\r\n      ${exp?`<div class=\"gexp\">\r\n        <blockquote class=\"orig\">${esc(r.text)}</blockquote>\r\n        <div class=\"plainbox\"><div class=\"lbl\">In modern English</div><p>${esc(r.plain_english)}</p></div>\r\n      </div>`:\"\"}\r\n    </article>`;\r\n  }).join(\"\");\r\n}\r\n\r\n/* signers */\r\nasync function loadStates(){\r\n  const rows=await q(\"select distinct state from signers order by state\",{});\r\n  const sel=document.getElementById(\"sstate\");\r\n  rows.forEach(r=>{const o=document.createElement(\"option\");o.value=r.state;o.textContent=r.state;sel.appendChild(o);});\r\n}\r\nfunction signerOrder(p){const x=p?\"s.\":\"\";switch(document.getElementById(\"ssort\").value){\r\n  case\"age_desc\":return `order by ${x}age_at_signing is null, ${x}age_at_signing desc, ${x}seq`;\r\n  case\"age_asc\":return `order by ${x}age_at_signing is null, ${x}age_at_signing asc, ${x}seq`;\r\n  case\"name\":return `order by ${x}name`;\r\n  case\"state\":return `order by ${x}state, ${x}seq`;\r\n  default:return `order by ${x}seq`;}}\r\nasync function fetchSigners(){\r\n  const fts=ftsQuery(document.getElementById(\"sq\").value.trim());\r\n  const state=document.getElementById(\"sstate\").value;\r\n  const cols=\"seq,name,state,birth_year,age_at_signing,birthplace,education,occupation\";\r\n  const sc=cols.split(\",\").map(c=>\"s.\"+c).join(\",\");\r\n  let sql,params;\r\n  if(fts&&state){sql=`select ${sc} from signers_fts f join signers s on cast(f.seq as integer)=s.seq where f.signers_fts match :q and s.state=:state ${signerOrder(true)}`;params={q:fts,state};}\r\n  else if(fts){sql=`select ${sc} from signers_fts f join signers s on cast(f.seq as integer)=s.seq where f.signers_fts match :q ${signerOrder(true)}`;params={q:fts};}\r\n  else if(state){sql=`select ${cols} from signers where state=:state ${signerOrder(false)}`;params={state};}\r\n  else{sql=`select ${cols} from signers ${signerOrder(false)}`;params={};}\r\n  try{SROWS=await q(sql,params);}catch(e){document.getElementById(\"slist\").innerHTML=`<p class=\"empty sm\">Query error: ${esc(e.message||e)}</p>`;return;}\r\n  renderSigners();\r\n}\r\nfunction renderSigners(){\r\n  document.getElementById(\"scount\").textContent=SROWS.length+(SROWS.length===1?\" signer\":\" signers\");\r\n  const list=document.getElementById(\"slist\");\r\n  if(!SROWS.length){\r\n    list.innerHTML=`<div class=\"empty\"><div class=\"star\">&#10038;</div><p class=\"big\">No signers match</p><p class=\"sm\">Try a different name, or clear the search and state filter.</p><button class=\"clearbtn\" data-clear=\"s\">Clear filters</button></div>`;\r\n    return;\r\n  }\r\n  list.style.display=\"flex\";list.style.flexDirection=\"column\";list.style.gap=\"10px\";\r\n  list.innerHTML=SROWS.map(r=>{\r\n    const exp=SEXP===r.seq;\r\n    const born=esc(r.birthplace)+(r.birth_year?`, ${r.birth_year}`:\"\");\r\n    const age = (r.age_at_signing==null)\r\n      ? `<div class=\"agebox\"><div class=\"n q\">?</div><div class=\"cap\">age not recorded</div></div>`\r\n      : `<div class=\"agebox\"><div class=\"n\">${r.age_at_signing}</div><div class=\"cap\">at signing</div></div>`;\r\n    return `<article class=\"card\">\r\n      <div class=\"srow\" data-s=\"${r.seq}\">\r\n        <div class=\"smid\">\r\n          <h3 class=\"sname\">${esc(r.name)}</h3>\r\n          <div class=\"schips\"><span class=\"chip state\">${esc(r.state)}</span><span class=\"chip\">${esc(r.occupation)}</span></div>\r\n        </div>\r\n        ${age}\r\n        <span class=\"chev\">${exp?\"&#9650;\":\"&#9660;\"}</span>\r\n      </div>\r\n      ${exp?`<div class=\"sexp\">\r\n        <div class=\"fact\"><div class=\"lbl\">Born</div><p>${born}</p></div>\r\n        <div class=\"fact\"><div class=\"lbl\">Education</div><p>${esc(r.education)}</p></div>\r\n        <div class=\"fact\"><div class=\"lbl\">Represented</div><p>${esc(r.state)}</p></div>\r\n      </div>`:\"\"}\r\n    </article>`;\r\n  }).join(\"\");\r\n}\r\n\r\n/* events */\r\ndocument.getElementById(\"glist\").addEventListener(\"click\",e=>{\r\n  const clear=e.target.closest(\"[data-clear]\");\r\n  if(clear){document.getElementById(\"gq\").value=\"\";document.getElementById(\"gtheme\").value=\"\";fetchGrievances();return;}\r\n  const row=e.target.closest(\"[data-g]\"); if(row){const n=+row.dataset.g;GEXP=(GEXP===n)?null:n;renderGrievances();}\r\n});\r\ndocument.getElementById(\"slist\").addEventListener(\"click\",e=>{\r\n  const clear=e.target.closest(\"[data-clear]\");\r\n  if(clear){document.getElementById(\"sq\").value=\"\";document.getElementById(\"sstate\").value=\"\";fetchSigners();return;}\r\n  const row=e.target.closest(\"[data-s]\"); if(row){const n=+row.dataset.s;SEXP=(SEXP===n)?null:n;renderSigners();}\r\n});\r\nlet gdeb;document.getElementById(\"gq\").addEventListener(\"input\",()=>{clearTimeout(gdeb);gdeb=setTimeout(fetchGrievances,180);});\r\ndocument.getElementById(\"gtheme\").addEventListener(\"change\",fetchGrievances);\r\ndocument.getElementById(\"gplain\").addEventListener(\"click\",()=>{GPLAIN=!GPLAIN;document.getElementById(\"gplain\").classList.toggle(\"on\",GPLAIN);renderGrievances();});\r\nlet sdeb;document.getElementById(\"sq\").addEventListener(\"input\",()=>{clearTimeout(sdeb);sdeb=setTimeout(fetchSigners,180);});\r\ndocument.getElementById(\"sstate\").addEventListener(\"change\",fetchSigners);\r\ndocument.getElementById(\"ssort\").addEventListener(\"change\",fetchSigners);\r\n\r\n(async function init(){\r\n  try{\r\n    await loadThemes(); await loadSections(); await fetchGrievances();\r\n    await loadStates(); await fetchSigners();\r\n  }catch(e){\r\n    document.getElementById(\"glist\").innerHTML=`<div class=\"empty\"><p class=\"big\">Could not reach the data layer</p><p class=\"sm\">${esc(e.message||e)}. Is the <code>${DB}</code> database selected for this app?</p></div>`;\r\n  }\r\n})();\r\n</script>\r\n</body>\r\n</html>\r\n", "is_private": 0, "sql_databases": "[\"declaration250\"]", "stored_queries": "[]", "csp_origins": "[]", "changed_fields": "[\"name\", \"description\", \"html\", \"is_private\", \"sql_databases\", \"stored_queries\", \"csp_origins\"]", "created_at": "2026-07-02T23:39:22.249956+00:00"}], "truncated": false}