{"id":255,"date":"2021-03-03T04:30:46","date_gmt":"2021-03-03T04:30:46","guid":{"rendered":"https:\/\/trubianvillage.com\/registry\/home\/"},"modified":"2026-07-22T18:10:50","modified_gmt":"2026-07-22T18:10:50","slug":"home","status":"publish","type":"page","link":"https:\/\/trubianvillage.com\/registry\/","title":{"rendered":"Home"},"content":{"rendered":"\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1.0\">\n<title>People of the Record Registry \u2014 Standalone Preview<\/title>\n<style>\n:root{--bg:#07140d;--panel:#102418;--panel2:#163522;--gold:#d8b15a;--text:#f7f0d8;--muted:#c7b98b;--line:#34523b;--ok:#45c487;--danger:#c95b5b;--info:#6ea8fe}\n*{box-sizing:border-box}\nbody{margin:0;font-family:Arial,Helvetica,sans-serif;background:radial-gradient(circle at top,#21442a,#07140d 58%);color:var(--text)}\nheader{padding:30px 18px;text-align:center;border-bottom:2px solid var(--gold);background:#0b1b12}\nh1,h2,h3{color:var(--gold)}p{line-height:1.65}\n.wrap{max-width:1240px;margin:auto;padding:18px}\n.card{background:rgba(16,36,24,.97);border:1px solid var(--line);border-radius:14px;padding:18px;margin:14px 0}\n.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:12px}\n.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:12px}\n.stat{padding:14px;border:1px solid var(--line);border-radius:12px;background:#0b1b12}\n.stat strong{font-size:1.5rem;color:var(--gold)}\nbutton,input,select,textarea{width:100%;padding:10px;margin:6px 0;border-radius:9px;border:1px solid #52694b;background:#08130c;color:var(--text)}\nbutton{cursor:pointer;border:0;background:linear-gradient(135deg,#b78c33,#e2c36f);color:#191306;font-weight:700}\nbutton.secondary{background:#1f3927;color:var(--text);border:1px solid var(--gold)}\nbutton.ok{background:var(--ok);color:#07140d}\nbutton.danger{background:var(--danger);color:#fff}\nbutton.info{background:var(--info);color:#061428}\n.tabs{display:flex;gap:8px;flex-wrap:wrap;margin:14px 0}\n.tabs button{width:auto}\n.hidden{display:none!important}\n.badge{display:inline-block;padding:5px 9px;border:1px solid var(--gold);border-radius:999px;color:var(--gold);font-size:.84rem;margin:3px}\n.muted{color:var(--muted)}\n.notice{border-left:4px solid var(--gold);background:#0b1b12;padding:13px;border-radius:8px}\n.record{padding:13px;border:1px solid var(--line);border-radius:10px;background:#0b1b12;margin:10px 0}\n.inline{display:flex;gap:8px;flex-wrap:wrap}\n.inline button,.inline a{width:auto}\n.audioList{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:8px}\n.audioList button{text-align:left;background:#0b1b12;color:var(--text);border:1px solid var(--line)}\n.audioList button.active{border:2px solid var(--gold)}\ntable{width:100%;border-collapse:collapse}\nth,td{padding:9px;border-bottom:1px solid var(--line);text-align:left;vertical-align:top}\nth{color:var(--gold)}\n@media(max-width:650px){.tabs button{width:100%}}\n<\/style>\n<\/head>\n<body>\n<header>\n<h1>People of the Record Registry<\/h1>\n<p>Standalone Working Preview \u2014 Free Registration, Family Trees, Equity Roll, and Audiobook<\/p>\n<span class=\"badge\">Completely Free<\/span>\n<span class=\"badge\">Account Required<\/span>\n<span class=\"badge\">Evidence Required<\/span>\n<span class=\"badge\">Working Offline Preview<\/span>\n<\/header>\n\n<div class=\"wrap\">\n<section class=\"card\">\n<h2>Purpose and Scope<\/h2>\n<p>This working preview demonstrates the complete user experience without requiring PHP, a database, or a server. Data entered here is stored only in this browser using local storage.<\/p>\n<div class=\"notice\"><b>Important:<\/b> This preview is for testing the interface. The production package uses secure PHP and SQLite storage.<\/div>\n<\/section>\n\n<section class=\"card\">\n<h2>Audiobook Guide<\/h2>\n<p class=\"muted\">Press a chapter button or play the full guide. On mobile devices, playback must begin with a tap.<\/p>\n<h3 id=\"audioTitle\">1. Welcome<\/h3>\n<div class=\"inline\">\n<button type=\"button\" id=\"playChapterBtn\">\u25b6 Play Chapter<\/button>\n<button type=\"button\" id=\"playAllBtn\">\u25b6 Play Full Guide<\/button>\n<button type=\"button\" class=\"secondary\" id=\"pauseBtn\">\u23f8 Pause<\/button>\n<button type=\"button\" class=\"secondary\" id=\"resumeBtn\">\u23ef Resume<\/button>\n<button type=\"button\" class=\"danger\" id=\"stopBtn\">\u25a0 Stop<\/button>\n<\/div>\n<div class=\"grid\">\n<div><label>Narrator Voice<\/label><select id=\"voiceSelect\"><\/select><\/div>\n<div><label>Playback Speed<\/label><select id=\"speechRate\"><option value=\".75\">0.75x<\/option><option value=\".9\">0.90x<\/option><option value=\"1\" selected>1.0x<\/option><option value=\"1.15\">1.15x<\/option><option value=\"1.3\">1.3x<\/option><\/select><\/div>\n<\/div>\n<div id=\"audioStatus\" class=\"notice\">Audiobook ready.<\/div>\n<div id=\"audioList\" class=\"audioList\"><\/div>\n<\/section>\n\n<section class=\"card\">\n<h2>Create an Account or Sign In<\/h2>\n<div class=\"grid\">\n<input id=\"loginEmail\" type=\"email\" placeholder=\"Email\">\n<input id=\"loginPassword\" type=\"password\" placeholder=\"Password\">\n<\/div>\n<button id=\"loginBtn\">Sign In<\/button>\n<button class=\"secondary\" id=\"logoutBtn\">Log Out<\/button>\n<p id=\"sessionInfo\" class=\"muted\">Current access: public<\/p>\n<\/section>\n\n<div class=\"tabs\">\n<button data-tab=\"account\">Create Account<\/button>\n<button data-tab=\"application\">Registry Application<\/button>\n<button data-tab=\"dashboard\">My Portal<\/button>\n<button data-tab=\"tree\">Family Tree<\/button>\n<button data-tab=\"connections\">Connections<\/button>\n<button data-tab=\"registry\">Registry Directory<\/button>\n<button data-tab=\"equity\">Bloodline Equity Directory<\/button>\n<button data-tab=\"admin\">Administration<\/button>\n<\/div>\n\n<section id=\"account\" class=\"tab card\">\n<h2>Create a Free Account<\/h2>\n<div class=\"grid\">\n<input id=\"aName\" placeholder=\"Full Name\">\n<input id=\"aEmail\" type=\"email\" placeholder=\"Email\">\n<input id=\"aPhone\" placeholder=\"Phone\">\n<input id=\"aAddress\" placeholder=\"Street Address\">\n<input id=\"aCity\" placeholder=\"City\">\n<input id=\"aState\" placeholder=\"State\">\n<input id=\"aZip\" placeholder=\"Postal Code\">\n<input id=\"aCountry\" placeholder=\"Country\" value=\"United States\">\n<input id=\"aPassword\" type=\"password\" placeholder=\"Create Password \u2014 10 Characters Minimum\">\n<\/div>\n<button id=\"createAccountBtn\">Create Free Account<\/button>\n<div id=\"accountResult\"><\/div>\n<\/section>\n\n<section id=\"application\" class=\"tab card hidden\">\n<h2>People of the Record Application<\/h2>\n<div class=\"grid\">\n<input id=\"birthName\" placeholder=\"Birth or Maiden Name\">\n<input id=\"dob\" type=\"date\">\n<input id=\"birthPlace\" placeholder=\"Place of Birth\">\n<input id=\"father\" placeholder=\"Father's Full Name\">\n<input id=\"mother\" placeholder=\"Mother's Full Name\">\n<input id=\"ancestor\" placeholder=\"Documented Ancestor or Family Line\">\n<input id=\"branch\" placeholder=\"Family Branch\">\n<input id=\"recordLocation\" placeholder=\"County, Parish, State, or Record Location\">\n<\/div>\n<textarea id=\"lineage\" rows=\"6\" placeholder=\"Explain each generation between the documented ancestor and you.\"><\/textarea>\n<textarea id=\"evidenceSummary\" rows=\"5\" placeholder=\"Describe the records supporting the connection.\"><\/textarea>\n<button id=\"submitApplicationBtn\">Submit Application<\/button>\n<div id=\"applicationResult\"><\/div>\n<\/section>\n\n<section id=\"dashboard\" class=\"tab card hidden\">\n<h2>Registrant Portal<\/h2>\n<div id=\"dashboardOut\"><\/div>\n<\/section>\n\n<section id=\"tree\" class=\"tab card hidden\">\n<h2>My Family Tree<\/h2>\n<p class=\"muted\">In this preview, family-tree access activates immediately after the sample application is approved by the preview administrator.<\/p>\n<div class=\"grid\">\n<input id=\"tName\" placeholder=\"Full Name\">\n<input id=\"tBirthName\" placeholder=\"Birth \/ Maiden Name\">\n<input id=\"tDob\" type=\"date\">\n<input id=\"tDod\" type=\"date\">\n<input id=\"tPlace\" placeholder=\"Place of Birth\">\n<input id=\"tRelationship\" placeholder=\"Relationship to You\">\n<input id=\"tFather\" placeholder=\"Father\">\n<input id=\"tMother\" placeholder=\"Mother\">\n<input id=\"tSpouse\" placeholder=\"Spouse\">\n<input id=\"tBranch\" placeholder=\"Family Branch\">\n<input id=\"tRecord\" placeholder=\"Record Reference\">\n<\/div>\n<textarea id=\"tNotes\" rows=\"4\" placeholder=\"Genealogical notes\"><\/textarea>\n<button id=\"addTreeBtn\">Add Person<\/button>\n<div id=\"treeOut\"><\/div>\n<\/section>\n\n<section id=\"connections\" class=\"tab card hidden\">\n<h2>Possible Family Connections<\/h2>\n<div id=\"connectionsOut\"><\/div>\n<\/section>\n\n<section id=\"registry\" class=\"tab card hidden\">\n<h2>Approved Registry Directory<\/h2>\n<div id=\"registryOut\"><\/div>\n<\/section>\n\n<section id=\"equity\" class=\"tab card hidden\">\n<h2>Bloodline Equity Claim Directory<\/h2>\n<div id=\"equityOut\"><\/div>\n<\/section>\n\n<section id=\"admin\" class=\"tab card hidden\">\n<h2>Preview Administration<\/h2>\n<div class=\"notice\">This preview provides a local demonstration administrator. No real password is embedded.<\/div>\n<div id=\"adminStats\" class=\"stats\"><\/div>\n<h3>Application Review<\/h3>\n<div id=\"adminApps\"><\/div>\n<h3>Backup Demonstration<\/h3>\n<p>This preview exports a JSON copy of all locally stored preview data.<\/p>\n<div class=\"inline\">\n<button class=\"ok\" id=\"downloadBackupBtn\">Download Preview Database<\/button>\n<button class=\"danger\" id=\"resetPreviewBtn\">Reset Preview Data<\/button>\n<\/div>\n<\/section>\n<\/div>\n\n<script>\n\"use strict\";\n\nconst STORAGE_KEY = \"peopleOfRecordStandalonePreviewV2\";\n\nconst initialState = {\n  currentUser: null,\n  accounts: [],\n  applications: [],\n  trees: [],\n  registry: [],\n  equity: []\n};\n\nfunction loadState() {\n  try {\n    const raw = localStorage.getItem(STORAGE_KEY);\n    return raw ? JSON.parse(raw) : structuredClone(initialState);\n  } catch (error) {\n    return JSON.parse(JSON.stringify(initialState));\n  }\n}\n\nlet state = loadState();\n\nfunction saveState() {\n  localStorage.setItem(STORAGE_KEY, JSON.stringify(state));\n}\n\nfunction escapeHtml(value) {\n  return String(value ?? \"\").replace(\/[&<>\"']\/g, char => ({\n    \"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#039;\"\n  }[char]));\n}\n\nfunction showTab(id) {\n  document.querySelectorAll(\".tab\").forEach(section => section.classList.add(\"hidden\"));\n  document.getElementById(id).classList.remove(\"hidden\");\n  if (id === \"dashboard\") renderDashboard();\n  if (id === \"tree\") renderTree();\n  if (id === \"connections\") renderConnections();\n  if (id === \"registry\") renderRegistry();\n  if (id === \"equity\") renderEquity();\n  if (id === \"admin\") renderAdmin();\n}\n\ndocument.querySelectorAll(\"[data-tab]\").forEach(button => {\n  button.addEventListener(\"click\", () => showTab(button.dataset.tab));\n});\n\nfunction currentAccount() {\n  return state.accounts.find(account => account.email === state.currentUser) || null;\n}\n\nfunction currentApplication() {\n  return state.applications.find(app => app.email === state.currentUser) || null;\n}\n\nfunction updateSessionDisplay() {\n  const account = currentAccount();\n  document.getElementById(\"sessionInfo\").textContent = account\n    ? \"Current access: registrant \u2022 \" + account.fullName\n    : \"Current access: public\";\n}\n\ndocument.getElementById(\"createAccountBtn\").addEventListener(\"click\", () => {\n  const account = {\n    fullName: document.getElementById(\"aName\").value.trim(),\n    email: document.getElementById(\"aEmail\").value.trim().toLowerCase(),\n    phone: document.getElementById(\"aPhone\").value.trim(),\n    address: document.getElementById(\"aAddress\").value.trim(),\n    city: document.getElementById(\"aCity\").value.trim(),\n    state: document.getElementById(\"aState\").value.trim(),\n    zip: document.getElementById(\"aZip\").value.trim(),\n    country: document.getElementById(\"aCountry\").value.trim(),\n    password: document.getElementById(\"aPassword\").value\n  };\n\n  if (!account.fullName || !account.email || !account.phone || !account.address || !account.city || !account.state || !account.zip || account.password.length < 10) {\n    document.getElementById(\"accountResult\").innerHTML = '<div class=\"record\">Complete all fields. Password must contain at least 10 characters.<\/div>';\n    return;\n  }\n\n  if (state.accounts.some(item => item.email === account.email)) {\n    document.getElementById(\"accountResult\").innerHTML = '<div class=\"record\">An account already exists for this email.<\/div>';\n    return;\n  }\n\n  state.accounts.push(account);\n  state.currentUser = account.email;\n  saveState();\n  updateSessionDisplay();\n  document.getElementById(\"accountResult\").innerHTML = '<div class=\"record\">Free account created. You may now submit the registry application.<\/div>';\n  showTab(\"application\");\n});\n\ndocument.getElementById(\"loginBtn\").addEventListener(\"click\", () => {\n  const email = document.getElementById(\"loginEmail\").value.trim().toLowerCase();\n  const password = document.getElementById(\"loginPassword\").value;\n  const account = state.accounts.find(item => item.email === email && item.password === password);\n  if (!account) {\n    alert(\"Invalid preview login.\");\n    return;\n  }\n  state.currentUser = account.email;\n  saveState();\n  updateSessionDisplay();\n  document.getElementById(\"loginPassword\").value = \"\";\n  showTab(\"dashboard\");\n});\n\ndocument.getElementById(\"logoutBtn\").addEventListener(\"click\", () => {\n  state.currentUser = null;\n  saveState();\n  updateSessionDisplay();\n  showTab(\"account\");\n});\n\ndocument.getElementById(\"submitApplicationBtn\").addEventListener(\"click\", () => {\n  const account = currentAccount();\n  if (!account) {\n    alert(\"Create or sign in to an account first.\");\n    return;\n  }\n\n  if (currentApplication()) {\n    document.getElementById(\"applicationResult\").innerHTML = '<div class=\"record\">This account already has an application.<\/div>';\n    return;\n  }\n\n  const app = {\n    email: account.email,\n    fullName: account.fullName,\n    birthName: document.getElementById(\"birthName\").value.trim(),\n    dob: document.getElementById(\"dob\").value,\n    birthPlace: document.getElementById(\"birthPlace\").value.trim(),\n    father: document.getElementById(\"father\").value.trim(),\n    mother: document.getElementById(\"mother\").value.trim(),\n    ancestor: document.getElementById(\"ancestor\").value.trim(),\n    branch: document.getElementById(\"branch\").value.trim(),\n    recordLocation: document.getElementById(\"recordLocation\").value.trim(),\n    lineage: document.getElementById(\"lineage\").value.trim(),\n    evidence: document.getElementById(\"evidenceSummary\").value.trim(),\n    status: \"Pending Review\",\n    registryNumber: \"\",\n    claimNumber: \"\",\n    notes: \"\"\n  };\n\n  if (!app.ancestor || !app.lineage || !app.evidence) {\n    document.getElementById(\"applicationResult\").innerHTML = '<div class=\"record\">Complete the ancestor, lineage, and evidence fields.<\/div>';\n    return;\n  }\n\n  state.applications.push(app);\n  saveState();\n  document.getElementById(\"applicationResult\").innerHTML = '<div class=\"record\">Application submitted for review.<\/div>';\n  showTab(\"dashboard\");\n});\n\nfunction renderDashboard() {\n  const account = currentAccount();\n  if (!account) {\n    document.getElementById(\"dashboardOut\").innerHTML = '<div class=\"record\">Sign in to view the portal.<\/div>';\n    return;\n  }\n  const app = currentApplication();\n  const tree = state.trees.filter(person => person.ownerEmail === account.email);\n  document.getElementById(\"dashboardOut\").innerHTML = `\n    <div class=\"record\">\n      <h3>${escapeHtml(account.fullName)}<\/h3>\n      <p><b>Email:<\/b> ${escapeHtml(account.email)}<br>\n      <b>Registry Status:<\/b> ${app ? escapeHtml(app.status) : \"Application not submitted\"}<br>\n      <b>Registry Number:<\/b> ${app ? escapeHtml(app.registryNumber) : \"\"}<br>\n      <b>Claim Number:<\/b> ${app ? escapeHtml(app.claimNumber) : \"\"}<br>\n      <b>Claimed Ancestor:<\/b> ${app ? escapeHtml(app.ancestor) : \"\"}<br>\n      <b>Family-tree people:<\/b> ${tree.length}<\/p>\n      ${app && app.notes ? `<p><b>Review Notes:<\/b> ${escapeHtml(app.notes)}<\/p>` : \"\"}\n    <\/div>`;\n}\n\ndocument.getElementById(\"addTreeBtn\").addEventListener(\"click\", () => {\n  const account = currentAccount();\n  const app = currentApplication();\n  if (!account || !app || app.status !== \"Approved\") {\n    alert(\"The preview administrator must approve the application first.\");\n    return;\n  }\n\n  const person = {\n    ownerEmail: account.email,\n    fullName: document.getElementById(\"tName\").value.trim(),\n    birthName: document.getElementById(\"tBirthName\").value.trim(),\n    dob: document.getElementById(\"tDob\").value,\n    dod: document.getElementById(\"tDod\").value,\n    place: document.getElementById(\"tPlace\").value.trim(),\n    relationship: document.getElementById(\"tRelationship\").value.trim(),\n    father: document.getElementById(\"tFather\").value.trim(),\n    mother: document.getElementById(\"tMother\").value.trim(),\n    spouse: document.getElementById(\"tSpouse\").value.trim(),\n    branch: document.getElementById(\"tBranch\").value.trim(),\n    record: document.getElementById(\"tRecord\").value.trim(),\n    notes: document.getElementById(\"tNotes\").value.trim()\n  };\n\n  if (!person.fullName) {\n    alert(\"Enter a full name.\");\n    return;\n  }\n\n  state.trees.push(person);\n  saveState();\n  renderTree();\n});\n\nfunction renderTree() {\n  const account = currentAccount();\n  if (!account) {\n    document.getElementById(\"treeOut\").innerHTML = '<div class=\"record\">Sign in to use the family tree.<\/div>';\n    return;\n  }\n  const people = state.trees.filter(person => person.ownerEmail === account.email);\n  document.getElementById(\"treeOut\").innerHTML = people.length\n    ? people.map(person => `\n      <div class=\"record\">\n        <h3>${escapeHtml(person.fullName)}<\/h3>\n        <p>${escapeHtml(person.relationship)} \u2022 ${escapeHtml(person.branch)}<br>\n        Father: ${escapeHtml(person.father)}<br>\n        Mother: ${escapeHtml(person.mother)}<br>\n        Spouse: ${escapeHtml(person.spouse)}<br>\n        Record: ${escapeHtml(person.record)}<\/p>\n      <\/div>`).join(\"\")\n    : '<div class=\"record\">No family-tree people entered.<\/div>';\n}\n\nfunction renderConnections() {\n  const account = currentAccount();\n  if (!account) {\n    document.getElementById(\"connectionsOut\").innerHTML = '<div class=\"record\">Sign in to view connections.<\/div>';\n    return;\n  }\n  const mine = state.trees.filter(person => person.ownerEmail === account.email);\n  const others = state.trees.filter(person => person.ownerEmail !== account.email);\n  const matches = [];\n\n  mine.forEach(a => {\n    others.forEach(b => {\n      let score = 0;\n      if (a.fullName.toLowerCase() === b.fullName.toLowerCase()) score += 6;\n      if (a.dob && a.dob === b.dob) score += 3;\n      if (a.father && a.father.toLowerCase() === b.father.toLowerCase()) score += 3;\n      if (a.mother && a.mother.toLowerCase() === b.mother.toLowerCase()) score += 3;\n      if (score >= 6) matches.push({a,b,score});\n    });\n  });\n\n  document.getElementById(\"connectionsOut\").innerHTML = matches.length\n    ? matches.map(match => `<div class=\"record\"><h3>${escapeHtml(match.a.fullName)} \u2194 ${escapeHtml(match.b.fullName)}<\/h3><p>Match strength: ${match.score}<br>Status: Possible Match \u2014 Review Required<\/p><\/div>`).join(\"\")\n    : '<div class=\"record\">No possible cross-tree connections found.<\/div>';\n}\n\nfunction renderRegistry() {\n  document.getElementById(\"registryOut\").innerHTML = state.registry.length\n    ? `<table><thead><tr><th>Registry Number<\/th><th>Name<\/th><th>Family Branch<\/th><th>Ancestral Line<\/th><\/tr><\/thead><tbody>${state.registry.map(row => `<tr><td>${escapeHtml(row.registryNumber)}<\/td><td>${escapeHtml(row.fullName)}<\/td><td>${escapeHtml(row.branch)}<\/td><td>${escapeHtml(row.ancestor)}<\/td><\/tr>`).join(\"\")}<\/tbody><\/table>`\n    : '<div class=\"record\">No approved registry records.<\/div>';\n}\n\nfunction renderEquity() {\n  document.getElementById(\"equityOut\").innerHTML = state.equity.length\n    ? `<table><thead><tr><th>Claim Number<\/th><th>Registry Number<\/th><th>Name<\/th><th>Family Branch<\/th><th>Ancestral Line<\/th><\/tr><\/thead><tbody>${state.equity.map(row => `<tr><td>${escapeHtml(row.claimNumber)}<\/td><td>${escapeHtml(row.registryNumber)}<\/td><td>${escapeHtml(row.fullName)}<\/td><td>${escapeHtml(row.branch)}<\/td><td>${escapeHtml(row.ancestor)}<\/td><\/tr>`).join(\"\")}<\/tbody><\/table>`\n    : '<div class=\"record\">No Bloodline Equity Claim records.<\/div>';\n}\n\nfunction renderAdmin() {\n  document.getElementById(\"adminStats\").innerHTML = `\n    <div class=\"stat\"><strong>${state.accounts.length}<\/strong><br>accounts<\/div>\n    <div class=\"stat\"><strong>${state.applications.length}<\/strong><br>applications<\/div>\n    <div class=\"stat\"><strong>${state.registry.length}<\/strong><br>approved registry<\/div>\n    <div class=\"stat\"><strong>${state.equity.length}<\/strong><br>equity records<\/div>\n    <div class=\"stat\"><strong>${state.trees.length}<\/strong><br>tree people<\/div>`;\n\n  document.getElementById(\"adminApps\").innerHTML = state.applications.length\n    ? state.applications.map((app,index) => `\n      <div class=\"record\">\n        <h3>${escapeHtml(app.fullName)}<\/h3>\n        <p><b>Email:<\/b> ${escapeHtml(app.email)}<br>\n        <b>Ancestor:<\/b> ${escapeHtml(app.ancestor)}<br>\n        <b>Lineage:<\/b> ${escapeHtml(app.lineage)}<br>\n        <b>Evidence:<\/b> ${escapeHtml(app.evidence)}<br>\n        <b>Status:<\/b> ${escapeHtml(app.status)}<\/p>\n        <textarea id=\"notes-${index}\" rows=\"3\" placeholder=\"Review notes\">${escapeHtml(app.notes)}<\/textarea>\n        <div class=\"inline\">\n          <button class=\"ok\" onclick=\"reviewApplication(${index},'Approved')\">Approve<\/button>\n          <button class=\"info\" onclick=\"reviewApplication(${index},'More Evidence Required')\">More Evidence<\/button>\n          <button class=\"secondary\" onclick=\"reviewApplication(${index},'Provisionally Connected')\">Provisional<\/button>\n          <button class=\"danger\" onclick=\"reviewApplication(${index},'Denied')\">Deny<\/button>\n        <\/div>\n      <\/div>`).join(\"\")\n    : '<div class=\"record\">No applications.<\/div>';\n}\n\nwindow.reviewApplication = function(index,status) {\n  const app = state.applications[index];\n  app.status = status;\n  app.notes = document.getElementById(\"notes-\" + index).value.trim();\n\n  state.registry = state.registry.filter(row => row.email !== app.email);\n  state.equity = state.equity.filter(row => row.email !== app.email);\n\n  if (status === \"Approved\") {\n    app.registryNumber = \"POR-\" + String(index + 1).padStart(8,\"0\");\n    app.claimNumber = \"BEC-\" + String(index + 1).padStart(8,\"0\");\n\n    state.registry.push({\n      email: app.email,\n      registryNumber: app.registryNumber,\n      fullName: app.fullName,\n      branch: app.branch,\n      ancestor: app.ancestor\n    });\n\n    state.equity.push({\n      email: app.email,\n      claimNumber: app.claimNumber,\n      registryNumber: app.registryNumber,\n      fullName: app.fullName,\n      branch: app.branch,\n      ancestor: app.ancestor\n    });\n  }\n\n  saveState();\n  renderAdmin();\n};\n\ndocument.getElementById(\"downloadBackupBtn\").addEventListener(\"click\", () => {\n  const blob = new Blob([JSON.stringify(state,null,2)], {type:\"application\/json\"});\n  const link = document.createElement(\"a\");\n  link.href = URL.createObjectURL(blob);\n  link.download = \"PeopleOfRecord_Preview_Backup_\" + new Date().toISOString().replace(\/[:.]\/g,\"-\") + \".json\";\n  link.click();\n  URL.revokeObjectURL(link.href);\n});\n\ndocument.getElementById(\"resetPreviewBtn\").addEventListener(\"click\", () => {\n  if (!confirm(\"Reset all preview data?\")) return;\n  localStorage.removeItem(STORAGE_KEY);\n  location.reload();\n});\n\n\/* Audiobook *\/\nconst chapters = [\n  [\"Welcome\",\"Welcome to the People of the Record Registry. This is a completely free documentary and genealogical database.\"],\n  [\"Registry Purpose\",\"The registry records people, family lines, evidence, and connected family trees. Its purpose is to build a reliable database of the People of the Record and their living descendants.\"],\n  [\"Eligibility\",\"An approved registry record makes a person eligible to choose further participation under the Tree and River Covenant. Participation remains voluntary.\"],\n  [\"Separate Systems\",\"The Registry Directory and Bloodline Equity Claim Directory are separate but connected. Approval places a person in both records.\"],\n  [\"Family Trees\",\"Approved registrants may build family trees. The system compares names, parents, spouses, dates, locations, and record references.\"],\n  [\"Bloodline Equity Claim\",\"The Bloodline Equity Claim is the collective genealogical roll of approved descendants represented by the registry.\"],\n  [\"Backups\",\"Administrators can download a complete database backup so the latest records can be preserved if the website fails.\"]\n];\n\nlet chapterIndex = 0;\nlet playAllMode = false;\nlet voices = [];\n\nfunction setAudioStatus(message,error=false) {\n  const box = document.getElementById(\"audioStatus\");\n  box.textContent = message;\n  box.style.borderLeftColor = error ? \"var(--danger)\" : \"var(--gold)\";\n}\n\nfunction refreshVoices() {\n  if (!(\"speechSynthesis\" in window)) {\n    setAudioStatus(\"This browser does not support text-to-speech.\",true);\n    return;\n  }\n  voices = speechSynthesis.getVoices();\n  const select = document.getElementById(\"voiceSelect\");\n  select.innerHTML = \"\";\n  if (!voices.length) {\n    const option = document.createElement(\"option\");\n    option.textContent = \"Browser default voice\";\n    select.appendChild(option);\n    return;\n  }\n  voices.forEach((voice,index) => {\n    const option = document.createElement(\"option\");\n    option.value = index;\n    option.textContent = voice.name + \" \u2014 \" + voice.lang;\n    select.appendChild(option);\n  });\n}\n\nfunction renderAudio() {\n  document.getElementById(\"audioTitle\").textContent = (chapterIndex + 1) + \". \" + chapters[chapterIndex][0];\n  const list = document.getElementById(\"audioList\");\n  list.innerHTML = \"\";\n  chapters.forEach((chapter,index) => {\n    const button = document.createElement(\"button\");\n    button.type = \"button\";\n    button.textContent = (index + 1) + \". \" + chapter[0];\n    button.classList.toggle(\"active\",index === chapterIndex);\n    button.addEventListener(\"click\",() => {\n      chapterIndex = index;\n      playAllMode = false;\n      renderAudio();\n      playChapter();\n    });\n    list.appendChild(button);\n  });\n}\n\nfunction playChapter() {\n  if (!(\"speechSynthesis\" in window)) {\n    setAudioStatus(\"Text-to-speech is unavailable.\",true);\n    return;\n  }\n  speechSynthesis.cancel();\n  setTimeout(() => {\n    const utterance = new SpeechSynthesisUtterance(chapters[chapterIndex][1]);\n    const selected = Number(document.getElementById(\"voiceSelect\").value);\n    if (voices[selected]) utterance.voice = voices[selected];\n    utterance.rate = Number(document.getElementById(\"speechRate\").value || 1);\n    utterance.onstart = () => setAudioStatus(\"Playing: \" + chapters[chapterIndex][0]);\n    utterance.onerror = event => {\n      if (![\"canceled\",\"interrupted\"].includes(event.error)) setAudioStatus(\"Playback error: \" + event.error,true);\n    };\n    utterance.onend = () => {\n      if (playAllMode && chapterIndex < chapters.length - 1) {\n        chapterIndex++;\n        renderAudio();\n        setTimeout(playChapter,150);\n      } else {\n        playAllMode = false;\n        setAudioStatus(\"Audiobook chapter complete.\");\n      }\n    };\n    speechSynthesis.speak(utterance);\n  },100);\n}\n\ndocument.getElementById(\"playChapterBtn\").addEventListener(\"click\",() => {\n  playAllMode = false;\n  playChapter();\n});\ndocument.getElementById(\"playAllBtn\").addEventListener(\"click\",() => {\n  chapterIndex = 0;\n  playAllMode = true;\n  renderAudio();\n  playChapter();\n});\ndocument.getElementById(\"pauseBtn\").addEventListener(\"click\",() => {\n  if (speechSynthesis.speaking) {\n    speechSynthesis.pause();\n    setAudioStatus(\"Audiobook paused.\");\n  }\n});\ndocument.getElementById(\"resumeBtn\").addEventListener(\"click\",() => {\n  if (speechSynthesis.paused) {\n    speechSynthesis.resume();\n    setAudioStatus(\"Audiobook resumed.\");\n  }\n});\ndocument.getElementById(\"stopBtn\").addEventListener(\"click\",() => {\n  playAllMode = false;\n  speechSynthesis.cancel();\n  setAudioStatus(\"Audiobook stopped.\");\n});\n\nif (\"speechSynthesis\" in window) {\n  speechSynthesis.onvoiceschanged = refreshVoices;\n}\nrefreshVoices();\nsetTimeout(refreshVoices,500);\nsetTimeout(refreshVoices,1500);\nrenderAudio();\nupdateSessionDisplay();\n<\/script>\n<\/body>\n<\/html>\n<h2 style=\"text-align: center;\">Cuthaugula Coahuila Tribal Registry\n<\/h2>\n\n\n\n\n\n\n\n\n\n\n\n<p>&nbsp;<\/p>\n<p>Trubian Village Tribal Land Development<\/p>\n<p><\/p>\n\n\n\n\n\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1122,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"class_list":["post-255","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/pages\/255","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/users\/1122"}],"replies":[{"embeddable":true,"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/comments?post=255"}],"version-history":[{"count":234,"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/pages\/255\/revisions"}],"predecessor-version":[{"id":1725,"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/pages\/255\/revisions\/1725"}],"wp:attachment":[{"href":"https:\/\/trubianvillage.com\/registry\/wp-json\/wp\/v2\/media?parent=255"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}