local ADDON_NAME, RPAL = ...

-- ============================================================
-- ODYN Persona / Living Inner Voice v4
-- Character-scoped persona + thought engine. PersonaLearning.lua supplies the
-- calibrated/observed behavioural model; this file turns that model into a
-- quiet inner voice using mundane thoughts, preferences, memory and needs.
-- ============================================================

local VERSION = 5

local function clamp(v, lo, hi)
    v = tonumber(v) or lo
    if v < lo then return lo end
    if v > hi then return hi end
    return v
end

local function trim(s)
    return tostring(s or ""):gsub("^%s+", ""):gsub("%s+$", "")
end

local function shallowCopy(t)
    local out = {}
    for k,v in pairs(t or {}) do out[k] = v end
    return out
end

local DEFAULT_TRAITS = {
    chaoticLawful = 50,          -- 0 Chaotic <-> 100 Lawful
    forgivingVindictive = 50,    -- 0 Forgiving <-> 100 Vindictive
    altruisticSelfish = 50,      -- 0 Altruistic <-> 100 Selfish
    truthfulDeceitful = 50,      -- 0 Truthful <-> 100 Deceitful
    gentleBrutal = 50,           -- 0 Gentle <-> 100 Brutal
    superstitiousRational = 50,  -- 0 Superstitious <-> 100 Rational
    renegadeParagon = 50,        -- 0 Renegade <-> 100 Paragon
    cautiousImpulsive = 50,      -- 0 Cautious <-> 100 Impulsive
    asceticBonVivant = 50,       -- 0 Ascetic <-> 100 Bon Vivant
    valorousSpineless = 50,      -- 0 Valorous <-> 100 Spineless
    introvertedExtroverted = 50, -- 0 Introverted <-> 100 Extroverted
}

RPAL.PERSONALITY_TRAIT_PAIRS = {
    chaoticLawful = {left="Chaotic", right="Lawful", description="Improvisation and rule-breaking versus order, procedure and respect for rules."},
    forgivingVindictive = {left="Forgiving", right="Vindictive", description="Whether slights are released or remembered and answered."},
    altruisticSelfish = {left="Altruistic", right="Selfish", description="How readily other people's needs are placed ahead of the character's own."},
    truthfulDeceitful = {left="Truthful", right="Deceitful", description="Direct honesty versus comfort with bluffing, concealment and manipulation."},
    gentleBrutal = {left="Gentle", right="Brutal", description="Soft handling and restraint versus intimidation, cruelty and force."},
    superstitiousRational = {left="Superstitious", right="Rational", description="Omens, fate and instinct versus evidence, explanation and reason."},
    renegadeParagon = {left="Renegade", right="Paragon", description="Defying expectations versus embodying duty, standards and responsibility."},
    cautiousImpulsive = {left="Cautious", right="Impulsive", description="Planning and risk awareness versus acting first and adapting later."},
    asceticBonVivant = {left="Ascetic", right="Bon vivant", description="Simplicity and restraint versus comfort, indulgence and worldly pleasures."},
    valorousSpineless = {left="Valorous", right="Spineless", description="Standing ground under pressure versus avoiding danger when fear takes over."},
    introvertedExtroverted = {left="Introverted", right="Extroverted", description="A private inward social rhythm versus energy drawn from active social engagement."},
}

-- Intentionally plain, everyday inner voice. These lines avoid assuming gender,
-- exact time, current location, combat state or a specific scene. The point is
-- to sound like stray thoughts, not dramatic narration or RP instructions.
local POOLS = {
    mundane = {
        "Some faces are easier to remember than names.",
        "Maybe I should get some drinks.",
        "Am I... tired?",
        "My shoulders could use a proper stretch.",
        "I wanna eat something, but can't put my finger on it.",
        "What time is it?",
        "My back hurts a bit, I think.",
        "Some extra coins would be nice right now.",
        "A quieter life sounds tempting on some days.",
        "I could use one small task to focus on.",
        "I should take stock of what I am carrying.",
        "I should probably drink some water.",
        "I should make a proper list one of these days.",
        "I should check what I am carrying.",
        "I could go for something warm to eat.",
        "I should check my pockets later.",
        "I keep noticing details I usually pass over.",
        "I think I need to stretch.",
        "I should really organize my things sometime.",
        "Where does all my money actually go?",
        "Maybe I carry too much stuff around.",
        "A quiet minute would be nice.",
        "My attention keeps wandering today.",
        "I should deal with one of those small repairs soon.",
        "A proper list would make the little tasks easier to remember.",
        "What would I even eat if I had to choose right now?",
        "I wonder if I have enough coin on me.",
        "I should probably clean something when I get the chance.",
        "Did I leave anything unfinished?",
        "I could use a better place to keep small things.",
        "Why do I always remember things at the least useful moment?",
        "I should probably sit properly for once.",
        "I wonder what I have in my bag that I forgot about.",
        "Maybe I need a new pair of boots someday.",
        "I should stop putting the small chores off.",
        "I could really use something sweet.",
        "I wonder if I locked everything up.",
        "I should probably keep a little more coin aside.",
        "I feel like I am forgetting a name.",
        "I should check whether I still have everything I came with.",
    },
    reflective = {
        "I wonder if I have been overthinking that.",
        "That keeps replaying in my head more than I'd like.",
        "I wonder what habit of mine people notice first.",
        "Have I been making this harder than it needs to be?",
        "Hard to tell whether I'm being honest with myself about that.",
        "I wonder if I changed my mind without noticing.",
        "Maybe I have been worrying about the wrong part.",
        "I wonder why that keeps coming back to mind.",
        "Funny how one old thing still refuses to stay old.",
        "Maybe I am more stubborn about that than I thought.",
        "I wonder if I actually care about that as much as I think.",
        "My head could use a break from circling that.",
        "I wonder if I would make the same choice again.",
        "I've been circling that decision for too long.",
        "Maybe that was simpler than I made it sound.",
        "I wonder if I am missing something obvious.",
        "Maybe I should give that another look later.",
        "I wonder why that bothered me so much.",
    },
    social = {
        "Maybe I should talk to someone I have not seen in a while.",
        "I wonder if I owe someone a reply.",
        "I get curious about people more often than I let on.",
        "Maybe I came across differently than I meant to.",
        "I wonder who I would actually call a close friend.",
        "I should probably check in on someone soon.",
        "Maybe I should be the one to start the conversation.",
        "I wonder how often I talk over people without noticing.",
        "There are people I probably haven't thanked properly.",
        "Maybe I assumed too much about what someone meant.",
        "I wonder who I am easiest to talk to.",
        "I should probably remember that name.",
        "I wonder how much I miss while I'm busy thinking of an answer.",
        "I wonder if someone is waiting to hear from me.",
        "There are definitely faces I pretend to remember.",
        "Wonder who I'd actually want to hear from right now.",
        "I wonder who would notice if I went quiet for a while.",
        "I should probably make time for people I actually like.",
        "Maybe I have been a little too distant lately.",
        "I wonder who I would trust with a small favor.",
    },
    comfort = {
        "A decent meal would be nice.",
        "I could use something warm to drink.",
        "I should find somewhere comfortable to sit later.",
        "I wonder what snack would hit the spot.",
        "Maybe I just need a little rest.",
        "A hot meal sounds better the more I think about it.",
        "I could really go for something familiar.",
        "A slower minute sounds good right now.",
        "I wonder what food I never get tired of.",
        "A clean shirt would feel good right now.",
        "My back is reminding me that it exists again.",
        "Maybe I need a proper night's rest sometime.",
        "I could use a comfortable chair.",
        "I wonder if I packed anything good to eat.",
        "Maybe I should treat myself to something small.",
        "A quiet corner would be nice.",
        "I should probably eat before I forget again.",
        "I could use something cold to drink.",
        "Maybe I just need five minutes to myself.",
        "I wonder what would make me feel properly rested.",
    },
    practical = {
        "What is the easiest way to handle this?",
        "I should probably make a list.",
        "There has to be a simpler way.",
        "That small problem is going to become a bigger one if I keep ignoring it.",
        "Half the time I buy things before remembering what I actually needed.",
        "What can I get done quickly?",
        "I should probably keep some coin aside.",
        "Maybe I need a better system for remembering things.",
        "Too many little priorities are competing in my head.",
        "There is no reason to make a simple problem complicated.",
        "I should check my supplies sometime.",
        "I keep starting things before the last one is done.",
        "I wonder what I can leave behind without missing it.",
        "I should probably replace that before it breaks.",
        "Maybe I can solve that with what I already have.",
        "The useful things are never where I want them when I need them.",
        "I wonder what I am wasting time on.",
        "I should start keeping better notes.",
        "One step ahead would be nice for once.",
        "What am I forgetting to prepare for?",
    },
    curious = {
        "I wonder how that works.",
        "I should ask about that sometime.",
        "There is probably a story behind that.",
        "I wonder what I have never bothered to learn.",
        "Maybe I should try something new.",
        "I wonder why people do it that way.",
        "I should look that up when I get the chance.",
        "There has to be more to that than it looks like.",
        "I wonder what would happen if I tried it differently.",
        "Maybe I should learn one completely useless thing.",
        "I wonder what I would be unexpectedly good at.",
        "I should ask someone who actually knows.",
        "I wonder how long that has been a thing.",
        "Maybe I have been assuming the wrong answer.",
        "I wonder what is inside that.",
        "I probably missed a detail there.",
        "Maybe there is an easier explanation.",
        "I wonder what I would notice if I looked twice.",
        "That detail feels worth holding onto.",
        "Why have I never asked that before?",
    },
    restless = {
        "I feel like doing something, I just do not know what.",
        "Maybe I need a change of scenery.",
        "I could walk somewhere for no reason.",
        "I need a small project.",
        "Maybe I should rearrange something.",
        "I want something I can just start without thinking too hard.",
        "I feel like I have been waiting for something.",
        "Maybe I should try a different route next time.",
        "I need something to keep my hands busy.",
        "I wonder if I can make this more interesting.",
        "One of those unfinished little things is nagging at me.",
        "I could use a little movement.",
        "I wonder what I would do if I had nothing planned.",
        "Maybe I just need something new to think about.",
        "That idea keeps sitting there, waiting for me to do something with it.",
        "I feel like changing something small.",
        "Maybe I should go find something to do.",
        "I wonder why I suddenly feel impatient.",
        "Staring at the same problem isn't making it any less annoying.",
        "Part of me wants to just start and figure it out as I go.",
    },
    kind = {
        "I keep noticing when somebody looks a little lost.",
        "It bothers me when someone is clearly uncomfortable and nobody seems to notice.",
        "I wonder whether that person is doing alright.",
        "I still remember the people who helped me without making a fuss about it.",
        "Seeing somebody relax a little makes me feel better too.",
        "I keep noticing the people standing slightly outside the conversation.",
        "I wonder whether anyone nearby could use a bit of company.",
        "I do not like the feeling of somebody being left to struggle alone.",
        "I keep remembering a small kindness somebody showed me earlier.",
        "I get a little uneasy when somebody insists they are fine but does not look it.",
        "I wonder who around here has had a rougher day than they are showing.",
        "I like it when helping somebody can stay simple and quiet.",
        "I keep noticing the little moments where somebody makes space for another person.",
        "It is nice seeing someone look relieved after being tense for a while.",
        "I wonder whether that person has anybody familiar nearby.",
        "I feel better around people who notice when somebody else is struggling.",
        "I keep thinking about the person who looked tired earlier.",
        "It bothers me more than I expect when somebody is treated like an inconvenience.",
        "I wonder whether a familiar face would make things easier for them.",
        "Somebody being quietly decent tends to stick in my head."
    },
    guarded = {
        "I am still not sure what I make of that.",
        "Something about that wording keeps bothering me.",
        "I keep wondering what part of that I did not hear.",
        "I am not completely comfortable with how easy that sounded.",
        "There is a little bit of doubt still sitting there.",
        "I keep noticing that I have not quite relaxed about that yet.",
        "Something in that exchange still feels slightly off to me.",
        "I wonder whether I am missing a piece of the story.",
        "I keep thinking about the part that was left unsaid.",
        "I am not ready to feel certain about that yet.",
        "That was easy enough to hear and harder to believe.",
        "I keep remembering the pause before the answer.",
        "There is still a small question mark hanging over that.",
        "I wonder why I did not feel entirely comfortable with that.",
        "Some part of me is still watching that a little closely.",
        "I keep thinking about whether the story fits together as neatly as it sounded.",
        "That detail has not stopped feeling strange yet.",
        "I am still a little wary of how simple that explanation was.",
        "I keep thinking there was more going on there than I caught.",
        "Something about that has not earned my full trust yet."
    },
    ambitious = {
        "Part of me wants to aim a little higher.",
        "I wonder what I could get better at next.",
        "I'm getting tired of waiting for the perfect moment.",
        "Maybe I can turn this into something useful.",
        "I wonder what opportunity I keep overlooking.",
        "That goal is starting to feel more serious than a passing thought.",
        "Maybe I have been thinking too small.",
        "I wonder what I could finish if I really focused.",
        "There's more I could do with what I already know.",
        "Part of me wants to ask for more instead of waiting for it.",
        "I wonder what I could be unusually good at.",
        "That connection could be useful later.",
        "Maybe I need a clearer next step.",
        "I wonder what would actually move me forward.",
        "Waiting is starting to feel less like progress.",
        "Maybe I can do better than just getting by.",
        "I wonder what I would choose if I knew I could manage it.",
        "That plan is starting to feel like something I actually want to make real.",
        "Maybe I should save more for something bigger.",
        "I wonder what I am capable of if I stop playing it safe.",
    },
    selfish = {
        "What is actually in this for me?",
        "Maybe I should keep some time for myself.",
        "I do not have to volunteer for every problem.",
        "Maybe I should say no more often.",
        "I should probably protect my own coin a little better.",
        "Maybe I deserve the better option this once.",
        "I should not confuse being useful with being available.",
        "Maybe I can let someone else handle that.",
        "I wonder why I am making this my responsibility.",
        "I should probably keep something back for myself.",
        "Maybe I do not owe an explanation for wanting something.",
        "I should stop treating everyone else's urgency like mine.",
        "Maybe I can be a little inconvenient for once.",
        "I wonder if I am giving more than I actually want to.",
        "I should probably think about what I want first.",
        "Maybe I should keep the easy route for myself.",
        "I wonder if anyone would do the same for me.",
        "I should probably save my energy for something that matters to me.",
        "Maybe I can choose myself without making it complicated.",
        "I wonder how much easier this would be if I just walked away.",
    },
    chaotic = {
        "I feel like doing something different just to break the sameness.",
        "The usual way of doing this feels a little boring right now.",
        "I keep wondering what happens if I take a less obvious route.",
        "Part of me wants to improvise and see where it goes.",
        "I feel like changing one small thing for no important reason.",
        "I keep getting curious about the option nobody seems to be using.",
        "I would not mind a little harmless unpredictability.",
        "My attention keeps drifting toward the less sensible option.",
        "I feel like taking the long way just because it is different.",
        "I keep wanting to poke at the routine a little.",
        "Something in me gets restless when everything is too orderly for too long.",
        "I wonder whether doing this differently would actually be more interesting.",
        "I feel like making a small change and dealing with the result afterward.",
        "The thought of doing exactly what is expected is not very exciting right now.",
        "I keep looking for a way to make this feel less repetitive.",
        "Part of me wants to try the odd option just to know what it is like.",
        "I feel like wandering off the usual path for a bit.",
        "I keep noticing the choices that look slightly unusual.",
        "A little variety would be nice.",
        "I feel like doing something I did not plan in advance."
    },
    forgiving = {
        "That is not bothering me quite as much as it was.",
        "I can feel some of the irritation fading already.",
        "I keep remembering it without getting as annoyed this time.",
        "Part of me is tired of carrying that argument around.",
        "I wonder whether I will even care about that in a few days.",
        "The memory is still there, but the anger around it feels smaller.",
        "I keep thinking about it and feeling less certain that I am still upset.",
        "That mistake feels more ordinary now than it did when it happened.",
        "I am starting to remember the rest of the person, not just the thing that annoyed me.",
        "The sharp part of that memory is wearing down a little.",
        "I wonder why I was holding onto that so tightly.",
        "I keep noticing that I am less tense when I think about it now.",
        "That does not feel important enough to stay angry about forever.",
        "I can remember what happened without feeling the same heat behind it.",
        "Part of me just feels tired of being annoyed about the same thing.",
        "I keep thinking about whether it was as personal as it felt at first.",
        "That memory is starting to feel more distant.",
        "I wonder whether the apology meant more to me than I admitted.",
        "The irritation comes back, but it does not stay as long.",
        "I am not as interested in being angry about that as I used to be."
    },
    vindictive = {
        "I am still annoyed about that.",
        "I keep remembering exactly what bothered me.",
        "That irritation has not faded as much as I expected.",
        "I wonder whether they even realize I am still bothered by it.",
        "The memory keeps bringing the same little flash of annoyance back.",
        "I still do not feel especially warm toward them after that.",
        "I keep thinking about the tone they used.",
        "That is still sitting badly with me.",
        "I thought I would be over that by now, but apparently not.",
        "I keep remembering the part where they made it worse.",
        "I wonder whether I would react differently if it happened again.",
        "The irritation comes back surprisingly fast whenever I remember it.",
        "I am not ready to feel neutral about that yet.",
        "I keep thinking about how unnecessary that felt.",
        "That memory still makes me tense a little.",
        "I wonder why that particular thing got under my skin so badly.",
        "I still feel myself getting annoyed when the memory comes up.",
        "There is a part of me that has not finished being angry about that.",
        "I keep remembering how quickly my mood changed when that happened.",
        "That still feels more irritating than it probably looks from the outside."
    },
    dutiful = {
        "I keep thinking about the thing I said I would finish.",
        "Loose ends bother me more when somebody is waiting on me.",
        "I feel better when I know exactly what is expected of me.",
        "I keep remembering a promise I do not want to leave hanging.",
        "There is a small satisfaction in getting something done properly.",
        "I keep thinking about whether I left any part of that unfinished.",
        "I dislike the feeling of somebody having to remind me twice.",
        "I keep track of responsibilities more easily than I track little comforts.",
        "I wonder whether I have forgotten something somebody is counting on.",
        "I feel more settled once the boring part of a job is actually done.",
        "I keep thinking about the details that are easiest to miss when I rush.",
        "It bothers me when I know I could have been more prepared.",
        "I keep remembering where I said I would be and when.",
        "I feel strangely relieved when everything is where it is supposed to be.",
        "I wonder whether there is still one small obligation sitting unfinished.",
        "I keep noticing tasks that would be easier if I finished them before starting another.",
        "It is hard for me to relax when I know something important is still waiting.",
        "I like knowing that people can rely on me without having to chase me down.",
    },
    rebellious = {
        "I keep wanting to do this my own way.",
        "The usual procedure is getting on my nerves a little.",
        "I wonder why that restriction bothers me as much as it does.",
        "I feel boxed in when every small choice already has a prescribed answer.",
        "I keep looking for the route that does not require asking three people first.",
        "Part of me wants to improvise instead of following the usual order.",
        "I wonder whether anybody would even care if I handled this differently.",
        "I keep noticing how quickly I get impatient with pointless formality.",
        "There is something satisfying about solving a problem without waiting for permission.",
        "I feel more comfortable when I have room to change my mind halfway through.",
        "I keep thinking about the option nobody bothered to put on the list.",
        "The more unnecessary rules pile up, the more I want to find another way.",
        "I wonder whether the standard way is actually useful here or just familiar.",
        "I keep wanting to cut around the part that feels like ceremony.",
        "I do not like feeling as if somebody else already decided every small choice for me.",
        "I feel more awake when I can improvise a little.",
        "I keep noticing which rules solve a real problem and which ones just slow things down.",
        "I would rather have a little room to maneuver than a perfectly neat procedure.",
    },
    arcane = {
        "I wonder how that spell actually works.",
        "Maybe I should read more about that kind of magic.",
        "I wonder what part of that is technique and what part is instinct.",
        "I should probably pay more attention to magical details.",
        "Maybe there is a cleaner way to control that effect.",
        "I wonder what rule of magic I take for granted.",
        "I should ask someone who understands the theory.",
        "Maybe I have been treating magic like a tool without thinking about it.",
        "I wonder how much practice that actually takes.",
        "I should probably learn the limits before trusting it.",
        "Maybe I would enjoy studying something completely impractical.",
        "I wonder what makes one spell feel easier than another.",
        "I should remember that strange does not mean random.",
        "Maybe I should keep better notes on magical things.",
        "I wonder what I would learn if I watched the process instead of the result.",
        "I should probably not assume I understand a spell from seeing it once.",
        "Maybe there is a pattern I have not noticed yet.",
        "I wonder how much of magic is just very precise habit.",
    },
    nature = {
        "I could use some fresh air.",
        "I keep thinking about somewhere quiet and green.",
        "I wonder what the weather feels like away from all the buildings.",
        "A long walk somewhere open sounds good.",
        "I keep noticing how much calmer running water makes me feel.",
        "I wonder what plants I would recognize without somebody telling me.",
        "I miss the feeling of having more sky around me.",
        "I keep thinking about the smell of wet earth after rain.",
        "Somewhere with fewer walls sounds appealing right now.",
        "I wonder what I would grow if I had a little patch of land.",
        "I keep picturing a place quiet enough to hear leaves moving.",
        "A bit of wind and open space would be nice.",
        "I wonder which season I actually feel most comfortable in.",
        "I keep thinking about how different a place feels when nobody has tried to tidy it.",
        "I would not mind spending a while near water.",
        "I miss hearing ordinary outdoor sounds instead of constant voices.",
        "I wonder what kind of animal I would be happiest to see nearby.",
        "Somewhere green sounds like a good place to let my head go quiet for a bit.",
    },
}

local MOTIF_POOLS = {
    money={
        "Some extra coins would be nice right now.", "I should probably know how much coin I have.",
        "Maybe I should save a little more before spending again.", "I wonder what I own that I never actually use.",
        "I should probably keep better track of small expenses.", "Maybe I should hold onto the next bit of coin I earn.",
    },
    food={
        "I wanna eat something, but can't put my finger on it.", "I wonder what would taste good right now.",
        "Maybe I should learn one meal really well.", "I could definitely justify a snack.",
        "I wonder what I have not eaten in a long time.", "I should probably stop forgetting meals when I get busy.",
    },
    drink={
        "Maybe I should get some drinks.", "I wonder what I would order without thinking about it.",
        "I should probably drink something before I forget.", "A good drink would be nice.",
        "Maybe I should keep something decent to drink on hand.", "I wonder what drink I never get tired of.",
    },
    home={
        "A quieter life sounds tempting on some days.", "I wonder what would make a place feel properly mine.",
        "Maybe I should make my space a little more comfortable.", "I wonder what I would keep if I had a permanent home.",
        "Maybe I would actually enjoy a quieter life someday.", "I should probably fix up the place I keep returning to.",
    },
    duty={
        "One of my obligations could use attention soon.", "I wonder what responsibility I am putting off.",
        "Maybe I should finish one obligation before finding another.", "I should probably remember what I promised.",
        "I wonder if someone is counting on me for something.", "Maybe I should get the boring responsibility out of the way first.",
    },
    travel={
        "I wonder where I would go with no particular reason.", "Maybe I should take a different road next time.",
        "I wonder how many places I have only passed through.", "Maybe a change of scenery would do me good.",
        "I should probably travel a little lighter.", "I wonder what place I would return to without needing a reason.",
    },
    danger={
        "I should probably notice exits more often.", "I wonder which risk I have become too comfortable with.",
        "Maybe I should keep a backup plan.", "I should probably check my gear before trusting it.",
        "I wonder what I would do first if something went wrong.", "Maybe I should stop assuming quiet means safe.",
    },
    magic={
        "I wonder how that kind of magic actually works.", "Maybe I should learn a little more before making assumptions about it.",
        "I wonder what rule makes that possible.", "I should probably pay more attention to magical details.",
        "Maybe there is a simpler explanation for that effect.", "I wonder what part of magic is mostly practice.",
    },
    nature={
        "I could use some fresh air.", "Maybe I should spend more time somewhere green.",
        "I wonder what I could grow if I had the space.", "A long walk would probably clear my head.",
        "I should probably learn more about useful plants.", "Maybe I miss open space more than I think.",
    },
    family={
        "I should probably check in on family sometime.", "I wonder which habit of mine came from home.",
        "Maybe I should remember the stories people told me growing up.", "I wonder what my family would say about this.",
        "I should probably make time for the people who feel like family.", "Maybe I take familiar people for granted sometimes.",
    },
    work={
        "I should probably finish the small job first.", "I wonder what kind of work I actually enjoy.",
        "Maybe I need a better routine for getting things done.", "I should probably stop calling busy the same thing as useful.",
        "I wonder what task I have gotten surprisingly good at.", "Maybe I should clean up my tools before I forget.",
    },
    knowledge={
        "I should probably read more about that.", "I wonder what I only think I understand.",
        "Maybe I should ask someone who knows better.", "I wonder what fact I have been repeating without checking.",
        "I should probably keep better notes.", "Maybe I would enjoy learning something completely unrelated for once.",
    },
    freedom={
        "I could use a little more room to do things my own way.", "Maybe I should stop asking permission for harmless things.",
        "I wonder what I would choose with no expectations attached.", "I should probably keep at least one option open.",
        "Maybe I have been following a routine I do not even like.", "I wonder what I would change if nobody objected.",
    },
    justice={
        "I wonder what would actually be fair here.", "Maybe I should hear both sides before deciding.",
        "I should probably hold the same standard for everyone.", "I wonder if I am being fair or just certain.",
        "Maybe the right answer is the inconvenient one.", "I should probably remember who has the least say in this.",
    },
    revenge={
        "I do not forget things that easily.", "I wonder if they think that is settled.",
        "Maybe I should remember exactly how that happened.", "I should probably stop giving endless second chances.",
        "I wonder whether they would understand the lesson if it came back around.", "Maybe I am not ready to let that go.",
    },
    faith={
        "I wonder what I really believe when nobody is asking.", "Maybe I should think about that belief more carefully.",
        "I should probably make time for the things I consider sacred.", "I wonder which beliefs I inherited and which I chose.",
        "Maybe I should stop treating faith and certainty like the same thing.", "I wonder what gives me confidence when there is no clear answer.",
    },
    power={
        "I wonder what I could do with more influence.", "Maybe I should stop ignoring useful leverage.",
        "I should probably know who actually makes the decisions.", "I wonder what I would change if I had the authority.",
        "Maybe I should be more careful about who I depend on.", "I wonder what kind of power I would refuse even if offered.",
    },
    craft={
        "I should probably repair something before it gets worse.", "I wonder if I could make that myself.",
        "Maybe I should keep better care of my tools.", "I wonder what I could build if I had the right materials.",
        "I should probably stop saving every scrap just because it might be useful.", "Maybe I should finish one small project properly.",
    },
    medicine={
        "I should probably keep a few useful supplies nearby.", "I wonder if I know enough to handle a small injury properly.",
        "Maybe I should replace old bandages and medicine before I need them.", "I should probably pay more attention to small aches.",
        "I wonder what remedy I have been taking for granted.", "Maybe I should learn one practical medical thing I do not know yet.",
    },
    sea={
        "I wonder how long I could stay near the water without getting bored.", "Maybe I miss the sound of waves more than I think.",
        "I should probably keep my balance better than that.", "I wonder what makes one voyage feel easy and another miserable.",
        "Maybe I would enjoy being on a ship again.", "I wonder which coast I remember most clearly.",
    },
    music={
        "I wonder what song is stuck in my head.", "Maybe I should listen to some music later.",
        "I should probably learn the name of that tune someday.", "I wonder what kind of music I never get tired of.",
        "Maybe I should hum something and get it out of my system.", "I wonder which song I know far more of than I admit.",
    },
}

-- Hotfix 35: expand the ordinary inner-voice library. These are intentionally
-- plain, context-safe thoughts that do not assume gender, exact time or place.
for _,line in ipairs({
    "Did I put that where I usually put it?",
    "I should remember to check my things later.",
    "I could use a short break.",
    "Why did I walk over here again?",
    "There was a small thing I meant to do.",
    "I wonder if I am carrying too much.",
    "Maybe I should drink something.",
    "I could probably eat a little.",
    "I should stretch when I get the chance.",
    "Did I forget to bring something?",
    "I should stop putting that off.",
    "I wonder where I left that one thing.",
    "Maybe I should tidy my bag sometime.",
    "I could use a quieter minute.",
    "I wonder if I have enough supplies.",
    "I should check my pockets before I lose something.",
    "Maybe I need to sit down for a bit.",
    "I wonder what I would eat if I had to pick right now.",
    "I should probably get something to drink soon.",
    "Did I already do that?",
    "I feel like I am forgetting a small detail.",
    "I should probably replace that thing eventually.",
    "Maybe I should keep a little more coin on hand.",
    "I wonder how much junk I have collected.",
    "I need a better place for small things.",
    "I should check whether anything needs fixing.",
    "Maybe I should clean my boots sometime.",
    "I could do with a proper meal.",
    "I wonder if I locked everything up.",
    "I should probably stop carrying things I never use.",
    "Maybe I should write things down before I forget them.",
    "What was the name again?",
    "I should remember that face.",
    "Did I misunderstand something earlier?",
    "Maybe I should ask instead of guessing.",
    "I wonder if I have been standing oddly.",
    "My shoulders feel a little stiff.",
    "I should probably rest my eyes for a moment.",
    "Maybe I need some fresh air.",
    "I wonder if I am hungry or just bored.",
    "I should probably save that for later.",
    "I keep starting things before the last one is done.",
    "I wonder what I was about to say.",
    "There was a point I wanted to make.",
    "I should probably check the weather before going anywhere far.",
    "Maybe I should keep a spare of that.",
    "I wonder if that noise was always there.",
    "I should pay more attention to little details.",
    "Maybe I should stop fiddling with that.",
    "I wonder how long I have had this habit.",
    "I should probably take better care of my gear.",
    "Maybe I should find something useful to do.",
    "I wonder if I need anything before I leave.",
    "I should check my bag again later.",
    "Maybe I should keep my hands busy.",
    "I wonder if I have been sitting too long.",
    "I should probably drink more water.",
    "Maybe I could use something warm.",
    "I wonder what I would order without thinking about it.",
    "I should probably keep some food around.",
    "Maybe I am just a little tired.",
    "I wonder if I slept badly.",
    "I should probably slow down a little.",
    "Maybe I need to move around more.",
    "I wonder if I have enough coin for something unnecessary.",
    "I should probably not buy another useless thing.",
    "Maybe one useless thing would be fine.",
    "I wonder what I spend the most coin on.",
    "I should probably remember to save some.",
    "Maybe I should look through my things sometime.",
    "I wonder what I have forgotten I own.",
    "I should get rid of a few things I never use.",
    "Maybe I should keep that. It might be useful.",
    "I wonder if that is actually useful or if I just like having it.",
    "I should probably make a small list.",
    "Maybe I should do the easy thing first.",
    "I wonder what I can finish quickly.",
    "I should probably stop overcomplicating this.",
    "Maybe the simple answer is enough.",
    "I wonder if I am missing an obvious answer.",
    "I should probably ask someone who knows.",
    "Maybe I can figure it out myself.",
    "I wonder if I should say something.",
    "Maybe I should just listen for a bit.",
    "I should probably remember to ask about that.",
    "I wonder if I came across strangely.",
    "Maybe I talked too much there.",
    "Maybe I did not say enough there.",
    "I wonder if they noticed that.",
    "I should probably not read too much into it.",
    "Maybe that meant nothing.",
    "I wonder if I am making this awkward in my head.",
    "I should probably let that conversation be what it was.",
    "Maybe I should check in with someone later.",
    "I wonder who I have not spoken to in a while.",
    "I should probably remember who helped me recently.",
    "Maybe I owe someone a small favor.",
    "I wonder if someone owes me one.",
    "I should probably not forget that promise.",
    "Maybe I should deal with that before it becomes annoying.",
    "I wonder if that can wait.",
    "I should probably stop saying 'later' to everything.",
    "Maybe later is fine for this one.",
    "I wonder what I would do with a completely free day.",
    "I should probably pick up a new little hobby.",
    "Maybe I need something different to think about.",
    "I wonder what I would be unexpectedly good at.",
    "I should probably learn something practical.",
    "Maybe I should learn something completely useless.",
    "I wonder what tune is stuck in my head.",
    "I should probably stop tapping my fingers.",
    "Maybe I am more restless than I thought.",
    "I wonder if I need a change of scenery.",
    "I should probably take a different route sometime.",
    "Maybe I should go somewhere familiar instead.",
    "I wonder what place always puts me at ease.",
    "I should probably make somewhere feel more like home.",
    "Maybe I miss something familiar.",
    "I wonder what smell reminds me of home.",
    "I should probably keep one comfortable thing nearby.",
    "Maybe I just want a quiet corner.",
    "I wonder if everyone has thoughts this random.",
}) do
    POOLS.mundane[#POOLS.mundane+1]=line
end


-- Persona Beta natural-language expansion. These are deliberately ordinary,
-- low-stakes thoughts: concrete sensations, wants, memories and small curiosities.
-- They broaden repeated thoughts without turning Persona into a quote generator.
local EXTRA_NATURAL_THOUGHTS={
    mundane={
        "My shoulders feel a little stiff.","I keep noticing the weight of my bag.","I wonder whether I have anything useful tucked away that I forgot about.","My boots could probably use some attention.","I keep thinking I left some tiny thing unfinished.","I could use a few minutes with nothing demanding my attention.","My hands feel a little dry.","I wonder what I would eat if I had to pick something right now.","I keep wanting to check whether everything is still in my pockets.","I have that vague feeling that I meant to do something earlier.","I could do with a cleaner shirt.","My neck is a little tighter than I noticed a minute ago.","I wonder how much coin I actually have on me.","I keep thinking about some small thing I meant to replace.","I could use somewhere comfortable to lean for a while.","My feet are starting to notice how long I have been standing.","I wonder if I packed anything I actually want to eat.","I keep remembering chores at the least useful times.","I feel like I have one loose thread of a thought I cannot quite catch.","I could probably use a stretch.","I wonder whether I have been carrying something I do not need.","I keep thinking about reorganizing my things and never doing it.","My eyes could use a short break.","I have a vague craving for something salty.","I wonder where I put that thing I was thinking about earlier.",
    },
    reflective={
        "That little detail keeps coming back to me.","I keep remembering the same expression for some reason.","I wonder why that bothered me more than the rest of it.","Something about that still feels unfinished in my head.","I keep replaying one small part and skipping over the rest.","I thought that would leave my mind faster than it has.","I wonder whether I understood that the way it was meant.","That memory feels different every time I come back to it.","I keep noticing new little details when I think about that.","I am not sure why my mind picked that part to hold onto.","Something I dismissed earlier feels a little more important now.","I keep circling the same question without finding anything new in it.","I wonder whether I was more affected by that than I realized.","That is still sitting somewhere in the back of my head.","I keep thinking about how ordinary that moment felt at the time.","I wonder what I would remember first if somebody asked me about it.","A tiny part of that has stayed surprisingly clear.","I keep coming back to the tone more than the words.","I wonder why some things stick and others disappear almost immediately.","That thought keeps returning whenever things get quiet.",
    },
    social={
        "I wonder who I would actually enjoy seeing right now.","There are a couple of people I have not crossed paths with in a while.","I keep wondering what an old familiar face is doing these days.","I would not mind a conversation that does not need to go anywhere.","I wonder who would make this silence feel less empty.","I keep thinking there is somebody I have not heard from lately.","A familiar voice would be nice right now.","I wonder who I would notice first in a crowded room.","There are people I only seem to think about when things get quiet.","I would not mind running into somebody I already know.","I wonder who would understand what I mean without much explaining.","I keep remembering little bits of old conversations.","Some people are easier to miss than I expect.","I wonder whether anybody familiar is nearby.","I could use a face I do not have to figure out from scratch.","I keep thinking about people I have not seen enough lately.","I wonder whose company would feel easiest right now.","I miss having someone familiar to exchange a look with.","I wonder who I would be happiest to bump into by accident.",
    },
    comfort={
        "Something warm to drink sounds good.","I could go for a proper meal.","A comfortable chair sounds unusually appealing.","I would not mind somewhere quiet for a few minutes.","Something sweet would be nice.","I could use a little warmth.","A cool drink sounds good right now.","I would happily trade a bit of noise for somewhere calmer.","I keep thinking about food even though I cannot decide what kind.","A clean bed sounds very good right now.","I could use a slow meal instead of eating in a hurry.","Something familiar to eat would hit the spot.","I would not mind taking my boots off for a while.","A little shade would be nice.","I keep thinking about finding somewhere softer to sit.","A few quiet minutes and something to drink would do nicely.","I could use a bit of fresh air.","Somewhere warm and dry sounds good.","I would not say no to a snack.","I keep thinking about the last really good meal I had.",
    },
    curious={
        "I wonder what that is actually made of.","I keep wanting to know how that works.","There is probably some very ordinary explanation I have never heard.","I wonder how long people have been doing that.","Something about that detail keeps catching my attention.","I would like to hear somebody explain that properly.","I wonder what I would notice if I looked at it up close.","I keep thinking there must be a reason for that little difference.","I wonder who first figured that out.","There is something there I do not quite understand yet.","I keep wanting to ask where that came from.","I wonder what the boring answer is, not just the interesting one.","That looks like the sort of thing I could lose an hour learning about.","I keep noticing one detail I cannot explain.","I wonder whether that is difficult or just unfamiliar.","There is probably more history behind that than I know.","I keep thinking about how somebody learned to do that the first time.","I wonder what I am missing because I do not know the right question.","That has made me curious enough to remember it later.","I would not mind knowing a little more about that.",
    },
    restless={
        "I feel like walking somewhere, even without a destination.","My hands want something to do.","I could use a change of scenery.","I keep looking for something small to occupy myself with.","Standing around is starting to feel a little stale.","I feel like taking the long way somewhere.","I could go for a short walk.","I keep wanting to move even though there is no real reason to.","I would not mind finding a small task to disappear into.","My attention keeps drifting toward anything that looks different.","I feel like doing something with my hands for a while.","I could use a little noise or movement around me.","I keep shifting without realizing it.","I would not mind wandering until something catches my interest.","There is a little too much unused energy sitting in me right now.","I keep thinking about finding something simple to do.","I feel like getting up and changing where I am standing.","I could use something new to look at.","My attention is getting bored before the rest of me is.","I keep waiting for something to happen and noticing the waiting.",
    },
    guarded={
        "I am still not sure what I make of that.","Something about that wording keeps bothering me.","I keep wondering what part of that I did not hear.","I am not completely comfortable with how easy that sounded.","There is a little bit of doubt still sitting there.","I keep noticing that I have not quite relaxed about that yet.","Something in that exchange still feels slightly off to me.","I wonder whether I am missing a piece of the story.","I keep thinking about the part that was left unsaid.","I am not ready to feel certain about that yet.","That was easy enough to hear and harder to believe.","I keep remembering the pause before the answer.","There is still a small question mark hanging over that.","I wonder why I did not feel entirely comfortable with that.","Some part of me is still watching that a little closely.","I keep thinking about whether the story fits together as neatly as it sounded.","That detail has not stopped feeling strange yet.","I am still a little wary of how simple that explanation was.","I keep thinking there was more going on there than I caught.","Something about that has not earned my full trust yet.",
    },
    ambitious={
        "I keep thinking about what I could get better at next.","There is something satisfying about making visible progress.","I would like to have one thing I can point to and say I improved it.","I keep wondering what I could finish if I gave it a proper stretch of attention.","I feel like putting some effort into something that actually matters to me.","There are a few things I would like to be better at than I am now.","I keep thinking about what I could build on from here.","I would like a clearer sense that I am moving somewhere.","Something in me wants a project with a real finish line.","I keep wondering what skill would be worth sharpening next.","I would not mind having something concrete to work toward.","I keep thinking about the things I am almost good at.","There is one part of me that gets restless when nothing is improving.","I would like to make a little more of what I already know.","I keep thinking about what would feel like real progress instead of just activity.",
    },
}
for category,rows in pairs(EXTRA_NATURAL_THOUGHTS)do
    if type(POOLS[category])=="table"then for _,line in ipairs(rows)do POOLS[category][#POOLS[category]+1]=line end end
end

RPAL.PERSONALITY_FALLBACK_THOUGHTS = POOLS.mundane

local THEME_WORDS = {
    money={"coin","coins","money","gold","wealth","rich","merchant","trade","profit","paid","payment","fortune"},
    food={"food","eat","meal","cook","cooking","hungry","snack","baker","bread","meat","fruit"},
    drink={"drink","drinks","ale","wine","tea","coffee","tavern","beer","whiskey","whisky"},
    home={"home","farm","house","settle","cottage","homestead","room","apartment"},
    duty={"duty","honor","honour","responsibility","oath","serve","service","obligation","promise","discipline"},
    travel={"travel","road","wander","explore","journey","sail","adventure","voyage","caravan"},
    danger={"danger","guard","soldier","war","fight","combat","cautious","paranoid","risk","survival","weapon"},
    magic={"magic","arcane","mage","spell","sorcery","fel","void","light","wizard","enchant","rune"},
    nature={"nature","forest","woods","tree","trees","druid","animal","animals","herb","garden","wild","flower"},
    family={"family","parent","mother","father","sibling","brother","sister","kin"},
    work={"work","craft","job","smith","doctor","healer","engineer","profession","business","labor","labour"},
    knowledge={"knowledge","book","books","read","study","scholar","learn","history","research","library"},
    freedom={"freedom","free","independent","independence","choice","liberty","wanderer","renegade","rebel"},
    justice={"justice","fair","fairness","law","right","wrong","protect","innocent","guilty"},
    revenge={"revenge","vengeance","grudge","payback","retaliation","betray","betrayed"},
    faith={"faith","believe","belief","prayer","pray","religion","sacred","temple","church","god","gods"},
    power={"power","authority","control","influence","command","leader","leadership","rank","status"},
    craft={"craft","build","make","smith","forge","sew","tailor","engineer","woodwork","repair","tools"},
    medicine={"medicine","medical","doctor","healer","heal","injury","wound","bandage","herb","remedy"},
    sea={"sea","ocean","ship","sail","sailor","navy","harbor","harbour","dock","coast","island"},
    music={"music","song","sing","singer","instrument","lute","violin","drum","melody","tune"},
}

local CATEGORY_LEXICON = {
    kind={"kind","kindhearted","gentle","helpful","caring","compassionate","generous","protective","altruistic","patient"},
    selfish={"selfish","greedy","self-centered","self centred","opportunistic","materialistic","stingy","possessive"},
    guarded={"guarded","cautious","careful","suspicious","paranoid","distrustful","watchful","reserved","private"},
    ambitious={"ambitious","driven","competitive","determined","goal-oriented","goal oriented","aspiring","power-hungry","power hungry"},
    restless={"restless","impatient","energetic","fidgety","adventurous","spontaneous"},
    chaotic={"reckless","chaotic","impulsive","unpredictable","mischievous","wild"},
    curious={"curious","inquisitive","scholarly","studious","observant","analytical","clever","bookish"},
    forgiving={"forgiving","merciful","lenient","understanding","patient"},
    vindictive={"vindictive","vengeful","spiteful","resentful","grudge","unforgiving"},
    dutiful={"dutiful","lawful","disciplined","reliable","responsible","honorable","honourable","proper","loyal"},
    rebellious={"rebellious","renegade","defiant","independent","rule-breaking","rule breaking","unruly","anti-authority","anti authority"},
    arcane={"arcane","magical","mage","wizard","scholar of magic","spellcaster"},
    nature={"natural","nature-loving","nature loving","druidic","outdoorsy","wilds","forest"},
    social={"social","friendly","talkative","outgoing","chatty","gregarious"},
    reflective={"reflective","thoughtful","introspective","pensive","self-aware","self aware"},
    practical={"practical","pragmatic","organized","organised","methodical","efficient","resourceful"},
}

local LIKE_STARTERS = {"likes ","loves ","enjoys ","prefers ","is fond of ","cares about "}
local AVOID_STARTERS = {"hates ","dislikes ","avoids ","fears ","distrusts ","cannot stand ","can't stand "}
local GOAL_STARTERS = {"wants to ","wants ","hopes to ","hopes ","dreams of ","aims to ","plans to ","tries to "}
local VALUE_STARTERS = {"values ","believes in ","stands for ","cares deeply about ","prioritizes ","prioritises "}

local briefCacheText, briefCacheValue = nil, nil

local function wordFound(text, word)
    if text=="" or word=="" then return false end
    local start = 1
    while true do
        local a,b = text:find(word,start,true)
        if not a then return false end
        local before = a<=1 and " " or text:sub(a-1,a-1)
        local after = b>=#text and " " or text:sub(b+1,b+1)
        local leftOK = not before:match("[%w_]")
        local rightOK = not after:match("[%w_]")
        if leftOK and rightOK then return true end
        start = b+1
    end
end

local function collectPhrase(sentence, starters, output)
    local lower = sentence:lower()
    for _,starter in ipairs(starters) do
        local at = lower:find(starter,1,true)
        if at then
            local value = trim(sentence:sub(at+#starter))
            value = value:gsub("[,;].*$","")
            local lowerValue=value:lower()
            local clauseCuts={" but "," and wants "," and hopes "," and dreams "," and aims "," and plans "," and likes "," and loves "," and enjoys "," and hates "," and dislikes "," and avoids "," and fears "," and values "," and believes "}
            local cut=nil
            for _,marker in ipairs(clauseCuts) do local pos=lowerValue:find(marker,1,true);if pos and (not cut or pos<cut) then cut=pos end end
            if cut then value=value:sub(1,cut-1) end
            value = trim(value):sub(1,58)
            if value~="" then
                local exists=false
                for _,v in ipairs(output) do if v:lower()==value:lower() then exists=true break end end
                if not exists then output[#output+1]=value end
            end
            return true
        end
    end
    return false
end

local function splitSentences(text)
    local out = {}
    text=tostring(text or ""):gsub("\r","\n")
    for sentence in text:gmatch("[^%.%!%?\n]+") do
        sentence=trim(sentence)
        if sentence~="" then out[#out+1]=sentence end
    end
    return out
end

local function analyseBriefText(text)
    text = trim(text):sub(1,1800)
    if briefCacheText==text and briefCacheValue then return briefCacheValue end
    local lower = text:lower()
    local analysis = {
        text=text, themes={}, themeScores={}, themePolarity={}, categoryBias={}, likes={}, avoids={}, goals={}, values={},
        signals={}, sentenceCount=0, matchCount=0, confidence=0,
    }
    local sentences = splitSentences(text)
    analysis.sentenceCount=#sentences

    for theme,words in pairs(THEME_WORDS) do
        local score=0
        for _,word in ipairs(words) do if wordFound(lower,word) then score=score+1 end end
        if score>0 then
            analysis.themeScores[theme]=score
            analysis.themes[#analysis.themes+1]=theme
            analysis.matchCount=analysis.matchCount+score
        end
    end
    for category,words in pairs(CATEGORY_LEXICON) do
        local score=0
        for _,word in ipairs(words) do
            if wordFound(lower,word) then
                local negated = lower:find("not "..word,1,true) or lower:find("never "..word,1,true)
                score=score+(negated and -0.7 or 1)
                analysis.matchCount=analysis.matchCount+1
            end
        end
        if score~=0 then analysis.categoryBias[category]=score end
    end

    for _,sentence in ipairs(sentences) do
        if collectPhrase(sentence,LIKE_STARTERS,analysis.likes) then analysis.matchCount=analysis.matchCount+1 end
        if collectPhrase(sentence,AVOID_STARTERS,analysis.avoids) then analysis.matchCount=analysis.matchCount+1 end
        if collectPhrase(sentence,GOAL_STARTERS,analysis.goals) then analysis.matchCount=analysis.matchCount+1 end
        if collectPhrase(sentence,VALUE_STARTERS,analysis.values) then analysis.matchCount=analysis.matchCount+1 end
    end

    -- Likes/dislikes/goals/values are not just displayed back to the player:
    -- they change theme polarity. A character who "hates magic" should not be
    -- fed the same magic-thought pool as a character who "loves magic".
    local themeSet={}
    for _,key in ipairs(analysis.themes) do themeSet[key]=true end
    local function phraseThemes(phrase,delta)
        local l=tostring(phrase or ""):lower()
        for theme,words in pairs(THEME_WORDS) do
            for _,word in ipairs(words) do
                if wordFound(l,word) then
                    analysis.themeScores[theme]=(analysis.themeScores[theme] or 0)+math.abs(delta)
                    analysis.themePolarity[theme]=(analysis.themePolarity[theme] or 0)+delta
                    if not themeSet[theme] then analysis.themes[#analysis.themes+1]=theme;themeSet[theme]=true end
                    break
                end
            end
        end
    end
    for _,v in ipairs(analysis.likes) do phraseThemes(v,1.0) end
    for _,v in ipairs(analysis.avoids) do phraseThemes(v,-1.25) end
    for _,v in ipairs(analysis.goals) do phraseThemes(v,.70) end
    for _,v in ipairs(analysis.values) do phraseThemes(v,.85) end
    table.sort(analysis.themes,function(a,b)
        local sa,sb=analysis.themeScores[a] or 0,analysis.themeScores[b] or 0
        if sa==sb then return a<b end
        return sa>sb
    end)

    -- Phrase semantics feed categories as small, understandable nudges.
    local function bump(cat,amount) analysis.categoryBias[cat]=(analysis.categoryBias[cat] or 0)+amount end
    for _,v in ipairs(analysis.values) do
        local l=v:lower()
        if l:find("family",1,true) or l:find("friend",1,true) or l:find("help",1,true) then bump("kind",1.4) end
        if l:find("freedom",1,true) or l:find("independ",1,true) then bump("rebellious",1.2) end
        if l:find("duty",1,true) or l:find("honor",1,true) or l:find("honour",1,true) or l:find("law",1,true) then bump("dutiful",1.2) end
        if l:find("coin",1,true) or l:find("money",1,true) or l:find("wealth",1,true) then bump("ambitious",.8) end
    end
    for _,v in ipairs(analysis.avoids) do
        local l=v:lower()
        if l:find("magic",1,true) or l:find("arcane",1,true) then bump("arcane",-1.2);bump("nature",.4) end
        if l:find("people",1,true) or l:find("crowd",1,true) then bump("social",-.9);bump("guarded",.6) end
        if l:find("rule",1,true) or l:find("authority",1,true) then bump("rebellious",.9) end
    end
    for _,v in ipairs(analysis.goals) do
        local l=v:lower();bump("ambitious",.45)
        if l:find("settle",1,true) or l:find("farm",1,true) or l:find("home",1,true) then analysis.themeScores.home=(analysis.themeScores.home or 0)+1 end
        if l:find("learn",1,true) or l:find("study",1,true) then bump("curious",.8) end
    end

    local signalList={}
    for cat,score in pairs(analysis.categoryBias) do
        if math.abs(score)>=.7 then signalList[#signalList+1]={name=cat,score=score} end
    end
    table.sort(signalList,function(a,b)return math.abs(a.score)>math.abs(b.score) end)
    for i=1,math.min(6,#signalList) do
        local row=signalList[i]
        analysis.signals[#analysis.signals+1]=(row.score<0 and "less " or "")..row.name
    end
    local words=0
    for _ in lower:gmatch("[%w']+") do words=words+1 end
    analysis.confidence=clamp(math.floor((math.min(1,analysis.matchCount/10)*65 + math.min(1,words/80)*35)+.5),0,100)
    briefCacheText,briefCacheValue=text,analysis
    return analysis
end

function RPAL.AnalyzePersonalityBriefText(text)
    return analyseBriefText(text)
end

local function ensureData()
    local roleplay = RPAL.GetRoleplayData and RPAL.GetRoleplayData() or (RPAL.char and RPAL.char.roleplay)
    if not roleplay then return nil end
    local p = type(roleplay.personality)=="table" and roleplay.personality or {}
    roleplay.personality = p

    local oldVersion=tonumber(p.version) or 0
    -- Persona is character-scoped opt-in. Existing calibrated characters are
    -- grandfathered in; untouched/reset characters begin at the introduction.
    if p.optedIn==nil then
        p.optedIn=(type(p.learning)=="table" and p.learning.calibrated==true) and true or false
    end
    if p.enabled==nil then p.enabled=true end
    local personaSettings=RPAL.GetSettings and RPAL.GetSettings() or nil
    if personaSettings and personaSettings.personaEnabled==false then p.enabled=false
    elseif personaSettings and personaSettings.personaEnabled~=false then p.enabled=true end
    p.alignment = type(p.alignment)=="table" and p.alignment or {good=0.34,neutral=0.46,evil=0.20}
    p.alignment.good = clamp(p.alignment.good,0,1)
    p.alignment.neutral = clamp(p.alignment.neutral,0,1)
    p.alignment.evil = clamp(p.alignment.evil,0,1)
    local total = p.alignment.good+p.alignment.neutral+p.alignment.evil
    if total<=0 then p.alignment.good,p.alignment.neutral,p.alignment.evil,total=0.34,0.46,0.20,1 end
    p.alignment.good,p.alignment.neutral,p.alignment.evil=p.alignment.good/total,p.alignment.neutral/total,p.alignment.evil/total

    p.traits = type(p.traits)=="table" and p.traits or {}
    if oldVersion<2 and type(p.facets)=="table" then
        -- Preserve the spirit of Hotfix 33 personalities without exposing the
        -- old six sliders. The new spectra are the canonical model from v2 on.
        local f=p.facets
        if p.traits.altruisticSelfish==nil then p.traits.altruisticSelfish=clamp(100-(tonumber(f.warmth) or 55),0,100) end
        if p.traits.forgivingVindictive==nil then p.traits.forgivingVindictive=clamp(25+((tonumber(f.ambition) or 45)*.18)+((tonumber(f.caution) or 50)*.12),0,100) end
        if p.traits.renegadeParagon==nil then p.traits.renegadeParagon=clamp(50+((tonumber(f.caution) or 50)-50)*.35-((tonumber(f.impulse) or 45)-50)*.45,0,100) end
    end
    for key,value in pairs(DEFAULT_TRAITS) do p.traits[key]=clamp(p.traits[key]~=nil and p.traits[key] or value,0,100) end

    p.description = trim(p.description):sub(1,1800)
    p.customThoughts = type(p.customThoughts)=="table" and p.customThoughts or {}
    p.autonomy = type(p.autonomy)=="table" and p.autonomy or {}
    if p.autonomy.scene==nil and p.autonomy.session~=nil then p.autonomy.scene=p.autonomy.session end
    if p.autonomy.scene==nil then p.autonomy.scene=true end
    p.autonomy.session=p.autonomy.scene
    if p.autonomy.social==nil then p.autonomy.social=true end
    if p.autonomy.ambient==nil then p.autonomy.ambient=false end
    if p.autonomy.needs==nil then p.autonomy.needs=true end
    if p.autonomy.memory==nil then p.autonomy.memory=true end
    if p.autonomy.brief==nil then p.autonomy.brief=false end -- legacy Character Brief influence; UI removed in v3
    if p.autonomy.custom==nil then p.autonomy.custom=true end
    if p.autonomy.learning==nil then p.autonomy.learning=true end
    if p.autonomy.learningInsights==nil then p.autonomy.learningInsights=true end
    if p.autonomy.onlineReactions==nil then p.autonomy.onlineReactions=true end
    if oldVersion<4 then
        -- Hotfix 36: after calibration, Persona is an autonomous read-only system.
        -- Preserve learned data, but retire manual autonomy/custom-output controls.
        p.autonomy.scene=true
        p.autonomy.session=true
        p.autonomy.social=true
        p.autonomy.ambient=false
        p.autonomy.needs=true
        p.autonomy.memory=true
        p.autonomy.brief=false
        p.autonomy.custom=false
        p.autonomy.learning=true
        p.autonomy.learningInsights=true
        p.autonomy.onlineReactions=true
        p.autonomy.frequency="balanced"
    end
    local freq=p.autonomy.frequency
    if freq~="rare" and freq~="quiet" and freq~="balanced" and freq~="active" and freq~="expressive" then p.autonomy.frequency="balanced" end

    p.state = type(p.state)=="table" and p.state or {}
    p.state.appetite=clamp(p.state.appetite or 0.34,0,1)
    p.state.restlessness=clamp(p.state.restlessness or 0.30,0,1)
    p.state.vigilance=clamp(p.state.vigilance or 0.35,0,1)
    p.state.connection=clamp(p.state.connection or 0.45,0,1)
    p.state.reflection=clamp(p.state.reflection or 0.45,0,1)
    p.state.lastAt=tonumber(p.state.lastAt) or time()
    p.history=type(p.history)=="table" and p.history or {}
    p.version=VERSION
    return p
end

function RPAL.GetPersonalityData() return ensureData() end

function RPAL.IsPersonaOptedIn()
    local p=ensureData()
    return p and p.optedIn==true or false
end

function RPAL.EnablePersonaForCharacter()
    local p=ensureData();if not p then return false end
    p.optedIn=true;p.enabled=true
    local settings=RPAL.GetSettings and RPAL.GetSettings() or nil
    if settings then settings.personaEnabled=true end
    RPAL._sceneSparkNextAt=nil;RPAL._personalityAmbientNextAt=nil
    return true
end

function RPAL.IsPersonaSystemEnabled()
    -- This function sits directly on several CHAT_MSG hot paths. Do not call
    -- ensureData()/GetSettings() here: those normalize a large character model
    -- and were being paid multiple times for every RP line even when Persona was
    -- disabled. Read the already-initialized state only.
    local settings=RPAL.db and RPAL.db.settings or nil
    if settings and settings.personaEnabled==false then return false end
    local roleplay=RPAL.GetRoleplayData and RPAL.GetRoleplayData() or (RPAL.char and RPAL.char.roleplay)
    local p=roleplay and roleplay.personality or nil
    if not p or p.enabled==false or p.optedIn~=true then return false end
    -- Once PersonaLearning is loaded, calibration is a hard gate. Nothing from
    -- Persona should learn, think or animate before calibration is complete.
    if RPAL.IsPersonalityCalibrated and not RPAL.IsPersonalityCalibrated() then return false end
    return true
end

local personaWorkQueue={}
local personaWorkHead=1
local personaWorkTail=0
local personaWorkFrame=CreateFrame("Frame")
personaWorkFrame:Hide()
RPAL._personaWorkPending=0

local function ResetPersonaWorkQueue()
    personaWorkQueue={}
    personaWorkHead=1
    personaWorkTail=0
    RPAL._personaWorkPending=0
    personaWorkFrame:Hide()
end
RPAL.ClearPersonaWorkQueue=ResetPersonaWorkQueue

function RPAL.QueuePersonaWork(tag,fn)
    if type(fn)~="function" then return false end
    if RPAL.IsPersonaSystemEnabled and not RPAL.IsPersonaSystemEnabled() then return false end
    -- Hard ceiling prevents a crowded event from creating an unbounded backlog.
    -- At 60 FPS this still permits roughly 60 Persona jobs/second while keeping
    -- synchronous CHAT_MSG delivery free from the expensive classifiers.
    local pending=personaWorkTail-personaWorkHead+1
    if pending>=80 then
        RPAL._perfStats=RPAL._perfStats or {}
        RPAL._perfStats.personaQueueDrops=(RPAL._perfStats.personaQueueDrops or 0)+1
        return false
    end
    personaWorkTail=personaWorkTail+1
    personaWorkQueue[personaWorkTail]={tag=tag or"persona",fn=fn}
    RPAL._personaWorkPending=personaWorkTail-personaWorkHead+1
    personaWorkFrame:Show()
    return true
end

personaWorkFrame:SetScript("OnUpdate",function(self)
    local job=personaWorkQueue[personaWorkHead]
    if not job then ResetPersonaWorkQueue();return end
    personaWorkQueue[personaWorkHead]=nil
    personaWorkHead=personaWorkHead+1
    RPAL._personaWorkPending=math.max(0,personaWorkTail-personaWorkHead+1)
    if RPAL.IsPersonaSystemEnabled and not RPAL.IsPersonaSystemEnabled() then
        ResetPersonaWorkQueue();return
    end
    local profiler=debugprofilestop
    local started=profiler and profiler() or 0
    local ok,err=pcall(job.fn)
    local elapsed=profiler and (profiler()-started) or 0
    RPAL._perfStats=RPAL._perfStats or {}
    local ps=RPAL._perfStats
    ps.personaJobs=(ps.personaJobs or 0)+1
    ps.personaLastMs=elapsed
    ps.personaMaxMs=math.max(tonumber(ps.personaMaxMs)or 0,elapsed)
    if not ok then
        ps.personaJobErrors=(ps.personaJobErrors or 0)+1
        if RPAL.DebugLog then pcall(RPAL.DebugLog,"Persona queued work failed: "..tostring(err)) end
    end
    if personaWorkHead>personaWorkTail then ResetPersonaWorkQueue() end
end)

function RPAL.SyncPersonaEventRegistrations(enabled)
    if enabled==nil then enabled=RPAL.IsPersonaSystemEnabled and RPAL.IsPersonaSystemEnabled() or false end
    for _,name in ipairs({"SetPersonaLearningEventsEnabled","SetPersonaContinuityEventsEnabled","SetPersonaCognitionEventsEnabled"}) do
        local fn=RPAL[name]
        if type(fn)=="function" then pcall(fn,enabled and true or false) end
    end
    return enabled and true or false
end

function RPAL.SetPersonaSystemEnabled(enabled)
    enabled=enabled and true or false
    local settings=RPAL.GetSettings and RPAL.GetSettings() or nil
    if settings then settings.personaEnabled=enabled end
    local p=ensureData()
    if p then p.enabled=enabled end
    if not enabled then
        RPAL._sceneSparkNextAt=nil
        RPAL._personalityAmbientNextAt=nil
        if RPAL.ClearPersonaWorkQueue then RPAL.ClearPersonaWorkQueue() end
    end
    -- Persona OFF now means OFF at the event layer too: chat/target/addon hooks
    -- are unregistered rather than waking up merely to discover they are off.
    if RPAL.SyncPersonaEventRegistrations then RPAL.SyncPersonaEventRegistrations(enabled) end
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return enabled
end

function RPAL.PersonalityWeightsToPoint(good,neutral,evil)
    good,neutral,evil=tonumber(good) or 0,tonumber(neutral) or 0,tonumber(evil) or 0
    local sum=good+neutral+evil
    if sum<=0 then good,neutral,evil,sum=.34,.46,.20,1 end
    good,neutral,evil=good/sum,neutral/sum,evil/sum
    -- Upright triangle: Neutral at the top, Good lower-left, Evil lower-right.
    return (neutral*.50)+(good*.08)+(evil*.92), (neutral*.08)+(good*.88)+(evil*.88)
end

function RPAL.PersonalityPointToWeights(x,y)
    x,y=clamp(x,0,1),clamp(y,0,1)
    -- Project any cursor point to the closest valid horizontal slice of the
    -- triangle before turning it into barycentric weights. This keeps the core
    -- under the mouse even when the user drags outside the visible edges.
    local neutral=clamp((.88-y)/.80,0,1)
    local lower=1-neutral
    local half=.42*lower
    local minX=.50-half
    local maxX=.50+half
    if maxX>minX then x=clamp(x,minX,maxX) else x=.50 end
    local evil=0
    if lower>.0001 and maxX>minX then evil=lower*((x-minX)/(maxX-minX)) end
    evil=clamp(evil,0,lower)
    local good=lower-evil
    local sum=good+neutral+evil
    if sum<=0 then return .34,.46,.20 end
    return good/sum,neutral/sum,evil/sum
end

function RPAL.SetPersonalityAlignment(good,neutral,evil,silent)
    local p=ensureData();if not p then return false end
    local sum=(tonumber(good) or 0)+(tonumber(neutral) or 0)+(tonumber(evil) or 0)
    if sum<=0 then return false end
    p.alignment.good=clamp((tonumber(good) or 0)/sum,0,1)
    p.alignment.neutral=clamp((tonumber(neutral) or 0)/sum,0,1)
    p.alignment.evil=clamp((tonumber(evil) or 0)/sum,0,1)
    if not silent and RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

function RPAL.SetPersonalityTrait(key,value,silent)
    local p=ensureData();key=tostring(key or "")
    if not p or DEFAULT_TRAITS[key]==nil then return false end
    p.traits[key]=clamp(value,0,100)
    if not silent and RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

-- Compatibility for any Hotfix 33 code still calling the old facet setter.
function RPAL.SetPersonalityFacet(key,value,silent)
    local map={warmth="altruisticSelfish",caution="renegadeParagon",ambition="forgivingVindictive",impulse="renegadeParagon"}
    local target=map[tostring(key or "")]
    if not target then return false end
    local v=tonumber(value) or 50
    if key=="warmth" then v=100-v end
    if key=="impulse" then v=100-v end
    return RPAL.SetPersonalityTrait(target,v,silent)
end

function RPAL.SetPersonalityDescription(text)
    local p=ensureData();if not p then return false end
    p.description=trim(text):sub(1,1800)
    briefCacheText,briefCacheValue=nil,nil
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

function RPAL.AddPersonalityCustomThought(text)
    local p=ensureData();text=trim(text)
    if not p or text=="" then return false,"Write a thought first." end
    text=text:sub(1,220)
    for _,existing in ipairs(p.customThoughts) do if tostring(existing):lower()==text:lower() then return false,"That thought already exists." end end
    if #p.customThoughts>=60 then return false,"Maximum 60 custom thoughts." end
    p.customThoughts[#p.customThoughts+1]=text
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

function RPAL.DeletePersonalityCustomThought(index)
    local p=ensureData();index=math.floor(tonumber(index) or 0)
    if not p or index<1 or not p.customThoughts[index] then return false end
    table.remove(p.customThoughts,index)
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

function RPAL.GetPersonalityBriefAnalysis()
    local p=ensureData();if not p then return analyseBriefText("") end
    return analyseBriefText(p.description or "")
end

function RPAL.GetPersonalityDetectedMotifs()
    local a=RPAL.GetPersonalityBriefAnalysis();local out={}
    for _,key in ipairs(a and a.themes or {}) do out[#out+1]=key end
    return out
end

local function categoryWeights(p,context)
    local t=p.traits or DEFAULT_TRAITS
    local a=p.alignment
    if RPAL.GetEffectivePersonalityAlignment then
        local learned=RPAL.GetEffectivePersonalityAlignment()
        if learned then a=learned end
    end
    local s=p.state
    local function tv(key)
        if RPAL.GetEffectivePersonalityTrait then return clamp((RPAL.GetEffectivePersonalityTrait(key) or 50)/100,0,1) end
        return clamp((t[key] or 50)/100,0,1)
    end
    local lawful=tv("chaoticLawful");local chaotic=1-lawful
    local vindictive=tv("forgivingVindictive");local forgiving=1-vindictive
    local selfish=tv("altruisticSelfish");local altruistic=1-selfish
    local deceitful=tv("truthfulDeceitful");local truthful=1-deceitful
    local brutal=tv("gentleBrutal");local gentle=1-brutal
    local rational=tv("superstitiousRational");local superstitious=1-rational
    local paragon=tv("renegadeParagon");local renegade=1-paragon
    local impulsive=tv("cautiousImpulsive");local cautious=1-impulsive
    local bonvivant=tv("asceticBonVivant");local ascetic=1-bonvivant
    local spineless=tv("valorousSpineless");local valorous=1-spineless
    local extroverted=tv("introvertedExtroverted");local introverted=1-extroverted
    local function assoc(key)
        if RPAL.GetPersonalityAssociationWeight then return tonumber(RPAL.GetPersonalityAssociationWeight(key)) or 0 end
        return 0
    end
    local magicLike=math.max(0,assoc("magic"));local natureLike=math.max(0,assoc("nature"))
    local drinkLike=math.max(0,assoc("drink"));local foodLike=math.max(0,assoc("food"));local moneyLike=math.max(0,assoc("money"))
    local survivalFood,survivalWater=nil,nil
    local settings=RPAL.GetSettings and RPAL.GetSettings() or nil
    if settings and settings.survivalEnabled and RPAL.GetSurvivalState then
        local ok,state=pcall(RPAL.GetSurvivalState)
        if ok and type(state)=="table" then
            survivalFood=tonumber(state.food)
            survivalWater=tonumber(state.water)
        end
    end
    local hunger=survivalFood and clamp((55-survivalFood)/55,0,1) or 0
    local thirst=survivalWater and clamp((55-survivalWater)/55,0,1) or 0

    local w={
        mundane=2.55,
        reflective=.46+s.reflection*.38+introverted*.20+superstitious*.12,
        social=.46+s.connection*.40+extroverted*.74-introverted*.12,
        comfort=.68+s.appetite*.72+bonvivant*.38+foodLike*.24+drinkLike*.22+hunger*.95+thirst*1.12,
        practical=.72+a.neutral*.28+lawful*.22+rational*.38+cautious*.20+ascetic*.12,
        curious=.54+rational*.24+magicLike*.34+natureLike*.12,
        restless=.36+s.restlessness*.58+renegade*.16+impulsive*.46,
        kind=.20+a.good*.58+altruistic*.90+gentle*.48+forgiving*.18,
        guarded=.20+s.vigilance*.58+a.evil*.12+vindictive*.18+cautious*.42+introverted*.16+deceitful*.12,
        ambitious=.18+selfish*.34+a.evil*.16+deceitful*.16+moneyLike*.18,
        selfish=.06+selfish*.95+a.evil*.20,
        chaotic=.05+chaotic*.72+impulsive*.40+renegade*.18,
        forgiving=.10+forgiving*.88+a.good*.18+gentle*.14,
        vindictive=.05+vindictive*.90+a.evil*.22+brutal*.12,
        dutiful=.12+lawful*.48+paragon*.72+truthful*.10+a.good*.08,
        rebellious=.08+renegade*.78+chaotic*.24,
        arcane=.05+magicLike*.90,
        nature=.05+natureLike*.90,
    }

    if context=="social" then w.social=w.social+.62+extroverted*.20;w.kind=w.kind+.18;w.guarded=w.guarded+.12 end
    if context=="ambient" then w.mundane=w.mundane+.95;w.comfort=w.comfort+.32;w.restless=w.restless+.16 end
    if context=="scene" then w.mundane=w.mundane+.42;w.practical=w.practical+.10;w.social=w.social+.10 end

    if p.autonomy.needs==false then
        w.comfort=.68+bonvivant*.30;w.restless=.36+impulsive*.30;w.guarded=math.max(.20,w.guarded-s.vigilance*.58);w.social=math.max(.42,w.social-s.connection*.40);w.reflective=.46+introverted*.18
    end

    if RPAL.ApplyLearnedAssociationCategoryWeights then RPAL.ApplyLearnedAssociationCategoryWeights(w) end

    if p.autonomy.memory~=false and #p.history>0 then
        local last=p.history[#p.history]
        if last and last.category and w[last.category] then w[last.category]=w[last.category]+.26 end
    end

    for key,value in pairs(w) do w[key]=math.max(.02,value) end
    return w
end

local function weightedKey(map)
    local total=0
    for _,v in pairs(map or {}) do total=total+math.max(0,tonumber(v) or 0) end
    if total<=0 then return nil end
    local roll=math.random()*total
    for key,v in pairs(map) do
        roll=roll-math.max(0,tonumber(v) or 0)
        if roll<=0 then return key end
    end
    return next(map)
end

local function recentTextMap(p)
    local seen={}
    local start=math.max(1,#p.history-79)
    for i=start,#p.history do
        local row=p.history[i]
        if type(row)=="table" then
            if row.text then seen[tostring(row.text)]=true end
            if row.rawText then seen[tostring(row.rawText)]=true end
        end
    end
    return seen
end

local function evolveState(p)
    if p.autonomy.needs==false then return end
    local s=p.state
    local now=time()
    local elapsed=math.max(0,now-(tonumber(s.lastAt) or now));s.lastAt=now
    local hours=math.min(4,elapsed/3600)
    s.appetite=clamp(s.appetite+(hours*.09)+((math.random()-.5)*.04),0,1)
    s.restlessness=clamp(s.restlessness+(hours*.04)+((math.random()-.5)*.07),0,1)
    s.vigilance=clamp(s.vigilance+((math.random()-.5)*.055),0,1)
    s.connection=clamp(s.connection+((math.random()-.5)*.05),0,1)
    s.reflection=clamp(s.reflection+((math.random()-.5)*.05),0,1)
end

local function archetype(p)
    local a=p.alignment
    if RPAL.GetEffectivePersonalityAlignment then a=RPAL.GetEffectivePersonalityAlignment() or a end
    local moral="Grounded"
    if a.good>.56 then moral="Good-leaning" elseif a.evil>.56 then moral="Dark-leaning" elseif a.neutral>.56 then moral="Neutral" end
    local labels={}
    local function addPair(key,left,right)
        local value=(RPAL.GetEffectivePersonalityTrait and RPAL.GetEffectivePersonalityTrait(key)) or (p.traits and p.traits[key]) or 50
        if value<=27 then labels[#labels+1]=left elseif value>=73 then labels[#labels+1]=right end
    end
    addPair("introvertedExtroverted","Introverted","Extroverted")
    addPair("altruisticSelfish","Altruistic","Self-reliant")
    addPair("forgivingVindictive","Forgiving","Vindictive")
    addPair("gentleBrutal","Gentle","Brutal")
    addPair("cautiousImpulsive","Cautious","Impulsive")
    addPair("renegadeParagon","Renegade","Paragon")
    addPair("chaoticLawful","Chaotic","Lawful")
    if #labels==0 then labels[1]="Balanced" end
    return labels[1].." • "..moral
end

function RPAL.GetPersonalityArchetype()
    local p=ensureData();return p and archetype(p) or "Unformed"
end

function RPAL.GetPersonalityAlignmentLabel()
    local p=ensureData();if not p then return "Neutral" end
    local a=(RPAL.GetEffectivePersonalityAlignment and RPAL.GetEffectivePersonalityAlignment()) or p.alignment
    if a.good>.58 then return "Good" end
    if a.evil>.58 then return "Evil" end
    if a.neutral>.58 then return "Neutral" end
    local top=math.max(a.good,a.neutral,a.evil)
    if top==a.good then return "Good-leaning" end
    if top==a.evil then return "Evil-leaning" end
    return "Neutral-leaning"
end

local function choosePoolThought(p,context)
    local category=weightedKey(categoryWeights(p,context)) or "mundane"
    local pool=POOLS[category] or POOLS.mundane
    local recent=recentTextMap(p)
    local candidates={}
    for _,line in ipairs(pool) do if not recent[line] then candidates[#candidates+1]=line end end
    if #candidates==0 then candidates=pool end
    return candidates[math.random(1,#candidates)],category,"persona"
end

local NATURAL_ACTIVITY_TOPICS = {
    cooking=true,fishing=true,hunting=true,dueling=true,dancing=true,training=true,shopping=true,
    gambling=true,archaeology=true,flying=true,horses=true,storytelling=true,games=true,craft=true,
}
local NATURAL_ACTIVITY_ACTIONS = {
    cooking="cook something", fishing="go fishing", hunting="go hunting", dueling="find a decent duel",
    dancing="go dancing", training="get some training in", shopping="go shopping", gambling="play a few games of chance",
    archaeology="do a little archaeology", flying="go flying", horses="spend some time around horses",
    storytelling="tell a few stories", games="play something", craft="make something with my hands",
}
local NATURAL_ACTIVITY_GERUNDS = {
    cooking="cooking something", fishing="going fishing", hunting="going hunting", dueling="having a decent duel",
    dancing="going dancing", training="getting some training in", shopping="going shopping", gambling="playing a few games of chance",
    archaeology="doing a little archaeology", flying="going flying", horses="spending some time around horses",
    storytelling="telling a few stories", games="playing something", craft="making something with my hands",
}
local NATURAL_PEOPLE_TOPICS = {
    guards=true,military=true,merchants=true,scholars=true,healers=true,criminals=true,pirates=true,commonfolk=true,
    elders=true,strangers=true,nobility=true,mages=true,warlocks=true,paladins=true,priests=true,
    druids=true,shamans=true,rogues=true,warriors=true,hunters=true,monks=true,deathknights=true,demonhunters=true,
    evokers=true,mercenaries=true,adventurers=true,knights=true,humans=true,dwarves=true,gnomes=true,nightelves=true,
    highelves=true,voidelves=true,draenei=true,worgen=true,pandaren=true,orcs=true,trolls=true,tauren=true,goblins=true,
    forsaken=true,vulpera=true,bloodelves=true,kultirans=true,darkiron=true,lightforged=true,mechagnomes=true,
    dracthyr=true,earthen=true,undead=true,demons=true,dragons=true,elementals=true,spirits=true,
}
local NATURAL_PLACE_TOPICS = {
    cities=true,wilderness=true,taverns=true,mountains=true,beaches=true,deserts=true,swamps=true,caves=true,
    graveyards=true,ruins=true,gardens=true,rooftops=true,stormwind=true,boralus=true,dalaran=true,silvermoon=true,
    ironforge=true,farms=true,citylife=true,inns=true,markets=true,libraries=true,sea=true,
}
local NATURAL_CONSUMABLE_TOPICS = {
    food=true,drink=true,alcohol=true,tea=true,coffee=true,sweets=true,meat=true,vegetables=true,spicyfood=true,
}
-- Object/material preferences need object-shaped language. Falling back to a
-- generic "this catches my interest" template made things such as Armor sound
-- like an abstract hobby rather than something the character actually likes.
local NATURAL_OBJECT_TOPICS = {
    armor=true,weapons=true,jewelry=true,artifacts=true,books=true,
}
local NATURAL_PROPER_TOPIC_LABELS = {
    light=true,naaru=true,oldgods=true,kirintor=true,argentcrusade=true,cenarion=true,earthenring=true,illidari=true,
    shadopan=true,explorersleague=true,si7=true,alliance=true,horde=true,stormwind=true,boralus=true,dalaran=true,
    silvermoon=true,ironforge=true,titans=true,
}

local function naturalTopicLabel(key,def)
    local label=tostring((def and def.display) or key or "something")
    if NATURAL_PROPER_TOPIC_LABELS[key] then return label end
    return (label:gsub("^%u",string.lower))
end

local function objectTopicPool(key,label,positive)
    if key=="armor" then
        if positive then return {
            "I always notice a well-kept set of armor.","Good armor has a satisfying weight to it.","I like seeing armor that has actually been looked after.",
            "A solid set of armor is hard for me not to appreciate.","I tend to notice the little details in armor before anything flashy.","Well-fitted armor just looks right.",
            "I have a soft spot for armor that shows a bit of use without looking neglected.","I like the look of armor that was made for work rather than display.",
            "There is something reassuring about a dependable set of armor.","I could spend a while looking over the workmanship on good armor.",
            "I tend to appreciate armor more when the practical details make sense.","A clean buckle, a sound strap, a plate sitting where it should... I notice that sort of thing.",
            "Armor looks better to me when it has clearly been worn rather than merely shown off.","I like armor that looks as though somebody trusts it with their life.",
            "There is a certain comfort in seeing armor that has been properly maintained.","I have always liked the practical little choices that go into a good set of armor.",
            "A sturdy set of armor can be oddly pleasing to look at.","I tend to linger on the details when someone's armor is put together well.",
            "The wear on a good set of armor can tell you almost as much as the design.","I like armor that looks useful first and impressive second.",
            "I can appreciate a good piece of armor without needing it to be ornate.","Well-made armor has a kind of quiet appeal to it.",
            "I notice when armor moves naturally with the person wearing it.","A dependable set of armor is one of those things I rarely get tired of seeing.",
        } else return {
            "I have never cared much for armor.","Heavy armor looks uncomfortable before it looks impressive to me.","I get tired just looking at too much plate.",
            "I do not really understand the appeal of being wrapped in armor all day.","Bulky armor tends to put me off.","I would rather not spend any longer in armor than I have to.",
            "The weight alone is enough to make armor unappealing to me.","I have never liked how restrictive armor can look.","Too much armor makes me feel boxed in just thinking about it.",
            "I tend to notice the awkwardness of armor before the craftsmanship.","Armor has never been something I enjoy dealing with.","All those straps and plates look like more trouble than they are worth to me.",
            "I can appreciate the purpose of armor without liking it.","The clatter of heavy armor gets on my nerves after a while.","I have little patience for armor that values display over movement.",
            "Ornate armor usually does less for me than people seem to expect.","I would rather wear almost anything that lets me move freely.","Armor tends to feel like a necessary nuisance more than anything else.",
            "I do not miss the weight whenever I can go without armor.","The thought of spending a whole day in plate is exhausting.","Armor can look impressive and still be the last thing I want on me.",
            "I have never been fond of how much maintenance armor demands.","I tend to prefer protection that does not make itself so noticeable.","A room full of clanking armor gets old very quickly for me.",
        } end
    elseif key=="weapons" then
        if positive then return {
            "I tend to notice a well-kept weapon.","A balanced weapon is satisfying in a way that is hard to explain.","I like seeing a weapon that has clearly been maintained properly.",
            "Good workmanship on a weapon always catches my eye.","I tend to notice grips, edges and balance before decoration.","A practical weapon usually appeals to me more than an ornate one.",
            "I can appreciate a weapon that looks made to be used.","There is something satisfying about a clean edge and a sound grip.","I like weapons that feel honest about what they are for.",
            "A familiar weapon can be strangely comforting.","I notice when somebody clearly knows how to care for their weapon.","I have a soft spot for weapons with a little honest wear on them.",
            "The small differences between two similar weapons can keep my attention for a while.","I like the feel of a weapon that sits naturally in the hand.",
            "A well-balanced weapon is one of those little things I appreciate immediately.","I could spend longer than I mean to looking over good craftsmanship on a weapon.",
            "I tend to prefer weapons that look dependable rather than decorative.","There is something neat about a weapon with no unnecessary parts.","I like seeing the little signs that a weapon is actually used and cared for.",
            "A good weapon tends to make sense the moment you pick it up.","I notice when a weapon's design feels deliberate rather than flashy.","A properly maintained weapon is pleasant to see.",
            "I have always liked the practical craft behind a dependable weapon.","There are worse ways to lose a few minutes than comparing good weapons.",
        } else return {
            "I do not get much enjoyment out of weapons.","Weapons are easier for me to tolerate than admire.","I rarely find myself impressed by a weapon just for being a weapon.",
            "Too much fascination with weapons gets tiring quickly.","I would rather not have weapons be the first thing I notice in a room.","I have never really understood collecting weapons for the sake of it.",
            "A wall covered in weapons does very little for me.","I tend to think about what weapons do before I think about how they look.","I do not enjoy handling weapons when I do not need to.",
            "The appeal of ornate weapons is mostly lost on me.","I can respect a useful weapon without being fond of it.","I would happily spend less time around drawn weapons.",
            "Weapons make a room feel tenser than I like.","I have little patience for people who turn every weapon into a conversation piece.","I would rather see a weapon put away than displayed.",
            "I do not find much comfort in having weapons close at hand.","The sound of steel being handled can put me on edge faster than I would like.","I tend to notice the danger of a weapon before the craftsmanship.",
            "I have never been especially fond of carrying more weapon than I need.","A weapon can be beautifully made and still leave me cold.","I would rather not spend my spare time discussing weapons.",
            "I do not care much whether a weapon is impressive if it is not necessary.","Too many weapons in one place make me uneasy rather than curious.","Weapons are one of those things I prefer to keep practical and brief.",
        } end
    end
    if positive then return {
        "I have a soft spot for "..label..".","I tend to notice well-made "..label..".","I like seeing "..label.." that has clearly been looked after.",
        "There is something satisfying about good "..label..".","I usually pay a little more attention when "..label.." is around.","I can appreciate the small details in "..label..".",
        "I do not get tired of looking over "..label.." very quickly.","I like "..label.." more when the practical details make sense.","Good "..label.." tends to hold my attention for a while.",
        "I can lose a few minutes noticing the little differences in "..label..".","I tend to prefer "..label.." that looks used rather than merely displayed.","There is a quiet appeal to well-kept "..label..".",
        "I like the craftsmanship that goes into good "..label..".","I notice when "..label.." has been put together thoughtfully.","I have always found decent "..label.." pleasant to look over.",
        "I tend to appreciate "..label.." without needing it to be flashy.","There is usually some little detail in "..label.." that I end up noticing.","I like "..label.." best when it feels practical rather than ornamental.",
        "Well-made "..label.." has a way of holding my attention.","I can understand why people take pride in good "..label..".","I tend to look twice when "..label.." is made particularly well.",
        "I like the little signs of use and care on "..label..".","There is something dependable about good "..label.." that appeals to me.","I rarely mind spending a little time looking over "..label..".",
    } else return {
        "I have never cared much for "..label..".","I can do without "..label.." most of the time.","I rarely find myself impressed by "..label..".",
        "I tend to lose patience with "..label.." fairly quickly.","I would rather not spend much time dealing with "..label..".","The appeal of "..label.." is mostly lost on me.",
        "I can understand the use of "..label.." without liking it.","I do not get much enjoyment out of "..label..".","I tend to notice the inconvenient parts of "..label.." first.",
        "I would not miss "..label.." if I saw less of it for a while.","I have never had much of a taste for "..label..".","Too much attention paid to "..label.." gets tiring for me.",
        "I would rather keep "..label.." practical and brief.","I do not feel much urge to linger over "..label..".","I tend to be indifferent at best toward "..label..".",
        "I have never really understood the fascination with "..label..".","I would rather spend my attention on something other than "..label..".","I can appreciate good workmanship and still not care for "..label..".",
        "I rarely find "..label.." worth dwelling on.","I do not mind going a long while without thinking about "..label..".","I tend to get tired of "..label.." before other people do.",
        "There is very little about "..label.." that draws me in.","I would not choose "..label.." if I had an easy alternative.","I have always found "..label.." more trouble than appeal.",
    } end
end

local function naturalTopicLine(key,score,def)
    local label=naturalTopicLabel(key,def)
    local positive=(tonumber(score) or 0)>0
    local pool

    if key=="charity" then
        if positive then pool={"I like it when helping somebody can stay simple.","It feels good when a small bit of help actually lands where it should.","I have a soft spot for people who help without making a performance of it.","Seeing somebody get a fair break tends to sit well with me.","I would rather leave someone a little better off than I found them.","There is something satisfying about making a rough moment easier for somebody.","I like generosity best when nobody needs to announce it.","A useful kindness usually feels better than a grand promise."}
        else pool={"I do not have much patience for charity used as a performance.","Being generous on command has never sat naturally with me.","I would rather choose who I help than be guilted into it.","Some appeals for charity feel more like pressure than kindness.","I get wary when generosity comes with an audience.","I do not like being told that every stranger's trouble belongs to me.","Help means less to me when it is demanded instead of offered.","I have little interest in kindness that keeps score out loud."}end
    elseif key=="betrayal" then
        if positive then pool={"Betrayal can be useful, but I would never mistake it for clean.","Sometimes turning on somebody is the practical choice; that does not make it pleasant.","I understand why people betray each other better than I trust anyone who enjoys it.","There are situations where loyalty costs more than it deserves.","I can see the value in changing sides before a bad cause drags me down.","Blind loyalty has never impressed me much.","There are promises I would break before I let them become a cage.","I can accept betrayal as a choice without pretending it leaves nothing behind."}
        else pool={"Betrayal gets under my skin faster than most things.","Once somebody makes trust feel foolish, I do not forget it easily.","I hate the way betrayal makes every older memory look suspicious.","Being lied to is bad enough; being made to feel stupid for trusting is worse.","I have very little patience for people who treat loyalty as disposable.","A broken promise lingers longer with me than an ordinary argument.","I can forgive mistakes more easily than deliberate betrayal.","Trust takes too long to build for me to shrug off somebody breaking it."}end
    elseif key=="markets" and positive then
        pool={
            "Maybe I should wander through the markets sometime.","I haven't taken a slow walk through the markets in a while.","Wouldn't mind seeing what the stalls have today.",
            "The markets sound like a decent place to lose an hour.","I kind of miss the noise of the markets.","I could spend a while looking through stalls without needing anything in particular.",
            "Maybe I should see what the markets have one of these days.","I miss wandering past stalls and letting something catch my eye.","A slow walk through the markets sounds pretty good.",
            "I wonder what sort of odd little things are turning up in the markets lately.","I would not mind getting lost in the market crowd for a bit.","I keep thinking about the smell and noise of a busy market.",
            "Maybe I should go browse the stalls when I have nothing else pulling at me.","I could go for the kind of afternoon where I buy one thing I did not plan to buy.","The markets sound like a good place to let my attention wander.",
            "I miss taking my time from stall to stall without having somewhere else to be.","A crowded market sounds oddly inviting today.","I would not mind hearing merchants argue over prices for a while.",
            "I could spend a lazy hour seeing what people have dragged in to sell.","The thought of wandering around a market with no real purpose sounds good.",
            "I miss the little bits of conversation you overhear in a busy market.","Maybe there is something worth browsing for even if I do not need anything.","I would not mind the noise of a market around me for a while.",
            "A market is one of the few places where wandering aimlessly still feels like doing something.",
        }
    elseif NATURAL_ACTIVITY_TOPICS[key] then
        local action=NATURAL_ACTIVITY_ACTIONS[key]or("make time for "..label)
        local gerund=NATURAL_ACTIVITY_GERUNDS[key]or("spending some time with "..label)
        if positive then pool={
            "Maybe I should "..action.." sometime.","Wouldn't mind "..gerund.." for a while.","I haven't made much time for "..label.." lately.","The thought of "..label.." is pretty appealing right now.",
            "I kind of miss "..label..".","I wonder when I last properly enjoyed "..label..".","I could happily lose a little time to "..label.." again.","I keep thinking "..gerund.." would be a nice change of pace.",
            "It has been long enough that "..label.." sounds fresh again.","I would not mind making a little room for "..label.." soon.","I keep getting the urge to "..action.." one of these days.",
            "A bit of time spent "..gerund.." would probably feel good.","I miss the simple part of "..label.." more than anything complicated about it.","I could see myself "..gerund.." for longer than I planned.",
            "Maybe I should "..action.." when I have a quiet stretch.","I have been in the mood for "..label.." more than usual lately.","I keep picturing myself "..gerund.." and not hurrying anywhere afterward.",
            "I would not mind falling back into "..label.." for an afternoon.","There is something comfortable about the idea of "..gerund.." again.","I could use the kind of distraction "..label.." gives me.",
            "It might be nice to "..action.." without making a whole day of it.","I have caught myself missing "..label.." a few times lately.","I would probably enjoy "..gerund.." more than sitting around thinking about it.",
            "The urge to "..action.." keeps turning up at odd moments.",
        } else pool={
            "I don't think I'm in the mood for "..label..".","I could happily skip "..label.." for a while.","Maybe I've had enough of "..label.." lately.","The thought of "..label.." really does not sound appealing right now.",
            "I would rather spend my time on something other than "..label..".","I have not been missing "..label.." at all.","I could go a good while without "..label.." and be perfectly fine.","Even the idea of "..gerund.." feels like work right now.",
            "I am not eager to "..action.." again anytime soon.","I think I have had my fill of "..label.." for the moment.","I keep finding reasons to put "..label.." off.","There are plenty of things I would rather do than "..action..".",
            "I do not have much patience for "..label.." lately.","I would be fine letting "..label.." wait for another day.","The urge to "..action.." is nowhere to be found right now.","I get tired of "..label.." faster than I used to.",
            "I would rather not lose any time to "..label.." today.","Nothing about "..gerund.." sounds especially pleasant right now.","I am more relieved than disappointed when I can skip "..label..".","I do not think "..label.." would improve my mood at the moment.",
            "I have been avoiding "..label.." without really missing it.","I would rather leave "..label.." alone for a while.","Even thinking about "..label.." makes me want a different distraction.","I am in no hurry to make time for "..label.." again.",
        } end
    elseif NATURAL_PEOPLE_TOPICS[key] then
        if positive then pool={
            "I usually feel fairly comfortable around "..label..".","I wouldn't mind running into "..label.." again.","I suppose I have a bit of a soft spot for "..label..".","I tend to relax a little faster around "..label..".",
            "I usually find "..label.." easier company than most.","I do not mind having "..label.." around.","I tend to enjoy conversations with "..label..".","Something about being around "..label.." usually sits well with me.",
            "I seem to get along with "..label.." more often than not.","I usually find myself a little more open around "..label..".","I would not mind sharing a table with "..label.." for a while.","I tend to expect decent company from "..label..".",
            "I usually like the atmosphere better when "..label.." are around.","I rarely feel the need to keep "..label.." at arm's length.","I have had enough good experiences with "..label.." to notice the pattern.","I tend to warm up to "..label.." fairly quickly.",
            "I would rather meet "..label.." than avoid them.","There is something familiar about the kind of company "..label.." provide.","I generally feel at ease talking with "..label..".","I have a little more patience for "..label.." than I do for most people.",
            "I often end up enjoying "..label.." more than I expect.","I tend to leave conversations with "..label.." in a better mood.","I would not complain if I ended up around "..label.." today.","I have noticed I am usually glad when "..label.." turn up.",
        } else pool={
            "I'd rather not deal with "..label.." if I can help it.","I still don't feel especially comfortable around "..label..".","Something about "..label.." tends to put me on edge.","I rarely relax properly around "..label..".",
            "I tend to keep a bit more distance from "..label..".","I do not usually enjoy being around "..label.." for long.","I find "..label.." tiring more often than not.","I would rather not be stuck in a long conversation with "..label..".",
            "I tend to watch "..label.." more carefully than other people.","I have never felt especially at ease around "..label..".","I usually prefer having some space between myself and "..label..".","I find it harder to relax when "..label.." are around.",
            "I do not look forward to dealing with "..label..".","I seem to run out of patience around "..label.." fairly quickly.","I would rather meet almost anyone else than "..label.." on a bad day.","I tend to feel guarded around "..label.." even when nothing is happening.",
            "I have had enough unpleasant experiences with "..label.." to notice the pattern.","I do not usually come away from "..label.." feeling better.","I would be perfectly happy seeing less of "..label.." for a while.","I rarely feel disappointed when "..label.." keep their distance.",
            "I find the company of "..label.." difficult to enjoy.","Something in me tightens a little when "..label.." show up.","I tend to expect friction when "..label.." are involved.","I would rather not have "..label.." taking up much of my attention today.",
        } end
    elseif NATURAL_PLACE_TOPICS[key] then
        if positive then pool={
            "I wouldn't mind spending some time around "..label.." again.","Maybe I should spend an afternoon around "..label.." sometime.","Maybe I miss "..label.." a little.","Being around "..label.." sounds like a decent change of scenery.",
            "I could see myself lingering around "..label.." for a while.","I wonder when I'll end up around "..label.." again.","I have been missing the feel of "..label.." lately.","A little time around "..label.." would probably suit me.",
            "I would not mind wandering around "..label.." without much purpose.","I keep thinking about the atmosphere around "..label..".","There is something about "..label.." I tend to settle into easily.","I could use a few quiet hours around "..label..".",
            "The thought of being around "..label.." again is surprisingly pleasant.","I tend to lose track of time around "..label.." in a good way.","I would happily end up around "..label.." today.","I have a soft spot for the particular feel of "..label..".",
            "I could do with the sights and sounds around "..label.." for a while.","It has been a little too long since I spent time around "..label..".","I tend to feel more like myself around "..label..".","I would not mind having nowhere to be except somewhere around "..label..".",
            "A slow walk around "..label.." sounds good.","I have caught myself thinking about "..label.." more than once lately.","The idea of ending up around "..label.." feels easy to like.","I would probably linger longer than I meant to if I found myself around "..label..".",
        } else pool={
            "I would rather not spend too long around "..label..".","Something about "..label.." never really sits right with me.","I don't think I miss "..label.." much.","I'd be fine avoiding "..label.." for a while.",
            "I never feel completely at ease around "..label..".","I tend to get tired of "..label.." fairly quickly.","I would rather be almost anywhere else than around "..label.." on a bad day.","The atmosphere around "..label.." usually wears on me.",
            "I do not have much desire to wander around "..label..".","I rarely feel better after spending time around "..label..".","I would not mind a long break from "..label..".","There is something about "..label.." that makes me want to keep moving.",
            "I tend to notice the unpleasant parts of "..label.." first.","I have never really settled comfortably around "..label..".","The thought of lingering around "..label.." does not appeal to me.","I am usually ready to leave "..label.." before everyone else.",
            "I would rather pass through "..label.." than spend the day there.","I do not miss the feel of "..label.." when I am away from it.","I have little patience for the atmosphere around "..label..".","I would be perfectly content not seeing "..label.." for a while.",
            "I tend to feel a little more tense around "..label..".","I do not find much comfort in being around "..label..".","A change of scenery away from "..label.." sounds better to me.","I have never understood why people enjoy lingering around "..label.." so much.",
        } end
    elseif NATURAL_CONSUMABLE_TOPICS[key] then
        if positive then pool={
            "I could go for some "..label..".","Some "..label.." sounds good right now.","Maybe I should get some "..label.." later.","I haven't had decent "..label.." in a while.","I would not say no to some "..label..".",
            "I have been craving "..label.." a little lately.","A bit of "..label.." would hit the spot.","I keep thinking about getting some "..label..".","I could happily make room for "..label.." right now.","It has been too long since I had good "..label..".",
            "I would not mind finding somewhere that does decent "..label..".","The thought of "..label.." is making me hungrier than I was a minute ago.","I have always had a weakness for good "..label..".","Some proper "..label.." would be nice.",
            "I could make a small detour for "..label.." without much convincing.","I tend to notice when someone nearby has "..label..".","I would probably enjoy "..label.." more than whatever I was planning to have.","I keep getting the taste for "..label.." in my head.",
            "A quiet moment with some "..label.." sounds good.","I would be pleased if "..label.." happened to turn up right now.","I have not grown tired of "..label.." yet.","I could go for the familiar taste of "..label..".",
            "I would not need much persuasion to have some "..label..".","Good "..label.." is one of those little things I tend to appreciate.",
        } else pool={
            "I think I'll pass on "..label..".","I really don't feel like having "..label..".","Maybe I've had enough "..label.." for a while.","The thought of "..label.." does not sound good at all right now.","I'd rather have something other than "..label..".",
            "I have no appetite for "..label.." today.","I could go a long while without "..label..".","Even the smell of "..label.." is not doing much for me.","I do not think I could be talked into "..label.." right now.","I have had more than enough "..label.." lately.",
            "I would rather find something completely different from "..label..".","The taste of "..label.." is the last thing I want at the moment.","I never seem to enjoy "..label.." as much as other people do.","I would not miss "..label.." if I stopped having it for a while.",
            "I tend to lose my appetite when "..label.." is the only option.","I could happily give "..label.." a rest.","I do not understand the fuss over "..label..".","There are plenty of things I would choose before "..label..".",
            "I am more likely to leave "..label.." untouched than finish it.","The idea of "..label.." is making me want something else instead.","I have never developed much of a taste for "..label..".","I would rather skip it than settle for "..label..".",
            "I have had enough disappointing "..label.." to stop expecting much.","I would not go out of my way for "..label..".",
        } end
    elseif NATURAL_OBJECT_TOPICS[key] then
        pool=objectTopicPool(key,label,positive)
    else
        -- Every learned association still gets a large, semantically broad
        -- fallback bank. These lines express affinity/aversion rather than a
        -- pasted-on claim that the topic is "interesting", so concepts such as
        -- Duty, Armor or Betrayal do not read like the same hobby template.
        if positive then pool={
            "I have a soft spot for "..label..".","Something about "..label.." usually sits well with me.","I have grown fairly fond of "..label..".","I usually find something to appreciate in "..label..".",
            "I do not get tired of "..label.." very easily.","I tend to respond well when "..label.." comes up.","There is something about "..label.." that sits well with me.","I have noticed that "..label.." usually leaves me in a better mood.",
            "I am rarely unhappy to have "..label.." around in some form.","I suppose "..label.." suits me better than I once thought.","I have more patience for "..label.." than I do for most things.","I tend to look favorably on "..label..".",
            "I keep finding little reasons to like "..label..".","I have never needed much convincing when it comes to "..label..".","I usually enjoy the part of things that involves "..label..".","I tend to miss "..label.." when it has been absent for a while.",
            "I have become more comfortable with "..label.." over time.","I rarely mind when "..label.." becomes part of the day.","I am starting to think I like "..label.." more than I admit.","I tend to settle into "..label.." easily enough.",
            "There is something familiar and pleasant about "..label.." to me.","I usually come away from "..label.." feeling fairly satisfied.","I have had enough good experiences with "..label.." to notice the pattern.","I would not mind a little more "..label.." in the near future.",
        } else pool={
            "I have never really taken to "..label..".","I can do without "..label.." for a while.","Something about "..label.." tends to wear on me.","I have never felt especially comfortable with "..label..".",
            "I tend to run out of patience with "..label.." quickly.","I would rather have less to do with "..label..".","I rarely come away from "..label.." feeling better.","There is something about "..label.." that does not sit well with me.",
            "I have noticed that "..label.." usually puts me in a worse mood.","I do not miss "..label.." when it is absent.","I have very little enthusiasm for "..label..".","I tend to avoid "..label.." when there is an easy alternative.",
            "I have never understood the appeal of "..label..".","I usually feel relieved when I do not have to deal with "..label..".","I get tired of "..label.." faster than most things.","I do not have much patience left for "..label..".",
            "I keep finding small reasons to dislike "..label..".","I would not complain if "..label.." stayed out of my way for a while.","I tend to feel a little more tense when "..label.." becomes relevant.","I rarely choose "..label.." when I have another option.",
            "I have had enough bad experiences with "..label.." to notice the pattern.","I do not think "..label.." is ever going to be much to my taste.","I would rather leave "..label.." alone when I have the choice.","I can tolerate "..label.." when necessary, but that is about it.",
        } end
    end
    return pool[math.random(1,#pool)]
end

local function chooseMotifThought(p)
    local choices={}
    if RPAL.GetPersonalityTopAssociations then
        for _,row in ipairs(RPAL.GetPersonalityTopAssociations(20,false) or {}) do
            if row and row.key and math.abs(tonumber(row.score) or 0)>.18 then
                local strength=math.abs(tonumber(row.score) or 0)
                local n=math.max(1,math.min(6,math.floor(((row.confidence or 0)*3)+(strength*3)+.5)))
                for _=1,n do choices[#choices+1]=row end
            end
        end
    end
    if #choices==0 then return nil end
    local recent=recentTextMap(p)
    for tries=1,10 do
        local row=choices[math.random(1,#choices)]
        local key=row.key;local score=tonumber(row.score) or 0;local pool=MOTIF_POOLS[key];local line
        if pool and score>0 then
            line=pool[math.random(1,#pool)]
        else
            local def=RPAL.PERSONALITY_ASSOCIATION_TOPICS and RPAL.PERSONALITY_ASSOCIATION_TOPICS[key]
            line=naturalTopicLine(key,score,def)
        end
        if line and (not recent[line] or tries==10) then return line,key,score>0 and "learned-like" or "learned-dislike" end
    end
    return nil
end

local COMBO_THOUGHTS={
    intro_kind={
        "I would not mind helping somebody without turning it into a whole conversation.",
        "Quiet company sounds easier than a crowded room right now.",
        "I keep noticing people who look like they could use a little company.",
        "I would rather be useful in a small way than make a big thing of it.",
        "I wonder who would be comfortable just sitting nearby without much talking.",
    },
    extro_kind={
        "I feel like finding somebody familiar to talk to.",
        "A bit of company would probably improve my mood.",
        "I keep wondering who is around and in the mood to talk.",
        "I would not mind pulling somebody into an easy conversation.",
        "I feel more awake when there are people around to bounce words off.",
    },
    cautious_vindictive={
        "I am still annoyed, but I do not feel any hurry to do anything about it.",
        "I hold onto irritation longer than I like to admit.",
        "That irritation has not gone anywhere, even if I am quiet about it.",
        "I wonder whether they realize I still remember how that went.",
        "I am not in a rush, but I have not forgotten it either.",
    },
    impulsive_altruistic={
        "I get restless when somebody clearly needs help and nobody moves.",
        "Part of me wants to step in before I have even thought the whole thing through.",
        "I keep noticing how quickly I react when somebody looks stuck.",
        "It is hard for me to just watch when there is something obvious I could do.",
        "I feel the urge to help first and sort out the details afterward.",
    },
    rational_gentle={
        "I keep trying to find the least messy way to explain what I mean.",
        "I would rather understand the problem clearly than make it louder.",
        "I keep thinking there is a calmer explanation hiding in the details.",
        "I feel better when I can make sense of something without turning it into a fight.",
        "I wonder what part of this actually needs explaining and what part does not.",
    },
    superstitious_cautious={
        "Something about this still feels slightly wrong to me.",
        "I keep noticing little things that make me uneasy even if I cannot explain why.",
        "There is a small part of me that does not want to dismiss that feeling yet.",
        "I keep wondering whether the odd little details mean anything.",
        "I do not have a reason for it, but I am not completely relaxed about this.",
    },
    lawful_paragon={
        "I feel better when I know exactly what I agreed to do.",
        "I keep thinking about the part of this that is actually my responsibility.",
        "Loose ends bother me more when I know somebody is counting on me.",
        "I would rather finish what I said I would finish than leave it hanging.",
        "I keep track of promises more carefully than I track most other things.",
    },
    chaotic_renegade={
        "I keep wanting to find my own way around this instead of doing it the usual way.",
        "The obvious route is not doing much for me right now.",
        "I wonder what happens if I approach this from a completely different angle.",
        "I feel a little boxed in when there is only one accepted way to do something.",
        "Part of me wants to improvise just to see whether it works better.",
    },
    bonvivant_extro={
        "A lively place and something good to eat sounds nice.",
        "I feel like being somewhere with voices, food, and a bit of movement.",
        "I keep thinking about finding somewhere pleasant to spend an hour with company.",
        "Good food sounds even better if I do not have to eat it alone.",
        "I would not mind somewhere busy enough that I can just sink into the noise.",
    },
    ascetic_intro={
        "Quiet and simple sounds especially good right now.",
        "I do not feel like I need much beyond a calm place to sit.",
        "I keep wanting fewer things around me, not more.",
        "A little space and nothing demanding my attention would be enough.",
        "I feel like stripping the next few minutes down to something very simple.",
    },
    selfish_deceitful={
        "I am not especially eager to explain every part of what I am thinking.",
        "There are a few things I would rather keep to myself for now.",
        "I keep noticing which details are actually useful to share and which are not.",
        "Part of me likes having a little information that is only mine.",
        "I do not feel any need to make my motives easier for everybody else to read.",
    },
    truthful_altruistic={
        "I dislike leaving somebody confused when I could explain what happened plainly.",
        "I keep thinking about whether they understood what I was actually trying to say.",
        "I feel better when I can be straightforward without making somebody feel small.",
        "I would rather clear up a misunderstanding than let it sit there getting stranger.",
        "I keep wanting the important part of this to be understood without dressing it up.",
    },
    brutal_valorous={
        "I can feel myself getting more comfortable when a problem becomes direct.",
        "I do not mind pressure nearly as much as I mind waiting around for it.",
        "Part of me would rather face the ugly part than keep imagining it.",
        "I keep noticing that fear makes me want to plant my feet harder, not move away.",
        "There is a part of me that gets calmer once I know exactly what I am facing.",
    },
    cautious_spineless={
        "I keep noticing exits without really meaning to.",
        "I feel better when I know there is room to step away if things turn bad.",
        "Part of me is already wondering how crowded this could get.",
        "I do not like the feeling of being boxed in somewhere unfamiliar.",
        "I keep checking how easy it would be to leave if I suddenly wanted to.",
    },
    intro_vindictive={
        "I am still annoyed enough that silence feels easier than talking about it.",
        "I keep remembering that without feeling any urge to bring it up.",
        "I wonder whether they have any idea that I am still bothered by it.",
        "That irritation sits quietly until something reminds me of it again.",
        "I do not feel like talking about it, but I have not stopped thinking about it.",
    },
    extro_impulsive={
        "I feel like going over and talking to somebody instead of standing here thinking about it.",
        "I keep looking around for somebody interesting enough to start a conversation with.",
        "Waiting around is making me more tempted to just say hello to somebody.",
        "I feel like finding out what happens if I start the conversation first.",
        "Part of me wants to go bother somebody familiar just for the company.",
    },
}

local function chooseCombinationThought(p)
    local function v(key)return ((RPAL.GetEffectivePersonalityTrait and RPAL.GetEffectivePersonalityTrait(key)) or (p.traits and p.traits[key]) or 50)/100 end
    local lawful=v("chaoticLawful");local vind=v("forgivingVindictive");local selfish=v("altruisticSelfish");local deceit=v("truthfulDeceitful");local brutal=v("gentleBrutal");local rational=v("superstitiousRational");local paragon=v("renegadeParagon");local impulsive=v("cautiousImpulsive");local bon=v("asceticBonVivant");local spineless=v("valorousSpineless");local extro=v("introvertedExtroverted")
    local candidates={}
    local function add(key,condition)if condition then candidates[#candidates+1]=key end end
    add("intro_kind",extro<.34 and selfish<.42);add("extro_kind",extro>.66 and selfish<.42);add("cautious_vindictive",impulsive<.36 and vind>.62);add("impulsive_altruistic",impulsive>.66 and selfish<.40);add("rational_gentle",rational>.64 and brutal<.40);add("superstitious_cautious",rational<.36 and impulsive<.42);add("lawful_paragon",lawful>.64 and paragon>.62);add("chaotic_renegade",lawful<.36 and paragon<.38);add("bonvivant_extro",bon>.64 and extro>.60);add("ascetic_intro",bon<.36 and extro<.40);add("selfish_deceitful",selfish>.64 and deceit>.60);add("truthful_altruistic",selfish<.38 and deceit<.40);add("brutal_valorous",brutal>.64 and spineless<.40);add("cautious_spineless",impulsive<.38 and spineless>.60);add("intro_vindictive",extro<.38 and vind>.62);add("extro_impulsive",extro>.64 and impulsive>.62)
    if #candidates==0 then return nil end
    local key=candidates[math.random(1,#candidates)];local pool=COMBO_THOUGHTS[key];return pool[math.random(1,#pool)],"reflective","persona-combo"
end

local SURVIVAL_THOUGHTS={
    hungry={
        "I should get something to eat.",
        "Food sounds really good right now.",
        "I am definitely getting hungry.",
        "I should find a proper meal soon.",
        "I keep thinking about food.",
        "Something warm to eat would be nice.",
        "I should probably eat before I get distracted again.",
        "I could use a bite of something.",
    },
    thirsty={
        "I should get something to drink.",
        "I am getting pretty thirsty.",
        "Water would be good right now.",
        "I should probably drink something soon.",
        "My mouth feels a little dry.",
        "I could really use a drink.",
        "I should stop forgetting to drink.",
        "Something cold to drink would be nice.",
    },
}

local function chooseSurvivalThought(p)
    local settings=RPAL.GetSettings and RPAL.GetSettings() or nil
    if not settings or not settings.survivalEnabled or not RPAL.GetSurvivalState then return nil end
    local ok,state=pcall(RPAL.GetSurvivalState)
    if not ok or type(state)~="table" then return nil end
    local food=tonumber(state.food) or 100
    local water=tonumber(state.water) or 100
    local recent=recentTextMap(p)
    local pool
    if water<=30 and (food>30 or water<=food) then pool=SURVIVAL_THOUGHTS.thirsty
    elseif food<=30 then pool=SURVIVAL_THOUGHTS.hungry
    elseif water<=48 and math.random()<.28 then pool=SURVIVAL_THOUGHTS.thirsty
    elseif food<=48 and math.random()<.22 then pool=SURVIVAL_THOUGHTS.hungry end
    if not pool then return nil end
    local candidates={}
    for _,line in ipairs(pool) do if not recent[line] then candidates[#candidates+1]=line end end
    if #candidates==0 then candidates=pool end
    return candidates[math.random(1,#candidates)],"comfort","survival"
end

local function choosePersonThought(p)
    if not RPAL.GetPersonaPeople then return nil end
    local people=RPAL.GetPersonaPeople(14) or {}
    if #people==0 then return nil end
    local eligible={}
    for _,row in ipairs(people) do
        if row.ambientEligible==true and (row.confidence or 0)>=.30 and math.abs(row.score or 0)>=.26 and row.display and row.display~="" then
            local n=math.max(1,math.min(5,math.floor((row.confidence or 0)*4+math.abs(row.score or 0)*2+.5)))
            local recentInteractions=tonumber(row.recentInteractions)or 0;local recentSessions=tonumber(row.recentSessions)or 0
            if recentInteractions>=2 or recentSessions>=2 then n=n+8+math.min(10,recentInteractions+recentSessions*2)
            elseif recentInteractions>0 then n=n+2 end
            for _=1,n do eligible[#eligible+1]=row end
        end
    end
    if #eligible==0 then return nil end
    local row=eligible[math.random(1,#eligible)]
    local name=tostring(row.display)
    local pool
    if row.score>=.48 then
        pool={
            "I wonder what "..name.." is up to.","I wouldn't mind running into "..name.." again.","Wonder how "..name.." is doing.","Talking to "..name.." again could be nice.","Been a while since I properly caught up with "..name..".","I kind of miss having "..name.." around.","Funny how "..name.." keeps crossing my mind.","I wonder where "..name.." ended up today.","Could use one of those easy conversations with "..name..".","Seeing "..name.." again would be a nice surprise.","I haven't heard from "..name.." in a bit.",name.." would probably make this less dull.","I wonder what "..name.." would make of this.","Running into "..name.." again sounds pretty good.","I could probably lose an hour talking to "..name.." without noticing.","There are worse ways to spend time than around "..name..".","I miss the familiarity of having "..name.." nearby.","Wonder what sort of trouble "..name.." has found lately.",name.." is getting hard to think of as just another acquaintance.","Would be good to hear "..name.." again.","I wonder if "..name.." has been keeping busy.","Some people are easy to forget for a while. "..name.." isn't one of them.","I haven't properly laughed with "..name.." in a while.",name.." has become a strangely familiar part of things."
        }
    elseif row.score<=-.48 then
        pool={
            "I could do without seeing "..name.." for a while.","I still don't know what to make of "..name..".","I'd rather not deal with "..name.." right now.","Something about "..name.." still bothers me.","Even thinking about "..name.." is a little tiring.",name.." has a talent for lingering in the wrong part of my head.","I haven't forgotten the way "..name.." handled that.","The thought of "..name.." still brings that irritation back.","I wonder if "..name.." is still as difficult as I remember.","Something about "..name.." puts me on edge.",name.." keeps leaving a bad taste in my mouth.","I could happily go a while without crossing paths with "..name..".","I don't like how easily "..name.." can sour my mood.","Just remembering "..name.." is enough to bring the old irritation back.",name.." is easier to tolerate from a distance.","I wonder what new headache "..name.." has found by now.","Nothing about running into "..name.." sounds appealing right now.","I still feel a little guarded whenever "..name.." comes to mind.","I have no particular urge to see "..name.." again.","Some people fade with time. The annoyance around "..name.." hasn't quite managed it."
        }
    else
        pool={
            "I wonder what "..name.." is doing.","I still haven't figured "..name.." out.","I wonder what I actually think of "..name..".","Something about "..name.." still feels undecided in my head.","I can't quite tell where I stand with "..name..".","I wonder what another conversation with "..name.." would feel like.",name.." is still a bit of a question mark to me.","I keep changing my mind about "..name..".","I wonder whether "..name.." is easier to read than I make them seem.","Hard to pin down what sort of impression "..name.." has actually left.","I haven't settled on "..name.." yet.","There's something unfinished about my impression of "..name..".","I wonder what I'd notice first if I ran into "..name.." again.",name.." still sits somewhere between familiar and uncertain in my head.","I can't decide whether I understand "..name.." any better than before."
        }
    end
    local recent=recentTextMap(p);local candidates={}
    for _,line in ipairs(pool)do if not recent[line]then candidates[#candidates+1]=line end end
    if#candidates==0 then candidates=pool end
    return candidates[math.random(1,#candidates)],"social","relationship"
end

function RPAL.GeneratePersonalityThought(context)
    local p=ensureData();if not p or p.enabled==false or (RPAL.IsPersonaSystemEnabled and not RPAL.IsPersonaSystemEnabled()) then return nil end
    context=tostring(context or "ambient")
    evolveState(p)
    local line,category,source,mind

    local survivalRoll=(context~="preview" and math.random()<.34) or (context=="preview" and math.random()<.22)
    if survivalRoll then line,category,source=chooseSurvivalThought(p) end
    -- Persona 2.0 owns quiet/background wording. The established survival,
    -- cadence and compatibility paths remain intact around this semantic layer.
    if not line and RPAL.GeneratePersonaMindThought then
        line,category,source,mind=RPAL.GeneratePersonaMindThought(context,p)
    end
    if not line and math.random()<.18 then line,category,source=choosePersonThought(p) end
    if not line and math.random()<.08 then line,category,source=chooseCombinationThought(p) end
    local customAllowed=p.autonomy.custom~=false and #p.customThoughts>0
    if not line and customAllowed and math.random()<0.08 then
        local recent=recentTextMap(p);local candidates={}
        for _,v in ipairs(p.customThoughts) do if not recent[v] then candidates[#candidates+1]=v end end
        if #candidates==0 then candidates=p.customThoughts end
        line=candidates[math.random(1,#candidates)];category="custom";source="custom"
    elseif not line and math.random()<0.36 then
        line,category,source=chooseMotifThought(p)
        if not line then line,category,source=choosePoolThought(p,context) end
    elseif not line then
        line,category,source=choosePoolThought(p,context)
    end
    if not line then return nil end

    local row={text=line,rawText=line,category=category or "thought",source=source or "persona",at=time(),context=context,mind=mind}
    p.history[#p.history+1]=row
    while #p.history>120 do table.remove(p.history,1) end

    if p.autonomy.needs~=false then
        if category=="comfort" or category=="food" or category=="drink" then p.state.appetite=clamp(p.state.appetite-.16,0,1) end
        if category=="restless" or category=="chaotic" or category=="rebellious" then p.state.restlessness=clamp(p.state.restlessness-.10,0,1) end
        if category=="social" or category=="kind" then p.state.connection=clamp(p.state.connection-.09,0,1) end
        if category=="guarded" or category=="danger" then p.state.vigilance=clamp(p.state.vigilance-.07,0,1) end
        if category=="reflective" or category=="curious" then p.state.reflection=clamp(p.state.reflection-.08,0,1) end
    end
    return line,row
end

function RPAL.GetPersonalityHistory(limit)
    local p=ensureData();local out={};if not p then return out end
    limit=math.max(1,math.min(36,math.floor(tonumber(limit) or 8)))
    for i=math.max(1,#p.history-limit+1),#p.history do out[#out+1]=p.history[i] end
    return out
end

local FREQUENCY_RANGES={
    rare={18*60,28*60}, quiet={14*60,22*60}, balanced={9*60,16*60}, active={7*60,12*60}, expressive={5*60,9*60},
}

function RPAL.GetPersonalitySparkDelay(fresh)
    local p=ensureData();local freq=p and p.autonomy.frequency or "balanced"
    local range=FREQUENCY_RANGES[freq] or FREQUENCY_RANGES.balanced
    local lo,hi=range[1],range[2]
    if fresh then lo=math.max(4*60,lo-90);hi=math.max(lo+60,hi-90) end
    return math.random(lo,hi)
end

function RPAL.GetPersonalityFrequencyDescription(value)
    local map={rare="roughly every 18–28 min",quiet="roughly every 14–22 min",balanced="roughly every 9–16 min",active="roughly every 7–12 min",expressive="roughly every 5–9 min"}
    return map[tostring(value or "balanced")] or map.balanced
end

function RPAL.GetPersonalitySocialSparkChance()
    local p=ensureData();if not p or p.autonomy.social==false then return 0 end
    local map={rare=.08,quiet=.14,balanced=.27,active=.37,expressive=.48}
    return map[p.autonomy.frequency] or .27
end

function RPAL.IsPersonalitySceneThoughtEnabled()
    local p=ensureData();return p and p.enabled~=false and (not RPAL.IsPersonaSystemEnabled or RPAL.IsPersonaSystemEnabled()) and p.autonomy.scene~=false
end

function RPAL.IsPersonalitySocialThoughtEnabled()
    local p=ensureData();return p and p.enabled~=false and (not RPAL.IsPersonaSystemEnabled or RPAL.IsPersonaSystemEnabled()) and p.autonomy.social~=false
end

function RPAL.MaybeShowAmbientPersonalityThought()
    local p=ensureData();if not p or p.enabled==false or (RPAL.IsPersonaSystemEnabled and not RPAL.IsPersonaSystemEnabled()) or p.autonomy.ambient~=true then return false end
    if InCombatLockdown and InCombatLockdown() then return false end
    if UnitIsAFK and UnitIsAFK("player") then return false end
    local now=(GetTime and GetTime()) or 0
    local freq=p.autonomy.frequency or "balanced"
    local baseMap={rare=48*60,quiet=36*60,balanced=25*60,active=19*60,expressive=15*60}
    local base=baseMap[freq] or baseMap.balanced
    if not RPAL._personalityAmbientNextAt then RPAL._personalityAmbientNextAt=now+math.random(base,base+14*60);return false end
    if now<RPAL._personalityAmbientNextAt then return false end
    local thought,row=RPAL.GeneratePersonalityThought("ambient")
    if thought and RPAL.ShowSceneSpark then RPAL.ShowSceneSpark(thought,row) end
    RPAL._personalityAmbientNextAt=now+math.random(base,base+14*60)
    return thought and true or false
end

function RPAL.SetPersonalityFrequency(value)
    local p=ensureData();value=tostring(value or "balanced"):lower()
    if not p or not FREQUENCY_RANGES[value] then return false end
    p.autonomy.frequency=value;RPAL._sceneSparkNextAt=nil;RPAL._personalityAmbientNextAt=nil
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

function RPAL.SetPersonalityAutonomy(key,value)
    local p=ensureData();key=tostring(key or "")
    local valid={scene=true,session=true,social=true,ambient=true,needs=true,memory=true,brief=true,custom=true,learning=true,learningInsights=true,onlineReactions=true}
    if not p or not valid[key] then return false end
    if key=="session" then key="scene" end
    p.autonomy[key]=value and true or false
    if key=="scene" then p.autonomy.session=p.autonomy.scene end
    if key=="ambient" then RPAL._personalityAmbientNextAt=nil end
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end

function RPAL.GetPersonalityStateSummary()
    local p=ensureData();if not p then return {} end
    return {
        appetite=math.floor(p.state.appetite*100+.5), restlessness=math.floor(p.state.restlessness*100+.5),
        vigilance=math.floor(p.state.vigilance*100+.5), connection=math.floor(p.state.connection*100+.5),
        reflection=math.floor(p.state.reflection*100+.5),
    }
end

function RPAL.ResetPersonality()
    local roleplay=RPAL.GetRoleplayData and RPAL.GetRoleplayData() or nil
    if not roleplay then return false end
    -- Remove only a Currently line that Persona still owns before discarding
    -- its transient ownership token. Never touch the rest of the TRP field.
    if RPAL.ClearPersonaCurrentlyActivity then pcall(RPAL.ClearPersonaCurrentlyActivity) end
    roleplay.personality={optedIn=false,enabled=true}
    briefCacheText,briefCacheValue=nil,nil
    RPAL._sceneSparkNextAt=nil;RPAL._personalityAmbientNextAt=nil
    RPAL._personaContinuityNextThoughtAt=nil;RPAL._personaContinuityLastStateAt=nil
    RPAL._personaIncomingReactionAt=nil
    ensureData()
    if RPAL.ClosePersonaLivingConfig then pcall(RPAL.ClosePersonaLivingConfig,true) end
    if RPAL.ClosePersonalityCalibration then pcall(RPAL.ClosePersonalityCalibration) end
    if RPAL.RefreshPersonalityUI then RPAL.RefreshPersonalityUI() end
    return true
end
RPAL.ResetPersonaCompletely=RPAL.ResetPersonality
