From 42582352d6ea368db6935949c6b2ebc11221825f Mon Sep 17 00:00:00 2001 From: Georg Tomitsch Date: Fri, 15 May 2026 21:58:30 +0200 Subject: [PATCH] Add storage-backed story history --- data/ink-src/kaiserpunk.ink | 620 +++++++++++++++++++++---- data/ink/kaiserpunk.ink.json | 2 +- dist/engine/ink-engine.js | 20 +- dist/engine/ink-engine.js.map | 2 +- dist/server-ink.js | 10 +- dist/server-ink.js.map | 2 +- public/css/style.css | 34 ++ public/js/game-loop-module.js | 40 +- public/js/loader.js | 1 + public/js/sentence-queue-module.js | 26 +- public/js/socket-client-module.js | 6 +- public/js/story-history-module.js | 189 ++++++++ public/js/tts-factory-module.js | 12 +- public/js/ui-display-handler-module.js | 168 ++++++- src/engine/ink-engine.ts | 19 +- src/server-ink.ts | 10 +- 16 files changed, 1048 insertions(+), 113 deletions(-) create mode 100644 public/js/story-history-module.js diff --git a/data/ink-src/kaiserpunk.ink b/data/ink-src/kaiserpunk.ink index 2948477..fbef562 100644 --- a/data/ink-src/kaiserpunk.ink +++ b/data/ink-src/kaiserpunk.ink @@ -1,7 +1,8 @@ // Kaiserpunk Horror Intro // Ink source file draft -// Covers: opening train journey, class selection, name builder, supernatural stance, -// spiritual-sense selection, first Viktor relationship choices, and arrival at Eibenreith. +// Covers: opening train journey, class selection, name builder, baggage definition, +// mirror/self-description, supernatural stance, spiritual-sense selection, +// first Viktor relationship choices, and arrival at Eibenreith. VAR birth_class = "unset" VAR title_part = "" @@ -10,6 +11,12 @@ VAR common_name = "" VAR surname = "" VAR full_name = "" +VAR baggage_style = "unset" +VAR hair_detail = "unset" +VAR complexion_detail = "unset" +VAR face_detail = "unset" +VAR outfit_detail = "unset" + VAR supernatural_belief = "unset" // believer, sceptic, performer, undecided VAR supernatural_senses = "unset" // genuine, faked, repressed, ambiguous VAR viktor_relation = "unset" // trust, tension, utility, dependence, provocation @@ -52,12 +59,10 @@ In truth, he is an officer lent to a delicate matter by channels that prefer not He folds the newspaper, though you are quite certain he had not been reading it. -"You have been very quiet, gnädiges Fräulein." +"You have been very quiet, gnädiges Fräulein. For a lady on her first official journey, you show remarkable restraint." The form of address is technically correct if you are noble, excessive if you are not, and perfectly chosen because he does not yet know which part of you is useful, which part is costume, and which part is threat. -"For a lady on her first official journey," he adds, "you show remarkable restraint." - You look around the compartment before you answer. The answer comes from somewhere older than the letter in your reticule. It comes from the place you began. * [The compartment seems built for people who never wonder whether they belong in it.] #class:noble @@ -90,9 +95,79 @@ You look around the compartment before you answer. The answer comes from somewhe === class_noble_background === -"Restraint is not a virtue, Herr Nowak," you say. "It is often only good breeding with its mouth shut." +Viktor waits for the answer owed to his remark. The train jolts once, then settles again into its hard, confident rhythm. -His brows move almost imperceptibly. +* "Restraint is not a virtue, Herr Nowak. It is often only good breeding with its mouth shut." + ~ eccentric += 1 + His brows move almost imperceptibly. + + "Then good breeding has military applications," he says. + + * "Only when properly commanded." + ~ lover += 1 + ~ viktor_suspicion += 1 + "You intend to command it yourself?" + + "Whenever possible." + + * "Only when men mistake silence for obedience." + ~ sapphic += 1 + ~ viktor_suspicion += 1 + "That is an ambitious distinction." + + "It has preserved many women from being understood too early." + + * "I prefer any discipline that leaves a clean record." + ~ detective += 1 + ~ viktor_trust += 1 + "A useful preference," he says. "If sincere." + + "If it is not sincere, I have stated it early enough for you to investigate." + + - + -> class_noble_explanation + +* "You need not test whether I can sit still, Herr Nowak. I was trained by people with less patience and sharper eyes." + ~ detective += 1 + ~ viktor_trust += 1 + "A family education, then." + + * "A family sentence, more often." + ~ eccentric += 1 + "You speak as if birth were a prison." + + "Only when it is furnished well enough for visitors to admire." + + * "An education in rooms where every chair has rank." + ~ class_confidence += 1 + "Then Hohenreith may not surprise you." + + "That depends on whether they have better chairs than secrets." + + - + -> class_noble_explanation + +* "If this is remarkable restraint, Herr Nowak, I fear you have mostly escorted officers." + ~ lover += 1 + ~ viktor_suspicion += 1 + The corner of his mouth changes almost too little to notice. + + "Officers are less easily bored." + + * "Or less honest about it." + ~ lover += 1 + "You accuse the army of vanity." + + "No. I accuse men of consistency." + + * "Then I must try not to disappoint the army." + ~ careless += 1 + "That is precisely what I have been asked to prevent." + + - + -> class_noble_explanation + +=== class_noble_explanation === You learned young that every room contains a court, even when no emperor is present. A girl of your rank is trained to enter, to bow, to be introduced, to be placed, to speak only enough, to understand more than she admits, and to know that a family name can be both a key and a chain. @@ -108,9 +183,73 @@ Now choose the name by which Vienna invented you. === class_middle_background === -"Restraint," you say, "is easier when one has learned that every mistake is remembered by someone better placed." +Viktor's remark lingers between you with the odour of a polite accusation. -Viktor watches you more closely. +* "Restraint is easier when one has learned that every mistake is remembered by someone better placed." + ~ detective += 1 + ~ viktor_trust += 1 + Viktor watches you more closely. + + "A bitter lesson." + + * "A useful one. Bitterness is merely the taste left by instruction." + ~ eccentric += 1 + "You collect phrases like weapons." + + "Only the light ones. Heavy weapons attract permits." + + * "A common one. Some people only notice injustice when it reaches their own floor." + ~ sapphic += 1 + "You have made a study of floors?" + + "Of thresholds. They are more honest." + + - + -> class_middle_explanation + +* "If I am quiet, Herr Nowak, it is because men explain themselves faster when they dislike the silence." + ~ lover += 1 + ~ medium_reputation += 1 + "A method?" + + * "A courtesy. I let them begin with their favorite subject." + ~ lover += 1 + "Themselves." + + "You understand the principle already." + + * "An experiment. It has produced reliable results." + ~ detective += 1 + "Then I am part of your experiment." + + "Naturally. You sat opposite me." + + - + -> class_middle_explanation + +* "I was considering whether your concern is official, personal, or merely masculine." + ~ eccentric += 1 + ~ viktor_suspicion += 1 + His eyes harden by one exact degree. + + "Today it is official." + + * "How convenient. The other two may deny responsibility." + ~ eccentric += 1 + "I advise you not to make wit your first instrument at Hohenreith." + + "Then I shall make it the second." + + * "Then I shall treat it with the respect due to paper." + ~ detective += 1 + "Paper has moved armies." + + "And buried mistakes." + + - + -> class_middle_explanation + +=== class_middle_explanation === You were born in that broad, anxious territory between deference and ambition. Your family had books, invoices, respectability, perhaps a piano no one played well enough, perhaps a father with an office, a mother with callers, brothers who were expected to advance, and daughters who were expected not to make advancement look hungry. @@ -126,9 +265,65 @@ Now choose the name under which you entered the salons that first laughed at you === class_working_background === -"Restraint," you say, "is what people praise when they prefer not to see the effort." +Viktor's courtesy is smooth enough to be handled without fingerprints. You hear, beneath it, the question of how much this compartment has improved you. -The newspaper in Viktor's hand creases once. +* "Restraint is what people praise when they prefer not to see the effort." + ~ detective += 1 + ~ viktor_trust += 1 + The newspaper in Viktor's hand creases once. + + "You object to being praised?" + + * "Only cheaply." + ~ eccentric += 1 + "That may be difficult to avoid." + + "Then Hohenreith will have to spend more." + + * "Only when it hides the person doing the work." + ~ sapphic += 1 + He studies you as if the answer has come from farther down the train than first class. + + - + -> class_working_explanation + +* "I am quiet because people often prefer women of my origin either grateful or invisible. I am deciding which will inconvenience you less." + ~ eccentric += 1 + ~ viktor_suspicion += 1 + "I did not ask you to be grateful." + + * "No. You asked me to be manageable." + ~ eccentric += 1 + "I asked you nothing of the kind." + + "That is the benefit of rank. It asks through furniture." + + * "Then I shall postpone gratitude until you deserve it." + ~ lover += 1 + A pause. Then, very dryly: "A generous arrangement." + + - + -> class_working_explanation + +* "I was trying not to touch the upholstery as though it might accuse me." + ~ careless += 1 + ~ viktor_relation = "dependence" + Something like concern crosses his face, disguised too late as irritation. + + "The upholstery has survived ministers. It will survive you." + + * "Then I am already braver than I was." + ~ careless += 1 + "Courage measured against upholstery is not a military standard." + + * "I shall take that as reassurance, though you delivered it like a reprimand." + ~ lover += 1 + "I have had practice with both." + + - + -> class_working_explanation + +=== class_working_explanation === You were born among people who owned little but obligations. Work had a sound before it had a meaning: water, broom, bootsteps, breath, the clatter of dishes, the cough of men coming in from cold yards, women counting coins under their breath. You learned early that the high-born are not more observant than others. They are merely less often required to observe. @@ -377,7 +572,105 @@ Viktor has waited through your silence with a soldier's patience and a jailer's When the mountains return, they seem closer. --> supernatural_stance +-> mirror_definition + +=== mirror_definition === + +The black glass gives you the woman who will arrive in Eibenreith before any rumour has time to improve her. + +Choose what the window catches first. + +* [Dark ash-brown hair pinned with almost severe care.] + ~ hair_detail = "dark ash-brown" + The reflection has dark ash-brown hair, almost black where the tunnel has not quite left it, pinned with the severity of a woman who knows that disarray is forgiven less easily in the young. + -> mirror_complexion + +* [Chestnut hair arranged to look softer than the mind beneath it.] + ~ hair_detail = "chestnut" + The reflection has chestnut hair, warm where the lamp touches it, arranged with enough softness to flatter and enough control to warn the attentive. + -> mirror_complexion + +* [Cool fair hair made austere by dark travelling clothes.] + ~ hair_detail = "cool fair" + The reflection has cool fair hair, not golden enough for sentimental painters, but pale enough that the dark travelling clothes make your face appear more deliberate than gentle. + -> mirror_complexion + +* [Black-brown hair with a few escaped wisps already refusing discipline.] + ~ hair_detail = "black-brown" + The reflection has black-brown hair, glossy in the lamp's weak tremor, with two escaped wisps at the temple already committing small treasons against the pins. + -> mirror_complexion + +=== mirror_complexion === + +The window deepens, and with it the face. + +* [A fair, cool complexion that looks almost bloodless in railway light.] + ~ complexion_detail = "fair and cool" + Your complexion is fair and cool, made paler by smoke, glass, and the faint greenish cast of mountain light. + -> mirror_face + +* [A clear complexion that still remembers the city more than the sun.] + ~ complexion_detail = "clear and sheltered" + Your complexion has the clarity of rooms, gloves, and shaded streets; not sickly, but visibly protected from the labour that browns other lives. + -> mirror_face + +* [A face that has learned to look fragile when fragility is useful.] + ~ complexion_detail = "delicately pale" + Your complexion is delicately pale, the sort physicians and foolish men read too eagerly, and which you have never felt obliged to correct every time. + -> mirror_face + +* [A slightly warmer complexion that makes the severity of the outfit less forgiving.] + ~ complexion_detail = "warm fair" + Your complexion is warmer than Vienna's winter light would prefer, and that warmth makes the severe coat and collar seem chosen rather than imposed. + -> mirror_face + +=== mirror_face === + +The window keeps you just long enough to make judgement impolite. + +* [A long oval face, observant before it is beautiful.] + ~ face_detail = "long oval and observant" + The face is long and oval, with watchful eyes, a straight nose, and a mouth that knows how often women are punished for amusement before men call them clever. + -> mirror_outfit + +* [A composed face that seems trained equally for salons and interrogations.] + ~ face_detail = "composed and trained" + The face is composed rather than soft, with brows dark enough to sharpen silence and a mouth whose politeness has not yet promised mercy. + -> mirror_outfit + +* [A pretty face made less harmless by the steadiness of the eyes.] + ~ face_detail = "pretty but steady" + The face might be called pretty by people who do not like to work harder for adjectives, but the eyes disturb the compliment by appearing to have heard it before and found it insufficient. + -> mirror_outfit + +* [A severe face that becomes almost vulnerable only when caught unprepared.] + ~ face_detail = "severe and guarded" + The face is severe at first glance, guarded at the second, and only after that does it betray how young a woman may still be while carrying herself like a sealed document. + -> mirror_outfit + +=== mirror_outfit === + +The rest of the reflection is costume, armour, and evidence. + +* [Dark charcoal-plum travelling wool, restrained but expensive.] + ~ outfit_detail = "charcoal-plum travelling wool" + You wear a tailored travelling ensemble of dark charcoal wool with a plum undertone, high at the throat, close at the waist, expensive in the way that avoids asking to be admired. + -> supernatural_stance + +* [A severe black-brown coat and skirt, softened only by ivory at throat and cuffs.] + ~ outfit_detail = "black-brown travelling suit" + You wear a black-brown travelling suit and long coat, softened only by ivory at throat and cuffs, the lace narrow enough to seem like restraint rather than decoration. + -> supernatural_stance + +* [Bottle-green details hidden in an otherwise sombre travelling suit.] + ~ outfit_detail = "sombre suit with bottle-green details" + You wear a sombre travelling suit with bottle-green details so discreet that only close attention discovers them, which is nearly the point. + -> supernatural_stance + +* [A more fashionable ensemble, dark and narrow, calculated to be remembered.] + ~ outfit_detail = "fashionable dark travelling ensemble" + You wear a dark, narrow, more fashionable travelling ensemble, the hat and veil chosen with just enough theatrical instinct to make sceptical people use the word instinctive. + -> supernatural_stance === supernatural_stance === @@ -387,7 +680,7 @@ It calls you, in prose dry enough to pass through any number of offices, a woman The comital family at Jagdhaus Hohenreith has asked for discretion. Vienna has answered with a sealed letter, a woman reputed to speak with what is hidden, and a man opposite her who has orders of his own. -Before this journey, before this train, before the mountains began taking the sky piece by piece, what did you believe? +Before this journey, before this train, before the mountains began taking the sky piece by piece, belief had already taken its position in you. * [The dead are not silent. The living are merely poor listeners.] #supernatural:believer ~ supernatural_belief = "believer" @@ -431,7 +724,7 @@ Belief is one matter. Experience is another. People call a woman sensitive when they want her perceptions to sound like an illness. They call her hysterical when those perceptions inconvenience them. They call her inspired when they need her, and unstable when they do not. -What, beneath reputation and performance, has truly happened to you? +Beneath reputation and performance, memory has its own testimony. * [There have been moments you cannot explain away.] #powers:genuine ~ supernatural_senses = "genuine" @@ -477,19 +770,36 @@ Viktor opens a leather folder and removes a memorandum. He does not hand it to y "When we leave the railway," he says, "we will be met by a coach from Hohenreith. From that moment, appearances matter. Your hosts have been told that I assist with correspondence, travel, and practical arrangements. They need not be troubled with military definitions." -"And the villagers?" you ask. +* "And the villagers?" + "The villagers need not be troubled with anything." -"The villagers need not be troubled with anything." + There it is: the empire in miniature. A man, a folder, a locked sentence. -There it is: the empire in miniature. A man, a folder, a locked sentence. +* "How merciful. The empire has spared them vocabulary." + ~ eccentric += 1 + ~ viktor_suspicion += 1 + "The empire has spared them alarm," Viktor says. + + "It often uses the two interchangeably." + + There it is: the empire in miniature. A man, a folder, a locked sentence. + +* "You mean they are not to know whether I am guest, tool, or warning." + ~ detective += 1 + ~ viktor_trust += 1 + "I mean they are to know only what steadies the situation." + + "That is not a contradiction." + + There it is: the empire in miniature. A man, a folder, a locked sentence. + +- "You will be addressed according to the station you present," he continues. "The Graf's household will observe rank. Servants will observe what the household observes. Villagers may observe less and remember more. I advise restraint." The advice is sound. That makes it no less irritating. -How do you answer him? - -* ["If gentlemen were less easily led, Herr Nowak, ladies would require fewer methods."] #route:lover +* "If gentlemen were less easily led, Herr Nowak, ladies would require fewer methods." #route:lover ~ lover += 1 ~ viktor_relation = "provocation" ~ viktor_trust -= 1 @@ -498,17 +808,29 @@ How do you answer him? "A dangerous doctrine." - "A practical one." + * "A practical one." + "You intend to practice it at Hohenreith?" - "You intend to practice it at Hohenreith?" + * "Only where patriotism requires sacrifice." + ~ lover += 1 + He looks down at the memorandum, but not quickly enough to conceal that he is reassessing you. - "Only where patriotism requires sacrifice." + * "Only where men mistake desire for judgement." + ~ lover += 1 + "That may include more territory than the maps admit." - He looks down at the memorandum, but not quickly enough to conceal that he is reassessing you. + - + -> viktor_explains_orders - -> viktor_explains_orders + * "Dangerous doctrines travel best in good gloves." + ~ eccentric += 1 + "You intend to charm Hohenreith into confession?" -* ["If you wish me to pass as harmless, you must stop warning me like a gaoler."] #route:sapphic + "Only if Hohenreith insists on being charmed." + + -> viktor_explains_orders + +* "If you wish me to pass as harmless, you must stop warning me like a gaoler." #route:sapphic ~ sapphic += 1 ~ viktor_relation = "tension" ~ viktor_suspicion += 1 @@ -516,15 +838,21 @@ How do you answer him? "I am not your gaoler." - "No. A gaoler is at least honest about the key." + * "No. A gaoler is at least honest about the key." + The words surprise you by leaving a mark. Not on him, perhaps. On yourself. The closer the train carries you to Amalia's world, though you do not yet know her face, the more intolerable it seems that every female life there might be guarded by men who call the guarding concern. - The words surprise you by leaving a mark. Not on him, perhaps. On yourself. The closer the train carries you to Amalia's world, though you do not yet know her face, the more intolerable it seems that every female life there might be guarded by men who call the guarding concern. + * "Then do not stand between me and every locked door before I have touched the handle." + ~ viktor_trust += 1 + "Some doors are locked for cause." - Viktor folds the memorandum once, precisely. + "Then the cause had better survive examination." - -> viktor_explains_orders + - + Viktor folds the memorandum once, precisely. -* ["Then let us be exact. What do they know, what do they suspect, and what am I permitted to verify?"] #route:detective + -> viktor_explains_orders + +* "Then let us be exact. What do they know, what do they suspect, and what am I permitted to verify?" #route:detective ~ detective += 1 ~ viktor_relation = "professional" ~ viktor_trust += 1 @@ -532,17 +860,22 @@ How do you answer him? "They know that you come recommended. They suspect that you may be able to settle disturbances without police, priest, or press. You are permitted to verify fraud, coercion, threat to public order, or credible phenomena not presently classifiable." - "Credible phenomena not presently classifiable." + * "Credible phenomena not presently classifiable." + "That is the phrase." - "That is the phrase." + "A bureaucratic ghost." - "A bureaucratic ghost." + "The safest kind." - "The safest kind." + * "And if the phenomena become classifiable?" + "Then we classify them before others do." - -> viktor_explains_orders + "Spoken like a man who has seen reports bury graves." -* ["I shall do my best not to faint unless it is useful."] #route:careless + - + -> viktor_explains_orders + +* "I shall do my best not to faint unless it is useful." #route:careless ~ careless += 1 ~ viktor_relation = "dependence" ~ viktor_trust -= 1 @@ -550,19 +883,25 @@ How do you answer him? "I would prefer you did not faint at all." - "How ungallant." + * "How ungallant." + "How practical." - "How practical." + "Then you must be practical for both of us. I have never trusted the floor in strange houses." - "Then you must be practical for both of us. I have never trusted the floor in strange houses." + His answer is delayed by half a breath. - His answer is delayed by half a breath. + "That, gnädiges Fräulein, is precisely what concerns me." - "That, gnädiges Fräulein, is precisely what concerns me." + * "Then you must remain close enough to catch me." + ~ lover += 1 + "My orders did not specify theatrical collapses." - -> viktor_explains_orders + "How careless of them." -* ["Restraint is what timid people call obedience after they have forgotten who trained them."] #route:eccentric + - + -> viktor_explains_orders + +* "Restraint is what timid people call obedience after they have forgotten who trained them." #route:eccentric ~ eccentric += 1 ~ viktor_relation = "challenge" ~ viktor_suspicion += 2 @@ -570,15 +909,20 @@ How do you answer him? "You enjoy making enemies." - "No. I dislike the laziness of letting fools remain undecided." + * "No. I dislike the laziness of letting fools remain undecided." + "At Hohenreith, that dislike may become expensive." - "At Hohenreith, that dislike may become expensive." + "Then the Graf should have invited someone cheaper." - "Then the Graf should have invited someone cheaper." + * "Enemies are merely people honest enough to stand in the right place." + "You speak as though conflict were housekeeping." - The wheels strike a curve. The compartment leans. For a moment the two of you are held in the same narrow imbalance. + "It is. One discovers what belongs where." - -> viktor_explains_orders + - + The wheels strike a curve. The compartment leans. For a moment the two of you are held in the same narrow imbalance. + + -> viktor_explains_orders === viktor_explains_orders === @@ -596,27 +940,55 @@ No one has written the word daughter. Yet the omissions arrange themselves around the page like furniture around a corpse. -"There is another instruction," you say. +* "There is another instruction." + Viktor does not ask how you know. -Viktor does not ask how you know. + "There is always another instruction," he says. -"There is always another instruction," he says. +* "Your version is shorter than your silence. That means there is another instruction." + ~ detective += 1 + ~ viktor_trust += 1 + Viktor does not ask how you know. -"For you." + "There is always another instruction," he says. -"Yes." +* "How touching. Vienna trusts us both so little it had to divide the distrust." + ~ eccentric += 1 + ~ viktor_suspicion += 1 + Viktor does not ask how you know. -"Concerning me?" + "There is always another instruction," he says. -"Partly." +- + +* "For you." + "Yes." + +* "Concerning me." + "Partly." + +* "Concerning whether I am fraud, fool, or useful animal." + ~ viktor_suspicion += 1 + "Partly," he says, and this time the honesty has a blade in it. + +- The train begins to slow. The rhythm changes first in the floor, then in the window, then in the body. Houses gather beside the line. A station roof appears between drifting smoke and the dark combs of forested slopes. #sfx[steam-whistle.ogg] -"Then I shall try to be worth the ink," you say. +* "Then I shall try to be worth the ink." + "I sincerely hope so." -"I sincerely hope so." +* "Then I shall disappoint the instruction as creatively as circumstances permit." + ~ eccentric += 1 + "I sincerely hope you do not." -You cannot decide whether it is an insult, a prayer, or his first honest sentence. +* "Then keep your second instruction, Herr Nowak. I prefer primary sources." + ~ detective += 1 + "A preference not always granted in imperial service." + +- + +You cannot decide whether his answer is an insult, a prayer, or his first honest sentence. -> railway_station @@ -626,7 +998,41 @@ The station is small enough that the train seems briefly embarrassed to stop the A porter in a cap too large for him hurries along the platform. A woman with a basket steps back from the steam as if from an animal. Somewhere beyond the station building, a cart horse stamps at frozen mud. The signboard gives the place a name you have seen in the timetable but will not remember with affection. -Your luggage descends in stages: trunk, hatbox, smaller travelling case, dispatch case, folded rug, a narrow black case whose contents would embarrass both a priest and a conjurer if either searched it without imagination. Viktor oversees the transfer with clipped civility. He does not carry like a servant. He directs like a man pretending not to command. +Your luggage descends in stages. + +* [A disciplined official set: trunk, dispatch case, hatbox, and black séance case.] + ~ baggage_style = "official" + First comes a sober travelling trunk with brass corners dulled by use, then a dispatch case, then a hatbox, then the narrow black case whose contents would embarrass both a priest and a conjurer if either searched it without imagination. + ~ detective += 1 + -> station_luggage_common + +* [An elegant noblewoman's luggage: too correct to be accidental.] + ~ baggage_style = "elegant" + First comes a large trunk in dark leather, then a second smaller one for linen, then a round hatbox, a fitted toilette case, and a reticule kept too close to your hand for any porter to misunderstand its importance. + ~ class_confidence += 1 + -> station_luggage_common + +* [A performer’s luggage: harmless on top, less harmless beneath.] + ~ baggage_style = "performer" + First comes a respectable trunk, then a hatbox, then a travelling case of gloves, veils, ribbons, calling cards, and the small objects by which a room may be persuaded to believe in forces already present. + ~ medium_reputation += 1 + -> station_luggage_common + +* [A practical assortment that betrays too much preparation.] + ~ baggage_style = "practical" + First comes a battered trunk reinforced at the corners, then a leather case with notebooks, pencils, folded maps, spare gloves, a hand-lamp, and enough small necessities to offend anyone who prefers women decorative. + ~ detective += 1 + -> station_luggage_common + +* [An excessive pile that makes concealment impossible.] + ~ baggage_style = "excessive" + First comes one trunk, then another, then a hatbox, then a rug, then a dressing case, then the narrow black case, then a smaller parcel you had forgotten had survived packing. By the end even Viktor looks faintly outnumbered. + ~ careless += 1 + -> station_luggage_common + +=== station_luggage_common === + +Viktor oversees the transfer with clipped civility. He does not carry like a servant. He directs like a man pretending not to command. The coach from Hohenreith waits beyond the station yard: dark green paint, black wheels, the comital crest discreetly worn on the door, and two horses already restless beneath harness. The driver removes his hat when he sees you. Not too deeply. Deep enough for rank, not deep enough for reverence. #sfx[horse-neigh.ogg] @@ -694,73 +1100,97 @@ A shrine, perhaps. A boundary marker. A figure. The coach has passed before your Viktor has turned slightly toward the same slope. -"Did you see something?" he asks. +"Did you see something?" -* ["A woman in the wood, perhaps. Or a stone that wanted to be one."] #route:eccentric #statue_hint +* "A woman in the wood, perhaps. Or a stone that wanted to be one." #route:eccentric #statue_hint ~ eccentric += 1 ~ viktor_suspicion += 1 He studies the passing trees. "A local shrine?" - "If it is a shrine, it has not been loved recently." + * "If it is a shrine, it has not been loved recently." + "You speak as if stones notice neglect." - "You speak as if stones notice neglect." + "Do soldiers not?" - "Do soldiers not?" + He does not answer. - He does not answer. + * "No. Shrines face the faithful. That thing was listening sideways." + ~ supernatural_exposure += 1 + Viktor's hand rests on the coach strap, still and ready. - -> coach_nears_village + - + -> coach_nears_village -* ["A marker. I would like to know where that path leads."] #route:detective #statue_hint +* "A marker. I would like to know where that path leads." #route:detective #statue_hint ~ detective += 1 ~ viktor_trust += 1 "You saw a path?" - "Not clearly. Enough to ask later." + * "Not clearly. Enough to ask later." + Viktor looks back through the small rear window. The bend has already erased the slope. - Viktor looks back through the small rear window. The bend has already erased the slope. + "Ask carefully. Places people fail to mention are often more informative than those they recommend." - "Ask carefully. Places people fail to mention are often more informative than those they recommend." + * "Only a suggestion of one. If it exists, someone maintains the absence of it." + ~ detective += 1 + "You make absences sound expensive." - -> coach_nears_village + "They usually are." -* ["Only trees. The sort that make one grateful for gentlemen with revolvers."] #route:careless + - + -> coach_nears_village + +* "Only trees. The sort that make one grateful for gentlemen with revolvers." #route:careless ~ careless += 1 ~ viktor_relation = "dependence" His expression darkens by one official degree. "A revolver is a poor instrument against trees." - "Then I shall rely on your conversation to intimidate them." + * "Then I shall rely on your conversation to intimidate them." + The driver pretends not to hear. His shoulders, however, hear everything. - The driver pretends not to hear. His shoulders, however, hear everything. + * "How unfortunate. You seemed so professionally reassuring." + ~ lover += 1 + "I prefer enemies that identify themselves." - -> coach_nears_village + - + -> coach_nears_village -* ["Would you believe me if I said I had?"] #route:lover +* "Would you believe me if I said I had?" #route:lover ~ lover += 1 ~ viktor_suspicion += 1 "That would depend on what advantage you expected from the answer." - "Herr Nowak. You wound me." + * "Herr Nowak. You wound me." + "Not yet." - "Not yet." + It is the first thing he has said all day that almost sounds like flirtation, though perhaps only because danger has a talent for borrowing warmer clothes. - It is the first thing he has said all day that almost sounds like flirtation, though perhaps only because danger has a talent for borrowing warmer clothes. + * "Then watch the slope, not my intentions. One of them may be useful." + ~ viktor_trust += 1 + He obeys without admitting that he has done so. - -> coach_nears_village + - + -> coach_nears_village -* ["No." ] #route:sapphic +* "No." #route:sapphic ~ sapphic += 1 The denial is too quick, and you both hear it. You are not thinking of the stone now. You are thinking of the young woman waiting somewhere ahead: the Graf's daughter, the reason carefully not written into the memorandum, the stranger whose household has summoned you under a title both absurd and useful. - If this place keeps women in stone, you think, what does it do to them in houses? + * "It was only shadow." + If this place keeps women in stone, you think, what does it do to them in houses? - -> coach_nears_village + * "Or if I did, I prefer not to have it explained before I understand why it matters." + ~ detective += 1 + If this place keeps women in stone, you think, what does it do to them in houses? + + - + -> coach_nears_village === coach_nears_village === @@ -786,6 +1216,28 @@ Beside you, Viktor lowers his voice. "Remember: at Hohenreith, every courtesy will mean something. Here, every silence will." +* "Then we are already being received." + ~ detective += 1 + "Yes," he says. "And examined." + +* "You make it sound as if the village outranks the Graf." + ~ eccentric += 1 + "No," Viktor says. "Only as if it may have survived more than one." + +* "How fortunate that I packed several silences." + ~ lover += 1 + His mouth almost moves. "Use the plainest one first." + +* "I dislike being watched by people who will not introduce themselves." + ~ careless += 1 + "That," he says, "is unlikely to improve today." + +* "If Amalia has lived under this gaze all her life, I begin to understand why they sent for ghosts." + ~ sapphic += 1 + Viktor glances at you, but whatever answer he considers, he keeps it behind his teeth. + +- + The horses draw the coach past the churchyard wall. Above it, on the old plaster beside the gate, a faded painted woman looks down from beneath a flaking blue mantle. Her hands are folded in prayer. Her eyes, damaged by weather, no longer point in the same direction. For one breath, as the wheels pass over a buried runnel of water, the painted face seems less like the Holy Mother than like a mask put on something that had been waiting longer. diff --git a/data/ink/kaiserpunk.ink.json b/data/ink/kaiserpunk.ink.json index 77a9821..5ada41c 100644 --- a/data/ink/kaiserpunk.ink.json +++ b/data/ink/kaiserpunk.ink.json @@ -1 +1 @@ -{"inkVersion":21,"root":[[{"->":"intro_train"},["done",{"#n":"g-0"}],null],"done",{"intro_train":[["^The train has left Vienna behind, though Vienna has not yet left you. ","#","^chapter[Eibenreith] ","/#","#","^music[Kaiserpunk Waltz.mp3](crossfade, loop, lead=8)","/#","\n","^It clings to the black gloss of your travelling boots, to the cut of your coat, to the stiff little prison of your gloves. It lives in the seal upon the letter folded inside your reticule, in the thin scent of coal smoke that has insinuated itself even into first-class upholstery, in the fact that Herr Viktor Nowak sits opposite you as if the carriage were a field office and not a compartment lined in velvet, polished wood, and brass.","\n","^Outside the window, the last outskirts of the capital have broken apart into winter-browned fields and villages with church towers too small to compete with the engine's whistle. The rails take the land without asking permission. Embankments cut through orchards. Telegraph poles pass at regular intervals, each one vanishing behind you like a thought dismissed too quickly. ","#","^sfx[steam-whistle.ogg]","/#","\n","^You had expected the train to feel like a triumph of the age.","\n","^Instead it feels like an argument. ","#","^image[suedbahn.png](landscape)","/#","\n","^The machine throws itself southward with a violence that polite society would never admit to admiring. The lamps tremble in their fittings. Your cup rattles against its saucer. Beyond the glass, the country begins to rise, first gently, then with a firmer will, until the line itself seems to negotiate with the mountains through stone arches, black tunnels, and viaducts thrown across ravines with all the confidence of imperial engineering.","\n","^Viktor has not looked impressed once.","\n","^His civilian clothes are correct enough to pass without comment: dark frock coat, sober waistcoat, gloves, collar immaculate, the posture of a man who has never truly sat at ease in his life. But no tailor can disguise discipline. It remains in his shoulders, in the economy of his movements, in the way his eyes measure doors, windows, luggage rack, corridor, your face, then the door again.","\n","^On the paperwork he is your secretary and travelling companion.","\n","^In truth, he is an officer lent to a delicate matter by channels that prefer not to be named. Rittmeister Viktor Alois Nowak, though no one at Jagdhaus Hohenreith is expected to call him that. Your hosts have asked for a medium. The Cabinet has sent them you. The military has sent him to make certain that you do not become a scandal before you become useful.","\n","^He folds the newspaper, though you are quite certain he had not been reading it.","\n","^\"You have been very quiet, gnädiges Fräulein.\"","\n","^The form of address is technically correct if you are noble, excessive if you are not, and perfectly chosen because he does not yet know which part of you is useful, which part is costume, and which part is threat.","\n","^\"For a lady on her first official journey,\" he adds, \"you show remarkable restraint.\"","\n","^You look around the compartment before you answer. The answer comes from somewhere older than the letter in your reticule. It comes from the place you began.","\n","ev","str","^The compartment seems built for people who never wonder whether they belong in it.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^You count the cost of each detail before you can stop yourself.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^You notice first how clean everything is, and how carefully one must sit so as not to betray noticing.","/str","/ev",{"*":".^.c-2","flg":20},{"c-0":["^ ","#","^class:noble","/#","\n","ev","str","^noble","/str","/ev",{"VAR=":"birth_class","re":true},"ev",{"VAR?":"class_confidence"},2,"+",{"VAR=":"class_confidence","re":true},"/ev","ev",{"VAR?":"court_loyalty"},1,"+",{"VAR=":"court_loyalty","re":true},"/ev","^It is not luxury that unsettles you. Luxury is only wood, cloth, brass, service, silence. What matters is whether the servants glance twice, whether the guard lowers his voice, whether another passenger weighs your gloves and decides not to ask your business.","\n","^You were born among people who understood such things before they understood kindness.","\n",{"->":"class_noble_background"},{"#f":5}],"c-1":["^ ","#","^class:middle","/#","\n","ev","str","^middle","/str","/ev",{"VAR=":"birth_class","re":true},"ev",{"VAR?":"class_confidence"},1,"+",{"VAR=":"class_confidence","re":true},"/ev","^The upholstery, the lamps, the polished veneer, the quiet attendance at stations: none of it is magical. It is paid for. Accounted for. Itemised somewhere by someone with ink on his cuffs and a wife who knows how long candles may be burned before the household budget complains.","\n","^You were not born to this compartment, but you were born close enough to study its rules.","\n",{"->":"class_middle_background"},{"#f":5}],"c-2":["^ ","#","^class:working","/#","\n","ev","str","^working","/str","/ev",{"VAR=":"birth_class","re":true},"ev",{"VAR?":"class_confidence"},1,"-",{"VAR=":"class_confidence","re":true},"/ev","^The velvet looks soft enough to swallow fingerprints. The brass fittings have been polished by hands that will never sit here. The little curtain strap is worn where other travellers, all of them more certain than you, have touched it without gratitude.","\n","^You were not born on this side of service.","\n",{"->":"class_working_background"},{"#f":5}]}],null],"class_noble_background":["^\"Restraint is not a virtue, Herr Nowak,\" you say. \"It is often only good breeding with its mouth shut.\"","\n","^His brows move almost imperceptibly.","\n","^You learned young that every room contains a court, even when no emperor is present. A girl of your rank is trained to enter, to bow, to be introduced, to be placed, to speak only enough, to understand more than she admits, and to know that a family name can be both a key and a chain.","\n","^Your own family possesses no grand seat, no army of retainers, no ancient right to command provinces. But your name opened drawing-room doors in Vienna, and once inside those rooms you learned to make people repeat stories they had meant only to hint at. You learned how widows speak when priests are absent, how officers lie when flattered, how old men confess when they believe themselves admired, and how a young woman may be underestimated so consistently that underestimation becomes a profession.","\n","^Your reputation as a medium did not descend from heaven. It was assembled from half-lights, correct guesses, careful silences, and the willingness of better-born fools to mistake performance for revelation.","\n","^Before the court could use you, society had first to invent you.","\n","^Now choose the name by which Vienna invented you.","\n",{"->":"choose_name_noble"},null],"class_middle_background":["^\"Restraint,\" you say, \"is easier when one has learned that every mistake is remembered by someone better placed.\"","\n","^Viktor watches you more closely.","\n","^You were born in that broad, anxious territory between deference and ambition. Your family had books, invoices, respectability, perhaps a piano no one played well enough, perhaps a father with an office, a mother with callers, brothers who were expected to advance, and daughters who were expected not to make advancement look hungry.","\n","^You learned accounts before etiquette, etiquette before French, and French before you learned how easily a woman with a calm voice could make men explain themselves. You rose because you listened. You rose because you understood that fraud, faith, medicine, gossip, politics, and grief all use the same doors into the human mind.","\n","^The court does not like to admit that it needs middle-class competence. It prefers to borrow it, dress it properly, and call it discretion.","\n","^Your reputation as a medium gave them a word that sounded less dangerous than investigator.","\n","^Now choose the name under which you entered the salons that first laughed at you, then invited you back.","\n",{"->":"choose_name_middle"},null],"class_working_background":["^\"Restraint,\" you say, \"is what people praise when they prefer not to see the effort.\"","\n","^The newspaper in Viktor's hand creases once.","\n","^You were born among people who owned little but obligations. Work had a sound before it had a meaning: water, broom, bootsteps, breath, the clatter of dishes, the cough of men coming in from cold yards, women counting coins under their breath. You learned early that the high-born are not more observant than others. They are merely less often required to observe.","\n","^That was your first advantage.","\n","^A servant knows which door matters because she uses the others. A seamstress learns bodies because she measures them. A maid learns secrets because fine people leave their souls lying about like gloves, certain that no one beneath them has hands.","\n","^You rose by talent, patronage, imitation, nerve, and the terrible convenience of being believed harmless. By the time Vienna began whispering that you saw more than respectable people saw, you had already spent years seeing what respectable people missed.","\n","^The court has placed you in first class because it needs what birth did not give you.","\n","^Now choose the name you carried upward, altered perhaps in pronunciation, never quite cleansed of where it began.","\n",{"->":"choose_name_working"},null],"choose_name_noble":[["ev","str","^Valerie Eleonore Josepha","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Helene Cäcilie Franziska","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Clara Theresia Leopoldine","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Sophie Eleonore Auguste","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Mathilde Josepha Henriette","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Therese Valerie Franziska","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Ilona Theresia Eleonore","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Zdenka Eleonore Josepha","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Valerie Eleonore Josepha","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Valerie","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-1":["\n","ev","str","^Helene Cäcilie Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Helene","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-2":["\n","ev","str","^Clara Theresia Leopoldine","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Clara","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-3":["\n","ev","str","^Sophie Eleonore Auguste","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Sophie","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-4":["\n","ev","str","^Mathilde Josepha Henriette","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Mathilde","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-5":["\n","ev","str","^Therese Valerie Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Therese","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-6":["\n","ev","str","^Ilona Theresia Eleonore","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Ilona","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-7":["\n","ev","str","^Zdenka Eleonore Josepha","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Zdenka","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}]}],null],"choose_surname_noble":[["^Your title is fixed by birth and by the careful modesty of your family: not countess, not princess, not one of the brilliant names that gather ambassadors and creditors like dust.","\n","^A Freiin. Baronial. Usable. Admitted, but not enthroned.","\n","ev","str","^Freiin von Rauhenfels","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Freiin von Traunegg","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Freiin von Ebenwald","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Freiin von Arnsberg","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Freiin von Reichenau","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Freiin von Waldstätten","/str","/ev",{"*":".^.c-5","flg":20},{"c-0":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Rauhenfels","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-1":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Traunegg","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-2":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Ebenwald","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-3":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Arnsberg","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-4":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Reichenau","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-5":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Waldstätten","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}]}],null],"choose_name_middle":[["ev","str","^Clara Eleonore","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Anna Katharina","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Helene Theresia","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Rosa Franziska","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Johanna Elise","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Katharina Sophie","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Therese Leopoldine","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Magdalena Cäcilie","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Clara Eleonore","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Clara","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-1":["\n","ev","str","^Anna Katharina","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Anna","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-2":["\n","ev","str","^Helene Theresia","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Helene","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-3":["\n","ev","str","^Rosa Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Rosa","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-4":["\n","ev","str","^Johanna Elise","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Johanna","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-5":["\n","ev","str","^Katharina Sophie","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Katharina","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-6":["\n","ev","str","^Therese Leopoldine","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Therese","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-7":["\n","ev","str","^Magdalena Cäcilie","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Magdalena","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}]}],null],"choose_surname_middle":[["^Your family name contains no particle to soften the ascent. It must stand upright by itself.","\n","ev","str","^Leitner","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Wagner","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Kellner","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Baumgartner","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Fischer","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Schmid","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Pichler","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Rosenfeld","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Leitner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-1":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Wagner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-2":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Kellner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-3":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Baumgartner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-4":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Fischer","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-5":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Schmid","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-6":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Pichler","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-7":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Rosenfeld","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}]}],null],"choose_name_working":[["ev","str","^Anna","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Klara","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Agnes","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Leni","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Rosa","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Gertrud","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Elisabeth","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Franziska","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Anna","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Anna","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-1":["\n","ev","str","^Klara","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Klara","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-2":["\n","ev","str","^Agnes","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Agnes","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-3":["\n","ev","str","^Leni","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Leni","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-4":["\n","ev","str","^Rosa","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Rosa","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-5":["\n","ev","str","^Gertrud","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Gertrud","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-6":["\n","ev","str","^Elisabeth","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Elisabeth","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-7":["\n","ev","str","^Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Franziska","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}]}],null],"choose_surname_working":[["^A simple name can be a burden in Vienna. It tells people how little they must pretend to respect you before you have spoken.","\n","ev","str","^Pichler","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Huber","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Maier","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Gruber","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Schuster","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Krenn","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Wolf","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Moser","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Pichler","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-1":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Huber","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-2":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Maier","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-3":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Gruber","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-4":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Schuster","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-5":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Krenn","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-6":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Wolf","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-7":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Moser","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}]}],null],"assemble_full_name":["ev",{"VAR?":"birth_class"},"str","^noble","/str","==","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"given_names"},"str","^ ","/str","+",{"VAR?":"title_part"},"+","str","^ ","/str","+",{"VAR?":"surname"},"+","/ev",{"VAR=":"full_name","re":true},{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["\n","ev",{"VAR?":"title_part"},"str","^ ","/str","+",{"VAR?":"given_names"},"+","str","^ ","/str","+",{"VAR?":"surname"},"+","/ev",{"VAR=":"full_name","re":true},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"birth_class"},"str","^noble","/str","==","/ev",[{"->":".^.b","c":true},{"b":["\n","^On visiting cards, in letters, in the cautious mouths of servants, you are ","ev",{"VAR?":"full_name"},"out","/ev","^.","\n",{"->":".^.^.^.20"},null]}],[{"->":".^.b"},{"b":["\n","^On railway documents, hotel ledgers, and the tongues of people who have not yet decided how much respect you deserve, you are ","ev",{"VAR?":"full_name"},"out","/ev","^.","\n",{"->":".^.^.^.20"},null]}],"nop","\n","^But in the private chamber where a name is first answered before it is performed, you are ","ev",{"VAR?":"common_name"},"out","/ev","^.","\n","^Viktor has waited through your silence with a soldier's patience and a jailer's courtesy. The train enters another tunnel. For several seconds the compartment window gives you back only your own reflection: your hat, your pale face above the dark collar, your eyes too steady or not steady enough.","\n","^When the mountains return, they seem closer.","\n",{"->":"supernatural_stance"},null],"supernatural_stance":[["^The letter of commission in your reticule does not call you an investigator.","\n","^It calls you, in prose dry enough to pass through any number of offices, a woman whose unusual spiritual reputation has recommended her to a delicate household matter. The phrasing is exquisite. It neither affirms nor denies. It permits everyone involved to believe afterward that they had believed nothing improper.","\n","^The comital family at Jagdhaus Hohenreith has asked for discretion. Vienna has answered with a sealed letter, a woman reputed to speak with what is hidden, and a man opposite her who has orders of his own.","\n","^Before this journey, before this train, before the mountains began taking the sky piece by piece, what did you believe?","\n","ev","str","^The dead are not silent. The living are merely poor listeners.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^The supernatural is usually pain, fraud, fever, inheritance, or bad ventilation.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Belief is a costume. You wear it because men insist on dressing you in it.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^You have learned not to decide too early.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["^ ","#","^supernatural:believer","/#","\n","ev","str","^believer","/str","/ev",{"VAR=":"supernatural_belief","re":true},"ev",{"VAR?":"medium_reputation"},1,"+",{"VAR=":"medium_reputation","re":true},"/ev","ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^You have always thought disbelief a provincial arrogance of the educated. There are pressures in rooms where grief has been. There are words people speak before they know they have spoken. There are dreams that arrive with mud on their hems.","\n","^Perhaps the world is not haunted. Perhaps it is simply crowded.","\n",{"->":"spiritual_senses"},{"#f":5}],"c-1":["^ ","#","^supernatural:sceptic ","/#","#","^route:detective","/#","\n","ev","str","^sceptic","/str","/ev",{"VAR=":"supernatural_belief","re":true},"ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^The word spirit covers too much and explains too little. You have watched respectable people call an echo a message, a coincidence a sign, a trembling hand an angelic visitation. Men of science can be fools, but fools with candles and planchettes are no improvement.","\n","^If Hohenreith has ghosts, you expect them to keep accounts, write letters, leave footprints, and benefit someone.","\n",{"->":"spiritual_senses"},{"#f":5}],"c-2":["^ ","#","^supernatural:performer","/#","\n","ev","str","^performer","/str","/ev",{"VAR=":"supernatural_belief","re":true},"ev",{"VAR?":"medium_reputation"},2,"+",{"VAR=":"medium_reputation","re":true},"/ev","^You discovered early that men who distrust a woman's mind will sometimes worship her nerves. A conclusion from evidence irritates them. A vision, sighed through lowered lashes, makes them lean closer.","\n","^Very well. Let them lean.","\n",{"->":"spiritual_senses"},{"#f":5}],"c-3":["^ ","#","^supernatural:undecided","/#","\n","ev","str","^undecided","/str","/ev",{"VAR=":"supernatural_belief","re":true},"^There are things you can explain, things you cannot yet explain, and things that explanation damages before it helps. You have made a profession of standing at thresholds with a face composed enough for both sides to continue speaking.","\n","^Hohenreith will have to show you what kind of case it is.","\n",{"->":"spiritual_senses"},{"#f":5}]}],null],"spiritual_senses":[["^Belief is one matter. Experience is another.","\n","^People call a woman sensitive when they want her perceptions to sound like an illness. They call her hysterical when those perceptions inconvenience them. They call her inspired when they need her, and unstable when they do not.","\n","^What, beneath reputation and performance, has truly happened to you?","\n","ev","str","^There have been moments you cannot explain away.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Everything you do can be explained by observation, timing, and nerve.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Something happens, but never when summoned.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^You buried the first signs so thoroughly that even you do not know what remains.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["^ ","#","^powers:genuine","/#","\n","ev","str","^genuine","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"supernatural_exposure"},2,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^Once, as a child, you knew before the telegram came. Once, in a crowded room, a stranger's grief entered you with such force that your own knees failed. Once, in a mirror, you saw a door behind you that was not in the room when you turned.","\n","^You learned caution after that. It is unwise for a woman to know things before a man has asked her opinion.","\n",{"->":"viktor_first_exchange"},{"#f":5}],"c-1":["^ ","#","^powers:faked ","/#","#","^route:detective","/#","\n","ev","str","^faked","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^You notice rings removed too recently, mourning gloves worn too carefully, letters folded and refolded until the crease gives away the reader's obsession. You hear servants misname guests, mothers pause before daughters' rooms, officers lie by becoming too exact.","\n","^The dead have never told you anything. The living cannot stop telling you everything.","\n",{"->":"viktor_first_exchange"},{"#f":5}],"c-2":["^ ","#","^powers:ambiguous","/#","\n","ev","str","^ambiguous","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^Your reputation depends upon command. The truth, if truth it is, has no respect for appointments.","\n","^Sometimes a room changes pressure around you. Sometimes a face acquires an old expression no living person taught it. Sometimes names arrive before introductions. But the harder you reach, the more ordinary the world becomes.","\n",{"->":"viktor_first_exchange"},{"#f":5}],"c-3":["^ ","#","^powers:repressed ","/#","#","^route:eccentric","/#","\n","ev","str","^repressed","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^There are childhood memories sealed behind politeness: a nursery mirror turned to the wall, a nurse dismissed without reference, your mother's hand tightening around your wrist until the bones complained.","\n","^You became strange afterward in ways society found easier to admire than understand.","\n",{"->":"viktor_first_exchange"},{"#f":5}]}],null],"viktor_first_exchange":[["^The train emerges from the tunnel into a pale afternoon cut by dark firs and white rock. Far below, water shows itself only in flashes. The valley is no longer a view from a salon painting. It has depth enough to hide things.","\n","^Viktor opens a leather folder and removes a memorandum. He does not hand it to you at once.","\n","^\"When we leave the railway,\" he says, \"we will be met by a coach from Hohenreith. From that moment, appearances matter. Your hosts have been told that I assist with correspondence, travel, and practical arrangements. They need not be troubled with military definitions.\"","\n","^\"And the villagers?\" you ask.","\n","^\"The villagers need not be troubled with anything.\"","\n","^There it is: the empire in miniature. A man, a folder, a locked sentence.","\n","^\"You will be addressed according to the station you present,\" he continues. \"The Graf's household will observe rank. Servants will observe what the household observes. Villagers may observe less and remember more. I advise restraint.\"","\n","^The advice is sound. That makes it no less irritating.","\n","^How do you answer him?","\n","ev","str","^\"If gentlemen were less easily led, Herr Nowak, ladies would require fewer methods.\"","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^\"If you wish me to pass as harmless, you must stop warning me like a gaoler.\"","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^\"Then let us be exact. What do they know, what do they suspect, and what am I permitted to verify?\"","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^\"I shall do my best not to faint unless it is useful.\"","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^\"Restraint is what timid people call obedience after they have forgotten who trained them.\"","/str","/ev",{"*":".^.c-4","flg":20},{"c-0":["^ ","#","^route:lover","/#","\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev","str","^provocation","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_trust"},1,"-",{"VAR=":"viktor_trust","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^For the first time, amusement almost reaches his mouth.","\n","^\"A dangerous doctrine.\"","\n","^\"A practical one.\"","\n","^\"You intend to practice it at Hohenreith?\"","\n","^\"Only where patriotism requires sacrifice.\"","\n","^He looks down at the memorandum, but not quickly enough to conceal that he is reassessing you.","\n",{"->":"viktor_explains_orders"},{"#f":5}],"c-1":["^ ","#","^route:sapphic","/#","\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","ev","str","^tension","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^His gaze sharpens.","\n","^\"I am not your gaoler.\"","\n","^\"No. A gaoler is at least honest about the key.\"","\n","^The words surprise you by leaving a mark. Not on him, perhaps. On yourself. The closer the train carries you to Amalia's world, though you do not yet know her face, the more intolerable it seems that every female life there might be guarded by men who call the guarding concern.","\n","^Viktor folds the memorandum once, precisely.","\n",{"->":"viktor_explains_orders"},{"#f":5}],"c-2":["^ ","#","^route:detective","/#","\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev","str","^professional","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^He gives the smallest nod, as if you have chosen the only answer fit for adults.","\n","^\"They know that you come recommended. They suspect that you may be able to settle disturbances without police, priest, or press. You are permitted to verify fraud, coercion, threat to public order, or credible phenomena not presently classifiable.\"","\n","^\"Credible phenomena not presently classifiable.\"","\n","^\"That is the phrase.\"","\n","^\"A bureaucratic ghost.\"","\n","^\"The safest kind.\"","\n",{"->":"viktor_explains_orders"},{"#f":5}],"c-3":["^ ","#","^route:careless","/#","\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","ev","str","^dependence","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_trust"},1,"-",{"VAR=":"viktor_trust","re":true},"/ev","^Something in his expression tightens; not contempt exactly, but readiness.","\n","^\"I would prefer you did not faint at all.\"","\n","^\"How ungallant.\"","\n","^\"How practical.\"","\n","^\"Then you must be practical for both of us. I have never trusted the floor in strange houses.\"","\n","^His answer is delayed by half a breath.","\n","^\"That, gnädiges Fräulein, is precisely what concerns me.\"","\n",{"->":"viktor_explains_orders"},{"#f":5}],"c-4":["^ ","#","^route:eccentric","/#","\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev","str","^challenge","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_suspicion"},2,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^Viktor studies you as he might study an unfamiliar weapon found in luggage.","\n","^\"You enjoy making enemies.\"","\n","^\"No. I dislike the laziness of letting fools remain undecided.\"","\n","^\"At Hohenreith, that dislike may become expensive.\"","\n","^\"Then the Graf should have invited someone cheaper.\"","\n","^The wheels strike a curve. The compartment leans. For a moment the two of you are held in the same narrow imbalance.","\n",{"->":"viktor_explains_orders"},{"#f":5}]}],null],"viktor_explains_orders":["^Viktor gives you the memorandum at last.","\n","^The document is not long. That is part of its menace. Long documents invite argument; short ones carry authority.","\n","^A comital household. A hunting residence in Upper Styria, not the family's principal seat. Reports of disturbances among servants and villagers. No police action requested. No public ecclesiastical inquiry desired. No press. No correspondence beyond approved channels. Your presence to be explained as a discreet consultation requested by the family. Herr Nowak to assist in practical matters.","\n","^No one has written the word ghost.","\n","^No one has written the word fraud.","\n","^No one has written the word daughter.","\n","^Yet the omissions arrange themselves around the page like furniture around a corpse.","\n","^\"There is another instruction,\" you say.","\n","^Viktor does not ask how you know.","\n","^\"There is always another instruction,\" he says.","\n","^\"For you.\"","\n","^\"Yes.\"","\n","^\"Concerning me?\"","\n","^\"Partly.\"","\n","^The train begins to slow. The rhythm changes first in the floor, then in the window, then in the body. Houses gather beside the line. A station roof appears between drifting smoke and the dark combs of forested slopes. ","#","^sfx[steam-whistle.ogg]","/#","\n","^\"Then I shall try to be worth the ink,\" you say.","\n","^\"I sincerely hope so.\"","\n","^You cannot decide whether it is an insult, a prayer, or his first honest sentence.","\n",{"->":"railway_station"},null],"railway_station":["^The station is small enough that the train seems briefly embarrassed to stop there. ","#","^chapter[The Station] ","/#","#","^image[muerzzuschlag.png](portrait)","/#","\n","^A porter in a cap too large for him hurries along the platform. A woman with a basket steps back from the steam as if from an animal. Somewhere beyond the station building, a cart horse stamps at frozen mud. The signboard gives the place a name you have seen in the timetable but will not remember with affection.","\n","^Your luggage descends in stages: trunk, hatbox, smaller travelling case, dispatch case, folded rug, a narrow black case whose contents would embarrass both a priest and a conjurer if either searched it without imagination. Viktor oversees the transfer with clipped civility. He does not carry like a servant. He directs like a man pretending not to command.","\n","^The coach from Hohenreith waits beyond the station yard: dark green paint, black wheels, the comital crest discreetly worn on the door, and two horses already restless beneath harness. The driver removes his hat when he sees you. Not too deeply. Deep enough for rank, not deep enough for reverence. ","#","^sfx[horse-neigh.ogg]","/#","\n","^\"Gnädiges Fräulein? Herr Sekretär?\"","\n","ev",{"VAR?":"birth_class"},"str","^noble","/str","==","/ev",[{"->":".^.b","c":true},{"b":["\n","^He has been told enough to place you. That is a courtesy. It is also a warning.","\n",{"->":".^.^.^.28"},null]}],[{"->":".^.b"},{"b":["\n","^He hesitates over you by the smallest measure. The hesitation is not rudeness. It is calculation. First-class carriage, court letter, no title beyond Fräulein, and a man beside you who looks like he has arrested people for less than staring.","\n",{"->":".^.^.^.28"},null]}],"nop","\n","^Viktor answers before you can.","\n","^\"From Jagdhaus Hohenreith?\"","\n","^\"Jawohl, Herr Sekretär. The road is passable. If the mist holds, we should reach Eibenreith before dark.\"","\n","^The word enters the air without ceremony.","\n","^Eibenreith.","\n","^Not Hohenreith, the name printed on the invitation in a clean hand. Eibenreith: the village below it. A smaller name. Older in the mouth. A name with roots rather than stationery.","\n",{"->":"coach_journey"},null],"coach_journey":[["^The coach leaves the station behind and with it the last easy evidence of empire. ","#","^chapter[The Graben] ","/#","#","^music[Kaiserpunk Jodler.mp3](crossfade, loop, lead=4)","/#","\n","^At first the road follows a valley where telegraph wire still keeps company with it and the river moves in a pale, stony bed. Sawmills, fenced meadows, and farmhouses appear and vanish behind stands of spruce. The mountains do not rise all at once. They advance by jurisdiction. A wooded slope claims the left-hand sky, then a grey wall of limestone closes the north, then another ridge gathers to the east until even the clouds seem to have entered service.","\n","^The driver names places when Viktor asks, but the names are local and practical, meant for men who know which bridge floods and which farm breeds stubborn horses. Somewhere beyond the visible ridges, he says, lies the great white back of the Hochschwab. Eastward, beyond forest and pass, the Hohe Veitsch keeps its own weather. He says this not as a guide would say it, but as a man explaining neighbours who may or may not be in a temper.","\n","^The main valley narrows.","\n","^The road turns from it into a side Graben, and the change is immediate. Sound alters. The wheels no longer ring against open distance but grind between banks, roots, and wet stone. The air smells of leaf mould, resin, and cold water. Yews appear among the firs in dark, improbable patience, their needles too black for the afternoon.","\n","^\"Eibenreither Graben,\" the driver says, and crosses himself so quickly that the gesture might have been meant for a rut in the road.","\n","^Viktor notices. Of course he notices.","\n","^\"Bad road?\" he asks.","\n","^\"Old road,\" the driver says.","\n","^No one speaks for a while.","\n","^You watch the trees.","\n","^There are forests that invite stories because they are pretty, and forests that reject stories because whatever happened there did not require witnesses. This one belongs to the second kind. Its trunks stand close, not wildly, but with the air of a crowd making room for something carried through it long ago. The snow that remains in hollows is not clean. It has gathered needles, bark, and a yellowish stain where water has risen underneath.","\n","^On a slope above the road, half swallowed by undergrowth, you glimpse stone.","\n","^A shrine, perhaps. A boundary marker. A figure. The coach has passed before your eyes can persuade themselves of its shape. For one instant you are left with the impression of a woman's head inclined not in prayer, but in listening. ","#","^image[statue.png](square)","/#","\n","ev",{"VAR?":"supernatural_senses"},"str","^genuine","/str","==",{"VAR?":"supernatural_senses"},"str","^ambiguous","/str","==","||",{"VAR?":"supernatural_senses"},"str","^repressed","/str","==","||","/ev",[{"->":".^.b","c":true},{"b":["\n","^The back of your neck tightens.","\n","^Not fear. Recognition would be worse.","\n","ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev",{"->":".^.^.^.58"},null]}],[{"->":".^.b"},{"b":["\n","^You tell yourself that old stone, seen through moving branches, will become whatever the mind is cowardly enough to supply.","\n",{"->":".^.^.^.58"},null]}],"nop","\n","^Viktor has turned slightly toward the same slope.","\n","^\"Did you see something?\" he asks.","\n","ev","str","^\"A woman in the wood, perhaps. Or a stone that wanted to be one.\"","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^\"A marker. I would like to know where that path leads.\"","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^\"Only trees. The sort that make one grateful for gentlemen with revolvers.\"","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^\"Would you believe me if I said I had?\"","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^\"No.\" ","/str","/ev",{"*":".^.c-4","flg":20},{"c-0":["^ ","#","^route:eccentric ","/#","#","^statue_hint","/#","\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^He studies the passing trees.","\n","^\"A local shrine?\"","\n","^\"If it is a shrine, it has not been loved recently.\"","\n","^\"You speak as if stones notice neglect.\"","\n","^\"Do soldiers not?\"","\n","^He does not answer.","\n",{"->":"coach_nears_village"},{"#f":5}],"c-1":["^ ","#","^route:detective ","/#","#","^statue_hint","/#","\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^\"You saw a path?\"","\n","^\"Not clearly. Enough to ask later.\"","\n","^Viktor looks back through the small rear window. The bend has already erased the slope.","\n","^\"Ask carefully. Places people fail to mention are often more informative than those they recommend.\"","\n",{"->":"coach_nears_village"},{"#f":5}],"c-2":["^ ","#","^route:careless","/#","\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","ev","str","^dependence","/str","/ev",{"VAR=":"viktor_relation","re":true},"^His expression darkens by one official degree.","\n","^\"A revolver is a poor instrument against trees.\"","\n","^\"Then I shall rely on your conversation to intimidate them.\"","\n","^The driver pretends not to hear. His shoulders, however, hear everything.","\n",{"->":"coach_nears_village"},{"#f":5}],"c-3":["^ ","#","^route:lover","/#","\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"That would depend on what advantage you expected from the answer.\"","\n","^\"Herr Nowak. You wound me.\"","\n","^\"Not yet.\"","\n","^It is the first thing he has said all day that almost sounds like flirtation, though perhaps only because danger has a talent for borrowing warmer clothes.","\n",{"->":"coach_nears_village"},{"#f":5}],"c-4":["^ ","#","^route:sapphic","/#","\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","^The denial is too quick, and you both hear it.","\n","^You are not thinking of the stone now. You are thinking of the young woman waiting somewhere ahead: the Graf's daughter, the reason carefully not written into the memorandum, the stranger whose household has summoned you under a title both absurd and useful.","\n","^If this place keeps women in stone, you think, what does it do to them in houses?","\n",{"->":"coach_nears_village"},{"#f":5}]}],null],"coach_nears_village":["^The Graben opens reluctantly.","\n","^First comes the smell of smoke. Then a roof, low and dark with weather. Then another. Then a church tower, not high, not graceful, but thick-shouldered and pale against the slope behind it. Its walls look older than the village around them and less certain of victory. The windows are small. The churchyard wall holds the road at a distance, as if the dead require fortification from the living, or the living from something else. ","#","^chapter[Eibenreith Village] ","/#","#","^sfx[church-bells.ogg](max=8, fade) ","/#","#","^image[eibenreith.png](landscape)","/#","\n","^Eibenreith appears not as a village in a picture appears, all at once and composed for admiration, but by fragments.","\n","^A woman in a dark kerchief pauses with a pail in her hand. A boy stops driving geese and lets them complain around his boots. Two men outside a shed end their conversation at the same moment without looking at each other. Curtains stir in windows where no one admits to standing. A blacksmith's sign moves slightly in air you cannot feel. Water runs somewhere under boards, under stone, under the road itself, quick and cold and hidden.","\n","^The houses are not poor, not exactly. Many are solid, whitewashed, shingled, kept with the stubborn decency of people who repair what they cannot replace. Yet something in their arrangement troubles the eye. They turn toward the church but not fully. They keep the road but lean from it. They leave, between yard and fence and woodpile, narrow passages where shadow gathers too early.","\n","^The coach slows.","\n","^No one runs to greet it.","\n","^No one needs to. News has already entered the village by means faster than railway, telegraph, or imperial seal.","\n","^You sit very straight as Eibenreith takes its first look at you.","\n","^Beside you, Viktor lowers his voice.","\n","^\"Remember: at Hohenreith, every courtesy will mean something. Here, every silence will.\"","\n","^The horses draw the coach past the churchyard wall. Above it, on the old plaster beside the gate, a faded painted woman looks down from beneath a flaking blue mantle. Her hands are folded in prayer. Her eyes, damaged by weather, no longer point in the same direction.","\n","^For one breath, as the wheels pass over a buried runnel of water, the painted face seems less like the Holy Mother than like a mask put on something that had been waiting longer.","\n","^Then the coach enters the village proper, and the road bends toward the unseen height where Jagdhaus Hohenreith stands above Eibenreith under its newer name.","\n","end",null],"global decl":["ev","str","^unset","/str",{"VAR=":"birth_class"},"str","^","/str",{"VAR=":"title_part"},"str","^","/str",{"VAR=":"given_names"},"str","^","/str",{"VAR=":"common_name"},"str","^","/str",{"VAR=":"surname"},"str","^","/str",{"VAR=":"full_name"},"str","^unset","/str",{"VAR=":"supernatural_belief"},"str","^unset","/str",{"VAR=":"supernatural_senses"},"str","^unset","/str",{"VAR=":"viktor_relation"},0,{"VAR=":"lover"},0,{"VAR=":"sapphic"},0,{"VAR=":"detective"},0,{"VAR=":"careless"},0,{"VAR=":"eccentric"},0,{"VAR=":"class_confidence"},0,{"VAR=":"medium_reputation"},0,{"VAR=":"court_loyalty"},0,{"VAR=":"viktor_trust"},0,{"VAR=":"viktor_suspicion"},0,{"VAR=":"supernatural_exposure"},"/ev","end",null]}],"listDefs":{}} \ No newline at end of file +{"inkVersion":21,"root":[[{"->":"intro_train"},["done",{"#n":"g-0"}],null],"done",{"intro_train":[["^The train has left Vienna behind, though Vienna has not yet left you. ","#","^chapter[Eibenreith] ","/#","#","^music[Kaiserpunk Waltz.mp3](crossfade, loop, lead=8)","/#","\n","^It clings to the black gloss of your travelling boots, to the cut of your coat, to the stiff little prison of your gloves. It lives in the seal upon the letter folded inside your reticule, in the thin scent of coal smoke that has insinuated itself even into first-class upholstery, in the fact that Herr Viktor Nowak sits opposite you as if the carriage were a field office and not a compartment lined in velvet, polished wood, and brass.","\n","^Outside the window, the last outskirts of the capital have broken apart into winter-browned fields and villages with church towers too small to compete with the engine's whistle. The rails take the land without asking permission. Embankments cut through orchards. Telegraph poles pass at regular intervals, each one vanishing behind you like a thought dismissed too quickly. ","#","^sfx[steam-whistle.ogg]","/#","\n","^You had expected the train to feel like a triumph of the age.","\n","^Instead it feels like an argument. ","#","^image[suedbahn.png](landscape)","/#","\n","^The machine throws itself southward with a violence that polite society would never admit to admiring. The lamps tremble in their fittings. Your cup rattles against its saucer. Beyond the glass, the country begins to rise, first gently, then with a firmer will, until the line itself seems to negotiate with the mountains through stone arches, black tunnels, and viaducts thrown across ravines with all the confidence of imperial engineering.","\n","^Viktor has not looked impressed once.","\n","^His civilian clothes are correct enough to pass without comment: dark frock coat, sober waistcoat, gloves, collar immaculate, the posture of a man who has never truly sat at ease in his life. But no tailor can disguise discipline. It remains in his shoulders, in the economy of his movements, in the way his eyes measure doors, windows, luggage rack, corridor, your face, then the door again.","\n","^On the paperwork he is your secretary and travelling companion.","\n","^In truth, he is an officer lent to a delicate matter by channels that prefer not to be named. Rittmeister Viktor Alois Nowak, though no one at Jagdhaus Hohenreith is expected to call him that. Your hosts have asked for a medium. The Cabinet has sent them you. The military has sent him to make certain that you do not become a scandal before you become useful.","\n","^He folds the newspaper, though you are quite certain he had not been reading it.","\n","^\"You have been very quiet, gnädiges Fräulein. For a lady on her first official journey, you show remarkable restraint.\"","\n","^The form of address is technically correct if you are noble, excessive if you are not, and perfectly chosen because he does not yet know which part of you is useful, which part is costume, and which part is threat.","\n","^You look around the compartment before you answer. The answer comes from somewhere older than the letter in your reticule. It comes from the place you began.","\n","ev","str","^The compartment seems built for people who never wonder whether they belong in it.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^You count the cost of each detail before you can stop yourself.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^You notice first how clean everything is, and how carefully one must sit so as not to betray noticing.","/str","/ev",{"*":".^.c-2","flg":20},{"c-0":["^ ","#","^class:noble","/#","\n","ev","str","^noble","/str","/ev",{"VAR=":"birth_class","re":true},"ev",{"VAR?":"class_confidence"},2,"+",{"VAR=":"class_confidence","re":true},"/ev","ev",{"VAR?":"court_loyalty"},1,"+",{"VAR=":"court_loyalty","re":true},"/ev","^It is not luxury that unsettles you. Luxury is only wood, cloth, brass, service, silence. What matters is whether the servants glance twice, whether the guard lowers his voice, whether another passenger weighs your gloves and decides not to ask your business.","\n","^You were born among people who understood such things before they understood kindness.","\n",{"->":"class_noble_background"},{"#f":5}],"c-1":["^ ","#","^class:middle","/#","\n","ev","str","^middle","/str","/ev",{"VAR=":"birth_class","re":true},"ev",{"VAR?":"class_confidence"},1,"+",{"VAR=":"class_confidence","re":true},"/ev","^The upholstery, the lamps, the polished veneer, the quiet attendance at stations: none of it is magical. It is paid for. Accounted for. Itemised somewhere by someone with ink on his cuffs and a wife who knows how long candles may be burned before the household budget complains.","\n","^You were not born to this compartment, but you were born close enough to study its rules.","\n",{"->":"class_middle_background"},{"#f":5}],"c-2":["^ ","#","^class:working","/#","\n","ev","str","^working","/str","/ev",{"VAR=":"birth_class","re":true},"ev",{"VAR?":"class_confidence"},1,"-",{"VAR=":"class_confidence","re":true},"/ev","^The velvet looks soft enough to swallow fingerprints. The brass fittings have been polished by hands that will never sit here. The little curtain strap is worn where other travellers, all of them more certain than you, have touched it without gratitude.","\n","^You were not born on this side of service.","\n",{"->":"class_working_background"},{"#f":5}]}],null],"class_noble_background":[["^Viktor waits for the answer owed to his remark. The train jolts once, then settles again into its hard, confident rhythm.","\n",["ev",{"^->":"class_noble_background.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"Restraint is not a virtue, Herr Nowak. It is often only good breeding with its mouth shut.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"Only when properly commanded.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"Only when men mistake silence for obedience.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.5.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"I prefer any discipline that leaves a clean record.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"class_noble_background.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^His brows move almost imperceptibly.","\n","^\"Then good breeding has military applications,\" he says.","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"class_noble_background.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"You intend to command it yourself?\"","\n","^\"Whenever possible.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"class_noble_background.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.4.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"That is an ambitious distinction.\"","\n","^\"It has preserved many women from being understood too early.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-3":["ev",{"^->":"class_noble_background.0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.5.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^\"A useful preference,\" he says. \"If sincere.\"","\n","^\"If it is not sincere, I have stated it early enough for you to investigate.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[{"->":"class_noble_explanation"},["ev",{"^->":"class_noble_background.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"You need not test whether I can sit still, Herr Nowak. I was trained by people with less patience and sharper eyes.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.g-0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^\"A family sentence, more often.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.g-0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^\"An education in rooms where every chair has rank.\"",{"->":"$r","var":true},null]}],{"c-4":["ev",{"^->":"class_noble_background.0.g-0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^\"A family education, then.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-5":["ev",{"^->":"class_noble_background.0.g-0.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"You speak as if birth were a prison.\"","\n","^\"Only when it is furnished well enough for visitors to admire.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-6":["ev",{"^->":"class_noble_background.0.g-0.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"class_confidence"},1,"+",{"VAR=":"class_confidence","re":true},"/ev","^\"Then Hohenreith may not surprise you.\"","\n","^\"That depends on whether they have better chairs than secrets.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}]}],"g-1":[{"->":"class_noble_explanation"},["ev",{"^->":"class_noble_background.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^\"If this is remarkable restraint, Herr Nowak, I fear you have mostly escorted officers.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^\"Or less honest about it.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_noble_background.0.g-1.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-9","flg":18},{"s":["^\"Then I must try not to disappoint the army.\"",{"->":"$r","var":true},null]}],{"c-7":["ev",{"^->":"class_noble_background.0.g-1.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^The corner of his mouth changes almost too little to notice.","\n","^\"Officers are less easily bored.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-8":["ev",{"^->":"class_noble_background.0.g-1.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^\"You accuse the army of vanity.\"","\n","^\"No. I accuse men of consistency.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-9":["ev",{"^->":"class_noble_background.0.g-1.c-9.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","^\"That is precisely what I have been asked to prevent.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}]}],"g-2":[{"->":"class_noble_explanation"},null]}],null],"class_noble_explanation":["^You learned young that every room contains a court, even when no emperor is present. A girl of your rank is trained to enter, to bow, to be introduced, to be placed, to speak only enough, to understand more than she admits, and to know that a family name can be both a key and a chain.","\n","^Your own family possesses no grand seat, no army of retainers, no ancient right to command provinces. But your name opened drawing-room doors in Vienna, and once inside those rooms you learned to make people repeat stories they had meant only to hint at. You learned how widows speak when priests are absent, how officers lie when flattered, how old men confess when they believe themselves admired, and how a young woman may be underestimated so consistently that underestimation becomes a profession.","\n","^Your reputation as a medium did not descend from heaven. It was assembled from half-lights, correct guesses, careful silences, and the willingness of better-born fools to mistake performance for revelation.","\n","^Before the court could use you, society had first to invent you.","\n","^Now choose the name by which Vienna invented you.","\n",{"->":"choose_name_noble"},null],"class_middle_background":[["^Viktor's remark lingers between you with the odour of a polite accusation.","\n",["ev",{"^->":"class_middle_background.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"Restraint is easier when one has learned that every mistake is remembered by someone better placed.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_middle_background.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"A useful one. Bitterness is merely the taste left by instruction.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_middle_background.0.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"A common one. Some people only notice injustice when it reaches their own floor.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"class_middle_background.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^Viktor watches you more closely.","\n","^\"A bitter lesson.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"class_middle_background.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"You collect phrases like weapons.\"","\n","^\"Only the light ones. Heavy weapons attract permits.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"class_middle_background.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.4.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","^\"You have made a study of floors?\"","\n","^\"Of thresholds. They are more honest.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[{"->":"class_middle_explanation"},["ev",{"^->":"class_middle_background.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"If I am quiet, Herr Nowak, it is because men explain themselves faster when they dislike the silence.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_middle_background.0.g-0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"A courtesy. I let them begin with their favorite subject.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_middle_background.0.g-0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^\"An experiment. It has produced reliable results.\"",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"class_middle_background.0.g-0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev",{"VAR?":"medium_reputation"},1,"+",{"VAR=":"medium_reputation","re":true},"/ev","^\"A method?\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-4":["ev",{"^->":"class_middle_background.0.g-0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^\"Themselves.\"","\n","^\"You understand the principle already.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-5":["ev",{"^->":"class_middle_background.0.g-0.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^\"Then I am part of your experiment.\"","\n","^\"Naturally. You sat opposite me.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}]}],"g-1":[{"->":"class_middle_explanation"},["ev",{"^->":"class_middle_background.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^\"I was considering whether your concern is official, personal, or merely masculine.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_middle_background.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^\"How convenient. The other two may deny responsibility.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_middle_background.0.g-1.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^\"Then I shall treat it with the respect due to paper.\"",{"->":"$r","var":true},null]}],{"c-6":["ev",{"^->":"class_middle_background.0.g-1.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^His eyes harden by one exact degree.","\n","^\"Today it is official.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-7":["ev",{"^->":"class_middle_background.0.g-1.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"I advise you not to make wit your first instrument at Hohenreith.\"","\n","^\"Then I shall make it the second.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-8":["ev",{"^->":"class_middle_background.0.g-1.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^\"Paper has moved armies.\"","\n","^\"And buried mistakes.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}]}],"g-2":[{"->":"class_middle_explanation"},null]}],null],"class_middle_explanation":["^You were born in that broad, anxious territory between deference and ambition. Your family had books, invoices, respectability, perhaps a piano no one played well enough, perhaps a father with an office, a mother with callers, brothers who were expected to advance, and daughters who were expected not to make advancement look hungry.","\n","^You learned accounts before etiquette, etiquette before French, and French before you learned how easily a woman with a calm voice could make men explain themselves. You rose because you listened. You rose because you understood that fraud, faith, medicine, gossip, politics, and grief all use the same doors into the human mind.","\n","^The court does not like to admit that it needs middle-class competence. It prefers to borrow it, dress it properly, and call it discretion.","\n","^Your reputation as a medium gave them a word that sounded less dangerous than investigator.","\n","^Now choose the name under which you entered the salons that first laughed at you, then invited you back.","\n",{"->":"choose_name_middle"},null],"class_working_background":[["^Viktor's courtesy is smooth enough to be handled without fingerprints. You hear, beneath it, the question of how much this compartment has improved you.","\n",["ev",{"^->":"class_working_background.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"Restraint is what people praise when they prefer not to see the effort.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_working_background.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"Only cheaply.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_working_background.0.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"Only when it hides the person doing the work.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"class_working_background.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^The newspaper in Viktor's hand creases once.","\n","^\"You object to being praised?\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"class_working_background.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"That may be difficult to avoid.\"","\n","^\"Then Hohenreith will have to spend more.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"class_working_background.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.4.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","^He studies you as if the answer has come from farther down the train than first class.","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[{"->":"class_working_explanation"},["ev",{"^->":"class_working_background.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"I am quiet because people often prefer women of my origin either grateful or invisible. I am deciding which will inconvenience you less.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_working_background.0.g-0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"No. You asked me to be manageable.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_working_background.0.g-0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^\"Then I shall postpone gratitude until you deserve it.\"",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"class_working_background.0.g-0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"I did not ask you to be grateful.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-4":["ev",{"^->":"class_working_background.0.g-0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"I asked you nothing of the kind.\"","\n","^\"That is the benefit of rank. It asks through furniture.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-5":["ev",{"^->":"class_working_background.0.g-0.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^A pause. Then, very dryly: \"A generous arrangement.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}]}],"g-1":[{"->":"class_working_explanation"},["ev",{"^->":"class_working_background.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^\"I was trying not to touch the upholstery as though it might accuse me.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_working_background.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^\"Then I am already braver than I was.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"class_working_background.0.g-1.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^\"I shall take that as reassurance, though you delivered it like a reprimand.\"",{"->":"$r","var":true},null]}],{"c-6":["ev",{"^->":"class_working_background.0.g-1.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","ev","str","^dependence","/str","/ev",{"VAR=":"viktor_relation","re":true},"^Something like concern crosses his face, disguised too late as irritation.","\n","^\"The upholstery has survived ministers. It will survive you.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-7":["ev",{"^->":"class_working_background.0.g-1.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","^\"Courage measured against upholstery is not a military standard.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-8":["ev",{"^->":"class_working_background.0.g-1.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^\"I have had practice with both.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}]}],"g-2":[{"->":"class_working_explanation"},null]}],null],"class_working_explanation":["^You were born among people who owned little but obligations. Work had a sound before it had a meaning: water, broom, bootsteps, breath, the clatter of dishes, the cough of men coming in from cold yards, women counting coins under their breath. You learned early that the high-born are not more observant than others. They are merely less often required to observe.","\n","^That was your first advantage.","\n","^A servant knows which door matters because she uses the others. A seamstress learns bodies because she measures them. A maid learns secrets because fine people leave their souls lying about like gloves, certain that no one beneath them has hands.","\n","^You rose by talent, patronage, imitation, nerve, and the terrible convenience of being believed harmless. By the time Vienna began whispering that you saw more than respectable people saw, you had already spent years seeing what respectable people missed.","\n","^The court has placed you in first class because it needs what birth did not give you.","\n","^Now choose the name you carried upward, altered perhaps in pronunciation, never quite cleansed of where it began.","\n",{"->":"choose_name_working"},null],"choose_name_noble":[["ev","str","^Valerie Eleonore Josepha","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Helene Cäcilie Franziska","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Clara Theresia Leopoldine","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Sophie Eleonore Auguste","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Mathilde Josepha Henriette","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Therese Valerie Franziska","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Ilona Theresia Eleonore","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Zdenka Eleonore Josepha","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Valerie Eleonore Josepha","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Valerie","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-1":["\n","ev","str","^Helene Cäcilie Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Helene","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-2":["\n","ev","str","^Clara Theresia Leopoldine","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Clara","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-3":["\n","ev","str","^Sophie Eleonore Auguste","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Sophie","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-4":["\n","ev","str","^Mathilde Josepha Henriette","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Mathilde","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-5":["\n","ev","str","^Therese Valerie Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Therese","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-6":["\n","ev","str","^Ilona Theresia Eleonore","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Ilona","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}],"c-7":["\n","ev","str","^Zdenka Eleonore Josepha","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Zdenka","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_noble"},{"#f":5}]}],null],"choose_surname_noble":[["^Your title is fixed by birth and by the careful modesty of your family: not countess, not princess, not one of the brilliant names that gather ambassadors and creditors like dust.","\n","^A Freiin. Baronial. Usable. Admitted, but not enthroned.","\n","ev","str","^Freiin von Rauhenfels","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Freiin von Traunegg","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Freiin von Ebenwald","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Freiin von Arnsberg","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Freiin von Reichenau","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Freiin von Waldstätten","/str","/ev",{"*":".^.c-5","flg":20},{"c-0":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Rauhenfels","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-1":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Traunegg","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-2":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Ebenwald","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-3":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Arnsberg","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-4":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Reichenau","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-5":["\n","ev","str","^Freiin von","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Waldstätten","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}]}],null],"choose_name_middle":[["ev","str","^Clara Eleonore","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Anna Katharina","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Helene Theresia","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Rosa Franziska","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Johanna Elise","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Katharina Sophie","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Therese Leopoldine","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Magdalena Cäcilie","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Clara Eleonore","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Clara","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-1":["\n","ev","str","^Anna Katharina","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Anna","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-2":["\n","ev","str","^Helene Theresia","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Helene","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-3":["\n","ev","str","^Rosa Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Rosa","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-4":["\n","ev","str","^Johanna Elise","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Johanna","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-5":["\n","ev","str","^Katharina Sophie","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Katharina","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-6":["\n","ev","str","^Therese Leopoldine","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Therese","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}],"c-7":["\n","ev","str","^Magdalena Cäcilie","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Magdalena","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_middle"},{"#f":5}]}],null],"choose_surname_middle":[["^Your family name contains no particle to soften the ascent. It must stand upright by itself.","\n","ev","str","^Leitner","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Wagner","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Kellner","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Baumgartner","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Fischer","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Schmid","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Pichler","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Rosenfeld","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Leitner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-1":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Wagner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-2":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Kellner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-3":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Baumgartner","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-4":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Fischer","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-5":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Schmid","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-6":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Pichler","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-7":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Rosenfeld","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}]}],null],"choose_name_working":[["ev","str","^Anna","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Klara","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Agnes","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Leni","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Rosa","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Gertrud","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Elisabeth","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Franziska","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Anna","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Anna","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-1":["\n","ev","str","^Klara","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Klara","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-2":["\n","ev","str","^Agnes","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Agnes","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-3":["\n","ev","str","^Leni","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Leni","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-4":["\n","ev","str","^Rosa","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Rosa","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-5":["\n","ev","str","^Gertrud","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Gertrud","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-6":["\n","ev","str","^Elisabeth","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Elisabeth","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}],"c-7":["\n","ev","str","^Franziska","/str","/ev",{"VAR=":"given_names","re":true},"ev","str","^Franziska","/str","/ev",{"VAR=":"common_name","re":true},{"->":"choose_surname_working"},{"#f":5}]}],null],"choose_surname_working":[["^A simple name can be a burden in Vienna. It tells people how little they must pretend to respect you before you have spoken.","\n","ev","str","^Pichler","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Huber","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Maier","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Gruber","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^Schuster","/str","/ev",{"*":".^.c-4","flg":20},"ev","str","^Krenn","/str","/ev",{"*":".^.c-5","flg":20},"ev","str","^Wolf","/str","/ev",{"*":".^.c-6","flg":20},"ev","str","^Moser","/str","/ev",{"*":".^.c-7","flg":20},{"c-0":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Pichler","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-1":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Huber","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-2":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Maier","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-3":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Gruber","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-4":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Schuster","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-5":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Krenn","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-6":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Wolf","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}],"c-7":["\n","ev","str","^Fräulein","/str","/ev",{"VAR=":"title_part","re":true},"ev","str","^Moser","/str","/ev",{"VAR=":"surname","re":true},{"->":"assemble_full_name"},{"#f":5}]}],null],"assemble_full_name":["ev",{"VAR?":"birth_class"},"str","^noble","/str","==","/ev",[{"->":".^.b","c":true},{"b":["\n","ev",{"VAR?":"given_names"},"str","^ ","/str","+",{"VAR?":"title_part"},"+","str","^ ","/str","+",{"VAR?":"surname"},"+","/ev",{"VAR=":"full_name","re":true},{"->":".^.^.^.9"},null]}],[{"->":".^.b"},{"b":["\n","ev",{"VAR?":"title_part"},"str","^ ","/str","+",{"VAR?":"given_names"},"+","str","^ ","/str","+",{"VAR?":"surname"},"+","/ev",{"VAR=":"full_name","re":true},{"->":".^.^.^.9"},null]}],"nop","\n","ev",{"VAR?":"birth_class"},"str","^noble","/str","==","/ev",[{"->":".^.b","c":true},{"b":["\n","^On visiting cards, in letters, in the cautious mouths of servants, you are ","ev",{"VAR?":"full_name"},"out","/ev","^.","\n",{"->":".^.^.^.20"},null]}],[{"->":".^.b"},{"b":["\n","^On railway documents, hotel ledgers, and the tongues of people who have not yet decided how much respect you deserve, you are ","ev",{"VAR?":"full_name"},"out","/ev","^.","\n",{"->":".^.^.^.20"},null]}],"nop","\n","^But in the private chamber where a name is first answered before it is performed, you are ","ev",{"VAR?":"common_name"},"out","/ev","^.","\n","^Viktor has waited through your silence with a soldier's patience and a jailer's courtesy. The train enters another tunnel. For several seconds the compartment window gives you back only your own reflection: your hat, your pale face above the dark collar, your eyes too steady or not steady enough.","\n","^When the mountains return, they seem closer.","\n",{"->":"mirror_definition"},null],"mirror_definition":[["^The black glass gives you the woman who will arrive in Eibenreith before any rumour has time to improve her.","\n","^Choose what the window catches first.","\n","ev","str","^Dark ash-brown hair pinned with almost severe care.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Chestnut hair arranged to look softer than the mind beneath it.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Cool fair hair made austere by dark travelling clothes.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^Black-brown hair with a few escaped wisps already refusing discipline.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["\n","ev","str","^dark ash-brown","/str","/ev",{"VAR=":"hair_detail","re":true},"^The reflection has dark ash-brown hair, almost black where the tunnel has not quite left it, pinned with the severity of a woman who knows that disarray is forgiven less easily in the young.","\n",{"->":"mirror_complexion"},{"#f":5}],"c-1":["\n","ev","str","^chestnut","/str","/ev",{"VAR=":"hair_detail","re":true},"^The reflection has chestnut hair, warm where the lamp touches it, arranged with enough softness to flatter and enough control to warn the attentive.","\n",{"->":"mirror_complexion"},{"#f":5}],"c-2":["\n","ev","str","^cool fair","/str","/ev",{"VAR=":"hair_detail","re":true},"^The reflection has cool fair hair, not golden enough for sentimental painters, but pale enough that the dark travelling clothes make your face appear more deliberate than gentle.","\n",{"->":"mirror_complexion"},{"#f":5}],"c-3":["\n","ev","str","^black-brown","/str","/ev",{"VAR=":"hair_detail","re":true},"^The reflection has black-brown hair, glossy in the lamp's weak tremor, with two escaped wisps at the temple already committing small treasons against the pins.","\n",{"->":"mirror_complexion"},{"#f":5}]}],null],"mirror_complexion":[["^The window deepens, and with it the face.","\n","ev","str","^A fair, cool complexion that looks almost bloodless in railway light.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^A clear complexion that still remembers the city more than the sun.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^A face that has learned to look fragile when fragility is useful.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^A slightly warmer complexion that makes the severity of the outfit less forgiving.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["\n","ev","str","^fair and cool","/str","/ev",{"VAR=":"complexion_detail","re":true},"^Your complexion is fair and cool, made paler by smoke, glass, and the faint greenish cast of mountain light.","\n",{"->":"mirror_face"},{"#f":5}],"c-1":["\n","ev","str","^clear and sheltered","/str","/ev",{"VAR=":"complexion_detail","re":true},"^Your complexion has the clarity of rooms, gloves, and shaded streets; not sickly, but visibly protected from the labour that browns other lives.","\n",{"->":"mirror_face"},{"#f":5}],"c-2":["\n","ev","str","^delicately pale","/str","/ev",{"VAR=":"complexion_detail","re":true},"^Your complexion is delicately pale, the sort physicians and foolish men read too eagerly, and which you have never felt obliged to correct every time.","\n",{"->":"mirror_face"},{"#f":5}],"c-3":["\n","ev","str","^warm fair","/str","/ev",{"VAR=":"complexion_detail","re":true},"^Your complexion is warmer than Vienna's winter light would prefer, and that warmth makes the severe coat and collar seem chosen rather than imposed.","\n",{"->":"mirror_face"},{"#f":5}]}],null],"mirror_face":[["^The window keeps you just long enough to make judgement impolite.","\n","ev","str","^A long oval face, observant before it is beautiful.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^A composed face that seems trained equally for salons and interrogations.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^A pretty face made less harmless by the steadiness of the eyes.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^A severe face that becomes almost vulnerable only when caught unprepared.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["\n","ev","str","^long oval and observant","/str","/ev",{"VAR=":"face_detail","re":true},"^The face is long and oval, with watchful eyes, a straight nose, and a mouth that knows how often women are punished for amusement before men call them clever.","\n",{"->":"mirror_outfit"},{"#f":5}],"c-1":["\n","ev","str","^composed and trained","/str","/ev",{"VAR=":"face_detail","re":true},"^The face is composed rather than soft, with brows dark enough to sharpen silence and a mouth whose politeness has not yet promised mercy.","\n",{"->":"mirror_outfit"},{"#f":5}],"c-2":["\n","ev","str","^pretty but steady","/str","/ev",{"VAR=":"face_detail","re":true},"^The face might be called pretty by people who do not like to work harder for adjectives, but the eyes disturb the compliment by appearing to have heard it before and found it insufficient.","\n",{"->":"mirror_outfit"},{"#f":5}],"c-3":["\n","ev","str","^severe and guarded","/str","/ev",{"VAR=":"face_detail","re":true},"^The face is severe at first glance, guarded at the second, and only after that does it betray how young a woman may still be while carrying herself like a sealed document.","\n",{"->":"mirror_outfit"},{"#f":5}]}],null],"mirror_outfit":[["^The rest of the reflection is costume, armour, and evidence.","\n","ev","str","^Dark charcoal-plum travelling wool, restrained but expensive.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^A severe black-brown coat and skirt, softened only by ivory at throat and cuffs.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Bottle-green details hidden in an otherwise sombre travelling suit.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^A more fashionable ensemble, dark and narrow, calculated to be remembered.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["\n","ev","str","^charcoal-plum travelling wool","/str","/ev",{"VAR=":"outfit_detail","re":true},"^You wear a tailored travelling ensemble of dark charcoal wool with a plum undertone, high at the throat, close at the waist, expensive in the way that avoids asking to be admired.","\n",{"->":"supernatural_stance"},{"#f":5}],"c-1":["\n","ev","str","^black-brown travelling suit","/str","/ev",{"VAR=":"outfit_detail","re":true},"^You wear a black-brown travelling suit and long coat, softened only by ivory at throat and cuffs, the lace narrow enough to seem like restraint rather than decoration.","\n",{"->":"supernatural_stance"},{"#f":5}],"c-2":["\n","ev","str","^sombre suit with bottle-green details","/str","/ev",{"VAR=":"outfit_detail","re":true},"^You wear a sombre travelling suit with bottle-green details so discreet that only close attention discovers them, which is nearly the point.","\n",{"->":"supernatural_stance"},{"#f":5}],"c-3":["\n","ev","str","^fashionable dark travelling ensemble","/str","/ev",{"VAR=":"outfit_detail","re":true},"^You wear a dark, narrow, more fashionable travelling ensemble, the hat and veil chosen with just enough theatrical instinct to make sceptical people use the word instinctive.","\n",{"->":"supernatural_stance"},{"#f":5}]}],null],"supernatural_stance":[["^The letter of commission in your reticule does not call you an investigator.","\n","^It calls you, in prose dry enough to pass through any number of offices, a woman whose unusual spiritual reputation has recommended her to a delicate household matter. The phrasing is exquisite. It neither affirms nor denies. It permits everyone involved to believe afterward that they had believed nothing improper.","\n","^The comital family at Jagdhaus Hohenreith has asked for discretion. Vienna has answered with a sealed letter, a woman reputed to speak with what is hidden, and a man opposite her who has orders of his own.","\n","^Before this journey, before this train, before the mountains began taking the sky piece by piece, belief had already taken its position in you.","\n","ev","str","^The dead are not silent. The living are merely poor listeners.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^The supernatural is usually pain, fraud, fever, inheritance, or bad ventilation.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Belief is a costume. You wear it because men insist on dressing you in it.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^You have learned not to decide too early.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["^ ","#","^supernatural:believer","/#","\n","ev","str","^believer","/str","/ev",{"VAR=":"supernatural_belief","re":true},"ev",{"VAR?":"medium_reputation"},1,"+",{"VAR=":"medium_reputation","re":true},"/ev","ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^You have always thought disbelief a provincial arrogance of the educated. There are pressures in rooms where grief has been. There are words people speak before they know they have spoken. There are dreams that arrive with mud on their hems.","\n","^Perhaps the world is not haunted. Perhaps it is simply crowded.","\n",{"->":"spiritual_senses"},{"#f":5}],"c-1":["^ ","#","^supernatural:sceptic ","/#","#","^route:detective","/#","\n","ev","str","^sceptic","/str","/ev",{"VAR=":"supernatural_belief","re":true},"ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^The word spirit covers too much and explains too little. You have watched respectable people call an echo a message, a coincidence a sign, a trembling hand an angelic visitation. Men of science can be fools, but fools with candles and planchettes are no improvement.","\n","^If Hohenreith has ghosts, you expect them to keep accounts, write letters, leave footprints, and benefit someone.","\n",{"->":"spiritual_senses"},{"#f":5}],"c-2":["^ ","#","^supernatural:performer","/#","\n","ev","str","^performer","/str","/ev",{"VAR=":"supernatural_belief","re":true},"ev",{"VAR?":"medium_reputation"},2,"+",{"VAR=":"medium_reputation","re":true},"/ev","^You discovered early that men who distrust a woman's mind will sometimes worship her nerves. A conclusion from evidence irritates them. A vision, sighed through lowered lashes, makes them lean closer.","\n","^Very well. Let them lean.","\n",{"->":"spiritual_senses"},{"#f":5}],"c-3":["^ ","#","^supernatural:undecided","/#","\n","ev","str","^undecided","/str","/ev",{"VAR=":"supernatural_belief","re":true},"^There are things you can explain, things you cannot yet explain, and things that explanation damages before it helps. You have made a profession of standing at thresholds with a face composed enough for both sides to continue speaking.","\n","^Hohenreith will have to show you what kind of case it is.","\n",{"->":"spiritual_senses"},{"#f":5}]}],null],"spiritual_senses":[["^Belief is one matter. Experience is another.","\n","^People call a woman sensitive when they want her perceptions to sound like an illness. They call her hysterical when those perceptions inconvenience them. They call her inspired when they need her, and unstable when they do not.","\n","^Beneath reputation and performance, memory has its own testimony.","\n","ev","str","^There have been moments you cannot explain away.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Everything you do can be explained by observation, timing, and nerve.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^Something happens, but never when summoned.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^You buried the first signs so thoroughly that even you do not know what remains.","/str","/ev",{"*":".^.c-3","flg":20},{"c-0":["^ ","#","^powers:genuine","/#","\n","ev","str","^genuine","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"supernatural_exposure"},2,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^Once, as a child, you knew before the telegram came. Once, in a crowded room, a stranger's grief entered you with such force that your own knees failed. Once, in a mirror, you saw a door behind you that was not in the room when you turned.","\n","^You learned caution after that. It is unwise for a woman to know things before a man has asked her opinion.","\n",{"->":"viktor_first_exchange"},{"#f":5}],"c-1":["^ ","#","^powers:faked ","/#","#","^route:detective","/#","\n","ev","str","^faked","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^You notice rings removed too recently, mourning gloves worn too carefully, letters folded and refolded until the crease gives away the reader's obsession. You hear servants misname guests, mothers pause before daughters' rooms, officers lie by becoming too exact.","\n","^The dead have never told you anything. The living cannot stop telling you everything.","\n",{"->":"viktor_first_exchange"},{"#f":5}],"c-2":["^ ","#","^powers:ambiguous","/#","\n","ev","str","^ambiguous","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^Your reputation depends upon command. The truth, if truth it is, has no respect for appointments.","\n","^Sometimes a room changes pressure around you. Sometimes a face acquires an old expression no living person taught it. Sometimes names arrive before introductions. But the harder you reach, the more ordinary the world becomes.","\n",{"->":"viktor_first_exchange"},{"#f":5}],"c-3":["^ ","#","^powers:repressed ","/#","#","^route:eccentric","/#","\n","ev","str","^repressed","/str","/ev",{"VAR=":"supernatural_senses","re":true},"ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^There are childhood memories sealed behind politeness: a nursery mirror turned to the wall, a nurse dismissed without reference, your mother's hand tightening around your wrist until the bones complained.","\n","^You became strange afterward in ways society found easier to admire than understand.","\n",{"->":"viktor_first_exchange"},{"#f":5}]}],null],"viktor_first_exchange":[["^The train emerges from the tunnel into a pale afternoon cut by dark firs and white rock. Far below, water shows itself only in flashes. The valley is no longer a view from a salon painting. It has depth enough to hide things.","\n","^Viktor opens a leather folder and removes a memorandum. He does not hand it to you at once.","\n","^\"When we leave the railway,\" he says, \"we will be met by a coach from Hohenreith. From that moment, appearances matter. Your hosts have been told that I assist with correspondence, travel, and practical arrangements. They need not be troubled with military definitions.\"","\n",["ev",{"^->":"viktor_first_exchange.0.6.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"And the villagers?\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.7.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"How merciful. The empire has spared them vocabulary.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.8.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"You mean they are not to know whether I am guest, tool, or warning.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"viktor_first_exchange.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.6.s"},[{"#n":"$r2"}],"\n","^\"The villagers need not be troubled with anything.\"","\n","^There it is: the empire in miniature. A man, a folder, a locked sentence.","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"viktor_first_exchange.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.7.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"The empire has spared them alarm,\" Viktor says.","\n","^\"It often uses the two interchangeably.\"","\n","^There it is: the empire in miniature. A man, a folder, a locked sentence.","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"viktor_first_exchange.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.8.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^\"I mean they are to know only what steadies the situation.\"","\n","^\"That is not a contradiction.\"","\n","^There it is: the empire in miniature. A man, a folder, a locked sentence.","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^\"You will be addressed according to the station you present,\" he continues. \"The Graf's household will observe rank. Servants will observe what the household observes. Villagers may observe less and remember more. I advise restraint.\"","\n","^The advice is sound. That makes it no less irritating.","\n",["ev",{"^->":"viktor_first_exchange.0.g-0.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"If gentlemen were less easily led, Herr Nowak, ladies would require fewer methods.\" ","#","^route:lover","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-0.5.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"A practical one.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-0.6.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^\"Only where patriotism requires sacrifice.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-0.7.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^\"Only where men mistake desire for judgement.\"",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"viktor_first_exchange.0.g-0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.4.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev","str","^provocation","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_trust"},1,"-",{"VAR=":"viktor_trust","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^For the first time, amusement almost reaches his mouth.","\n","^\"A dangerous doctrine.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-4":["ev",{"^->":"viktor_first_exchange.0.g-0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.5.s"},[{"#n":"$r2"}],"\n","^\"You intend to practice it at Hohenreith?\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-5":["ev",{"^->":"viktor_first_exchange.0.g-0.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.6.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^He looks down at the memorandum, but not quickly enough to conceal that he is reassessing you.","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-6":["ev",{"^->":"viktor_first_exchange.0.g-0.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.7.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^\"That may include more territory than the maps admit.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}]}],"g-1":[{"->":"viktor_explains_orders"},["ev",{"^->":"viktor_first_exchange.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^\"Dangerous doctrines travel best in good gloves.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^\"If you wish me to pass as harmless, you must stop warning me like a gaoler.\" ","#","^route:sapphic","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-1.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-9","flg":18},{"s":["^\"No. A gaoler is at least honest about the key.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-1.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-10","flg":18},{"s":["^\"Then do not stand between me and every locked door before I have touched the handle.\"",{"->":"$r","var":true},null]}],{"c-7":["ev",{"^->":"viktor_first_exchange.0.g-1.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"You intend to charm Hohenreith into confession?\"","\n","^\"Only if Hohenreith insists on being charmed.\"","\n",{"->":"viktor_explains_orders"},{"->":".^.^.^.g-2"},{"#f":5}],"c-8":["ev",{"^->":"viktor_first_exchange.0.g-1.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","ev","str","^tension","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^His gaze sharpens.","\n","^\"I am not your gaoler.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-9":["ev",{"^->":"viktor_first_exchange.0.g-1.c-9.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","^The words surprise you by leaving a mark. Not on him, perhaps. On yourself. The closer the train carries you to Amalia's world, though you do not yet know her face, the more intolerable it seems that every female life there might be guarded by men who call the guarding concern.","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-10":["ev",{"^->":"viktor_first_exchange.0.g-1.c-10.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.4.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^\"Some doors are locked for cause.\"","\n","^\"Then the cause had better survive examination.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}]}],"g-2":["^Viktor folds the memorandum once, precisely.","\n",{"->":"viktor_explains_orders"},["ev",{"^->":"viktor_first_exchange.0.g-2.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-11","flg":18},{"s":["^\"Then let us be exact. What do they know, what do they suspect, and what am I permitted to verify?\" ","#","^route:detective","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-2.4.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-12","flg":18},{"s":["^\"Credible phenomena not presently classifiable.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-2.5.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-13","flg":18},{"s":["^\"And if the phenomena become classifiable?\"",{"->":"$r","var":true},null]}],{"c-11":["ev",{"^->":"viktor_first_exchange.0.g-2.c-11.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev","str","^professional","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^He gives the smallest nod, as if you have chosen the only answer fit for adults.","\n","^\"They know that you come recommended. They suspect that you may be able to settle disturbances without police, priest, or press. You are permitted to verify fraud, coercion, threat to public order, or credible phenomena not presently classifiable.\"","\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-12":["ev",{"^->":"viktor_first_exchange.0.g-2.c-12.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.4.s"},[{"#n":"$r2"}],"\n","^\"That is the phrase.\"","\n","^\"A bureaucratic ghost.\"","\n","^\"The safest kind.\"","\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-13":["ev",{"^->":"viktor_first_exchange.0.g-2.c-13.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.5.s"},[{"#n":"$r2"}],"\n","^\"Then we classify them before others do.\"","\n","^\"Spoken like a man who has seen reports bury graves.\"","\n",{"->":".^.^.^.g-3"},{"#f":5}]}],"g-3":[{"->":"viktor_explains_orders"},["ev",{"^->":"viktor_first_exchange.0.g-3.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-14","flg":18},{"s":["^\"I shall do my best not to faint unless it is useful.\" ","#","^route:careless","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-3.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-15","flg":18},{"s":["^\"How ungallant.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-3.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-16","flg":18},{"s":["^\"Then you must remain close enough to catch me.\"",{"->":"$r","var":true},null]}],{"c-14":["ev",{"^->":"viktor_first_exchange.0.g-3.c-14.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","ev","str","^dependence","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_trust"},1,"-",{"VAR=":"viktor_trust","re":true},"/ev","^Something in his expression tightens; not contempt exactly, but readiness.","\n","^\"I would prefer you did not faint at all.\"","\n",{"->":".^.^.^.g-4"},{"#f":5}],"c-15":["ev",{"^->":"viktor_first_exchange.0.g-3.c-15.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","^\"How practical.\"","\n","^\"Then you must be practical for both of us. I have never trusted the floor in strange houses.\"","\n","^His answer is delayed by half a breath.","\n","^\"That, gnädiges Fräulein, is precisely what concerns me.\"","\n",{"->":".^.^.^.g-4"},{"#f":5}],"c-16":["ev",{"^->":"viktor_first_exchange.0.g-3.c-16.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^\"My orders did not specify theatrical collapses.\"","\n","^\"How careless of them.\"","\n",{"->":".^.^.^.g-4"},{"#f":5}]}],"g-4":[{"->":"viktor_explains_orders"},["ev",{"^->":"viktor_first_exchange.0.g-4.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-17","flg":18},{"s":["^\"Restraint is what timid people call obedience after they have forgotten who trained them.\" ","#","^route:eccentric","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-4.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-18","flg":18},{"s":["^\"No. I dislike the laziness of letting fools remain undecided.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_first_exchange.0.g-4.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-19","flg":18},{"s":["^\"Enemies are merely people honest enough to stand in the right place.\"",{"->":"$r","var":true},null]}],{"c-17":["ev",{"^->":"viktor_first_exchange.0.g-4.c-17.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev","str","^challenge","/str","/ev",{"VAR=":"viktor_relation","re":true},"ev",{"VAR?":"viktor_suspicion"},2,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^Viktor studies you as he might study an unfamiliar weapon found in luggage.","\n","^\"You enjoy making enemies.\"","\n",{"->":".^.^.^.g-5"},{"#f":5}],"c-18":["ev",{"^->":"viktor_first_exchange.0.g-4.c-18.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","^\"At Hohenreith, that dislike may become expensive.\"","\n","^\"Then the Graf should have invited someone cheaper.\"","\n",{"->":".^.^.^.g-5"},{"#f":5}],"c-19":["ev",{"^->":"viktor_first_exchange.0.g-4.c-19.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","^\"You speak as though conflict were housekeeping.\"","\n","^\"It is. One discovers what belongs where.\"","\n",{"->":".^.^.^.g-5"},{"#f":5}]}],"g-5":["^The wheels strike a curve. The compartment leans. For a moment the two of you are held in the same narrow imbalance.","\n",{"->":"viktor_explains_orders"},null]}],null],"viktor_explains_orders":[["^Viktor gives you the memorandum at last.","\n","^The document is not long. That is part of its menace. Long documents invite argument; short ones carry authority.","\n","^A comital household. A hunting residence in Upper Styria, not the family's principal seat. Reports of disturbances among servants and villagers. No police action requested. No public ecclesiastical inquiry desired. No press. No correspondence beyond approved channels. Your presence to be explained as a discreet consultation requested by the family. Herr Nowak to assist in practical matters.","\n","^No one has written the word ghost.","\n","^No one has written the word fraud.","\n","^No one has written the word daughter.","\n","^Yet the omissions arrange themselves around the page like furniture around a corpse.","\n",["ev",{"^->":"viktor_explains_orders.0.14.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"There is another instruction.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_explains_orders.0.15.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"Your version is shorter than your silence. That means there is another instruction.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_explains_orders.0.16.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"How touching. Vienna trusts us both so little it had to divide the distrust.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"viktor_explains_orders.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.14.s"},[{"#n":"$r2"}],"\n","^Viktor does not ask how you know.","\n","^\"There is always another instruction,\" he says.","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"viktor_explains_orders.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.15.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^Viktor does not ask how you know.","\n","^\"There is always another instruction,\" he says.","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"viktor_explains_orders.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.16.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^Viktor does not ask how you know.","\n","^\"There is always another instruction,\" he says.","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[["ev",{"^->":"viktor_explains_orders.0.g-0.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"For you.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_explains_orders.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"Concerning me.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_explains_orders.0.g-0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^\"Concerning whether I am fraud, fool, or useful animal.\"",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"viktor_explains_orders.0.g-0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","^\"Yes.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-4":["ev",{"^->":"viktor_explains_orders.0.g-0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","^\"Partly.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-5":["ev",{"^->":"viktor_explains_orders.0.g-0.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"Partly,\" he says, and this time the honesty has a blade in it.","\n",{"->":".^.^.^.g-1"},{"#f":5}]}],"g-1":["^The train begins to slow. The rhythm changes first in the floor, then in the window, then in the body. Houses gather beside the line. A station roof appears between drifting smoke and the dark combs of forested slopes. ","#","^sfx[steam-whistle.ogg]","/#","\n",["ev",{"^->":"viktor_explains_orders.0.g-1.5.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^\"Then I shall try to be worth the ink.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_explains_orders.0.g-1.6.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^\"Then I shall disappoint the instruction as creatively as circumstances permit.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"viktor_explains_orders.0.g-1.7.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^\"Then keep your second instruction, Herr Nowak. I prefer primary sources.\"",{"->":"$r","var":true},null]}],{"c-6":["ev",{"^->":"viktor_explains_orders.0.g-1.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.5.s"},[{"#n":"$r2"}],"\n","^\"I sincerely hope so.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-7":["ev",{"^->":"viktor_explains_orders.0.g-1.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.6.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"I sincerely hope you do not.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-8":["ev",{"^->":"viktor_explains_orders.0.g-1.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.7.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^\"A preference not always granted in imperial service.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}]}],"g-2":["^You cannot decide whether his answer is an insult, a prayer, or his first honest sentence.","\n",{"->":"railway_station"},null]}],null],"railway_station":[["^The station is small enough that the train seems briefly embarrassed to stop there. ","#","^chapter[The Station] ","/#","#","^image[muerzzuschlag.png](portrait)","/#","\n","^A porter in a cap too large for him hurries along the platform. A woman with a basket steps back from the steam as if from an animal. Somewhere beyond the station building, a cart horse stamps at frozen mud. The signboard gives the place a name you have seen in the timetable but will not remember with affection.","\n","^Your luggage descends in stages.","\n","ev","str","^A disciplined official set: trunk, dispatch case, hatbox, and black séance case.","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^An elegant noblewoman's luggage: too correct to be accidental.","/str","/ev",{"*":".^.c-1","flg":20},"ev","str","^A performer’s luggage: harmless on top, less harmless beneath.","/str","/ev",{"*":".^.c-2","flg":20},"ev","str","^A practical assortment that betrays too much preparation.","/str","/ev",{"*":".^.c-3","flg":20},"ev","str","^An excessive pile that makes concealment impossible.","/str","/ev",{"*":".^.c-4","flg":20},{"c-0":["\n","ev","str","^official","/str","/ev",{"VAR=":"baggage_style","re":true},"^First comes a sober travelling trunk with brass corners dulled by use, then a dispatch case, then a hatbox, then the narrow black case whose contents would embarrass both a priest and a conjurer if either searched it without imagination.","\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev",{"->":"station_luggage_common"},{"#f":5}],"c-1":["\n","ev","str","^elegant","/str","/ev",{"VAR=":"baggage_style","re":true},"^First comes a large trunk in dark leather, then a second smaller one for linen, then a round hatbox, a fitted toilette case, and a reticule kept too close to your hand for any porter to misunderstand its importance.","\n","ev",{"VAR?":"class_confidence"},1,"+",{"VAR=":"class_confidence","re":true},"/ev",{"->":"station_luggage_common"},{"#f":5}],"c-2":["\n","ev","str","^performer","/str","/ev",{"VAR=":"baggage_style","re":true},"^First comes a respectable trunk, then a hatbox, then a travelling case of gloves, veils, ribbons, calling cards, and the small objects by which a room may be persuaded to believe in forces already present.","\n","ev",{"VAR?":"medium_reputation"},1,"+",{"VAR=":"medium_reputation","re":true},"/ev",{"->":"station_luggage_common"},{"#f":5}],"c-3":["\n","ev","str","^practical","/str","/ev",{"VAR=":"baggage_style","re":true},"^First comes a battered trunk reinforced at the corners, then a leather case with notebooks, pencils, folded maps, spare gloves, a hand-lamp, and enough small necessities to offend anyone who prefers women decorative.","\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev",{"->":"station_luggage_common"},{"#f":5}],"c-4":["\n","ev","str","^excessive","/str","/ev",{"VAR=":"baggage_style","re":true},"^First comes one trunk, then another, then a hatbox, then a rug, then a dressing case, then the narrow black case, then a smaller parcel you had forgotten had survived packing. By the end even Viktor looks faintly outnumbered.","\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev",{"->":"station_luggage_common"},{"#f":5}]}],null],"station_luggage_common":["^Viktor oversees the transfer with clipped civility. He does not carry like a servant. He directs like a man pretending not to command.","\n","^The coach from Hohenreith waits beyond the station yard: dark green paint, black wheels, the comital crest discreetly worn on the door, and two horses already restless beneath harness. The driver removes his hat when he sees you. Not too deeply. Deep enough for rank, not deep enough for reverence. ","#","^sfx[horse-neigh.ogg]","/#","\n","^\"Gnädiges Fräulein? Herr Sekretär?\"","\n","ev",{"VAR?":"birth_class"},"str","^noble","/str","==","/ev",[{"->":".^.b","c":true},{"b":["\n","^He has been told enough to place you. That is a courtesy. It is also a warning.","\n",{"->":".^.^.^.18"},null]}],[{"->":".^.b"},{"b":["\n","^He hesitates over you by the smallest measure. The hesitation is not rudeness. It is calculation. First-class carriage, court letter, no title beyond Fräulein, and a man beside you who looks like he has arrested people for less than staring.","\n",{"->":".^.^.^.18"},null]}],"nop","\n","^Viktor answers before you can.","\n","^\"From Jagdhaus Hohenreith?\"","\n","^\"Jawohl, Herr Sekretär. The road is passable. If the mist holds, we should reach Eibenreith before dark.\"","\n","^The word enters the air without ceremony.","\n","^Eibenreith.","\n","^Not Hohenreith, the name printed on the invitation in a clean hand. Eibenreith: the village below it. A smaller name. Older in the mouth. A name with roots rather than stationery.","\n",{"->":"coach_journey"},null],"coach_journey":[["^The coach leaves the station behind and with it the last easy evidence of empire. ","#","^chapter[The Graben] ","/#","#","^music[Kaiserpunk Jodler.mp3](crossfade, loop, lead=4)","/#","\n","^At first the road follows a valley where telegraph wire still keeps company with it and the river moves in a pale, stony bed. Sawmills, fenced meadows, and farmhouses appear and vanish behind stands of spruce. The mountains do not rise all at once. They advance by jurisdiction. A wooded slope claims the left-hand sky, then a grey wall of limestone closes the north, then another ridge gathers to the east until even the clouds seem to have entered service.","\n","^The driver names places when Viktor asks, but the names are local and practical, meant for men who know which bridge floods and which farm breeds stubborn horses. Somewhere beyond the visible ridges, he says, lies the great white back of the Hochschwab. Eastward, beyond forest and pass, the Hohe Veitsch keeps its own weather. He says this not as a guide would say it, but as a man explaining neighbours who may or may not be in a temper.","\n","^The main valley narrows.","\n","^The road turns from it into a side Graben, and the change is immediate. Sound alters. The wheels no longer ring against open distance but grind between banks, roots, and wet stone. The air smells of leaf mould, resin, and cold water. Yews appear among the firs in dark, improbable patience, their needles too black for the afternoon.","\n","^\"Eibenreither Graben,\" the driver says, and crosses himself so quickly that the gesture might have been meant for a rut in the road.","\n","^Viktor notices. Of course he notices.","\n","^\"Bad road?\" he asks.","\n","^\"Old road,\" the driver says.","\n","^No one speaks for a while.","\n","^You watch the trees.","\n","^There are forests that invite stories because they are pretty, and forests that reject stories because whatever happened there did not require witnesses. This one belongs to the second kind. Its trunks stand close, not wildly, but with the air of a crowd making room for something carried through it long ago. The snow that remains in hollows is not clean. It has gathered needles, bark, and a yellowish stain where water has risen underneath.","\n","^On a slope above the road, half swallowed by undergrowth, you glimpse stone.","\n","^A shrine, perhaps. A boundary marker. A figure. The coach has passed before your eyes can persuade themselves of its shape. For one instant you are left with the impression of a woman's head inclined not in prayer, but in listening. ","#","^image[statue.png](square)","/#","\n","ev",{"VAR?":"supernatural_senses"},"str","^genuine","/str","==",{"VAR?":"supernatural_senses"},"str","^ambiguous","/str","==","||",{"VAR?":"supernatural_senses"},"str","^repressed","/str","==","||","/ev",[{"->":".^.b","c":true},{"b":["\n","^The back of your neck tightens.","\n","^Not fear. Recognition would be worse.","\n","ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev",{"->":".^.^.^.58"},null]}],[{"->":".^.b"},{"b":["\n","^You tell yourself that old stone, seen through moving branches, will become whatever the mind is cowardly enough to supply.","\n",{"->":".^.^.^.58"},null]}],"nop","\n","^Viktor has turned slightly toward the same slope.","\n","^\"Did you see something?\"","\n",["ev",{"^->":"coach_journey.0.64.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"A woman in the wood, perhaps. Or a stone that wanted to be one.\" ","#","^route:eccentric ","/#","#","^statue_hint","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.65.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"If it is a shrine, it has not been loved recently.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.66.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"No. Shrines face the faithful. That thing was listening sideways.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"coach_journey.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.64.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^He studies the passing trees.","\n","^\"A local shrine?\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"coach_journey.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.65.s"},[{"#n":"$r2"}],"\n","^\"You speak as if stones notice neglect.\"","\n","^\"Do soldiers not?\"","\n","^He does not answer.","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"coach_journey.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.66.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"supernatural_exposure"},1,"+",{"VAR=":"supernatural_exposure","re":true},"/ev","^Viktor's hand rests on the coach strap, still and ready.","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":[{"->":"coach_nears_village"},["ev",{"^->":"coach_journey.0.g-0.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"A marker. I would like to know where that path leads.\" ","#","^route:detective ","/#","#","^statue_hint","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"Not clearly. Enough to ask later.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-5","flg":18},{"s":["^\"Only a suggestion of one. If it exists, someone maintains the absence of it.\"",{"->":"$r","var":true},null]}],{"c-3":["ev",{"^->":"coach_journey.0.g-0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^\"You saw a path?\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-4":["ev",{"^->":"coach_journey.0.g-0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","^Viktor looks back through the small rear window. The bend has already erased the slope.","\n","^\"Ask carefully. Places people fail to mention are often more informative than those they recommend.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}],"c-5":["ev",{"^->":"coach_journey.0.g-0.c-5.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^\"You make absences sound expensive.\"","\n","^\"They usually are.\"","\n",{"->":".^.^.^.g-1"},{"#f":5}]}],"g-1":[{"->":"coach_nears_village"},["ev",{"^->":"coach_journey.0.g-1.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-6","flg":18},{"s":["^\"Only trees. The sort that make one grateful for gentlemen with revolvers.\" ","#","^route:careless","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-1.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-7","flg":18},{"s":["^\"Then I shall rely on your conversation to intimidate them.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-1.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-8","flg":18},{"s":["^\"How unfortunate. You seemed so professionally reassuring.\"",{"->":"$r","var":true},null]}],{"c-6":["ev",{"^->":"coach_journey.0.g-1.c-6.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","ev","str","^dependence","/str","/ev",{"VAR=":"viktor_relation","re":true},"^His expression darkens by one official degree.","\n","^\"A revolver is a poor instrument against trees.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-7":["ev",{"^->":"coach_journey.0.g-1.c-7.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","^The driver pretends not to hear. His shoulders, however, hear everything.","\n",{"->":".^.^.^.g-2"},{"#f":5}],"c-8":["ev",{"^->":"coach_journey.0.g-1.c-8.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^\"I prefer enemies that identify themselves.\"","\n",{"->":".^.^.^.g-2"},{"#f":5}]}],"g-2":[{"->":"coach_nears_village"},["ev",{"^->":"coach_journey.0.g-2.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-9","flg":18},{"s":["^\"Would you believe me if I said I had?\" ","#","^route:lover","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-2.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-10","flg":18},{"s":["^\"Herr Nowak. You wound me.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-2.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-11","flg":18},{"s":["^\"Then watch the slope, not my intentions. One of them may be useful.\"",{"->":"$r","var":true},null]}],{"c-9":["ev",{"^->":"coach_journey.0.g-2.c-9.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","ev",{"VAR?":"viktor_suspicion"},1,"+",{"VAR=":"viktor_suspicion","re":true},"/ev","^\"That would depend on what advantage you expected from the answer.\"","\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-10":["ev",{"^->":"coach_journey.0.g-2.c-10.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","^\"Not yet.\"","\n","^It is the first thing he has said all day that almost sounds like flirtation, though perhaps only because danger has a talent for borrowing warmer clothes.","\n",{"->":".^.^.^.g-3"},{"#f":5}],"c-11":["ev",{"^->":"coach_journey.0.g-2.c-11.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"viktor_trust"},1,"+",{"VAR=":"viktor_trust","re":true},"/ev","^He obeys without admitting that he has done so.","\n",{"->":".^.^.^.g-3"},{"#f":5}]}],"g-3":[{"->":"coach_nears_village"},["ev",{"^->":"coach_journey.0.g-3.1.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-12","flg":18},{"s":["^\"No.\" ","#","^route:sapphic","/#",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-3.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-13","flg":18},{"s":["^\"It was only shadow.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_journey.0.g-3.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-14","flg":18},{"s":["^\"Or if I did, I prefer not to have it explained before I understand why it matters.\"",{"->":"$r","var":true},null]}],{"c-12":["ev",{"^->":"coach_journey.0.g-3.c-12.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.1.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","^The denial is too quick, and you both hear it.","\n","^You are not thinking of the stone now. You are thinking of the young woman waiting somewhere ahead: the Graf's daughter, the reason carefully not written into the memorandum, the stranger whose household has summoned you under a title both absurd and useful.","\n",{"->":".^.^.^.g-4"},{"#f":5}],"c-13":["ev",{"^->":"coach_journey.0.g-3.c-13.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n","^If this place keeps women in stone, you think, what does it do to them in houses?","\n",{"->":".^.^.^.g-4"},{"#f":5}],"c-14":["ev",{"^->":"coach_journey.0.g-3.c-14.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^If this place keeps women in stone, you think, what does it do to them in houses?","\n",{"->":".^.^.^.g-4"},{"#f":5}]}],"g-4":[{"->":"coach_nears_village"},null]}],null],"coach_nears_village":[["^The Graben opens reluctantly.","\n","^First comes the smell of smoke. Then a roof, low and dark with weather. Then another. Then a church tower, not high, not graceful, but thick-shouldered and pale against the slope behind it. Its walls look older than the village around them and less certain of victory. The windows are small. The churchyard wall holds the road at a distance, as if the dead require fortification from the living, or the living from something else. ","#","^chapter[Eibenreith Village] ","/#","#","^sfx[church-bells.ogg](max=8, fade) ","/#","#","^image[eibenreith.png](landscape)","/#","\n","^Eibenreith appears not as a village in a picture appears, all at once and composed for admiration, but by fragments.","\n","^A woman in a dark kerchief pauses with a pail in her hand. A boy stops driving geese and lets them complain around his boots. Two men outside a shed end their conversation at the same moment without looking at each other. Curtains stir in windows where no one admits to standing. A blacksmith's sign moves slightly in air you cannot feel. Water runs somewhere under boards, under stone, under the road itself, quick and cold and hidden.","\n","^The houses are not poor, not exactly. Many are solid, whitewashed, shingled, kept with the stubborn decency of people who repair what they cannot replace. Yet something in their arrangement troubles the eye. They turn toward the church but not fully. They keep the road but lean from it. They leave, between yard and fence and woodpile, narrow passages where shadow gathers too early.","\n","^The coach slows.","\n","^No one runs to greet it.","\n","^No one needs to. News has already entered the village by means faster than railway, telegraph, or imperial seal.","\n","^You sit very straight as Eibenreith takes its first look at you.","\n","^Beside you, Viktor lowers his voice.","\n","^\"Remember: at Hohenreith, every courtesy will mean something. Here, every silence will.\"","\n",["ev",{"^->":"coach_nears_village.0.31.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^\"Then we are already being received.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_nears_village.0.32.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^\"You make it sound as if the village outranks the Graf.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_nears_village.0.33.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-2","flg":18},{"s":["^\"How fortunate that I packed several silences.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_nears_village.0.34.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-3","flg":18},{"s":["^\"I dislike being watched by people who will not introduce themselves.\"",{"->":"$r","var":true},null]}],["ev",{"^->":"coach_nears_village.0.35.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-4","flg":18},{"s":["^\"If Amalia has lived under this gaze all her life, I begin to understand why they sent for ghosts.\"",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"coach_nears_village.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.31.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"detective"},1,"+",{"VAR=":"detective","re":true},"/ev","^\"Yes,\" he says. \"And examined.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"coach_nears_village.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.32.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"eccentric"},1,"+",{"VAR=":"eccentric","re":true},"/ev","^\"No,\" Viktor says. \"Only as if it may have survived more than one.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-2":["ev",{"^->":"coach_nears_village.0.c-2.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.33.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"lover"},1,"+",{"VAR=":"lover","re":true},"/ev","^His mouth almost moves. \"Use the plainest one first.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-3":["ev",{"^->":"coach_nears_village.0.c-3.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.34.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"careless"},1,"+",{"VAR=":"careless","re":true},"/ev","^\"That,\" he says, \"is unlikely to improve today.\"","\n",{"->":".^.^.g-0"},{"#f":5}],"c-4":["ev",{"^->":"coach_nears_village.0.c-4.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.35.s"},[{"#n":"$r2"}],"\n","ev",{"VAR?":"sapphic"},1,"+",{"VAR=":"sapphic","re":true},"/ev","^Viktor glances at you, but whatever answer he considers, he keeps it behind his teeth.","\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^The horses draw the coach past the churchyard wall. Above it, on the old plaster beside the gate, a faded painted woman looks down from beneath a flaking blue mantle. Her hands are folded in prayer. Her eyes, damaged by weather, no longer point in the same direction.","\n","^For one breath, as the wheels pass over a buried runnel of water, the painted face seems less like the Holy Mother than like a mask put on something that had been waiting longer.","\n","^Then the coach enters the village proper, and the road bends toward the unseen height where Jagdhaus Hohenreith stands above Eibenreith under its newer name.","\n","end",null]}],null],"global decl":["ev","str","^unset","/str",{"VAR=":"birth_class"},"str","^","/str",{"VAR=":"title_part"},"str","^","/str",{"VAR=":"given_names"},"str","^","/str",{"VAR=":"common_name"},"str","^","/str",{"VAR=":"surname"},"str","^","/str",{"VAR=":"full_name"},"str","^unset","/str",{"VAR=":"baggage_style"},"str","^unset","/str",{"VAR=":"hair_detail"},"str","^unset","/str",{"VAR=":"complexion_detail"},"str","^unset","/str",{"VAR=":"face_detail"},"str","^unset","/str",{"VAR=":"outfit_detail"},"str","^unset","/str",{"VAR=":"supernatural_belief"},"str","^unset","/str",{"VAR=":"supernatural_senses"},"str","^unset","/str",{"VAR=":"viktor_relation"},0,{"VAR=":"lover"},0,{"VAR=":"sapphic"},0,{"VAR=":"detective"},0,{"VAR=":"careless"},0,{"VAR=":"eccentric"},0,{"VAR=":"class_confidence"},0,{"VAR=":"medium_reputation"},0,{"VAR=":"court_loyalty"},0,{"VAR=":"viktor_trust"},0,{"VAR=":"viktor_suspicion"},0,{"VAR=":"supernatural_exposure"},"/ev","end",null]}],"listDefs":{}} \ No newline at end of file diff --git a/dist/engine/ink-engine.js b/dist/engine/ink-engine.js index e4f43ed..5ed3e1c 100644 --- a/dist/engine/ink-engine.js +++ b/dist/engine/ink-engine.js @@ -83,11 +83,27 @@ class InkEngine { if (!this.story) { throw new Error('No active Ink story to save'); } - return this.story.state.toJson(); + return JSON.stringify({ + inkState: this.story.state.toJson(), + nextTurnId: this.nextTurnId, + }); } loadGame(savedState) { this.story = this.loadStory(); - this.story.state.LoadJson(savedState); + let inkState = savedState; + try { + const parsed = JSON.parse(savedState); + if (parsed && typeof parsed.inkState === 'string') { + inkState = parsed.inkState; + if (Number.isInteger(parsed.nextTurnId)) { + this.nextTurnId = Math.max(1, parsed.nextTurnId); + } + } + } + catch { + // Backward compatibility with raw Ink state JSON. + } + this.story.state.LoadJson(inkState); return this.continueStory(); } loadStory() { diff --git a/dist/engine/ink-engine.js.map b/dist/engine/ink-engine.js.map index c1d0506..edd1e7c 100644 --- a/dist/engine/ink-engine.js.map +++ b/dist/engine/ink-engine.js.map @@ -1 +1 @@ -{"version":3,"file":"ink-engine.js","sourceRoot":"","sources":["../../src/engine/ink-engine.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"ink-engine.js","sourceRoot":"","sources":["../../src/engine/ink-engine.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/server-ink.js b/dist/server-ink.js index 8495302..0b7dfbf 100644 --- a/dist/server-ink.js +++ b/dist/server-ink.js @@ -138,11 +138,12 @@ async function handleGameApi(socket, method, args) { case 'loadGame': case 'loadGame()': { const slot = normalizeSaveSlot(args[0]); - if (!slots.has(slot)) { + const browserSave = typeof args[1] === 'string' ? args[1] : null; + if (!browserSave && !slots.has(slot)) { return { success: false, error: 'missing_save', result: false }; } const engine = getOrCreateEngine(socket.id); - socket.emit('narrativeResponse', engine.loadGame(slots.get(slot))); + socket.emit('narrativeResponse', engine.loadGame(browserSave || slots.get(slot))); socket.emit('gameLoaded', { slot }); return { success: true, result: true, running: true, slot }; } @@ -153,9 +154,10 @@ async function handleGameApi(socket, method, args) { return { success: false, error: 'game_not_running', result: false }; } const slot = normalizeSaveSlot(args[0]); - slots.set(slot, engine.saveGame()); + const savedState = engine.saveGame(); + slots.set(slot, savedState); socket.emit('gameSaved', { slot }); - return { success: true, result: true, slot }; + return { success: true, result: true, slot, savedState }; } case 'hasSaveGame': case 'hasSaveGame()': { diff --git a/dist/server-ink.js.map b/dist/server-ink.js.map index 8c6796c..2f816a8 100644 --- a/dist/server-ink.js.map +++ b/dist/server-ink.js.map @@ -1 +1 @@ -{"version":3,"file":"server-ink.js","sourceRoot":"","sources":["../src/server-ink.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"server-ink.js","sourceRoot":"","sources":["../src/server-ink.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/public/css/style.css b/public/css/style.css index 7a79810..4846eee 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -421,6 +421,11 @@ ol.choice { overflow-anchor: none; } +.story-block-archiving { + opacity: 0; + transition: opacity 320ms ease; +} + .story-image-block { box-sizing: border-box; margin: 0 auto; @@ -484,9 +489,38 @@ ol.choice { scroll-behavior: smooth; overscroll-behavior: contain; overflow-anchor: none; + scrollbar-width: none; /* transform: translateX(-1%) translateY(2%) rotateX(0deg) rotateY(-1deg) rotateZ(0deg); */ } +#page_right::-webkit-scrollbar { + display: none; +} + +#story_scrollbar { + position: sticky; + float: right; + top: 0.4rem; + width: 0.22rem; + height: calc(100% - 0.8rem); + margin-right: -1.5rem; + border-radius: 999px; + background: rgba(0, 0, 0, 0.12); + z-index: 12; + pointer-events: none; +} + +#story_scrollbar_thumb { + position: absolute; + left: 0; + right: 0; + top: 0; + min-height: 1rem; + border-radius: inherit; + background: rgba(0, 0, 0, 0.72); + transition: top 260ms ease, height 260ms ease; +} + /* ===== Scrollbar CSS ===== */ /* Firefox */ diff --git a/public/js/game-loop-module.js b/public/js/game-loop-module.js index 7bb8f3f..93cac48 100644 --- a/public/js/game-loop-module.js +++ b/public/js/game-loop-module.js @@ -9,7 +9,7 @@ class GameLoopModule extends BaseModule { super('game-loop', 'Game Loop'); // Dependencies - this.dependencies = ['ui-controller', 'socket-client', 'text-buffer', 'sentence-queue', 'playback-coordinator', 'animation-queue', 'audio-manager', 'tts-factory', 'ui-input-handler']; + this.dependencies = ['ui-controller', 'socket-client', 'text-buffer', 'sentence-queue', 'playback-coordinator', 'animation-queue', 'audio-manager', 'tts-factory', 'ui-input-handler', 'story-history']; // Game state this.gameState = { @@ -30,6 +30,7 @@ class GameLoopModule extends BaseModule { 'updateGameState', 'updateUIState', 'refreshGameApiState', + 'hasSaveGame', 'requestStartGame', 'requestSaveGame', 'requestLoadGame', @@ -136,7 +137,7 @@ class GameLoopModule extends BaseModule { const [running, hasSave] = await Promise.all([ socketClient.isGameRunning(), - socketClient.hasSaveGame(1) + this.hasSaveGame(1) ]); this.gameState.started = Boolean(running?.result); @@ -191,6 +192,10 @@ class GameLoopModule extends BaseModule { if (!socketClient) return; await this.resetClientPlaybackAndDisplay(); + const storyHistory = this.getModule('story-history'); + if (storyHistory && typeof storyHistory.startNewGame === 'function') { + await storyHistory.startNewGame(); + } const response = await socketClient.newGame(); if (!response?.success) { console.error('GameLoop: newGame failed', response); @@ -211,6 +216,12 @@ class GameLoopModule extends BaseModule { const response = await socketClient.saveGame(1); if (response?.success) { + const storyHistory = this.getModule('story-history'); + if (storyHistory && typeof storyHistory.saveSlot === 'function') { + await storyHistory.saveSlot(1, { + inkState: response.savedState || null + }); + } this.gameState.canLoad = true; this.updateUIState(); } @@ -223,7 +234,11 @@ class GameLoopModule extends BaseModule { const socketClient = this.getModule('socket-client'); if (!socketClient) return; - const hasSave = await socketClient.hasSaveGame(1); + const storyHistory = this.getModule('story-history'); + const browserSave = storyHistory && typeof storyHistory.loadSlot === 'function' + ? await storyHistory.loadSlot(1) + : null; + const hasSave = browserSave ? { result: true } : await socketClient.hasSaveGame(1); if (!hasSave?.result) { this.gameState.canLoad = false; this.updateUIState(); @@ -231,7 +246,14 @@ class GameLoopModule extends BaseModule { } await this.resetClientPlaybackAndDisplay(); - const response = await socketClient.loadGame(1); + if (browserSave?.gameId && storyHistory?.setCurrentGame) { + storyHistory.setCurrentGame(browserSave.gameId, browserSave.latestBlockId || 0); + } + const uiController = this.getModule('ui-controller'); + if (browserSave && uiController?.displayHandler?.restoreFromHistory) { + await uiController.displayHandler.restoreFromHistory(browserSave); + } + const response = await socketClient.loadGame(1, browserSave?.inkState || null); if (response?.success) { this.gameState.started = true; this.gameState.canSave = true; @@ -240,6 +262,16 @@ class GameLoopModule extends BaseModule { } } + async hasSaveGame(slot = 1) { + const storyHistory = this.getModule('story-history'); + if (storyHistory && typeof storyHistory.hasSaveSlot === 'function') { + const hasBrowserSave = await storyHistory.hasSaveSlot(slot); + if (hasBrowserSave) return { success: true, result: true, slot }; + } + const socketClient = this.getModule('socket-client'); + return socketClient?.hasSaveGame ? socketClient.hasSaveGame(slot) : { success: false, result: false }; + } + async resetClientPlaybackAndDisplay() { const playbackCoordinator = this.getModule('playback-coordinator'); if (playbackCoordinator && typeof playbackCoordinator.stop === 'function') { diff --git a/public/js/loader.js b/public/js/loader.js index d4a9218..0c5da4d 100644 --- a/public/js/loader.js +++ b/public/js/loader.js @@ -103,6 +103,7 @@ const ModuleLoader = (function() { // Core functionality modules { id: 'persistence-manager', script: '/js/persistence-manager-module.js', weight: 12 }, { id: 'localization', script: '/js/localization-module.js', weight: 12 }, + { id: 'story-history', script: '/js/story-history-module.js', weight: 8 }, { id: 'game-config', script: '/js/game-config-module.js', weight: 8 }, { id: 'text-processor', script: '/js/text-processor-module.js', weight: 15 }, { id: 'markup-parser', script: '/js/markup-parser-module.js', weight: 5 }, diff --git a/public/js/sentence-queue-module.js b/public/js/sentence-queue-module.js index 06539f0..2afc628 100644 --- a/public/js/sentence-queue-module.js +++ b/public/js/sentence-queue-module.js @@ -21,6 +21,8 @@ class SentenceQueueModule extends BaseModule { this.prefetchingCache = new Map(); this.activeImageWrap = null; this.autoplay = true; + this.inputMode = 'text'; + this.lastContinueAt = 0; // Bind methods this.bindMethods([ @@ -79,6 +81,14 @@ class SentenceQueueModule extends BaseModule { this.autoplay = value !== false; } }); + this.addEventListener(document, 'story:input-mode', (event) => { + this.inputMode = ['text', 'choice', 'end'].includes(event.detail) ? event.detail : 'text'; + }); + this.addEventListener(document, 'ui:command', (event) => { + if (event.detail?.type === 'continue') { + this.lastContinueAt = performance.now(); + } + }); return true; } catch (error) { console.error("Error initializing Sentence Queue:", error); @@ -139,6 +149,7 @@ class SentenceQueueModule extends BaseModule { if (this.onSentenceReadyCallback) { await new Promise(resolve => { sentence.onComplete = resolve; + sentence.playbackStartedAt = performance.now(); this.onSentenceReadyCallback(sentence, resolve); }); } @@ -148,7 +159,7 @@ class SentenceQueueModule extends BaseModule { await this.waitForSkippableMediaPause(mediaPauseSeconds, sentence.kind, sentence.id); } - if (sentence.kind === 'paragraph' && !this.shouldAutoplay()) { + if (this.shouldPauseAfterSentence(sentence)) { await this.waitForManualContinue(sentence.id); } @@ -495,6 +506,19 @@ class SentenceQueueModule extends BaseModule { } } + shouldPauseAfterSentence(sentence) { + if (sentence.kind !== 'paragraph' || this.shouldAutoplay()) { + return false; + } + if (this.lastContinueAt >= (sentence.playbackStartedAt || 0)) { + return false; + } + if (this.sentenceQueue.length <= 1 && this.inputMode === 'choice') { + return false; + } + return this.sentenceQueue.length > 1; + } + shouldAutoplay() { const persistenceManager = this.getModule('persistence-manager'); if (persistenceManager && typeof persistenceManager.getPreference === 'function') { diff --git a/public/js/socket-client-module.js b/public/js/socket-client-module.js index f0d914b..5de72c7 100644 --- a/public/js/socket-client-module.js +++ b/public/js/socket-client-module.js @@ -131,7 +131,7 @@ class SocketClientModule extends BaseModule { // Create Socket.IO connection (will automatically use /socket.io endpoint) this.socket = window.io(socketUrl, { reconnection: false, // We handle reconnection ourselves - transports: ['websocket', 'polling'] // Prefer WebSocket + transports: ['polling', 'websocket'] }); this.socket.on('connect', () => { @@ -573,8 +573,8 @@ class SocketClientModule extends BaseModule { return this.callGameApi('newGame', []); } - loadGame(slot = 1) { - return this.callGameApi('loadGame', [slot]); + loadGame(slot = 1, savedState = null) { + return this.callGameApi('loadGame', savedState ? [slot, savedState] : [slot]); } saveGame(slot = 1) { diff --git a/public/js/story-history-module.js b/public/js/story-history-module.js new file mode 100644 index 0000000..70ae4f6 --- /dev/null +++ b/public/js/story-history-module.js @@ -0,0 +1,189 @@ +/** + * Story History Module + * Stores rendered story blocks in IndexedDB and keeps only a short live window + * in the page DOM. + */ +import { BaseModule } from './base-module.js'; + +class StoryHistoryModule extends BaseModule { + constructor() { + super('story-history', 'Story History'); + + this.dependencies = ['persistence-manager']; + this.dbName = 'ttsAudioCacheDB'; + this.dbVersion = 2; + this.historyStore = 'storyHistoryStore'; + this.saveStore = 'storySaveStore'; + this.db = null; + this.currentGameId = null; + this.nextBlockId = 1; + this.visibleLimit = 20; + + this.bindMethods([ + 'initialize', + 'openDB', + 'startNewGame', + 'setCurrentGame', + 'recordBlock', + 'saveSlot', + 'loadSlot', + 'hasSaveSlot', + 'getSaveSlots', + 'getBlocks', + 'clearGame', + 'tx' + ]); + } + + async initialize() { + await this.openDB(); + this.reportProgress(100, 'Story history ready'); + return true; + } + + openDB() { + if (this.db) return Promise.resolve(this.db); + return new Promise((resolve, reject) => { + const request = indexedDB.open(this.dbName, this.dbVersion); + request.onerror = () => reject(request.error); + request.onsuccess = () => { + this.db = request.result; + resolve(this.db); + }; + request.onupgradeneeded = () => { + const db = request.result; + if (!db.objectStoreNames.contains(this.historyStore)) { + const historyStore = db.createObjectStore(this.historyStore, { keyPath: 'key' }); + historyStore.createIndex('gameId', 'gameId', { unique: false }); + historyStore.createIndex('gameOrder', ['gameId', 'blockId'], { unique: true }); + } + if (!db.objectStoreNames.contains(this.saveStore)) { + db.createObjectStore(this.saveStore, { keyPath: 'slot' }); + } + }; + }); + } + + tx(storeName, mode = 'readonly') { + return this.db.transaction(storeName, mode).objectStore(storeName); + } + + async startNewGame() { + const gameId = `game-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`; + this.currentGameId = gameId; + this.nextBlockId = 1; + const persistenceManager = this.getModule('persistence-manager'); + persistenceManager?.updatePreference?.('app', 'currentGameId', gameId); + return gameId; + } + + setCurrentGame(gameId, latestBlockId = 0) { + this.currentGameId = gameId || this.currentGameId; + this.nextBlockId = Math.max(1, Number(latestBlockId || 0) + 1); + } + + recordBlock(block) { + if (!this.db || !this.currentGameId || !block) return Promise.resolve(null); + const blockId = this.nextBlockId++; + const record = { + ...block, + key: `${this.currentGameId}:${blockId}`, + gameId: this.currentGameId, + blockId, + createdAt: Date.now() + }; + return new Promise((resolve, reject) => { + const request = this.tx(this.historyStore, 'readwrite').put(record); + request.onsuccess = () => resolve(record); + request.onerror = () => reject(request.error); + }); + } + + saveSlot(slot = 1, saveData = {}) { + if (!this.db) return Promise.resolve(false); + const record = { + slot, + ...saveData, + gameId: saveData.gameId || this.currentGameId, + latestBlockId: Math.max(0, this.nextBlockId - 1), + savedAt: Date.now() + }; + return new Promise((resolve, reject) => { + const request = this.tx(this.saveStore, 'readwrite').put(record); + request.onsuccess = () => resolve(record); + request.onerror = () => reject(request.error); + }); + } + + loadSlot(slot = 1) { + if (!this.db) return Promise.resolve(null); + return new Promise((resolve, reject) => { + const request = this.tx(this.saveStore).get(slot); + request.onsuccess = () => resolve(request.result || null); + request.onerror = () => reject(request.error); + }); + } + + async hasSaveSlot(slot = 1) { + return Boolean(await this.loadSlot(slot)); + } + + getSaveSlots() { + if (!this.db) return Promise.resolve([]); + return new Promise((resolve, reject) => { + const request = this.tx(this.saveStore).getAllKeys(); + request.onsuccess = () => resolve(request.result || []); + request.onerror = () => reject(request.error); + }); + } + + getBlocks(gameId = this.currentGameId, limit = this.visibleLimit, beforeBlockId = Infinity) { + if (!this.db || !gameId) return Promise.resolve([]); + return new Promise((resolve, reject) => { + const blocks = []; + const index = this.tx(this.historyStore).index('gameOrder'); + const upper = Number.isFinite(beforeBlockId) ? beforeBlockId : Number.MAX_SAFE_INTEGER; + const range = IDBKeyRange.bound([gameId, 0], [gameId, upper], false, true); + const request = index.openCursor(range, 'prev'); + request.onsuccess = () => { + const cursor = request.result; + if (!cursor || blocks.length >= limit) { + resolve(blocks.reverse()); + return; + } + blocks.push(cursor.value); + cursor.continue(); + }; + request.onerror = () => reject(request.error); + }); + } + + clearGame(gameId = this.currentGameId) { + if (!this.db || !gameId) return Promise.resolve(); + return new Promise((resolve, reject) => { + const store = this.tx(this.historyStore, 'readwrite'); + const index = store.index('gameId'); + const request = index.openCursor(IDBKeyRange.only(gameId)); + request.onsuccess = () => { + const cursor = request.result; + if (!cursor) { + resolve(); + return; + } + cursor.delete(); + cursor.continue(); + }; + request.onerror = () => reject(request.error); + }); + } +} + +const storyHistory = new StoryHistoryModule(); + +export { storyHistory as StoryHistory }; + +if (window.moduleRegistry) { + window.moduleRegistry.register(storyHistory); +} + +window.StoryHistory = storyHistory; diff --git a/public/js/tts-factory-module.js b/public/js/tts-factory-module.js index f34d216..f01ac13 100644 --- a/public/js/tts-factory-module.js +++ b/public/js/tts-factory-module.js @@ -32,7 +32,7 @@ class TTSFactoryModule extends BaseModule { this.db = null; // Will hold the DB connection this.dbName = 'ttsAudioCacheDB'; this.storeName = 'audioCacheStore'; - this.dbVersion = 1; + this.dbVersion = 2; this.currentCacheSize = 0; // Track current size in bytes this.maxCacheSizeBytes = 100 * 1024 * 1024; // 100 MB by default this.cacheInitialized = false; @@ -1537,6 +1537,16 @@ class TTSFactoryModule extends BaseModule { console.log("Created 'size' index."); } } + if (!db.objectStoreNames.contains('storyHistoryStore')) { + const historyStore = db.createObjectStore('storyHistoryStore', { keyPath: 'key' }); + historyStore.createIndex('gameId', 'gameId', { unique: false }); + historyStore.createIndex('gameOrder', ['gameId', 'blockId'], { unique: true }); + console.log("Object store 'storyHistoryStore' created."); + } + if (!db.objectStoreNames.contains('storySaveStore')) { + db.createObjectStore('storySaveStore', { keyPath: 'slot' }); + console.log("Object store 'storySaveStore' created."); + } }; }); } diff --git a/public/js/ui-display-handler-module.js b/public/js/ui-display-handler-module.js index a6a1a7f..fe957ae 100644 --- a/public/js/ui-display-handler-module.js +++ b/public/js/ui-display-handler-module.js @@ -9,7 +9,7 @@ class UIDisplayHandlerModule extends BaseModule { super('ui-display-handler', 'UI Display Handler'); // Module dependencies - this.dependencies = ['layout-renderer', 'playback-coordinator', 'game-config', 'localization']; + this.dependencies = ['layout-renderer', 'playback-coordinator', 'game-config', 'localization', 'story-history', 'sentence-queue']; // DOM elements this.container = null; @@ -20,6 +20,7 @@ class UIDisplayHandlerModule extends BaseModule { this.resizeTimer = null; this.storyResizeObserver = null; this.lastStoryMetrics = null; + this.visibleBlockLimit = 20; // Resources to preload this.cssPath = '/css/style.css'; @@ -35,6 +36,12 @@ class UIDisplayHandlerModule extends BaseModule { 'applyTranslations', 'displayText', 'renderSentence', + 'recordRenderedItem', + 'trimVisibleBlocks', + 'restoreFromHistory', + 'renderStoredItem', + 'loadPreviousHistoryPage', + 'updateStoryScrollbar', 'handleDeferredMediaBlock', 'renderImageBlock', 'calculateImageMetrics', @@ -76,6 +83,7 @@ class UIDisplayHandlerModule extends BaseModule { this.playbackCoordinator = this.getModule('playback-coordinator'); this.gameConfig = this.getModule('game-config'); this.localization = this.getModule('localization'); + this.storyHistory = this.getModule('story-history'); this.reportProgress(50, "Initializing display containers"); @@ -97,6 +105,14 @@ class UIDisplayHandlerModule extends BaseModule { this.addEventListener(document, 'story:scroll-to-turn', (event) => { this.scrollToTurn(event.detail?.turnId); }); + this.addEventListener(document, 'story:history-updated', (event) => { + this.updateStoryScrollbar(event.detail || {}); + }); + this.addEventListener(document, 'wheel', (event) => { + if (event.target?.closest?.('#page_right') && event.deltaY < 0 && this.pageRight?.scrollTop <= 2) { + this.loadPreviousHistoryPage(); + } + }, { passive: true }); this.addEventListener(document, 'story:process-state', (event) => { const state = event.detail?.state || 'ready'; const remark = document.getElementById('remark_text'); @@ -294,6 +310,12 @@ class UIDisplayHandlerModule extends BaseModule { this.pageRight.id = 'page_right'; bookContainer.appendChild(this.pageRight); } + if (!document.getElementById('story_scrollbar')) { + const storyScrollbar = document.createElement('div'); + storyScrollbar.id = 'story_scrollbar'; + storyScrollbar.innerHTML = '
'; + this.pageRight.appendChild(storyScrollbar); + } // Create or find story container this.container = document.getElementById('story'); @@ -478,7 +500,7 @@ class UIDisplayHandlerModule extends BaseModule { // Store element reference in sentence sentence.element = paragraphElement; - this.renderedItems.push({ + await this.recordRenderedItem({ type: sentence.kind === 'heading' ? 'heading' : 'paragraph', id: sentence.id, turnId: sentence.turnId ?? null, @@ -493,6 +515,7 @@ class UIDisplayHandlerModule extends BaseModule { paragraphIndex: sentence.paragraphIndex } }); + await this.trimVisibleBlocks(); this.scrollStoryToEnd(true); @@ -591,6 +614,137 @@ class UIDisplayHandlerModule extends BaseModule { }); } + async restoreFromHistory(saveRecord = {}) { + if (!this.paragraphContainer || !this.storyHistory || !saveRecord?.gameId) return; + const sentenceQueue = this.getModule('sentence-queue'); + if (!sentenceQueue || typeof sentenceQueue.prepareLayout !== 'function') return; + + const blocks = await this.storyHistory.getBlocks( + saveRecord.gameId, + this.visibleBlockLimit, + (saveRecord.latestBlockId || Number.MAX_SAFE_INTEGER) + 1 + ); + this.paragraphContainer.innerHTML = ''; + this.renderedItems = []; + + for (const item of blocks) { + await this.renderStoredItem(item); + } + + this.updateStoryScrollbar({ latestBlockId: saveRecord.latestBlockId || blocks.at(-1)?.blockId || 1 }); + this.scrollStoryToEnd(false); + } + + async renderStoredItem(item) { + const sentenceQueue = this.getModule('sentence-queue'); + if (!sentenceQueue) return null; + this.renderedItems.push(item); + + if (item.type === 'image') { + const imageLayout = typeof sentenceQueue.prepareImageLayout === 'function' + ? await sentenceQueue.prepareImageLayout(item.metadata || {}) + : null; + const imageElement = this.renderImageBlock({ + ...(item.metadata || {}), + imageLayout: imageLayout || item.metadata?.imageLayout + }, false); + if (imageElement && item.blockId != null) imageElement.dataset.storyBlockId = String(item.blockId); + return imageElement; + } + + if (item.type !== 'heading' && item.type !== 'paragraph') return null; + const layout = await sentenceQueue.prepareLayout(item.text, item.metadata || {}); + const element = this.layoutRenderer.renderParagraph(layout, { id: item.id }); + if (item.turnId != null) { + element.dataset.turnId = String(item.turnId); + element.classList.add('story-turn-block'); + } + if (item.blockId != null) element.dataset.storyBlockId = String(item.blockId); + element.querySelectorAll('.word').forEach(word => { + word.style.transition = 'none'; + word.style.animation = 'none'; + word.style.visibility = 'visible'; + word.style.opacity = '1'; + word.style.transform = 'translateY(0)'; + word.style.clipPath = 'inset(0 0 0 0)'; + }); + this.paragraphContainer.appendChild(element); + return element; + } + + async loadPreviousHistoryPage() { + if (!this.storyHistory || !this.paragraphContainer || this.loadingHistoryPage) return; + const firstBlock = this.paragraphContainer.querySelector('[data-story-block-id]'); + const beforeBlockId = Number(firstBlock?.dataset?.storyBlockId || 0); + if (!beforeBlockId || beforeBlockId <= 1) return; + + this.loadingHistoryPage = true; + try { + const blocks = await this.storyHistory.getBlocks( + this.storyHistory.currentGameId, + this.visibleBlockLimit, + beforeBlockId + ); + if (!blocks.length) return; + this.paragraphContainer.innerHTML = ''; + this.renderedItems = []; + for (const item of blocks) { + await this.renderStoredItem(item); + } + this.pageRight.scrollTop = 0; + this.updateStoryScrollbar({ latestBlockId: this.storyHistory.nextBlockId - 1 }); + } finally { + this.loadingHistoryPage = false; + } + } + + async recordRenderedItem(item) { + this.renderedItems.push(item); + if (this.storyHistory && typeof this.storyHistory.recordBlock === 'function') { + try { + const record = await this.storyHistory.recordBlock(item); + if (record && item.id) { + item.blockId = record.blockId; + item.gameId = record.gameId; + const element = document.getElementById(item.id); + if (element) element.dataset.storyBlockId = String(record.blockId); + } + document.dispatchEvent(new CustomEvent('story:history-updated', { + detail: { + gameId: record?.gameId || null, + latestBlockId: record?.blockId || null + } + })); + } catch (error) { + console.warn('UIDisplayHandler: Failed to store story history item:', error); + } + } + } + + updateStoryScrollbar(detail = {}) { + const thumb = document.getElementById('story_scrollbar_thumb'); + if (!thumb) return; + const latest = Math.max(1, Number(detail.latestBlockId || this.storyHistory?.nextBlockId || 1)); + const visible = Math.min(this.visibleBlockLimit, latest); + const heightPercent = Math.max(8, Math.min(100, (visible / latest) * 100)); + const topPercent = latest <= visible ? 0 : 100 - heightPercent; + thumb.style.height = `${heightPercent}%`; + thumb.style.top = `${topPercent}%`; + } + + async trimVisibleBlocks() { + if (!this.paragraphContainer) return; + const blocks = Array.from(this.paragraphContainer.querySelectorAll('.story-turn-block')); + const excess = blocks.length - this.visibleBlockLimit; + if (excess <= 0) return; + + blocks.slice(0, excess).forEach(block => { + block.classList.add('story-block-archiving'); + window.setTimeout(() => block.remove(), 360); + }); + this.renderedItems = this.renderedItems.slice(Math.max(0, this.renderedItems.length - this.visibleBlockLimit)); + } + animatePageScroll(targetTop, duration = 720) { if (!this.pageRight) return; if (!duration) { @@ -662,14 +816,15 @@ class UIDisplayHandlerModule extends BaseModule { })); if (sentence.kind === 'image') { - const element = this.renderImageBlock(sentence.metadata || {}, true); - this.renderedItems.push({ + const element = this.renderImageBlock({ ...(sentence.metadata || {}), id: sentence.id }, true); + await this.recordRenderedItem({ type: 'image', id: sentence.id, turnId: sentence.turnId ?? null, text: '', - metadata: sentence.metadata || {} + metadata: { ...(sentence.metadata || {}), id: sentence.id } }); + await this.trimVisibleBlocks(); this.scrollStoryToEnd(true); @@ -743,6 +898,9 @@ class UIDisplayHandlerModule extends BaseModule { const metrics = metadata.imageLayout || this.calculateImageMetrics(metadata.size); const figure = document.createElement('figure'); + if (metadata.id) { + figure.id = metadata.id; + } figure.className = [ 'story-image-block', `story-image-${metrics.size || 'landscape'}`, diff --git a/src/engine/ink-engine.ts b/src/engine/ink-engine.ts index 8e4dd0b..50a9dec 100644 --- a/src/engine/ink-engine.ts +++ b/src/engine/ink-engine.ts @@ -109,12 +109,27 @@ export class InkEngine { if (!this.story) { throw new Error('No active Ink story to save'); } - return this.story.state.toJson(); + return JSON.stringify({ + inkState: this.story.state.toJson(), + nextTurnId: this.nextTurnId, + }); } loadGame(savedState: string): TurnResult { this.story = this.loadStory(); - this.story.state.LoadJson(savedState); + let inkState = savedState; + try { + const parsed = JSON.parse(savedState); + if (parsed && typeof parsed.inkState === 'string') { + inkState = parsed.inkState; + if (Number.isInteger(parsed.nextTurnId)) { + this.nextTurnId = Math.max(1, parsed.nextTurnId); + } + } + } catch { + // Backward compatibility with raw Ink state JSON. + } + this.story.state.LoadJson(inkState); return this.continueStory(); } diff --git a/src/server-ink.ts b/src/server-ink.ts index 4d4ec59..6283603 100644 --- a/src/server-ink.ts +++ b/src/server-ink.ts @@ -130,11 +130,12 @@ async function handleGameApi( case 'loadGame': case 'loadGame()': { const slot = normalizeSaveSlot(args[0]); - if (!slots.has(slot)) { + const browserSave = typeof args[1] === 'string' ? args[1] : null; + if (!browserSave && !slots.has(slot)) { return { success: false, error: 'missing_save', result: false }; } const engine = getOrCreateEngine(socket.id); - socket.emit('narrativeResponse', engine.loadGame(slots.get(slot)!)); + socket.emit('narrativeResponse', engine.loadGame(browserSave || slots.get(slot)!)); socket.emit('gameLoaded', { slot }); return { success: true, result: true, running: true, slot }; } @@ -146,9 +147,10 @@ async function handleGameApi( return { success: false, error: 'game_not_running', result: false }; } const slot = normalizeSaveSlot(args[0]); - slots.set(slot, engine.saveGame()); + const savedState = engine.saveGame(); + slots.set(slot, savedState); socket.emit('gameSaved', { slot }); - return { success: true, result: true, slot }; + return { success: true, result: true, slot, savedState }; } case 'hasSaveGame':