(() => {
  const params = new URLSearchParams(window.location.search);
  const aliases = { david: "alice", matt: "bob", moto: "carol", aashik: "danny" };
  const requested = (params.get("persona") || "alice").toLowerCase();
  const personaId = ["alice", "bob", "carol", "danny"].includes(requested) ? requested : aliases[requested] || "alice";

  const people = {
    alice: {
      name: "Alice", initial: "A", defaultView: "overview",
      intro: "Here with you, Alice. This is the part of Kiduna that is yours alone. You have 5,420 USDC in portable value, including 18,400 $KIDUNA of available Compute. i can show what changed, arrange this by Realm, or help you inspect recovery without moving anything.",
      lines: [
        "Your life is yours to author; every system here should leave you more capable.",
        "The careful boundary is not a wall. It is how trust becomes possible.",
        "Your strength is not an inconvenience to the world. It is part of what the world is asking for.",
        "Return to your body before you turn a pattern into infrastructure.",
        "You are held in relationship without becoming owned by it."
      ],
      wallet: { kiduna: 18400, kidunaValue: 4600, usdc: 820, total: 5420, goal: 10000, working: 500, publicKey: "8cZp7fdX9qk4mD2a0P3nLm6VtR1eQ4Ls" },
      purchased: { usdc: 12000, kiduna: 48000 },
      earned: { total: 31200, categories: { organizing: 18000, creating: 9200, building: 4000 }, dunas: [
        ["Kinship Duna", 9000, 2400, 1200, 12600], ["Service Alliance", 6200, 2800, 1800, 10800], ["Mycelial Aid", 2800, 4000, 1000, 7800]
      ] },
      donated: 6400,
      spent: [["Service Alliance",18600],["Cosmic Humanity",12400],["Dunaversity Programs",11800],["Mycelial Aid",7600],["Relationships and Cell",4000]],
      onRamp: 12000, offRamp: 5400, offerings: { bought: 2100, sold: 7860 },
      invitees: [["Bob","now"],["Juniper Vale","this week"],["Common Thread","this month"],["Rook","quiet"],["Marisol North","this week"],["Quiet Current","paused"]],
      good: 68,
      goals: [["Portable reserve","5,420 / 10,000 USDC",54],["Systems that leave people capable","4 of 6 this season",67],["Protected restoration time","9 of 12 weeks",75]],
      impact: { compute: 54400, wisdom: 146, presence: 78, relationships: 6, headline: "Your work strengthened systems that leave people more capable.",
        wisdomUses: [["Consentful Systems","62 Sources"],["Records That Can Be Trusted","48 Sources"],["Field Notes","36 Sources"]],
        presenceUses: [["Service Alliance workflows","31 Sources"],["Mycelial Aid coordination","27 Sources"],["Small Tools, Long Memory","20 Sources"]] },
      history: [["in","Stripe crypto","18 Jun 2028",2400],["out","Sphere to bank","03 Jun 2028",1800],["in","Connected wallet","11 May 2028",1250]],
      impactCopy: "care-and-capacity goal you set"
    },
    bob: {
      name: "Bob", initial: "B", defaultView: "flow",
      intro: "Here with you, Bob. Your resources are moving through a wide Cell: 340,000 $KIDUNA flowed through your Realms and Relationships, and thirteen people entered through your invitations. i’ve opened Flow first so you can see recirculation before balance.",
      lines: [
        "A lineage is a span of care, not a claim on another person.",
        "Feed yourself before you ask the room to decide.",
        "Your usefulness does not depend on being available without end.",
        "The people around you do not need a hero. They need you whole.",
        "You are loved beyond the labor you can carry."
      ],
      wallet: { kiduna: 1240000, kidunaValue: 310000, usdc: 4260, total: 314260, goal: 350000, working: 1000, publicKey: "B7hQ2nsV4mK8dP0rT6yL3cX1aW9eJ5Fu" },
      purchased: { usdc: 60000, kiduna: 240000 },
      earned: { total: 1480000, categories: { organizing: 1050000, creating: 260000, building: 170000 }, dunas: [
        ["Kinship Duna",420000,70000,40000,530000],["Service Alliance",380000,80000,70000,530000],["Soul Kitchen",150000,60000,30000,240000],["Mountain River Trail",100000,50000,30000,180000]
      ] },
      donated: 140000,
      spent: [["Service Alliance",126000],["Soul Kitchen",74000],["Mountain River Trail",61000],["Dunaversity Programs",49000],["Relationships and Cell",30000]],
      onRamp: 60000, offRamp: 22610, offerings: { bought: 9200, sold: 38640 },
      invitees: [["Carol","now"],["Lantern House","now"],["Mica","this week"],["River Auntie","this week"],["Open Palm","this month"],["Devon Ash","quiet"],["Sunday Table","now"],["Tern","this month"],["June Assembly","this week"],["Cedar Light","paused"],["Bellwether","this month"],["Rae","this week"],["Moss Bridge","quiet"]],
      good: 74,
      goals: [["Portable operating reserve","314,260 / 350,000 USDC",90],["Invitees finding their footing","10 of 13 active",77],["One unscheduled day each week","2 of 4 this month",50]],
      impact: { compute: 340000, wisdom: 922, presence: 614, relationships: 13, headline: "What you organized kept moving after you stepped away.",
        wisdomUses: [["Lineage as Care","388 Sources"],["Hosting Without Surveillance","306 Sources"],["Welcome Table practices","228 Sources"]],
        presenceUses: [["Service Alliance hosting","247 Sources"],["Soul Kitchen shifts","204 Sources"],["Mountain River Trail","163 Sources"]] },
      history: [["out","Sphere to bank","19 Jul 2028",6200],["in","Stripe crypto","02 Jul 2028",10000],["out","Sphere to bank","15 Jun 2028",4800]],
      impactCopy: "care, continuity, and fair-work goal you set"
    },
    carol: {
      name: "Carol", initial: "C", defaultView: "impact",
      intro: "Here with you, Carol. i’ve opened Impact because contribution and recognition are the clearest center of your resources picture. Your Wisdom is in use by 1,480 Sources; your Presence is helping 903 Sources shape work without replacing their authority.",
      lines: [
        "Keep the wildness; make the moment of commitment exact.",
        "Play is not an escape from consequence. It is practice for meeting it differently.",
        "Your imagination belongs to you before it becomes useful to anyone else.",
        "The more-than-human world is not scenery. You are already in relationship with it.",
        "You are loved without having to turn that love into a performance."
      ],
      wallet: { kiduna: 310000, kidunaValue: 77500, usdc: 2140, total: 79640, goal: 90000, working: 750, publicKey: "C4mT8rpL2vN6xQ1aF9kD0sW7eH3yU5Jz" },
      purchased: { usdc: 40000, kiduna: 160000 },
      earned: { total: 760000, categories: { organizing: 150000, creating: 470000, building: 140000 }, dunas: [
        ["The Fellowship of Play",50000,180000,50000,280000],["Dunaversity",40000,160000,40000,240000],["Homeworld",35000,70000,30000,135000],["Cosmic Humanity",25000,60000,20000,105000]
      ] },
      donated: 110000,
      spent: [["The Fellowship of Play",170000],["Dunaversity Programs",130000],["Homeworld",90000],["Cosmic Humanity",70000],["Relationships and Cell",40000]],
      onRamp: 40000, offRamp: 18400, offerings: { bought: 6800, sold: 29400 },
      invitees: [["Danny","now"],["Kite String","this week"],["Blue Hour","this month"],["Anika Grove","this week"],["Paloma","quiet"],["Good Trouble","this week"],["Small Weather","this month"]],
      good: 81,
      goals: [["Creative runway","79,640 / 90,000 USDC",88],["Contributors visibly credited","38 of 42 works",90],["More-than-human practice","7 of 10 gatherings",70]],
      impact: { compute: 500000, wisdom: 1480, presence: 903, relationships: 7, headline: "The work grew because people could recognize themselves inside it.",
        wisdomUses: [["Practice-Led Facilitation","612 Sources"],["How to Be a Cricket Fan","483 Sources"],["The Play Commons","385 Sources"]],
        presenceUses: [["Dunaversity creation","367 Sources"],["Fellowship of Play","314 Sources"],["Homeworld Field Notes","222 Sources"]] },
      history: [["out","Sphere to bank","16 Jul 2028",5200],["in","Stripe crypto","28 Jun 2028",7500],["in","Connected wallet","06 Jun 2028",3200]],
      impactCopy: "creative contribution and recognition goal you set"
    },
    danny: {
      name: "Danny", initial: "D", defaultView: "identity",
      intro: "Here with you, Danny. i’ve opened Wallet and identity because recovery, low balances, and clear boundaries are the useful center today. You have 310 USDC here—below the 500 USDC working balance you set—and no automatic refill is active.",
      lines: [
        "A clear recovery path is a form of care for your future self.",
        "The river does not hurry because a system wants an update.",
        "Your boundary around sacred knowledge protects relationship; it does not diminish it.",
        "Strength can be quiet, offline, and entirely your own.",
        "You are loved in the world you repair and in the rest you allow yourself."
      ],
      wallet: { kiduna: 21000, kidunaValue: 5250, usdc: 310, total: 5560, goal: 7500, working: 500, publicKey: "D9qL1veR5tM3yB8nK0sW6aH2cF7pX4Ju" },
      purchased: { usdc: 9000, kiduna: 36000 },
      earned: { total: 28000, categories: { organizing: 8000, creating: 12000, building: 8000 }, dunas: [
        ["Mountain River Trail",4000,4000,2000,10000],["Mycelial Aid",2000,3000,3000,8000],["Indigenous Revival",1000,3000,2000,6000],["Dunaversity",1000,2000,1000,4000]
      ] },
      donated: 4000,
      spent: [["Mountain River Trail",12000],["Mycelial Aid",10000],["Indigenous Revival",8000],["Dunaversity Programs",6000],["Relationships and Cell",3000]],
      onRamp: 9000, offRamp: 2100, offerings: { bought: 1200, sold: 3850 },
      invitees: [["Red Clay","this week"],["Moth Radio","quiet"],["Grandmother Cedar","this month"]],
      good: 63,
      goals: [["Offline operating reserve","5,560 / 7,500 USDC",74],["Field records returned locally","14 of 20 records",70],["Sacred material kept bounded","12 of 12 checks",100]],
      impact: { compute: 39000, wisdom: 87, presence: 44, relationships: 3, headline: "Repair moved through the Field without asking private knowledge to become public.",
        wisdomUses: [["Field Records Without Extraction","39 Sources"],["Watershed Repair Log","31 Sources"],["Offline-First Builders","17 Sources"]],
        presenceUses: [["Mountain River Trail","19 Sources"],["Mycelial Aid field work","15 Sources"],["Dunaversity builders","10 Sources"]] },
      history: [["in","Stripe crypto","07 Jul 2028",900],["out","Sphere to bank","21 Jun 2028",700],["in","Connected wallet","09 May 2028",600]],
      impactCopy: "repair, recovery, and boundary goal you set"
    }
  };

  const person = people[personaId];
  const $ = (id) => document.getElementById(id);
  const number = (value, digits = 0) => Number(value).toLocaleString("en-US", { minimumFractionDigits: digits, maximumFractionDigits: digits });
  const compact = (value) => value >= 1000000 ? `${(value / 1000000).toFixed(value % 1000000 ? 2 : 0)}M` : value >= 1000 ? `${(value / 1000).toFixed(value % 1000 ? 1 : 0)}K` : number(value);
  const totalSpent = person.spent.reduce((sum, item) => sum + item[1], 0);
  const activity = person.invitees.reduce((result, item) => { result[item[1]] = (result[item[1]] || 0) + 1; return result; }, {});

  document.documentElement.dataset.persona = personaId;
  $("source-name").textContent = person.name;
  $("source-initial").textContent = person.initial;
  $("heading-name").textContent = person.name;
  $("total-value").textContent = number(person.wallet.total);
  $("usdc-balance").textContent = number(person.wallet.usdc, 2);
  $("usdc-value").textContent = `Worth ${number(person.wallet.usdc, 2)} USDC`;
  $("kiduna-balance").textContent = number(person.wallet.kiduna);
  $("kiduna-value").textContent = `Worth ${number(person.wallet.kidunaValue, 2)} USDC now`;
  const financialPercent = Math.min(100, Math.round(person.wallet.total / person.wallet.goal * 100));
  $("balance-goal-line").textContent = `${financialPercent}% of your ${number(person.wallet.goal)} USDC portable reserve goal`;
  $("balance-goal-track").style.width = `${financialPercent}%`;
  $("good-percent").textContent = `${person.good}%`;
  $("good-copy").textContent = person.impactCopy;
  $("good-track").style.width = `${person.good}%`;
  $("working-balance").textContent = `${number(person.wallet.working)} USDC`;
  $("public-key").textContent = person.wallet.publicKey;
  $("earned-title").textContent = `${number(person.earned.total)} $KIDUNA returned to you`;
  $("spent-total").textContent = `${number(totalSpent)} $KIDUNA`;
  $("impact-headline").textContent = person.impact.headline;

  $("flow-summary").innerHTML = [
    ["Compute purchased", `${number(person.purchased.kiduna)} K`, `${number(person.purchased.usdc)} USDC paid`],
    ["Earned", `${compact(person.earned.total)} K`, "Organizing · Creating · Building"],
    ["Donated", `${compact(person.donated)} K`, "Returned by your choice"],
    ["Compute spent", `${compact(totalSpent)} K`, "Across Realms and Relationships"],
    ["Offerings sold", `${number(person.offerings.sold)} USDC`, `${number(person.offerings.bought)} bought`]
  ].map(([label, value, note]) => `<div><span>${label}</span><b>${value}</b><small>${note}</small></div>`).join("");

  $("goal-list").innerHTML = person.goals.slice(0, 2).map(([label, value]) => `<li><span>${label}</span><b>${value}</b></li>`).join("");
  $("ripple-grid").innerHTML = [
    ["Compute through your Realms and Relationships", `${number(person.impact.compute)} K`, "Settled flow in this snapshot"],
    ["People using your Wisdom", number(person.impact.wisdom), "In permitted contexts"],
    ["People guided by your Presence", number(person.impact.presence), "Through aligned agents"],
    ["Direct Relationships in your Cell", number(person.impact.relationships), "Activity shown only in aggregate"]
  ].map(([label, value, note]) => `<article><small>${label}</small><strong>${value}</strong><span>${note}</span></article>`).join("");

  const categoryCopy = {
    organizing: "Lineage care from initial and ongoing Compute purchases across four generations.",
    creating: "Value returned as Compute flows through your Wisdom and Presence.",
    building: "Value returned as flow moves through agents you built and they prove useful."
  };
  $("earning-categories").innerHTML = Object.entries(person.earned.categories).map(([key, value]) => `<article class="earning-category"><header><b>${key[0].toUpperCase() + key.slice(1)}</b><strong>${number(value)}</strong></header><p>${categoryCopy[key]}</p></article>`).join("");
  $("duna-table").innerHTML = `<div class="duna-row header"><span>Duna</span><span>Organizing</span><span>Creating</span><span>Building</span><b>Total</b></div>${person.earned.dunas.map(([name, organizing, creating, building, total]) => `<div class="duna-row"><span>${name}</span><span>${number(organizing)}</span><span>${number(creating)}</span><span>${number(building)}</span><b>${number(total)}</b></div>`).join("")}`;

  const maxSpent = Math.max(...person.spent.map((item) => item[1]));
  $("realm-bars").innerHTML = person.spent.map(([realm, value]) => `<div class="bar-row"><span>${realm}</span><div class="bar-line"><i style="width:${Math.round(value / maxSpent * 100)}%"></i></div><b>${number(value)} K</b></div>`).join("");
  $("movement-history").innerHTML = `<div class="history-list">${person.history.map(([type, provider, date, value]) => `<div class="history-item"><span>${type === "in" ? "↓" : "↗"}</span><div><b>${provider}</b><small>${date}</small></div><strong>${type === "in" ? "+" : "−"}${number(value)} USDC</strong></div>`).join("")}</div>`;
  $("offering-totals").innerHTML = `<div class="offering-numbers"><div><span>Bought</span><strong>${number(person.offerings.bought)} USDC</strong></div><div><span>Sold</span><strong>${number(person.offerings.sold)} USDC</strong></div></div>`;

  $("impact-metrics").innerHTML = [
    ["Compute recirculated", `${number(person.impact.compute)} K`, "through Realms and Relationships"],
    ["Wisdom in use", number(person.impact.wisdom), "people in permitted contexts"],
    ["Presence in use", number(person.impact.presence), "people supported by aligned agents"]
  ].map(([label, value, note]) => `<article><span>${label}</span><strong>${value}</strong><small>${note}</small></article>`).join("");
  const useList = (items) => `<div class="use-list">${items.map(([label, value]) => `<div><span>${label}</span><b>${value}</b></div>`).join("")}</div>`;
  $("wisdom-uses").innerHTML = useList(person.impact.wisdomUses);
  $("presence-uses").innerHTML = useList(person.impact.presenceUses);
  $("all-goals").innerHTML = `<div class="goal-cards">${person.goals.map(([label, value, percent]) => `<article class="goal-card"><header><span>${label}</span><b>${percent}%</b></header><strong>${value}</strong><div class="goal-track"><span style="width:${percent}%"></span></div></article>`).join("")}</div>`;

  const views = { overview: "Whole picture", flow: "Flow and recirculation", impact: "Impact and goals", identity: "Wallet and identity" };
  function switchView(view, announce = false) {
    document.querySelectorAll("[data-dashboard-view]").forEach((panel) => panel.classList.toggle("active", panel.dataset.dashboardView === view));
    document.querySelectorAll("[data-view]").forEach((button) => {
      const selected = button.dataset.view === view;
      button.classList.toggle("active", selected);
      button.setAttribute("aria-selected", selected ? "true" : "false");
    });
    $("current-view-label").textContent = views[view];
    $("ki-context").textContent = views[view].toLowerCase();
    if (announce) addMessage(`i’ve brought ${views[view].toLowerCase()} forward.`, "ki");
  }

  let lineIndex = Math.floor(Date.now() / 12000) % person.lines.length;
  function showLine() { $("kinship-line").textContent = person.lines[lineIndex]; }
  showLine();
  window.setInterval(() => { lineIndex = (lineIndex + 1) % person.lines.length; $("kinship-line").style.opacity = "0"; window.setTimeout(() => { showLine(); $("kinship-line").style.opacity = "1"; }, 220); }, 12000);

  const messages = $("messages");
  function addMessage(text, who = "ki", html = false) {
    const message = document.createElement("div");
    message.className = `message ${who}`;
    if (html) message.innerHTML = text; else message.textContent = text;
    messages.appendChild(message);
    messages.scrollTop = messages.scrollHeight;
  }
  function setSuggestions(items) {
    $("suggestions").innerHTML = "";
    items.forEach((label) => {
      const button = document.createElement("button");
      button.type = "button";
      button.textContent = label;
      button.addEventListener("click", () => send(label));
      $("suggestions").appendChild(button);
    });
  }

  function showFocus(title, copy, cards) {
    const panel = $("focus-panel");
    panel.hidden = false;
    panel.innerHTML = `<div class="focus-top"><div><h2>${title}</h2><p>${copy}</p></div><button type="button" aria-label="Close focused view">×</button></div><div class="focus-content">${cards.map(([label, value]) => `<div><span>${label}</span><b>${value}</b></div>`).join("")}</div>`;
    panel.querySelector("button").addEventListener("click", clearFocus);
    panel.scrollIntoView({ behavior: "smooth", block: "start" });
  }
  function clearFocus() {
    $("focus-panel").hidden = true;
    $("focus-panel").innerHTML = "";
    $("ki-context").textContent = views[person.defaultView].toLowerCase();
  }

  function realmAsk() {
    switchView("flow");
    showFocus("Compute by Realm", "Settled Compute flow in this snapshot. Ask for a different period or grouping.", person.spent.slice(0, 3).map(([realm, value]) => [realm, `${number(value)} $KIDUNA`]));
    $("ki-context").textContent = "Compute by Realm";
    return `i’ve arranged Compute by Realm. ${person.spent[0][0]} is the largest settled flow at ${number(person.spent[0][1])} $KIDUNA. This shows where Compute moved, not whether a Realm or person is “better.”`;
  }
  function inviteeAsk() {
    const activeNow = activity.now || 0;
    const activeWeek = activity["this week"] || 0;
    const quiet = (activity.quiet || 0) + (activity.paused || 0);
    showFocus("Your Cell at a glance", "Aggregate participation only. Private Realms, Wisdom, and reasons for quiet are not visible here.", [["Active now", activeNow],["Active this week", activeWeek],["Quiet or paused", quiet]]);
    $("ki-context").textContent = "aggregate Cell activity";
    return `${activeNow ? `${activeNow} ${activeNow === 1 ? "invitee is" : "invitees are"} active now` : "No direct invitee is active right now"}; ${activeWeek} ${activeWeek === 1 ? "has" : "have"} been active this week. ${quiet} ${quiet === 1 ? "is" : "are"} quiet or paused. i can help you prepare a check-in, but i won’t infer why someone is quiet.`;
  }
  function goalAsk() {
    switchView("impact");
    showFocus("Shape a goal in your language", "A goal can be monetary, relational, ecological, restorative, or something else that helps you live.", [["Money", "Set a reserve or runway"],["Good", "Name a change you want to support"],["Care", "Protect rest or mutual capacity"]]);
    $("ki-context").textContent = "a new personal goal";
    return "What would you like this goal to help you notice? You can name money, repair, care, generosity, capacity, rest—or something the current dashboard does not know how to hold yet.";
  }
  function recirculationAsk() {
    switchView("overview");
    showFocus("Recirculation, not consumption", "What entered, transformed, and returned to circulation in the current snapshot.", [["Brought in", `${number(person.purchased.usdc)} USDC`],["Earned back", `${number(person.earned.total)} $KIDUNA`],["Returned by choice", `${number(person.donated)} $KIDUNA`]]);
    $("ki-context").textContent = "recirculation";
    return `You brought in ${number(person.purchased.usdc)} USDC and received ${number(person.purchased.kiduna)} $KIDUNA. Since then, ${number(person.earned.total)} $KIDUNA returned through Organizing, Creating, and Building; ${number(person.donated)} was donated; and ${number(totalSpent)} flowed through Realms and Relationships. That is movement, not a score of your worth.`;
  }
  function recoveryAsk() {
    switchView("identity");
    showFocus("Recovery readiness", "The prototype can show the sequence, but no real seed phrase or key share exists here.", [["Public key", "Visible"],["Seed phrase", "Masked"],["Key share", "Masked"]]);
    $("ki-context").textContent = "portable recovery";
    return "Start with paper: reveal the seed phrase only when you are private, write it down by hand, and store it somewhere separate from this device. Never put it in a screenshot, note, email, chat, or cloud drive. Then inspect the key share and download a portable snapshot.";
  }

  function replyFor(text) {
    const prompt = text.toLowerCase();
    if (/by realm|which realm|compute.*going/.test(prompt)) return realmAsk();
    if (/invitee|cell.*active|who.*active/.test(prompt)) return inviteeAsk();
    if (/set.*goal|new goal|revise.*goal/.test(prompt)) return goalAsk();
    if (/recircul|what.*moved|what.*transform|whole.*flow/.test(prompt)) return recirculationAsk();
    if (/recover|seed|key share|secure.*wallet/.test(prompt)) return recoveryAsk();
    if (/usdc.*history|on-ramp|off-ramp|movement/.test(prompt)) { switchView("flow"); return `Your full fixture shows ${number(person.onRamp)} USDC on-ramped and ${number(person.offRamp)} USDC off-ramped through Sphere. i’ve opened Flow; choose “All history” for a deeper cut.`; }
    if (/earn|organizing|creating|building/.test(prompt)) { switchView("flow"); return `You earned ${number(person.earned.total)} $KIDUNA: ${number(person.earned.categories.organizing)} Organizing, ${number(person.earned.categories.creating)} Creating, and ${number(person.earned.categories.building)} Building. i can regroup this by Duna or period.`; }
    if (/impact|wisdom|presence|good/.test(prompt)) { switchView("impact"); return `Your Wisdom is in use by ${number(person.impact.wisdom)} Sources and your Presence is helping ${number(person.impact.presence)}. These counts only include permitted contexts; they do not expose what another Source keeps private.`; }
    if (/balance|money|wallet/.test(prompt)) { switchView("overview"); return `Your complete portable balance is ${number(person.wallet.total)} USDC in current value: ${number(person.wallet.usdc,2)} USDC and ${number(person.wallet.kiduna)} $KIDUNA valued at ${number(person.wallet.kidunaValue,2)} USDC. The market reference is dated and can change.`; }
    if (/arrange|reconfigure|dashboard|page/.test(prompt)) return "Tell me what you want to notice first. i can organize this around money, Realms, recirculation, impact, goals, recovery, or a question in your own words.";
    if (/snapshot|export/.test(prompt)) { switchView("identity"); return "The portable snapshot belongs in Wallet and identity. It should contain what you need to restore your own context without silently exporting another Source’s private material. This prototype will preview, not create, that file."; }
    return "i can reshape this around your question. Try asking what recirculated, where Compute moved, which invitees are active, how your Wisdom is being used, or what recovery still needs your attention.";
  }

  function send(text) {
    const value = String(text || "").trim();
    if (!value) return;
    addMessage(value, "source");
    $("chat-input").value = "";
    $("chat-input").style.height = "auto";
    window.setTimeout(() => addMessage(replyFor(value), "ki"), 240);
  }

  addMessage(person.intro, "ki");
  setSuggestions(["Show me by Realm", "Which of my invitees are active?", "Set a goal", "What recirculated?", "Help me secure recovery"]);
  switchView(person.defaultView);

  document.querySelectorAll("[data-view]").forEach((button) => button.addEventListener("click", () => switchView(button.dataset.view)));
  document.querySelectorAll("[data-ask]").forEach((button) => button.addEventListener("click", () => send(button.dataset.ask)));
  $("clear-focus").addEventListener("click", () => { clearFocus(); switchView(person.defaultView); });
  $("chat-form").addEventListener("submit", (event) => { event.preventDefault(); send($("chat-input").value); });
  $("chat-input").addEventListener("input", (event) => { event.target.style.height = "auto"; event.target.style.height = `${Math.min(event.target.scrollHeight, 98)}px`; });
  $("chat-input").addEventListener("keydown", (event) => { if (event.key === "Enter" && !event.shiftKey) { event.preventDefault(); send(event.target.value); } });

  let toastTimer;
  function toast(text) { $("toast").textContent = text; $("toast").classList.add("visible"); window.clearTimeout(toastTimer); toastTimer = window.setTimeout(() => $("toast").classList.remove("visible"), 2600); }

  const actionSheet = $("action-sheet");
  let sheetConfirm = null;
  function closeSheet() { actionSheet.classList.remove("open"); actionSheet.setAttribute("aria-hidden", "true"); sheetConfirm = null; }
  function openSheet(config) {
    $("sheet-eyebrow").textContent = config.eyebrow || "Prototype action";
    $("sheet-title").textContent = config.title;
    $("sheet-copy").textContent = config.copy;
    $("sheet-body").innerHTML = `<div class="sheet-body-card">${config.rows.map(([label, value]) => `<div><span>${label}</span><b>${value}</b></div>`).join("")}</div>`;
    $("sheet-confirm").textContent = config.confirm || "Preview next step";
    sheetConfirm = config.onConfirm || (() => toast("Prototype only · no Action was executed."));
    actionSheet.classList.add("open"); actionSheet.setAttribute("aria-hidden", "false");
  }
  const actionConfig = {
    onramp: { title: "Buy Compute with a card", copy: "Stripe crypto headless would accept card payment and deliver $KIDUNA to this Solana wallet. You would inspect the exact price and amount before paying.", rows: [["Provider","Stripe crypto"],["Receives","$KIDUNA Compute"],["Status","No purchase started"]] },
    offramp: { title: "Move USDC out", copy: "Sphere would move USDC from this wallet toward a bank account you control. The exact destination, fees, and timing must be visible before confirmation.", rows: [["Provider","Sphere"],["Available",`${number(person.wallet.usdc,2)} USDC`],["Status","No transfer started"]] },
    connect: { title: "Connect a Solana wallet", copy: "Connection proves control of an address. It does not authorize a transfer, reveal a seed phrase, or move anything by itself.", rows: [["Network","Solana"],["Supported","$KIDUNA · USDC · Badges"],["Status","Not connected"]] },
    voice: { title: "Talk with Ki", copy: "Real-time voice is represented in this prototype but is not connected. The same conversation would remain visible here as text.", rows: [["Mode","Voice + text record"],["Authority","Conversation only"],["Status","Prototype simulation"]] }
  };
  document.querySelectorAll("[data-action]").forEach((button) => button.addEventListener("click", () => openSheet(actionConfig[button.dataset.action])));
  $("sheet-close").addEventListener("click", closeSheet); $("sheet-cancel").addEventListener("click", closeSheet);
  actionSheet.addEventListener("click", (event) => { if (event.target === actionSheet) closeSheet(); });
  $("sheet-confirm").addEventListener("click", () => { const fn = sheetConfirm; closeSheet(); if (fn) fn(); });

  document.querySelector("[data-copy='public']").addEventListener("click", async () => {
    try { await navigator.clipboard.writeText(person.wallet.publicKey); toast("Public key copied."); } catch { toast("Copy is unavailable in this preview."); }
  });
  $("reveal-seed").addEventListener("click", () => openSheet({ eyebrow: "Sensitive recovery material", title: "Reveal the seed phrase?", copy: "Make sure no one can see your screen. Write a real seed phrase on paper; never copy it into a digital note or message.", rows: [["This prototype","Contains no real secret"],["Best practice","Paper · private · separate"]], confirm: "Reveal prototype state", onConfirm: () => { $("seed-phrase").textContent = "PROTOTYPE ONLY · no recovery phrase exists"; toast("Prototype state revealed. No secret exists here."); } }));
  $("reveal-share").addEventListener("click", () => openSheet({ eyebrow: "Sensitive recovery material", title: "Reveal the key share?", copy: "A key share belongs in a separate recovery location. Do not store it beside the seed phrase.", rows: [["This prototype","Contains no real key share"],["Best practice","Store separately"]], confirm: "Reveal prototype state", onConfirm: () => { $("key-share").textContent = "PROTOTYPE ONLY · no key share exists"; toast("Prototype state revealed. No secret exists here."); } }));
  $("auto-refresh").addEventListener("change", (event) => {
    const wanted = event.target.checked; event.target.checked = !wanted;
    openSheet({ eyebrow: "Money rule", title: wanted ? "Turn on auto-refresh?" : "Turn off auto-refresh?", copy: wanted ? "Stripe would charge your saved card when USDC falls below the limit. Inspect the amount, ceiling, and cancellation rule before this becomes active." : "Turning this off stops future automatic card charges. It does not reverse a settled purchase.", rows: [["Below","100 USDC"],["Add","250 USDC"],["Current status", wanted ? "Off" : "On"]], confirm: wanted ? "Preview rule" : "Preview change", onConfirm: () => { event.target.checked = wanted; toast("Prototype preference changed locally; no payment rule was created."); } });
  });
  document.addEventListener("keydown", (event) => { if (event.key === "Escape") closeSheet(); });
})();
