/* The Quest for the Deleted Website (quest.html only).

   The quest survives reloads (and even restoring the website): the save
   file is questHero + questPronouns (JSON) + questWeapon + questHand +
   questEncounters (JSON) + questEnc1 (JSON) + questEnc2 + questKid +
   questEnc3 + questEnc4 + questEnc5 + questPrincess + questWeaponLost +
   questVillain + questVillainPronouns (JSON) + questAttacked in
   localStorage.

   All story text lives in TEXT, written in full with {token} substitutions.
   Tokens: {name} plus the pronoun forms {subj} {obj} {posd} {refl}.
   Capitalize the token to capitalize the substitution: {Subj} -> "She" */
(function () {
  var naming = document.getElementById('naming');
  if (!naming) return;

  var TEXT = {
    intro: '{name} was but a simple farmer living in the magical kingdom of' +
      ' Grazaikya, until one day when gade.gg was deleted.',
    setout: '{name} had wanted to log onto gade.gg, {posd} favorite website, but saw' +
      ' that it had been deleted, presumably by an evil, heartless monster.' +
      ' So {subj} picked up {posd} preferred weapon, and embarked on a quest' +
      ' to find the deleted website.',
    traverse: 'Clutching {posd} {weapon} in {posd} {hand} hand, {name}' +
      ' traversed across the lands of Grazaikya, determined to recover the' +
      ' deleted site.',
    enc1: '{name} attempted to cross a bridge over a river, but was' +
      ' accosted by a hideous creature. A bridge troll stopped {obj} and' +
      ' said "Before you may cross the river, you must first answer my' +
      ' riddle!".',
    enc1riddle: '"Very well, then", said {name}, "tell me your riddle,' +
      ' hideous beast". "Wow, rude" said the troll, aghast. It then stood' +
      ' for a moment, waiting for an apology that never came, and then' +
      ' continued: "I run, but never walk; I babble, but never talk. What' +
      ' am I?".',
    enc1attack: '{name} {attacked} the troll{withweapon}, but the' +
      ' troll attacked back, ripping off {posd} leg. {name} {attacked} the' +
      ' troll one more time, which ended its life. {name} hobbled away.',
    enc1wrong: '"{answer}?" asked {name}, unsure of {refl}. "Nope", said' +
      ' the troll, picking up {name} above its head. With a horrible' +
      " sound, the troll ripped off {name}'s leg, and threw {obj} across" +
      ' to the other side of the bridge. {name} hobbled away from the' +
      ' troll, who was laughing triumphantly.',
    enc1correct: '"A river!" said {name}. "Yeah, that\'s right!", answered' +
      ' the troll, "you\'re, like, super smart!". "Now let me pass, hideous' +
      ' beast", demanded {name}. The troll obliged, despite being pretty' +
      ' hurt by the name-calling. {name} continued onwards on {posd} quest.',
    enc2: 'While walking on a path through grassy fields, a young boy, no' +
      ' older than 16, ran up to {name}. "Are you an adventurer? Are you' +
      ' on a quest? Can I join?", the kid asked excitedly.',
    enc2yes: '"Why, certainly. The more the merrier!", said {name},' +
      ' cheerfully. The kid jumped up and twirled around in the air.' +
      ' "You won\'t regret this!", he said, foreshadowingly, "My name\'s' +
      ' Breigan!". Breigan and {name} continued on their quest.',
    enc2no: '"Shouldn\'t you be with your parents, kid?", asked {name}.' +
      ' The boy lowered his head and looked at the ground.' +
      ' "I don\'t have parents", he said, "not since the fire". He then' +
      ' slowly walked away, sulking, leaving {name} to continue {posd}' +
      ' quest alone.',
    enc3: 'At nightfall, {name} came across an abandoned cottage. Feeling' +
      ' tired, {subj} decided to use it for shelter for the night. Inside' +
      ' the cottage, {name} saw a seemingly untouched chest amongst the' +
      ' rubble. {Subj} tried to open it, but it was locked.',
    enc3pryBtn: 'Pry it open with your {weapon}',
    enc3pry: '{name} attempted to force the chest open with {posd}' +
      ' {weapon}. After a few tries, the chest broke open, revealing a' +
      ' horrifying row of teeth inside. The mimic lunged forward towards' +
      ' {name}, who, in {posd} panic, let go of {posd} {weapon}. {name}' +
      ' left the cottage, continuing the quest without {posd} {weapon}.',
    enc3leave: '"Better to leave things like that alone", {name} thought.' +
      " {Subj} had a good night's rest in the cottage, and continued" +
      ' onwards on {posd} quest in the morning.',
    enc4: 'While travelling along a road, {name} met an old man selling' +
      ' potions. "Potionseller!", {subj} said, "I am going into battle,' +
      ' and I need your strongest potions". "Well", the old man answered,' +
      ' "my strongest potions are quite expensive. Do you have the coin?".' +
      ' {name} did, in fact, not have any money.',
    enc4steal: '{name} {attacked} the potionseller{withweapon}, and took' +
      ' one of his potions. Once {subj} was far enough away, {subj} drank' +
      ' it. Suddenly, {subj} could feel {posd} body changing: {posd} limbs' +
      ' shrinking and {posd} nose embiggening. Suddenly, {name} found' +
      ' {refl} in the body of a pig. {Subj} sulked for a bit, and then' +
      ' continued onwards on {posd} quest, as a pig.',
    enc4explain: '"I have no money", {name} said, "but if you-", {subj}' +
      ' continued, but before {subj} could finish, the potionseller spat' +
      ' in {posd} face and said "piss off, poor-y!". {name} continued' +
      ' onwards on {posd} quest, potionless.',
    enc5: '{name} was walking along a road when {subj} passed a tower' +
      ' standing by the path. A beautiful young woman stuck her head out' +
      ' of the tallest window and shouted at {name}, "Oi! Are you here to' +
      ' rescue me?". Flustered, {name} answered "I wasn\'t planning on' +
      ' it. Are you a princess or something?". "Yeah, probably", said the' +
      ' likely princess.',
    enc5decline: '"Actually, I\'m quite busy", said {name}, walking away.' +
      ' "Aw, come on?", the probable princess asked. "No no, I simply' +
      ' must go", replied {name}, already too far away to hear whatever' +
      ' the potential princess said next.',
    enc5agree: '"All right, then", said {name}, "I\'m sure saving you' +
      ' won\'t take too much time". {Subj} looked at {posd} options.',
    enc5vines: '{name} started climbing up the side of the tower,' +
      ' grabbing on to the vines. The probable princess looked puzzled:' +
      ' "You know the door is unlocked, right?". {name}, already out of' +
      ' breath, replied "No, I\'ve committed now!". {Subj} had climbed up' +
      ' roughly 30 cm and was already straining all of {posd} muscles to' +
      ' hang on to the vines. "Seriously", said the princess, worried,' +
      ' "you should really just take the door". {name} lost {posd} grip' +
      ' on the vines and tumbled to the ground. Embarrassed, {subj}' +
      ' quickly ran away, continuing {posd} quest.',
    enc5door: '{name} walked up to the front door, expecting it to be' +
      ' locked. It was not. {Subj} then walked up the spiral staircase,' +
      ' expecting to be jumped by a monster or something. {Subj} was not.' +
      " Finally, {subj} reached the potential princess' door, which was" +
      ' already open. "I\'m confused", said {name}, "What did you need' +
      ' saving from?". "Boredom, mainly", replied the' +
      ' now-not-quite-so-likely princess. "I\'m Anastasia, by the way",' +
      ' she said, while walking down the stairs. Before {name} could' +
      ' protest, Anastasia had already joined {posd} quest.',
    princessrename: "{name} didn't like Anastasia's name, so {subj}" +
      ' started calling her {princess} instead.',
    kidrename: "{name} didn't like Breigan's name, so {subj} started" +
      ' calling him {kid} instead.',
    arrival: '{name} arrived at the tower of the evil wizard {subj} had' +
      ' heard was behind the deletion of gade.gg, {posd} favorite website.',
    confront: '{name} went inside the tower, seeing the massive dark' +
      ' gothic interior. There, sitting on a throne, was {vname}.' +
      ' "I suspect you have come to kill me", {vsubj} said, "for deleting' +
      ' gade.gg, your favorite website."'
  };

  /* The showdown endings, one handwritten text per situation. Key:
     chosen encounters' 1-based pool positions, a colon, then one S/F
     letter each, all in pool order — '123:SFS' = troll+kid+mimic with
     only the kid failed. Success is: troll = riddle solved, Breigan = joined,
     mimic = chest left alone. The wizard is only beatable with >= 2 S.
     Villain tokens: {vname} {vsubj} {vobj} {vposd} {vrefl}.
     Empty entries render nothing */
  var ENDINGS = {
    '123:SSS': '{name} ran towards {vname}, {attacking} {vobj} with {posd}' +
      ' {weapon}. {kid} came up behind {vname}, pushing {vobj}, and' +
      ' making {vobj} lose {vposd} balance. {vname} tried to cast a spell' +
      ' at either of them, but it was too late. {name} and {kid} killed' +
      ' {vname}, restoring the website for good.',
    '123:SSF': '{name} and {kid} ran towards {vname}, ready to punch {vobj}.' +
      ' With a flick of {vposd} wrist, {vname} cast a spell on {kid},' +
      ' disintegrating him immediately. {name} yelled out towards him, but' +
      ' there was nothing {subj} could do. Nothing, except avenge him.' +
      ' {name} ran up to {vname} and delivered a powerful punch. A punch' +
      ' so powerful that {vposd} head exploded. {vname} was dead, and the' +
      ' website was restored for good.',
    '123:SFS': '{name} ran towards {vname}. An epic duel commenced, with {vname}' +
      ' throwing spells and {name} {attacking} with {posd} {weapon}.' +
      ' Finally, when the dust settled, {name} stood victorious. {vname}' +
      ' was dead, and the website was restored for good.',
    '123:SFF': '{name} ran towards {vname}, ready to punch {vobj}. With a flick' +
      ' of {vposd} wrist, {vname} cast a spell on {name}, disintegrating' +
      ' {obj} immediately.',
    '123:FSS': '{name} hobbled towards {vname}, {attacking} {vobj} with {posd}' +
      ' {weapon}. {kid} came up behind {vname}, pushing {vobj}, and' +
      ' making {vobj} lose {vposd} balance. {vname} tried to cast a spell' +
      ' at either of them, but it was too late. {name} and {kid} killed' +
      ' {vname}, restoring the website for good.',
    '123:FSF': '{name} hobbled towards {vname}, ready to punch {vobj}. With a' +
      ' flick of {vposd} wrist, {vname} cast a spell on {kid},' +
      ' disintegrating him immediately. {name} yelled out towards him, but' +
      ' there was nothing {subj} could do. With another flick of {vposd}' +
      ' wrist, {vname} cast the same spell on {name}, disintegrating {obj}' +
      ' as well.',
    '123:FFS': '{name} hobbled towards {vname}, {attacking} {vobj} with {posd}' +
      ' {weapon}. With a flick of {vposd} wrist, {vname} cast a spell on' +
      ' {name}, disintegrating {obj} immediately.',
    '123:FFF': '{name} hobbled towards {vname}, ready to punch {vobj}. With a' +
      ' flick of {vposd} wrist, {vname} cast a spell on {name},' +
      ' disintegrating {obj} immediately.',
    /* Family 124 (troll, Breigan, potion): the one-legged pigs. The
       other six situations are aliased below */
    '124:FSF': '{name} hobbled towards {vname} on {posd} three remaining' +
      ' trotters, {posd} {weapon} clenched in {posd} pig mouth, with' +
      ' {kid} running ahead. With a flick of {vposd} wrist, {vname} cast' +
      ' a spell on {kid}, disintegrating him immediately. {name} let out' +
      ' a devastated squeal. With another flick of {vposd} wrist, {vname}' +
      ' cast the same spell on {name}, disintegrating {obj} as well.',
    '124:FFF': '{name} hobbled towards {vname} on {posd} three remaining' +
      ' trotters, {attacking} {vobj} with {posd} {weapon}. {vname}' +
      ' watched the limping pig approach for a while, mildly fascinated.' +
      ' Then, with a flick of {vposd} wrist, {vsubj} cast a spell on' +
      ' {name}, disintegrating {obj} immediately.',
    /* Family 134 (troll, mimic, potion): no Breigan, so the win
       threshold lands differently — same body, different fate. The
       three overlapping-outcome situations are aliased below */
    '134:SSF': '{name} charged towards {vname}, clutching {posd} {weapon}' +
      ' in {posd} pig mouth. {vname} laughed at the sight, flicking' +
      ' {vposd} wrist to cast a spell. But the spell missed: {vname} had' +
      ' never fought a pig before, and pigs are much lower to the ground' +
      ' than the heroes {vsubj} was used to. {name} {attacked} {vobj}' +
      ' before {vsubj} could try again. {vname} was dead, and the website' +
      ' was restored for good.',
    '134:SFS': '{name} ran towards {vname}, ready to punch {vobj}.' +
      ' {vname} flicked {vposd} wrist and cast a spell, but {name} dodged' +
      ' it and kept running. {Subj} reached the throne and delivered a' +
      ' powerful punch. A punch so powerful that {vposd} head exploded.' +
      ' {vname} was dead, and the website was restored for good.',
    '134:FSS': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}. An epic duel commenced, with {vname} throwing' +
      ' spells and {name} deflecting them on one leg. Finally, when the' +
      ' dust settled, {name} stood victorious. {vname} was dead, and the' +
      ' website was restored for good.',
    '134:FFS': '{name} hobbled towards {vname}, ready to punch {vobj}.' +
      ' {vname} watched {posd} slow approach with something between pity' +
      ' and boredom. With a flick of {vposd} wrist, {vname} cast a spell' +
      ' on {name}, disintegrating {obj} immediately.',
    '134:FFF': '{name} hobbled towards {vname} on {posd} three remaining' +
      ' trotters, ready to bite {vobj}. {vname} waited politely for the' +
      ' pig to arrive. Then, with a flick of {vposd} wrist, {vsubj} cast' +
      ' a spell on {name}, disintegrating {obj} immediately.',
    /* Family 234 (Breigan, mimic, potion): pig situations. The human
       ones are aliased from family 123 below */
    '234:SSF': '{name} charged towards {vname}, clutching {posd} {weapon}' +
      ' in {posd} pig mouth. {vname} hesitated. {Vsubj} had prepared for' +
      ' many things, but not for a pig with {aweapon}. {kid} used the' +
      ' moment to come up behind {vname}, pushing {vobj} and making {vobj}' +
      ' lose {vposd} balance. {name} {attacked} {vobj} before {vsubj}' +
      ' could get back up. {vname} was dead, and the website was restored' +
      ' for good.',
    '234:SFF': '{kid} ran towards {vname}, ready to punch {vobj}, with' +
      ' {name} trotting closely behind. With a flick of {vposd} wrist,' +
      ' {vname} cast a spell on {kid}, disintegrating him immediately.' +
      ' {name} let out a devastated squeal. With another flick of {vposd}' +
      ' wrist, {vname} cast the same spell on {name}, disintegrating {obj}' +
      ' as well.',
    '234:FSF': '{name} trotted towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}. {vname} was briefly impressed by the sight of a' +
      ' pig wielding {aweapon}, but not enough to be stopped. With a' +
      ' flick of {vposd} wrist, {vname} cast a spell on {name},' +
      ' disintegrating {obj} immediately.',
    '234:FFF': '{name} trotted towards {vname}, ready to bite {vobj}.' +
      ' {vname} looked at the pig for a long moment, almost feeling sorry' +
      ' for it. Then, with a flick of {vposd} wrist, {vsubj} cast a spell' +
      ' on {name}, disintegrating {obj} immediately.',
    /* Family 345 (mimic, potion, princess): Anastasia situations. The
       princess-less four are aliased below */
    '345:SSS': '{name} ran towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}. {vname} blocked the attack with a shield spell' +
      ' and began preparing a counterattack. While the wizard was busy,' +
      ' {princess} calmly walked up behind {vobj} and kicked {vobj} off' +
      ' the throne. {name} {attacked} {vobj} one final time before' +
      ' {vsubj} could get up. {vname} was dead, and the website was' +
      ' restored for good.',
    '345:SFS': '{name} charged towards {vname}, clutching {posd} {weapon}' +
      ' in {posd} pig mouth. "Is that a pig?", asked {vname}, bewildered.' +
      ' "I\'m honestly as confused as you are", answered {princess},' +
      ' already walking up behind the throne. Before {vname} could figure' +
      ' out what was going on, {princess} pushed {vobj} to the ground,' +
      ' and {name} {attacked} {vobj}. {vname} was dead, and the website' +
      ' was restored for good.',
    '345:FSS': '{name} ran towards {vname}, ready to punch {vobj}.' +
      ' {vname} flicked {vposd} wrist and cast a spell at {name}, but' +
      ' {princess} pulled {obj} out of the way at the last moment. Before' +
      ' {vname} could try again, {name} reached the throne and delivered' +
      ' a powerful punch. A punch so powerful that {vposd} head exploded.' +
      ' {vname} was dead, and the website was restored for good.',
    '345:FFS': '{name} trotted towards {vname}, ready to bite {vobj},' +
      ' with {princess} walking behind. With a flick of {vposd} wrist,' +
      ' {vname} cast a spell at {princess}, who calmly sidestepped it.' +
      ' {Vsubj} then cast the same spell at {name}, who did not sidestep' +
      ' it, and was disintegrated immediately. {princess} shrugged, and' +
      ' showed herself out.',
    /* Family 145 (troll, potion, princess): the one-legged Anastasia
       situations. The other six are aliased below */
    '145:FSS': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}. {vname} aimed a spell at {posd} remaining leg,' +
      ' but {princess} threw a rock at {vposd} head, ruining {vposd}' +
      ' concentration. Before {vname} could recover, {name} reached the' +
      ' throne and {attacked} {vobj} one final time. {vname} was dead,' +
      ' and the website was restored for good.',
    '145:FFS': '{name} hobbled towards {vname} on {posd} three remaining' +
      ' trotters, {posd} {weapon} clenched in {posd} pig mouth, with' +
      ' {princess} walking behind. With a flick of {vposd} wrist, {vname}' +
      ' cast a spell at {princess}, who calmly sidestepped it. {Vsubj}' +
      ' then cast the same spell at {name}, who, being a three-legged' +
      ' pig, could not. {princess} sighed, muttered something under her' +
      ' breath, and left the tower.',
    /* Family 135 (troll, mimic, princess): one new situation — the rest
       alias below */
    '135:FFS': '{name} hobbled towards {vname}, ready to punch {vobj},' +
      ' leaning on {princess} for support. With a flick of {vposd} wrist,' +
      ' {vname} cast a spell at {princess}, who calmly sidestepped it.' +
      ' {Vsubj} then cast the same spell at {name}, who could not' +
      ' sidestep anything, and was disintegrated immediately. {princess}' +
      ' stood in silence for a moment, then left the tower without a word.',
    /* Family 125 (troll, Breigan, princess): armed human throughout, so
       three losses have no armed-and-able precedent to alias */
    '125:SSS': '{name}, {kid} and {princess} charged towards {vname}' +
      ' together. {vname} began casting a spell, but {princess} reached' +
      ' the throne first and pushed {vobj} to the floor. What followed' +
      ' was less of a battle and more of a group activity: the three of' +
      ' them simply kicked {vname} until {vsubj} stopped moving. {name}' +
      ' had briefly considered using {posd} {weapon}, but kicking had' +
      ' felt more appropriate. {vname} was dead, and the website was' +
      ' restored for good.',
    '125:FSS': '{name} hobbled towards {vname}, but {kid} and {princess}' +
      ' had already run ahead. {princess} knocked {vname} to the ground,' +
      ' and {kid} sat down on {vposd} back to keep {vobj} there. By the' +
      ' time {name} finally reached the throne, {vname} was already dead.' +
      ' {Subj} tried not to feel left out. The website was restored for' +
      ' good.',
    '125:SFF': '{name} ran towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}. An epic duel commenced, with {vname} throwing' +
      ' spells and {name} {attacking} back. Slowly, however, {name} began' +
      ' to tire. With a flick of {vposd} wrist, {vname} cast a spell on' +
      ' {name}, disintegrating {obj} immediately.',
    '125:FSF': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}, with {kid} running ahead. With a flick of' +
      ' {vposd} wrist, {vname} cast a spell on {kid}, disintegrating him' +
      ' immediately. {name} let out a scream and {attacked} {vobj} with' +
      ' everything {subj} had left. It was not enough. With another flick' +
      ' of {vposd} wrist, {vname} cast the same spell on {name},' +
      ' disintegrating {obj} as well.',
    '125:FFS': '{name} hobbled towards {vname}, {attacking} {vobj} with' +
      ' {posd} {weapon}, leaning on {princess} for support. With a flick' +
      ' of {vposd} wrist, {vname} cast a spell at {princess}, who calmly' +
      ' sidestepped it. {name}, who had been leaning on her, lost {posd}' +
      ' balance and fell. With another flick of {vposd} wrist, {vname}' +
      ' cast a spell on {name}, disintegrating {obj} immediately.' +
      ' {princess} gave {vname} a long, disappointed look, and left the' +
      ' tower.',
    /* Family 235 (Breigan, mimic, princess): intact human throughout.
       The weaponless group kicking needs its own entry (the 125 version
       mentions the weapon); plus the unarmed one-companion losses */
    '235:SFS': '{name}, {kid} and {princess} charged towards {vname}' +
      ' together. {vname} began casting a spell, but {princess} reached' +
      ' the throne first and pushed {vobj} to the floor. What followed' +
      ' was less of a battle and more of a group activity: the three of' +
      ' them simply kicked {vname} until {vsubj} stopped moving. {vname}' +
      ' was dead, and the website was restored for good.',
    '235:SFF': '{name} and {kid} ran towards {vname}, ready to punch' +
      ' {vobj}. With a flick of {vposd} wrist, {vname} cast a spell on' +
      ' {kid}, disintegrating him immediately. {name} yelled out towards' +
      ' him, but there was nothing {subj} could do. With another flick of' +
      ' {vposd} wrist, {vname} cast the same spell on {name},' +
      ' disintegrating {obj} as well.',
    '235:FFS': '{name} ran towards {vname}, ready to punch {vobj}, with' +
      ' {princess} running beside {obj}. With a flick of {vposd} wrist,' +
      ' {vname} cast a spell at {princess}, who calmly sidestepped it.' +
      ' {Vsubj} then cast the same spell at {name}, who tried to sidestep' +
      ' it the same way {princess} had. {Subj} did not succeed, and was' +
      ' disintegrated immediately. {princess} pinched the bridge of her' +
      ' nose, turned around, and left the tower.',
    /* Family 245 (Breigan, potion, princess): armed and able-bodied
       throughout — the news are the pig situations */
    '245:SFS': '{name}, {kid} and {princess} charged towards {vname}' +
      ' together. {vname} took a moment too long deciding whether to aim' +
      ' at the boy, the princess, or the pig with {aweapon} in its mouth.' +
      ' {princess} used that moment to push {vobj} off the throne, {kid}' +
      ' pinned {vposd} arms, and {name} {attacked} {vobj}. {vname} was' +
      ' dead, and the website was restored for good.',
    '245:SFF': '{kid} ran towards {vname}, with {name} trotting behind,' +
      ' {posd} {weapon} clenched in {posd} pig mouth. With a flick of' +
      ' {vposd} wrist, {vname} cast a spell on {kid}, disintegrating him' +
      ' immediately. {name} let out a devastated squeal and charged. With' +
      ' another flick of {vposd} wrist, {vname} cast the same spell on' +
      ' {name}, disintegrating {obj} as well.',
    '245:FFS': '{name} trotted towards {vname}, {posd} {weapon} clenched' +
      ' in {posd} pig mouth, with {princess} walking behind. With a flick' +
      ' of {vposd} wrist, {vname} cast a spell at {princess}, who calmly' +
      ' sidestepped it. {Vsubj} then cast the same spell at {name}. The' +
      ' {weapon} clattered to the floor, its owner now a pile of dust.' +
      ' {princess} picked it up, considered it for a moment, then put it' +
      ' down again and left the tower.'
  };
  /* Family 234 with a human hero (potion succeeded) is the same fight as
     the corresponding two-legged 123 ending, reused verbatim */
  ENDINGS['234:SSS'] = ENDINGS['123:SSS'];
  ENDINGS['234:SFS'] = ENDINGS['123:SSF'];
  ENDINGS['234:FSS'] = ENDINGS['123:SFS'];
  ENDINGS['234:FFS'] = ENDINGS['123:SFF'];
  /* Family 124 reuses: humans match 123 (same legs/kid/weapon), pigs
     with both legs match 234 */
  ENDINGS['124:SSS'] = ENDINGS['123:SSS'];
  ENDINGS['124:SSF'] = ENDINGS['234:SSF'];
  ENDINGS['124:SFS'] = ENDINGS['123:SFS'];
  ENDINGS['124:SFF'] = ENDINGS['234:FSF'];
  ENDINGS['124:FSS'] = ENDINGS['123:FSS'];
  ENDINGS['124:FFS'] = ENDINGS['123:FFS'];
  /* Family 134 reuses, matched on state AND outcome */
  ENDINGS['134:SSS'] = ENDINGS['123:SFS'];
  ENDINGS['134:SFF'] = ENDINGS['234:FFF'];
  ENDINGS['134:FSF'] = ENDINGS['124:FFF'];
  /* Family 345 reuses: no princess collapses to lone-hero situations */
  ENDINGS['345:SSF'] = ENDINGS['123:SFS'];
  ENDINGS['345:SFF'] = ENDINGS['234:FSF'];
  ENDINGS['345:FSF'] = ENDINGS['123:SFF'];
  ENDINGS['345:FFF'] = ENDINGS['234:FFF'];
  /* Family 125 reuses (letters: troll, Breigan, princess) */
  ENDINGS['125:SSF'] = ENDINGS['123:SSS'];
  ENDINGS['125:SFS'] = ENDINGS['345:SSS'];
  ENDINGS['125:FFF'] = ENDINGS['123:FFS'];
  /* Family 245 reuses (letters: Breigan, potion, princess) */
  ENDINGS['245:SSS'] = ENDINGS['125:SSS'];
  ENDINGS['245:SSF'] = ENDINGS['123:SSS'];
  ENDINGS['245:FSS'] = ENDINGS['345:SSS'];
  ENDINGS['245:FSF'] = ENDINGS['125:SFF'];
  ENDINGS['245:FFF'] = ENDINGS['234:FSF'];
  /* Family 235 reuses (letters: Breigan, mimic, princess) */
  ENDINGS['235:SSS'] = ENDINGS['125:SSS'];
  ENDINGS['235:SSF'] = ENDINGS['123:SSS'];
  ENDINGS['235:FSS'] = ENDINGS['345:SSS'];
  ENDINGS['235:FSF'] = ENDINGS['125:SFF'];
  ENDINGS['235:FFF'] = ENDINGS['123:SFF'];
  /* Family 135 reuses (letters: troll, mimic, princess) */
  ENDINGS['135:SSS'] = ENDINGS['345:SSS'];
  ENDINGS['135:SSF'] = ENDINGS['123:SFS'];
  ENDINGS['135:SFS'] = ENDINGS['345:FSS'];
  ENDINGS['135:SFF'] = ENDINGS['123:SFF'];
  ENDINGS['135:FSS'] = ENDINGS['145:FSS'];
  ENDINGS['135:FSF'] = ENDINGS['123:FFS'];
  ENDINGS['135:FFF'] = ENDINGS['134:FFS'];
  /* Family 145 reuses (letters: troll, potion, princess) */
  ENDINGS['145:SSS'] = ENDINGS['345:SSS'];
  ENDINGS['145:SSF'] = ENDINGS['123:SFS'];
  ENDINGS['145:SFS'] = ENDINGS['345:SFS'];
  ENDINGS['145:SFF'] = ENDINGS['234:FSF'];
  ENDINGS['145:FSF'] = ENDINGS['123:FFS'];
  ENDINGS['145:FFF'] = ENDINGS['124:FFF'];

  /* The encounter pool. ROLLED of these are drawn per hero when the hand
     is chosen, stored in order in questEncounters; the ENDINGS set
     signature uses 1-based pool positions. Each entry knows how its save
     key resolves and what counts as success */
  var POOL = ['troll', 'kid', 'mimic', 'potion', 'princess'];
  var ROLLED = 3;
  function rollEncounters() {
    var pool = POOL.slice();
    var picked = [];
    while (picked.length < ROLLED && pool.length) {
      picked.push(pool.splice(Math.floor(Math.random() * pool.length), 1)[0]);
    }
    return picked;
  }

  /* The hero. The weapon is an icon glyph dropped into the {w} cell of the
     art (a fixed 2ch box, so the monospace grid survives). Keys are viewer
     sides, not hands: the hero faces the viewer */
  var ART = {
    base: ' o\n/|\\\n/ \\',
    right: ' o\n/|\\_{w}\n/ \\',
    left: '    o\n{w}_/|\\\n   / \\',
    /* Breigan, age 16, shorter than the hero */
    kid: ' o\n/|\\',
    /* Anastasia. The circumflex is a crown */
    princess: ' \u00f4\n/|\\\n/ \\',
    /* The hero as a pig (potion theft). Still clutches the weapon */
    pig: {
      base: '^..^\n(oo)\n /\\',
      right: '^..^\n(oo)_{w}\n /\\',
      left: '   ^..^\n{w}_(oo)\n    /\\'
    }
  };

  /* fa: Font Awesome class; em: Noto Emoji glyph (subsetted into
     fonts/noto-emoji.woff2 — resubset if the roster changes);
     attacked/attacking: the combat verbs */
  var WEAPONS = {
    sword: { em: '\uD83D\uDDE1', rot: true, attacked: 'slashed', attacking: 'slashing' },
    axe:   { em: '\uD83E\uDE93', reversed: true, attacked: 'chopped', attacking: 'chopping' },
    wand:  { fa: 'fa-wand-sparkles', attacked: 'zapped', attacking: 'zapping' },
    gun:   { fa: 'fa-gun', attacked: 'shot', attacking: 'shooting' }
  };

  var PRESETS = {
    she:  { subj: 'she',  obj: 'her',  posd: 'her',   refl: 'herself' },
    he:   { subj: 'he',   obj: 'him',  posd: 'his',   refl: 'himself' },
    they: { subj: 'they', obj: 'them', posd: 'their', refl: 'themself' }
  };

  var story = document.getElementById('story');
  var pronouns = document.getElementById('pronouns');
  var custom = document.getElementById('custom');
  var weapon = document.getElementById('weapon');
  var hand = document.getElementById('hand');
  var vnaming = document.getElementById('vnaming');
  var vpronouns = document.getElementById('vpronouns');

  function loadKey(key) {
    try { return localStorage.getItem(key); } catch (e) { return null; }
  }
  function saveKey(key, value) {
    try { localStorage.setItem(key, value); } catch (e) {}
  }
  function state() {
    var pron = null, enc1 = null, vpron = null, order = null;
    try { pron = JSON.parse(loadKey('questPronouns')); } catch (e) {}
    try { enc1 = JSON.parse(loadKey('questEnc1')); } catch (e) {}
    try { vpron = JSON.parse(loadKey('questVillainPronouns')); } catch (e) {}
    try { order = JSON.parse(loadKey('questEncounters')); } catch (e) {}
    var weaponKey = loadKey('questWeapon');
    return {
      name: loadKey('questHero'),
      pron: pron,
      weapon: WEAPONS[weaponKey] ? weaponKey : null,
      hand: loadKey('questHand'),
      /* The rolled encounter ids, in play order */
      order: order && order.length ? order : null,
      /* Set by the mimic eating the weapon: bare fists from then on,
         {attacked} becomes 'punched' */
      weaponLost: loadKey('questWeaponLost') === '1',
      /* { asked: bool, result: 'attack'|'solved'|'wrong'|null,
           answer: string (wrong only) } */
      enc1: enc1,
      /* 'yes' (Breigan joins) | 'no' | null */
      enc2: loadKey('questEnc2'),
      /* The kid's name once the rename question is answered ('Breigan'
         if declined); null while unanswered. He/him either way */
      kid: loadKey('questKid'),
      /* 'pry' (mimic eats the weapon) | 'leave' | null */
      enc3: loadKey('questEnc3'),
      /* 'steal' (hero becomes a pig) | 'explain' | null */
      enc4: loadKey('questEnc4'),
      /* 'decline' | 'agree' (mid-choice) | 'vines' | 'door' | null */
      enc5: loadKey('questEnc5'),
      /* The princess's name once the rename question is answered
         ('Anastasia' if declined); null while unanswered */
      princess: loadKey('questPrincess'),
      vname: loadKey('questVillain'),
      vpron: vpron,
      attacked: loadKey('questAttacked') === '1'
    };
  }

  function fill(text, vars) {
    return text.replace(/\{([A-Za-z]+)\}/g, function (token, key) {
      var value = vars[key.toLowerCase()];
      if (value === undefined) return token;
      if (key[0] !== key[0].toLowerCase()) {
        value = value.charAt(0).toUpperCase() + value.slice(1);
      }
      return value;
    });
  }

  /* Everything on the page is a function of the save file */
  function render() {
    var s = state();
    var vars = { name: s.name, kid: s.kid || 'Breigan',
      princess: s.princess || 'Anastasia' };
    if (s.pron) for (var k in s.pron) vars[k] = s.pron[k];
    naming.style.display = s.name ? 'none' : '';
    story.style.display = s.name ? '' : 'none';
    pronouns.style.display = s.name && !s.pron ? '' : 'none';
    weapon.style.display = s.pron && !s.weapon ? '' : 'none';
    hand.style.display = s.weapon && !s.hand ? '' : 'none';
    if (s.name) {
      document.getElementById('intro').textContent = fill(TEXT.intro, vars);
    }
    var setout = document.getElementById('setout');
    setout.style.display = s.pron ? '' : 'none';
    if (s.pron) setout.textContent = fill(TEXT.setout, vars);
    var traverse = document.getElementById('traverse');
    var armed = s.weapon && s.hand;
    traverse.style.display = armed ? '' : 'none';
    if (armed) {
      vars.weapon = s.weapon;
      /* {aweapon}: article included — 'a sword' but 'an axe' */
      vars.aweapon = (/^[aeiou]/.test(s.weapon) ? 'an ' : 'a ') + s.weapon;
      vars.hand = s.hand;
      traverse.textContent = fill(TEXT.traverse, vars);
    }

    /* The roll: which encounters this hero gets, in which order. Rolled
       lazily so pre-roll saves pick one up on their next render */
    var order = s.order;
    if (armed && !order) {
      order = rollEncounters();
      saveKey('questEncounters', JSON.stringify(order));
    }
    var resolvedEnc = {
      troll: !!(s.enc1 && s.enc1.result),
      kid: s.enc2 === 'no' || (s.enc2 === 'yes' && !!s.kid),
      mimic: !!s.enc3,
      potion: !!s.enc4,
      princess: s.enc5 === 'decline' || s.enc5 === 'vines' ||
        (s.enc5 === 'door' && !!s.princess)
    };
    /* Reorder the story's encounter groups to match the roll, and find
       the single encounter currently awaiting the player */
    var active = null;
    var arrival = document.getElementById('arrival');
    if (armed && order) {
      for (var oi = 0; oi < order.length; oi++) {
        var g = document.getElementById(
          'grp' + order[oi].charAt(0).toUpperCase() + order[oi].slice(1));
        if (g) story.insertBefore(g, arrival);
        if (active === null && !resolvedEnc[order[oi]]) active = order[oi];
      }
    }
    function appeared(id) {
      if (!armed || !order || order.indexOf(id) < 0) return false;
      return resolvedEnc[id] || id === active;
    }
    /* Weapon state as of a given encounter: lost only if the mimic ate it
       earlier in the order (texts must not change retroactively) */
    function armedAt(id) {
      var i = order ? order.indexOf(id) : -1;
      for (var j = 0; j < i; j++) {
        if (order[j] === 'mimic' && s.enc3 === 'pry') return false;
      }
      return true;
    }
    function combatVars(isArmed) {
      vars.attacked = isArmed ? WEAPONS[s.weapon].attacked : 'punched';
      vars.withweapon = isArmed ? ' with ' + vars.posd + ' ' + s.weapon : '';
    }

    /* The bridge troll's riddle */
    var showTroll = appeared('troll');
    if (showTroll) combatVars(armedAt('troll'));
    var enc1 = document.getElementById('enc1');
    enc1.style.display = showTroll ? '' : 'none';
    if (showTroll) enc1.textContent = fill(TEXT.enc1, vars);
    document.getElementById('enc1choice').style.display =
      showTroll && !s.enc1 ? '' : 'none';
    var asked = showTroll && s.enc1 && s.enc1.asked;
    var enc1riddle = document.getElementById('enc1riddle');
    enc1riddle.style.display = asked ? '' : 'none';
    if (asked) enc1riddle.textContent = fill(TEXT.enc1riddle, vars);
    document.getElementById('riddle').style.display =
      asked && !s.enc1.result ? '' : 'none';
    var attacked = showTroll && s.enc1 && s.enc1.result === 'attack';
    var enc1attack = document.getElementById('enc1attack');
    enc1attack.style.display = attacked ? '' : 'none';
    if (attacked) enc1attack.textContent = fill(TEXT.enc1attack, vars);
    var wrong = showTroll && s.enc1 && s.enc1.result === 'wrong';
    var enc1wrong = document.getElementById('enc1wrong');
    enc1wrong.style.display = wrong ? '' : 'none';
    if (wrong) {
      vars.answer = s.enc1.answer;
      enc1wrong.textContent = fill(TEXT.enc1wrong, vars);
    }
    var solved = showTroll && s.enc1 && s.enc1.result === 'solved';
    var enc1correct = document.getElementById('enc1correct');
    enc1correct.style.display = solved ? '' : 'none';
    if (solved) enc1correct.textContent = fill(TEXT.enc1correct, vars);

    /* Breigan */
    var showKid = appeared('kid');
    var enc2 = document.getElementById('enc2');
    enc2.style.display = showKid ? '' : 'none';
    if (showKid) enc2.textContent = fill(TEXT.enc2, vars);
    document.getElementById('enc2choice').style.display =
      showKid && !s.enc2 ? '' : 'none';
    var enc2yes = document.getElementById('enc2yes');
    var joined = showKid && s.enc2 === 'yes';
    enc2yes.style.display = joined ? '' : 'none';
    if (joined) enc2yes.textContent = fill(TEXT.enc2yes, vars);
    var enc2no = document.getElementById('enc2no');
    var declined = showKid && s.enc2 === 'no';
    enc2no.style.display = declined ? '' : 'none';
    if (declined) enc2no.textContent = fill(TEXT.enc2no, vars);
    /* The rename question holds up the journey until answered */
    document.getElementById('rename').style.display =
      joined && !s.kid ? '' : 'none';

    /* The mimic chest */
    var showMimic = appeared('mimic');
    var enc3 = document.getElementById('enc3');
    enc3.style.display = showMimic ? '' : 'none';
    if (showMimic) enc3.textContent = fill(TEXT.enc3, vars);
    var choosing3 = showMimic && !s.enc3;
    document.getElementById('enc3choice').style.display = choosing3 ? '' : 'none';
    if (choosing3) {
      document.getElementById('pryBtn').textContent = fill(TEXT.enc3pryBtn, vars);
    }
    var pried = showMimic && s.enc3 === 'pry';
    var enc3pry = document.getElementById('enc3pry');
    enc3pry.style.display = pried ? '' : 'none';
    if (pried) enc3pry.textContent = fill(TEXT.enc3pry, vars);
    var left = showMimic && s.enc3 === 'leave';
    var enc3leave = document.getElementById('enc3leave');
    enc3leave.style.display = left ? '' : 'none';
    if (left) enc3leave.textContent = fill(TEXT.enc3leave, vars);

    /* The potion seller */
    var showPotion = appeared('potion');
    var enc4 = document.getElementById('enc4');
    enc4.style.display = showPotion ? '' : 'none';
    if (showPotion) enc4.textContent = fill(TEXT.enc4, vars);
    document.getElementById('enc4choice').style.display =
      showPotion && !s.enc4 ? '' : 'none';
    var stole = showPotion && s.enc4 === 'steal';
    var enc4steal = document.getElementById('enc4steal');
    enc4steal.style.display = stole ? '' : 'none';
    if (stole) {
      combatVars(armedAt('potion'));
      enc4steal.textContent = fill(TEXT.enc4steal, vars);
    }
    var explained = showPotion && s.enc4 === 'explain';
    var enc4explain = document.getElementById('enc4explain');
    enc4explain.style.display = explained ? '' : 'none';
    if (explained) enc4explain.textContent = fill(TEXT.enc4explain, vars);

    /* Breigan's rename line (only when he was actually renamed) */
    var kidrename = document.getElementById('kidrename');
    var kidRenamed = joined && s.kid && s.kid !== 'Breigan';
    kidrename.style.display = kidRenamed ? '' : 'none';
    if (kidRenamed) kidrename.textContent = fill(TEXT.kidrename, vars);

    /* The probable princess */
    var showPrincess = appeared('princess');
    var enc5 = document.getElementById('enc5');
    enc5.style.display = showPrincess ? '' : 'none';
    if (showPrincess) enc5.textContent = fill(TEXT.enc5, vars);
    document.getElementById('enc5choice').style.display =
      showPrincess && !s.enc5 ? '' : 'none';
    var declined5 = showPrincess && s.enc5 === 'decline';
    var enc5decline = document.getElementById('enc5decline');
    enc5decline.style.display = declined5 ? '' : 'none';
    if (declined5) enc5decline.textContent = fill(TEXT.enc5decline, vars);
    var agreed = showPrincess && (s.enc5 === 'agree' ||
      s.enc5 === 'vines' || s.enc5 === 'door');
    var enc5agree = document.getElementById('enc5agree');
    enc5agree.style.display = agreed ? '' : 'none';
    if (agreed) enc5agree.textContent = fill(TEXT.enc5agree, vars);
    document.getElementById('enc5method').style.display =
      showPrincess && s.enc5 === 'agree' ? '' : 'none';
    var fell = showPrincess && s.enc5 === 'vines';
    var enc5vines = document.getElementById('enc5vines');
    enc5vines.style.display = fell ? '' : 'none';
    if (fell) enc5vines.textContent = fill(TEXT.enc5vines, vars);
    var rescued = showPrincess && s.enc5 === 'door';
    var enc5door = document.getElementById('enc5door');
    enc5door.style.display = rescued ? '' : 'none';
    if (rescued) enc5door.textContent = fill(TEXT.enc5door, vars);
    document.getElementById('prename').style.display =
      rescued && !s.princess ? '' : 'none';
    var princessrename = document.getElementById('princessrename');
    var pRenamed = rescued && s.princess && s.princess !== 'Anastasia';
    princessrename.style.display = pRenamed ? '' : 'none';
    if (pRenamed) princessrename.textContent = fill(TEXT.princessrename, vars);

    /* The wizard's tower: arrival, villain creation, then the ending */
    var encountersDone = armed && order && active === null;
    arrival.style.display = encountersDone ? '' : 'none';
    if (encountersDone) arrival.textContent = fill(TEXT.arrival, vars);
    vnaming.style.display = encountersDone && !s.vname ? '' : 'none';
    vpronouns.style.display =
      encountersDone && s.vname && !s.vpron ? '' : 'none';
    var showdown = encountersDone && s.vname && s.vpron;
    var confront = document.getElementById('confront');
    confront.style.display = showdown ? '' : 'none';
    if (showdown) {
      vars.vname = s.vname;
      for (var vk in s.vpron) vars['v' + vk] = s.vpron[vk];
      /* Showdown-time forms: unlike the troll fight, the ending happens
         after any weapon loss, so here punched/bare-handed applies */
      vars.attacked = s.weaponLost ? 'punched' : WEAPONS[s.weapon].attacked;
      vars.attacking = s.weaponLost ? 'punching' : WEAPONS[s.weapon].attacking;
      vars.withweapon = s.weaponLost ? '' : ' with ' + vars.posd + ' ' + s.weapon;
      confront.textContent = fill(TEXT.confront, vars);
    }
    document.getElementById('showdownAttack').style.display =
      showdown && !s.attacked ? '' : 'none';
    var ending = document.getElementById('ending');
    var endingText = '';
    var won = false;
    if (showdown && s.attacked) {
      /* The situation key: chosen encounters in pool order (1-based
         positions), then their outcomes in the same order */
      var successOf = {
        troll: s.enc1 && s.enc1.result === 'solved',
        kid: s.enc2 === 'yes',
        mimic: s.enc3 === 'leave',
        potion: s.enc4 === 'explain',
        princess: s.enc5 === 'door'
      };
      var chosen = order.slice().sort(function (a, b) {
        return POOL.indexOf(a) - POOL.indexOf(b);
      });
      var sig = '', letters = '', successes = 0;
      chosen.forEach(function (id) {
        sig += POOL.indexOf(id) + 1;
        letters += successOf[id] ? 'S' : 'F';
        successes += successOf[id] ? 1 : 0;
      });
      won = successes >= 2;
      endingText = ENDINGS[sig + ':' + letters] || '';
    }
    ending.style.display = endingText ? '' : 'none';
    if (endingText) ending.textContent = fill(endingText, vars);
    document.getElementById('endWin').style.display =
      showdown && s.attacked && won ? '' : 'none';
    /* Restart is offered after every ending — losses need it, wins may
       want another go */
    document.getElementById('endRestart').style.display =
      showdown && s.attacked ? '' : 'none';

    var figure = document.getElementById('figure');
    /* The hero faces the viewer: their left hand is on the viewer's
       right, so the art side is the opposite of the handedness */
    var side = s.hand === 'left' ? 'right' : 'left';
    /* The potion theft turned the hero into a pig (weapon still in trotter) */
    var isPig = s.enc4 === 'steal';
    var artSet = isPig ? ART.pig : ART;
    var hero;
    if (armed && !s.weaponLost) {
      var w = WEAPONS[s.weapon];
      /* Mirror so the weapon faces away from the body; 'reversed' marks
         glyphs whose natural facing is opposite the FA convention */
      var mirrored = side === 'left';
      if (w.reversed) mirrored = !mirrored;
      var flip = mirrored ? ' wpn-flip' : '';
      var icon = w.fa
        ? '<i class="fa-solid ' + w.fa + '"></i>'
        : '<span class="wpn-em' + (w.rot ? ' wpn-rot' : '') + '">' +
          w.em + '</span>';
      icon = '<span class="wpn' + flip + '">' + icon + '</span>';
      hero = artSet[side].replace('{w}', icon);
    } else {
      hero = artSet.base;
    }
    /* The troll took a leg (in combat or as a quiz penalty) */
    if (armed && (attacked || wrong)) {
      hero = hero.replace(isPig ? '/\\' : '/ \\', '/');
    }
    /* Companions line up on the hero's free side, away from the weapon —
       and stay there even if the weapon is later lost */
    var figs = ['<span class="fig">' + hero + '</span>'];
    function addCompanion(art) {
      var span = '<span class="fig">' + art + '</span>';
      if (side === 'right') figs.unshift(span);
      else figs.push(span);
    }
    if (joined) addCompanion(ART.kid);
    if (rescued) addCompanion(ART.princess);
    figure.innerHTML = figs.join('');
  }

  naming.addEventListener('submit', function (e) {
    e.preventDefault();
    var name = document.getElementById('heroName').value.trim();
    if (!name) return;
    saveKey('questHero', name);
    render();
  });

  /* Hero and villain share the pronoun-picker wiring; ids differ by prefix */
  function wirePronouns(form, customTable, customBtn, prefix, storageKey) {
    form.addEventListener('click', function (e) {
      var preset = e.target.getAttribute && e.target.getAttribute('data-preset');
      if (!preset) return;
      saveKey(storageKey, JSON.stringify(PRESETS[preset]));
      render();
    });
    customBtn.addEventListener('click', function () {
      customTable.style.display = customTable.style.display ? '' : 'none';
    });
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      var pron = {
        subj: document.getElementById(prefix + 'Subj').value.trim(),
        obj: document.getElementById(prefix + 'Obj').value.trim(),
        posd: document.getElementById(prefix + 'Posd').value.trim(),
        refl: document.getElementById(prefix + 'Refl').value.trim()
      };
      for (var k in pron) if (!pron[k]) return;
      saveKey(storageKey, JSON.stringify(pron));
      render();
    });
  }
  wirePronouns(pronouns, custom,
    document.getElementById('customBtn'), 'pn', 'questPronouns');
  wirePronouns(vpronouns, document.getElementById('vcustom'),
    document.getElementById('vcustomBtn'), 'vpn', 'questVillainPronouns');

  vnaming.addEventListener('submit', function (e) {
    e.preventDefault();
    var name = document.getElementById('villainName').value.trim();
    if (!name) return;
    saveKey('questVillain', name);
    render();
  });

  document.getElementById('showdownAttack').addEventListener('click', function (e) {
    if (e.target.tagName !== 'BUTTON') return;
    saveKey('questAttacked', '1');
    render();
  });

  /* A restart or a completed quest wipes the whole save file, hero
     included — a fresh run starts at "Name your hero" */
  function clearRun() {
    try {
      ['questHero', 'questPronouns', 'questWeapon', 'questHand', 'questEncounters',
        'questEnc1', 'questEnc2', 'questKid', 'questEnc3', 'questEnc4', 'questEnc5', 'questPrincess',
        'questWeaponLost',
        'questVillain', 'questVillainPronouns', 'questAttacked'
      ].forEach(function (k) { localStorage.removeItem(k); });
    } catch (err) {}
  }

  /* Winning genuinely restores gade.gg: same keys the 404's restore
     hatch clears, then home — where the guard no longer redirects */
  document.getElementById('endWin').addEventListener('click', function (e) {
    if (e.target.tagName !== 'BUTTON') return;
    /* Permanent — survives the save wipe and the restore. The
       achievements system on the main page reads it, so the Adventurer
       toast greets the return home */
    saveKey('questWon', '1');
    clearRun();
    try {
      localStorage.removeItem('siteDeleted');
      localStorage.removeItem('siteDeletedViews');
      localStorage.removeItem('questStarted');
    } catch (err) {}
    location.href = '/';
  });

  document.getElementById('endRestart').addEventListener('click', function (e) {
    if (e.target.tagName !== 'BUTTON') return;
    clearRun();
    render();
  });

  weapon.addEventListener('click', function (e) {
    var chosen = e.target.getAttribute && e.target.getAttribute('data-weapon');
    if (!chosen) return;
    saveKey('questWeapon', chosen);
    render();
  });

  hand.addEventListener('click', function (e) {
    var chosen = e.target.getAttribute && e.target.getAttribute('data-hand');
    if (!chosen) return;
    saveKey('questHand', chosen);
    render();
  });

  document.getElementById('enc1choice').addEventListener('click', function (e) {
    var act = e.target.getAttribute && e.target.getAttribute('data-act');
    if (!act) return;
    saveKey('questEnc1', JSON.stringify(act === 'attack'
      ? { asked: false, result: 'attack' }
      : { asked: true, result: null }));
    render();
  });

  document.getElementById('riddle').addEventListener('submit', function (e) {
    e.preventDefault();
    var raw = document.getElementById('riddleAnswer').value.trim();
    if (!raw) return;
    var answer = raw.toLowerCase();
    var enc1 = answer === 'a river' || answer === 'river' || answer === 'water'
      ? { asked: true, result: 'solved' }
      : { asked: true, result: 'wrong', answer: raw };
    saveKey('questEnc1', JSON.stringify(enc1));
    render();
  });

  document.getElementById('riddleAttack').addEventListener('click', function () {
    saveKey('questEnc1', JSON.stringify({ asked: true, result: 'attack' }));
    render();
  });

  document.getElementById('enc2choice').addEventListener('click', function (e) {
    var ans = e.target.getAttribute && e.target.getAttribute('data-ans');
    if (!ans) return;
    saveKey('questEnc2', ans);
    render();
  });

  /* Breigan and Anastasia share the rename wiring */
  function wireRename(divId, formId, inputId, storageKey, defaultName) {
    var form = document.getElementById(formId);
    document.getElementById(divId).addEventListener('click', function (e) {
      var ans = e.target.getAttribute && e.target.getAttribute('data-rename');
      if (!ans) return;
      if (ans === 'no') {
        saveKey(storageKey, defaultName);
        render();
      } else {
        form.style.display = '';
      }
    });
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      var name = document.getElementById(inputId).value.trim();
      if (!name) return;
      saveKey(storageKey, name);
      render();
    });
  }
  wireRename('rename', 'renameForm', 'kidName', 'questKid', 'Breigan');
  wireRename('prename', 'prenameForm', 'princessName',
    'questPrincess', 'Anastasia');

  document.getElementById('enc3choice').addEventListener('click', function (e) {
    var act = e.target.getAttribute && e.target.getAttribute('data-act');
    if (!act) return;
    saveKey('questEnc3', act);
    if (act === 'pry') saveKey('questWeaponLost', '1');
    render();
  });

  document.getElementById('enc4choice').addEventListener('click', function (e) {
    var act = e.target.getAttribute && e.target.getAttribute('data-act');
    if (!act) return;
    saveKey('questEnc4', act);
    render();
  });

  document.getElementById('enc5choice').addEventListener('click', function (e) {
    var act = e.target.getAttribute && e.target.getAttribute('data-act');
    if (!act) return;
    saveKey('questEnc5', act);
    render();
  });

  document.getElementById('enc5method').addEventListener('click', function (e) {
    var act = e.target.getAttribute && e.target.getAttribute('data-act');
    if (!act) return;
    saveKey('questEnc5', act);
    render();
  });

  render();
})();
