Your browser lacks required capabilities. Please upgrade it or switch to another to continue.
Loading…
{
"name": "New In Town",
"ifid": "06277e68-7ff7-497d-b112-62f04fb86021",
"format": "SugarCube",
"format-version": "2.36.1",
"start": "Start"
}<<set $player = {
"name": "Emma",
"portrait": "emma.jpg",
"current_location": "",
"core_traits": {"corruption": 0, "confidence": 0, "money": 500, "intelligence": 5},
"flags": {"game_started": false, "first_night_complete": false, "met_mick": false, "campus_started": false, "job_hunt_done": false, "asked_jolene": false, "first_shift_done": false, "bar_lesson_learned": false, "had_restless_night": false, "discovered_porn": false, "seen_mick_shower": false, "learned_seduction": false, "discovered_teasing": false, "caught_mick": false, "touched_mick": false, "gave_blowjob": false, "mick_sex": false, "sex_unlock": false, "mall_unlocked": false, "bar_handjob_done": false, "noticed_hole": false, "learned_glory_hole": false, "watched_glory_hole": false, "glory_hole_handjob": false, "glory_hole_blowjob": false, "public_flashed": false, "public_dirty_talk": false, "public_handjob": false, "public_blowjob": false, "public_sex": false, "bar_groped": false, "met_harlan": false, "test_failed": false, "grade_c": false, "grade_b": false, "grade_a": false, "harlan_warning": false, "harlan_offered_study": false, "harlan_shift": false, "harlan_kissed": false, "harlan_handjob": false, "harlan_blowjob": false, "harlan_sex": false},
"wardrobe": {"basic_bra": {"id": "basic_bra", "name": "Basic Bra", "slot": "bra", "image": "./videos/images/clothing/basic_bra.jpg"}, "cotton_panties": {"id": "cotton_panties", "name": "Cotton Panties", "slot": "underwear", "image": "./videos/images/clothing/cotton_panties.jpg"}, "hoodie": {"id": "hoodie", "name": "Hoodie", "slot": "top", "image": "./videos/images/clothing/hoodie.jpg"}, "jeans": {"id": "jeans", "name": "Jeans", "slot": "bottom", "image": "./videos/images/clothing/jeans.jpg"}, "sneakers": {"id": "sneakers", "name": "Sneakers", "slot": "shoes", "image": "./videos/images/clothing/sneakers.jpg"}},
"equipped": {"bra": "basic_bra", "underwear": "cotton_panties", "top": "hoodie", "bottom": "jeans", "dress": null, "legwear": null, "shoes": "sneakers"}
}>><<set $npcs = {"d4b60146-51b2-4974-8432-47dc01825c68": {"name": "Jolene", "portrait": "jolene.jpg", "core_traits": {"mentorship": 0}, "flags": {}, "schedule": []}, "8f0d5b36-a169-4a5a-9908-29df8b36c0a4": {"name": "Mick", "portrait": "mick.jpg", "core_traits": {"love": 0, "trust": 10, "corruption": 0}, "flags": {}, "schedule": []}, "4e08ae6d-9bb4-494b-b20f-f1d2e7d217e0": {"name": "Professor Harlan", "portrait": "professor_harlan.jpg", "core_traits": {"love": 0, "trust": 0, "corruption": 0}, "flags": {}, "schedule": []}}>><<set $flags = {
"game_started": true,
"debug_mode": false
}>><<set $flags_meta = {}>><<set $game_state = {
"current_canvas": "",
"visited_locations": [],
"visited_nodes": [],
"trigger_history": {},
"activity_trigger_history": {},
"visited_choices": {},
"time_state": {
"current_hour": 14,
"current_minute": 0,
"current_day": "Monday",
"current_week": 1,
"day": 1
},
"rent_state": {
"last_paid_week": 1,
"warnings": 0,
"is_due": false
}
}>><<nobr>>
<div class="game-intro">
<h1>New In Town</h1>
<p class="game-description">Emma, a 21-year-old from a sheltered background, arrives in a rough city for college. She rents a room above a bar owned by Jolene and her husband Mick. She has $500 to her name. Rent is $150 a week. She quickly learns that to get what you want here, you have to find methods.
</p>
<div class="developer-intro">
<p class="developer-about">We're a small indie studio crafting intimate, story-driven experiences. Every game is made with care, and your support helps us keep creating. If you enjoy our work, consider supporting us!</p>
<p class="support-link">👉 <a href="https://www.patreon.com/cw/nutgames844" target="_blank" rel="noopener">Support us on Patreon</a></p>
</div>
<div class="age-gate">
<p class="age-warning">⚠️ This game contains adult content intended for players 18 years of age or older.</p>
<div class="age-buttons">
[[✓ I am 18 or older - Enter Game->StartingCanvas_opening_arrival_Node_1]]
[[✗ I am NOT 18 or older->AgeBlocked]]
</div>
</div>
<div class="developer-footer">
<p class="developer-credit">Developed by <strong>NutGames</strong></p>
<p class="support-link">👉 <a href="https://www.patreon.com/cw/nutgames844" target="_blank" rel="noopener">Support us on Patreon</a></p>
</div>
</div>
<</nobr>><div class="blocked-page">
<h2>Access Denied</h2>
<p>This content is not available for you.</p>
<p>Please close this page.</p>
</div><!-- Time Display Widgets -->
<<widget "timeFormatted">>
<<set _hour to $game_state.time_state.current_hour>>
<<set _minute to $game_state.time_state.current_minute>>
<<set _displayHour to (_hour is 0 ? 12 : (_hour > 12 ? _hour - 12 : _hour))>>
<<set _ampm to (_hour < 12 ? "AM" : "PM")>>
<<set _minuteStr to (_minute < 10 ? "0" + _minute : _minute)>>
<<print _displayHour + ":" + _minuteStr + " " + _ampm>>
<</widget>>
<<widget "timeDisplay">>
<div id="time-widget" class="time-display">
<div class="time-line">
<span id="time-display"><<timeFormatted>></span> | <span id="current-day"><<print $game_state.time_state.current_day>></span>
</div>
<div class="control-line">
<button class="time-btn" onclick="advanceTime(10)" title="Advance 10 minutes">></button> | <button class="time-btn" onclick="advanceTime(60)" title="Advance 1 hour">>></button> | <button class="time-btn" onclick="advanceTime(1440)" title="Advance 1 day">>>>>></button>
</div>
</div>
<</widget>>
<<widget "playerTraits">>
<div id="traits-widget" class="traits-display">
<div class="traits-header">Traits</div>
<<if $player and $player.core_traits and Object.keys($player.core_traits).length > 0>>
<<set _keys to Object.keys($player.core_traits).sort()>>
<ul class="traits-list">
<<for _i to 0; _i lt _keys.length; _i++>>
<<set _k to _keys[_i]>>
<li class="trait-item">
<span class="trait-name"><<print _k>></span>
<span class="trait-value"><<print $player.core_traits[_k]>></span>
</li>
<</for>>
</ul>
<<else>>
<div class="no-traits">No traits</div>
<</if>>
<div class="traits-hint">Updates after each choice.</div>
</div>
<</widget>>
<<widget "playerFlags">>
<div id="flags-widget" class="traits-display">
<div class="traits-header">Flags</div>
<<if $player and $player.flags and Object.keys($player.flags).length > 0>>
<<set _fkeys to Object.keys($player.flags).sort()>>
<ul class="traits-list">
<<for _j to 0; _j lt _fkeys.length; _j++>>
<<set _fk to _fkeys[_j]>>
<li class="trait-item">
<span class="trait-name"><<print _fk>></span>
<span class="trait-value"><<print $player.flags[_fk] ? '✔' : '✖'>></span>
</li>
<</for>>
</ul>
<<else>>
<div class="no-traits">No flags</div>
<</if>>
<div class="traits-hint">Set by choices and story logic.</div>
</div>
<</widget>>
<<widget "questsButton">>
<!-- Debug/legacy quest view - shows raw mechanics -->
<div id="quests-btn-widget">
<<if passage() isnot "QuestsPage">><<link "📋 Quests" "QuestsPage">><</link>><<else>>📋 Quests<</if>>
</div>
<</widget>>
<<widget "missingMediaButton">>
<<if $flags.debug_mode>>
<div id="missing-media-btn-widget" style="margin-bottom:8px;">
<<if passage() isnot "MissingMediaPage">><<link "⚠️ Missing Media" "MissingMediaPage">><</link>><<else>>⚠️ Missing Media<</if>>
</div>
<</if>>
<</widget>>
<<widget "journalButton">>
<!-- Guide - simplified what's next help -->
<div id="journal-btn-widget">
<<if passage() isnot "QuestsPage">><<link "📖 Guide" "QuestsPage">><</link>><<else>>📖 Guide<</if>>
</div>
<</widget>>
<<widget "statsButton">>
<div id="stats-btn-widget">
<<if passage() isnot "StatsPage">><<link "📊 Stats" "StatsPage">><</link>><<else>>📊 Stats<</if>>
</div>
<</widget>>
<<widget "scheduleButton">>
<<set _npcsWithSchedules to setup.getNpcsWithSchedules()>>
<<set _soloActivities to setup.getSoloActivitiesForToday()>>
<<if _npcsWithSchedules.length > 0 || _soloActivities.length > 0>>
<div id="schedule-btn-widget">
<<if passage() isnot "SchedulePage">><<link "📅 Schedules" "SchedulePage">><</link>><<else>>📅 Schedules<</if>>
</div>
<</if>>
<</widget>>
<<widget "patreonButton">>
<div id="patreon-btn-widget">
<a href="https://www.patreon.com/cw/nutgames844" target="_blank" rel="noopener" class="patreon-link">
<svg class="patreon-icon" viewBox="0 0 24 24" width="16" height="16">
<path fill="currentColor" d="M15.386.524c-4.764 0-8.64 3.876-8.64 8.64 0 4.75 3.876 8.613 8.64 8.613 4.75 0 8.614-3.864 8.614-8.613C24 4.4 20.136.524 15.386.524M.003 23.537h4.22V.524H.003"/>
</svg>
Support Us
</a>
</div>
<</widget>>
<<widget "flagsButton">>
<div id="flags-btn-widget">
<<if passage() isnot "FlagsPage">><<link "🚩 Flags" "FlagsPage">><</link>><<else>>🚩 Flags<</if>>
</div>
<</widget>><<missingMediaButton>>
<<timeDisplay>>
<<journalButton>>
<<statsButton>>
<<scheduleButton>>
<<flagsButton>>
<<playerTraits>>
<<patreonButton>>
<style>
#time-widget {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 8px;
margin-bottom: 10px;
font-family: 'Courier New', monospace;
font-size: 14px;
line-height: 1.2;
color: #212529;
}
.time-line {
text-align: center;
margin-bottom: 4px;
font-weight: bold;
color: #000000;
}
.control-line {
text-align: center;
font-size: 12px;
}
.time-btn {
background: #e9ecef;
border: 1px solid #ced4da;
border-radius: 3px;
color: #495057;
cursor: pointer;
padding: 3px 6px;
font-size: 12px;
font-family: 'Courier New', monospace;
font-weight: bold;
}
.time-btn:hover {
background: #dee2e6;
color: #000000;
border-color: #adb5bd;
}
#traits-widget {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 8px;
margin-top: 8px;
font-family: 'Courier New', monospace;
font-size: 13px;
color: #212529;
}
#flags-widget {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 8px;
margin-top: 8px;
font-family: 'Courier New', monospace;
font-size: 13px;
color: #212529;
}
.traits-header {
font-weight: bold;
margin-bottom: 6px;
}
.traits-list {
list-style: none;
padding-left: 0;
margin: 0;
}
.trait-item {
display: flex;
justify-content: space-between;
border-bottom: 1px dashed #e2e3e5;
padding: 2px 0;
}
.trait-name {
color: #495057;
}
.trait-value {
color: #0d6efd;
font-weight: bold;
}
.no-traits {
font-style: italic;
color: #6c757d;
}
.traits-hint {
margin-top: 6px;
font-size: 11px;
color: #6c757d;
}
#time-display, #current-day {
font-family: 'Courier New', monospace;
color: #000000;
}
#quests-btn-widget {
background: #e7f3ff;
border: 1px solid #007bff;
border-radius: 4px;
padding: 6px 8px;
margin-bottom: 8px;
text-align: center;
}
#quests-btn-widget a {
color: #007bff;
text-decoration: none;
font-weight: bold;
}
#quests-btn-widget a:hover {
color: #0056b3;
text-decoration: underline;
}
#journal-btn-widget {
background: linear-gradient(180deg, #fdf6e3 0%, #f5e6d3 100%);
border: 1px solid #c9b896;
border-radius: 4px;
padding: 6px 8px;
margin-bottom: 8px;
text-align: center;
}
#journal-btn-widget a {
color: #6d5a40;
text-decoration: none;
font-weight: bold;
font-family: 'Georgia', serif;
}
#journal-btn-widget a:hover {
color: #4a3f30;
text-decoration: underline;
}
#stats-btn-widget {
background: #f0f7e6;
border: 1px solid #28a745;
border-radius: 4px;
padding: 6px 8px;
margin-bottom: 8px;
text-align: center;
}
#stats-btn-widget a {
color: #28a745;
text-decoration: none;
font-weight: bold;
}
#stats-btn-widget a:hover {
color: #1e7e34;
text-decoration: underline;
}
#schedule-btn-widget {
background: #e8f4fc;
border: 1px solid #3b82f6;
border-radius: 4px;
padding: 6px 8px;
margin-bottom: 8px;
text-align: center;
}
#schedule-btn-widget a {
color: #3b82f6;
text-decoration: none;
font-weight: bold;
}
#schedule-btn-widget a:hover {
color: #2563eb;
text-decoration: underline;
}
/* Flags Button in Sidebar */
#flags-btn-widget {
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 4px;
padding: 6px 8px;
margin-bottom: 8px;
text-align: center;
}
#flags-btn-widget a {
color: #856404;
text-decoration: none;
font-weight: bold;
}
#flags-btn-widget a:hover {
color: #5a4203;
text-decoration: underline;
}
/* Patreon Button in Sidebar */
#patreon-btn-widget {
margin: 15px 0 0 0;
padding: 15px 0 0 0;
border-top: 1px solid #444;
text-align: center;
}
/* Reduce gap between StoryCaption and Save/Restart menu */
#story-caption {
margin-bottom: 0 !important;
padding-bottom: 0 !important;
}
#menu-story {
margin-top: 8px !important;
}
.patreon-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 12px;
background: #f96854;
color: #fff !important;
border-radius: 4px;
text-decoration: none;
font-size: 0.9em;
font-weight: bold;
}
.patreon-link:hover {
background: #e85a47;
text-decoration: none !important;
}
.patreon-icon {
flex-shrink: 0;
}
.stats-card {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 6px;
padding: 12px;
margin-bottom: 12px;
}
.stats-name {
font-weight: bold;
font-size: 1.2em;
color: #212529;
margin-bottom: 8px;
border-bottom: 1px solid #dee2e6;
padding-bottom: 6px;
}
.stats-traits {
margin-top: 8px;
}
.stats-trait-item {
display: flex;
justify-content: space-between;
padding: 4px 8px;
border-bottom: 1px dashed #e2e3e5;
color: #343a40;
}
.stats-trait-value {
font-weight: bold;
color: #0d6efd;
}
/* Story Arc Help Page Styles */
.chapter-context {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
padding: 12px 16px;
border-radius: 8px;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.chapter-name {
font-size: 1.1em;
color: #e0e0e0;
font-weight: bold;
}
.chapter-mood {
font-size: 0.9em;
color: #a0a0a0;
font-style: italic;
}
.available-section h3 {
font-size: 1em;
color: #495057;
margin: 0 0 10px 0;
border-bottom: 1px solid #dee2e6;
padding-bottom: 6px;
}
.help-card {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 6px;
padding: 12px 16px;
margin-bottom: 10px;
}
.node-name {
font-weight: bold;
color: #212529;
}
.node-hint {
color: #6c757d;
font-size: 0.9em;
margin-top: 4px;
}
.narrative-hint {
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 6px;
padding: 12px;
margin: 16px 0;
}
.narrative-hint p {
margin: 0;
color: #856404;
}
.progress-summary {
text-align: center;
color: #6c757d;
font-size: 0.9em;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid #dee2e6;
}
.no-quests-msg {
font-style: italic;
color: #6c757d;
padding: 10px;
}
/* Quest Page - Simplified One Activity Per NPC */
.npc-section {
margin-bottom: 20px;
padding: 16px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: 10px;
border: 1px solid #dee2e6;
}
.npc-name {
font-size: 1.2em;
color: #2c3e50;
margin: 0 0 12px 0;
border-bottom: 2px solid #3498db;
padding-bottom: 8px;
font-weight: 600;
}
.guide-hint {
font-size: 0.85em;
color: #f0c040;
font-style: italic;
}
.quest-available {
color: #155724;
font-weight: 500;
padding: 10px 14px;
background: rgba(40, 167, 69, 0.1);
border-radius: 6px;
border-left: 4px solid #28a745;
}
.quest-locked {
color: #856404;
font-weight: 500;
padding: 10px 14px;
background: rgba(255, 193, 7, 0.15);
border-radius: 6px;
border-left: 4px solid #ffc107;
}
.quest-conditions {
color: #721c24;
font-weight: 500;
padding: 10px 14px;
background: rgba(220, 53, 69, 0.1);
border-radius: 6px;
border-left: 4px solid #dc3545;
}
.quest-waiting {
color: #856404;
font-weight: 500;
padding: 10px 14px;
background: rgba(255, 193, 7, 0.15);
border-radius: 6px;
border-left: 4px solid #ffc107;
font-style: italic;
}
.dev-canvas-info {
background: #17a2b8;
color: white;
padding: 6px 10px;
border-radius: 4px;
margin-bottom: 10px;
font-size: 11px;
font-family: 'Courier New', monospace;
}
.quest-complete {
color: #28a745;
font-style: italic;
padding: 10px 14px;
text-align: center;
}
.no-quests {
color: #6c757d;
font-style: italic;
padding: 12px;
text-align: center;
}
/* Trait Requirement Link */
.trait-requirement-link {
color: #721c24;
text-decoration: underline;
cursor: pointer;
}
.trait-requirement-link:hover {
color: #a71d2a;
}
/* Trait Activities Modal Overlay */
.trait-modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
/* Modal Container */
.trait-modal {
background: #fff;
border-radius: 12px;
max-width: 400px;
width: 90%;
max-height: 80vh;
overflow: hidden;
box-shadow: 0 10px 40px rgba(0,0,0,0.3);
}
.trait-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
background: #f8f9fa;
border-bottom: 1px solid #dee2e6;
}
.trait-modal-header h3 {
margin: 0;
font-size: 1.1em;
color: #333;
}
.trait-modal-close {
font-size: 24px;
cursor: pointer;
color: #666;
line-height: 1;
}
.trait-modal-close:hover {
color: #333;
}
.trait-modal-progress {
padding: 12px 20px;
background: rgba(220, 53, 69, 0.1);
color: #721c24;
font-weight: 500;
text-align: center;
}
.trait-modal-body {
padding: 16px 20px;
max-height: 50vh;
overflow-y: auto;
}
/* Activity List */
.trait-activity-list {
list-style: none;
padding: 0;
margin: 0;
}
.trait-activity-list li {
padding: 12px;
border-bottom: 1px solid #eee;
}
.trait-activity-list li:last-child {
border-bottom: none;
}
.activity-name {
font-weight: 600;
color: #333;
}
.activity-bonus {
float: right;
color: #28a745;
font-weight: 500;
}
.activity-hint {
margin-top: 4px;
color: #666;
font-size: 0.9em;
clear: both;
}
/* Effect Toast Notification */
.effect-toast {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.85);
color: #4ade80;
padding: 10px 20px;
border-radius: 6px;
font-size: 14px;
z-index: 9999;
white-space: nowrap;
}
/* Game Intro - Top Left Aligned */
.game-intro {
text-align: left;
}
/* Age Gate Section */
.age-gate {
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 8px;
padding: 20px;
margin: 20px 0;
text-align: center;
}
.age-warning {
font-weight: bold;
color: #856404;
margin-bottom: 15px;
}
.age-buttons {
display: flex;
flex-direction: column;
gap: 10px;
align-items: center;
}
/* Developer Intro Section (above age gate) */
.developer-intro {
text-align: left;
color: #555;
margin: 20px 0;
}
/* Developer Footer Section (below age gate) */
.developer-footer {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #dee2e6;
text-align: center;
color: #6c757d;
font-size: 0.9em;
}
.developer-intro a,
.developer-footer a {
color: #f96854;
text-decoration: none;
}
.developer-intro a:hover,
.developer-footer a:hover {
text-decoration: underline;
}
.developer-about {
line-height: 1.5;
margin: 10px 0;
}
.support-link {
margin-top: 8px;
}
.developer-footer .support-link {
font-weight: bold;
}
/* Age Blocked Page */
.blocked-page {
text-align: center;
padding: 50px;
color: #721c24;
background: #f8d7da;
border-radius: 8px;
margin: 50px auto;
max-width: 400px;
}
/* Override SugarCube default vertical centering */
#story {
align-items: flex-start !important;
justify-content: flex-start !important;
padding-top: 1em !important;
}
.passage {
margin-top: 0 !important;
padding-top: 0 !important;
}
/* New/Unvisited Canvas Highlight */
.new-canvas a {
color: #28a745 !important;
font-weight: 600;
}
.new-canvas a::before {
content: "✨ ";
}
/* Unlocked conditional choice highlight (in passages) */
.unlocked-choice a, .unlocked-choice .link-internal {
color: #f59e0b !important;
font-weight: 600;
}
.unlocked-choice a::before, .unlocked-choice .link-internal::before {
content: "🔓 ";
}
/* Unlocked choice canvas link highlight (in location activity list) */
.unlocked-choice-canvas a {
color: #f59e0b !important;
font-weight: 600;
}
.unlocked-choice-canvas a::before {
content: "🔓 ";
}
/* Navigation New Content Indicator */
.nav-new {
color: #ffc107;
font-weight: bold;
font-size: 1.1em;
}
/* Navigation Unlocked Choice Indicators */
.nav-unlocked {
color: #f59e0b;
font-weight: bold;
font-size: 1.0em;
}
.nav-unlocked-badge {
font-size: 0.65em;
padding: 2px 5px;
}
/* Navigation NPC Portrait Indicator */
.nav-npc-portrait {
width: 24px;
height: 24px;
border-radius: 50%;
object-fit: cover;
vertical-align: middle;
margin-left: 4px;
border: 2px solid #ccc;
}
/* ===============================================
VISUAL NAVIGATION GRID
=============================================== */
.location-nav-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
margin: 8px 0;
}
@media (min-width: 768px) {
.location-nav-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 1024px) {
.location-nav-grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Location Card */
.location-card {
display: flex;
flex-direction: column;
background: #2a2a2a;
border-radius: 8px;
overflow: hidden;
text-decoration: none !important;
color: inherit !important;
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
}
.location-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
}
/* Card Image Area (5:2 aspect ratio - more compact) */
.location-card-image {
width: 100%;
padding-bottom: 40%; /* 5:2 ratio */
background-size: cover;
background-position: center;
position: relative;
background-color: #1a1a1a;
}
/* Placeholder silhouette for locations without images */
.location-card-placeholder {
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #2d2d3a 0%, #1a1a2a 100%);
}
.location-card-placeholder svg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60%;
height: 60%;
opacity: 0.5;
}
/* Card Content Area */
.location-card-content {
padding: 6px 8px;
display: flex;
flex-direction: column;
gap: 2px;
}
.location-card-name {
font-weight: 600;
font-size: 0.9em;
line-height: 1.2;
color: #e0e0e0;
}
/* Indicators Row */
.location-card-indicators {
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
}
/* NEW badge (replaces ! indicator in visual mode) */
.nav-new-badge {
background: #ffc107;
color: #000;
font-size: 0.65em;
font-weight: bold;
padding: 2px 5px;
border-radius: 3px;
text-transform: uppercase;
}
/* NPC portrait badges (smaller version for cards) */
.nav-npc-badge {
width: 20px;
height: 20px;
border-radius: 50%;
object-fit: cover;
border: 1px solid #666;
}
/* Exit Links Section (text-only, below grid) */
.location-nav-exits {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #444;
}
.location-nav-exits a {
color: #aaa;
}
.location-nav-exits a:hover {
color: #fff;
}
/* Dev Mode Controls */
.dev-adj-btn {
background: #6c757d;
color: white;
border: none;
border-radius: 3px;
width: 20px;
height: 20px;
font-size: 14px;
font-weight: bold;
cursor: pointer;
padding: 0;
line-height: 1;
vertical-align: middle;
}
.dev-adj-btn:hover {
background: #5a6268;
}
.trait-controls {
display: flex;
align-items: center;
gap: 4px;
}
.trait-controls .trait-value {
min-width: 24px;
text-align: center;
}
/* Portrait System */
.portrait {
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
background: #e9ecef;
display: flex;
align-items: center;
justify-content: center;
}
.portrait img {
width: 100%;
height: 100%;
object-fit: cover;
}
.portrait-placeholder svg {
width: 70%;
height: 70%;
}
/* Dialog Block with Portrait */
.dialog-block {
display: flex;
align-items: center;
gap: 12px;
margin: 10px 0;
padding: 10px;
border-radius: 8px;
color: #212529;
}
.dialog-player {
border-left: 4px solid #007bff;
background: #e7f3ff;
}
.dialog-player strong {
color: #0056b3;
}
.dialog-npc {
border-left: 4px solid #6c757d;
background: #f8f9fa;
}
.dialog-npc strong {
color: #495057;
}
.dialog-content {
flex: 1;
}
/* Stats Card Portrait (larger) */
.stats-portrait {
width: 80px;
height: 100px;
border-radius: 8px;
overflow: hidden;
background: #e9ecef;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.stats-portrait img {
width: 100%;
height: 100%;
object-fit: cover;
}
.stats-portrait svg {
width: 60%;
height: 60%;
}
/* Stats Card with Portrait Layout */
.stats-card-with-portrait {
display: flex;
gap: 12px;
align-items: flex-start;
}
.stats-info {
flex: 1;
min-width: 0;
}
/* Wardrobe Page */
.wardrobe-page {
margin: 12px 0;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 10px;
padding: 16px;
}
.wardrobe-table {
width: 100%;
border-collapse: collapse;
}
.wardrobe-row {
border-bottom: 1px solid #dee2e6;
}
.wardrobe-row:last-child {
border-bottom: none;
}
.wardrobe-row-disabled {
opacity: 0.45;
}
.wardrobe-slot-label {
padding: 12px 8px;
font-weight: 700;
color: #333;
width: 90px;
vertical-align: middle;
font-size: 0.85em;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.wardrobe-slot-items {
padding: 10px 4px;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.wardrobe-item {
position: relative;
width: 76px;
height: 76px;
border: 2px solid #ccc;
border-radius: 8px;
cursor: pointer;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.wardrobe-item:hover {
border-color: #888;
transform: translateY(-1px);
box-shadow: 0 2px 6px rgba(0,0,0,0.12);
}
.wardrobe-item-equipped {
border-color: #28a745;
background: #e8f5e9;
box-shadow: 0 0 0 2px rgba(40, 167, 69, 0.25);
}
.wardrobe-item-equipped:hover {
border-color: #218838;
}
.wardrobe-item-locked {
opacity: 0.5;
cursor: not-allowed;
filter: grayscale(50%);
}
.wardrobe-item-locked:hover {
transform: none;
box-shadow: none;
border-color: #ccc;
}
.wardrobe-item-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.wardrobe-item-text {
font-size: 0.8em;
text-align: center;
padding: 6px;
word-break: break-word;
color: #333;
line-height: 1.2;
}
.wardrobe-badge-equipped {
position: absolute;
top: 2px;
right: 2px;
background: #28a745;
color: #fff;
font-size: 11px;
width: 18px;
height: 18px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.wardrobe-badge-locked {
position: absolute;
bottom: 2px;
right: 2px;
font-size: 13px;
}
.wardrobe-unequip-btn {
background: none;
border: 1px solid #6c757d;
color: #6c757d;
width: 28px;
height: 28px;
border-radius: 50%;
cursor: pointer;
font-size: 16px;
line-height: 1;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
transition: background 0.15s, color 0.15s;
}
.wardrobe-unequip-btn:hover {
background: #dc3545;
border-color: #dc3545;
color: #fff;
}
.wardrobe-disabled-hint,
.wardrobe-empty-hint {
color: #aaa;
font-style: italic;
font-size: 0.85em;
}
.entry-blocked {
color: #721c24;
font-weight: 500;
}
.entry-requirements {
color: #856404;
background: #fff3cd;
padding: 8px 12px;
border-radius: 6px;
font-size: 0.9em;
}
#wardrobe-btn-widget button {
background: #f8f9fa;
border: 1px solid #dee2e6;
color: #333;
padding: 6px 12px;
border-radius: 6px;
cursor: pointer;
width: 100%;
font-size: 0.95em;
margin: 4px 0;
}
#wardrobe-btn-widget button:hover {
background: #e9ecef;
border-color: #adb5bd;
}
/* Shop page styles */
.shop-page {
margin: 12px 0;
}
.shop-money {
background: #e8f5e9;
border: 1px solid #c8e6c9;
border-radius: 8px;
padding: 10px 16px;
font-size: 1.05em;
font-weight: 600;
color: #2e7d32;
margin-bottom: 16px;
display: inline-block;
}
.shop-tier {
margin-bottom: 20px;
border: 1px solid #dee2e6;
border-radius: 10px;
overflow: hidden;
background: #f8f9fa;
}
.shop-tier-locked {
opacity: 0.55;
}
.shop-tier-header {
background: #343a40;
color: #fff;
padding: 10px 16px;
font-weight: 700;
font-size: 0.95em;
display: flex;
justify-content: space-between;
align-items: center;
}
.shop-tier-locked .shop-tier-header {
background: #6c757d;
}
.shop-tier-req {
font-weight: 400;
font-size: 0.85em;
opacity: 0.8;
}
.shop-tier-locked-msg {
padding: 12px 16px;
color: #856404;
background: #fff3cd;
font-style: italic;
font-size: 0.9em;
text-align: center;
}
.shop-items {
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
}
.shop-slot-group {
margin-bottom: 4px;
}
.shop-slot-label {
font-weight: 700;
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #495057;
padding: 4px 0;
border-bottom: 1px solid #e9ecef;
margin-bottom: 6px;
}
.shop-slot-items {
display: flex;
flex-direction: column;
gap: 6px;
}
.shop-item {
display: flex;
align-items: center;
gap: 12px;
background: #fff;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 10px 14px;
transition: border-color 0.15s;
}
.shop-item-thumb {
width: 56px;
height: 56px;
border: 2px solid #ccc;
border-radius: 8px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
background: #f8f9fa;
flex-shrink: 0;
}
.shop-item-thumb-img {
width: 100%;
height: 100%;
object-fit: cover;
}
.shop-item-thumb-text {
font-size: 0.7em;
text-align: center;
padding: 4px;
word-break: break-word;
color: #666;
line-height: 1.2;
}
.shop-item:hover {
border-color: #adb5bd;
}
.shop-item-owned {
border-color: #28a745;
background: #e8f5e9;
}
.shop-item-unaffordable {
opacity: 0.55;
}
.shop-item-info {
display: flex;
flex-direction: column;
gap: 2px;
flex: 1;
min-width: 0;
}
.shop-item-name {
font-weight: 600;
color: #212529;
font-size: 0.95em;
}
.shop-item-action {
display: flex;
align-items: center;
gap: 10px;
}
.shop-item-price {
font-weight: 600;
color: #495057;
font-size: 0.95em;
}
.shop-item-owned-badge {
color: #28a745;
font-weight: 600;
font-size: 0.9em;
}
.shop-item-cant-afford {
color: #dc3545;
font-size: 0.85em;
font-style: italic;
}
.shop-buy-btn {
background: #007bff;
color: #fff;
border: none;
padding: 6px 16px;
border-radius: 6px;
cursor: pointer;
font-size: 0.9em;
font-weight: 600;
transition: background 0.15s;
}
.shop-buy-btn:hover {
background: #0056b3;
}
/* Rent page styles */
.rent-title {
color: #ffffff;
margin-bottom: 16px;
font-size: 1.4em;
}
.rent-choices {
margin: 16px 0;
display: flex;
flex-direction: column;
gap: 8px;
}
.rent-choices a {
display: block;
padding: 10px 16px;
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 6px;
color: #212529;
text-decoration: none;
font-weight: 500;
transition: background 0.15s, border-color 0.15s;
}
.rent-choices a:hover {
background: #e9ecef;
border-color: #adb5bd;
}
.rent-balance {
margin-top: 12px;
padding: 8px 12px;
background: rgba(0,0,0,0.04);
border-radius: 6px;
font-size: 0.95em;
}
.game-over-text {
text-align: center;
font-size: 1.5em;
font-weight: bold;
color: #dc2626;
margin: 20px 0;
letter-spacing: 2px;
}
</style><<nobr>>
<h2>What's Next</h2>
<<set _helpData = setup.help_data || {}>>
<<set _hasPlayer = _helpData.player && _helpData.player.activities && _helpData.player.activities.length > 0>>
<<set _hasNpcs = _helpData.npcs && Object.keys(_helpData.npcs).length > 0>>
<<if _hasPlayer>>
<div class="npc-section">
<h3 class="npc-name"><<print _helpData.player.name>></h3>
<<set _next = setup.getNextActivity("_player_")>>
<<if _next === null>>
<div class="quest-complete">✓ All activities completed!</div>
<<elseif _next.traitConditionsNotMet>>
<div class="quest-conditions">
🔒 <<print setup.formatCanvasConditions(_next.canvasConditions)>>
</div>
<<elseif _next.flagConditionsNotMet>>
<div class="quest-available">
→ <<print setup.formatFlagHint(_next.flagHint, _helpData.player.name)>>
</div>
<<elseif _next.daysConditionsNotMet>>
<div class="quest-waiting">
⏳ <<if _next.daysRemaining === 1>>Come back tomorrow<<else>>Wait <<print _next.daysRemaining>> more days<</if>>
</div>
<<elseif _next.conditionsNotMet>>
<div class="quest-conditions">
🔒 <<print setup.formatCanvasConditions(_next.canvasConditions)>>
</div>
<<elseif _next.isLocked>>
<div class="quest-locked">
🔒 <<print setup.formatTraitRequirements(_next.missingTraits)>>
</div>
<<else>>
<div class="quest-available">
→ <<print setup.formatActivityHint(_next.activity)>>
</div>
<</if>>
</div>
<</if>>
<<if _hasNpcs>>
<<for _npcId, _npcData range _helpData.npcs>>
<div class="npc-section">
<h3 class="npc-name"><<print _npcData.name>></h3>
<<set _next = setup.getNextActivity(_npcId)>>
<<if _next === null>>
<div class="quest-complete">✓ All activities completed!</div>
<<elseif _next.traitConditionsNotMet>>
<div class="quest-conditions">
🔒 <<print setup.formatCanvasConditions(_next.canvasConditions)>>
</div>
<<elseif _next.flagConditionsNotMet>>
<div class="quest-available">
→ <<print setup.formatFlagHint(_next.flagHint, _npcData.name)>>
</div>
<<elseif _next.daysConditionsNotMet>>
<div class="quest-waiting">
⏳ <<if _next.daysRemaining === 1>>Come back tomorrow<<else>>Wait <<print _next.daysRemaining>> more days<</if>>
</div>
<<elseif _next.conditionsNotMet>>
<div class="quest-conditions">
🔒 <<print setup.formatCanvasConditions(_next.canvasConditions)>>
</div>
<<elseif _next.isLocked>>
<div class="quest-locked">
🔒 <<print setup.formatTraitRequirements(_next.missingTraits)>>
</div>
<<else>>
<div class="quest-available">
→ <<print setup.formatActivityHint(_next.activity)>>
</div>
<</if>>
</div>
<</for>>
<</if>>
<<if !_hasPlayer && !_hasNpcs>>
<div class="no-quests">No activities available.</div>
<</if>>
<</nobr>>
<<return "← Back">><<set _position = setup.detectStoryPosition()>>
<<set _hint = setup.generateNarrativeHint()>>
<div class="journal-container">
<div class="journal-header">
<<if _position.current_chapter>>
<h2 class="journal-chapter-title"><<print _position.current_chapter.name>></h2>
<<if _position.current_chapter.mood>>
<div class="journal-chapter-mood <<print _position.current_chapter.mood>>">
<<print _position.current_chapter.description || "">>
</div>
<</if>>
<<else>>
<h2 class="journal-chapter-title">Your Story</h2>
<</if>>
<<if _position.progress_percent > 0>>
<div class="journal-progress">
<div class="journal-progress-bar">
<div class="journal-progress-fill" style="width: <<print _position.progress_percent>>%;"></div>
</div>
</div>
<</if>>
</div>
<!-- Memories (completed story moments) -->
<<if _position.completed_nodes.length > 0>>
<div class="journal-section">
<div class="journal-section-title">Memories</div>
<<for _i, _node range _position.completed_nodes>>
<div class="journal-memory <<if _node.is_milestone>>milestone<</if>>">
<div class="journal-memory-title"><<print _node.name>></div>
<<if _node.journal_entry>>
<<print _node.journal_entry>>
<</if>>
</div>
<</for>>
</div>
<</if>>
<!-- Active story threads (groups in progress) -->
<<if _position.active_groups.length > 0>>
<<set _incompleteGroups = _position.active_groups.filter(function(g) { return !g.isComplete && g.completed > 0; })>>
<<if _incompleteGroups.length > 0>>
<div class="journal-section">
<div class="journal-section-title">Unfolding</div>
<<for _i, _group range _incompleteGroups>>
<div class="journal-group">
<div class="journal-group-name"><<print _group.name>></div>
<div class="journal-group-progress">
<<print _group.description>>
</div>
</div>
<</for>>
</div>
<</if>>
<</if>>
<!-- Relationship states (NPC emotions) -->
<<if Object.keys($npcs).length > 0>>
<div class="journal-section">
<div class="journal-section-title">Connections</div>
<<for _npcId range Object.keys($npcs)>>
<<set _state = setup.interpretNpcState(_npcId)>>
<<if _state.npc_name>>
<div class="journal-npc">
<div class="journal-npc-name"><<print _state.npc_name>></div>
<div class="journal-npc-emotion"><<print _state.description>></div>
<<if _state.relationship_summary && _state.relationship_summary !== _state.description>>
<div class="journal-npc-summary"><<print _state.relationship_summary>></div>
<</if>>
</div>
<</if>>
<</for>>
</div>
<</if>>
<!-- Subtle narrative hint (only when needed) -->
<<if _hint.hint_type !== "none" && _hint.text>>
<div class="journal-hint <<print _hint.hint_type>>">
<<print _hint.text>>
</div>
<</if>>
<!-- Empty state -->
<<if _position.completed_nodes.length === 0 && Object.keys($npcs).length === 0>>
<div class="journal-empty">
Your story is just beginning...
</div>
<</if>>
<div class="journal-back-link">
[[Return to your story->Navigation]]
</div>
</div><<nobr>>
<h2>All Stats</h2>
<!-- Player Stats -->
<div class="stats-card stats-card-with-portrait">
<div class="stats-portrait">
<<if $player.portrait>>
<img @src="'./videos/' + $player.portrait" @alt="$player.name" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';">
<<else>>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>
<</if>>
</div>
<div class="stats-info">
<div class="stats-name">You (<<print $player.name>>)</div>
<div class="stats-traits">
<<if $player && $player.core_traits && Object.keys($player.core_traits).length > 0>>
<<for _tk, _tv range $player.core_traits>>
<div class="stats-trait-item">
<span><<print _tk>></span>
<span class="stats-trait-value"><<print _tv>></span>
</div>
<</for>>
<<else>>
<em>No traits</em>
<</if>>
</div>
</div>
</div>
<!-- NPC Stats -->
<<if Object.keys($npcs).length > 0>>
<<for _npcId, _npc range $npcs>>
<div class="stats-card stats-card-with-portrait">
<div class="stats-portrait">
<<if _npc.portrait>>
<img @src="'./videos/' + _npc.portrait" @alt="_npc.name" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';">
<<else>>
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>
<</if>>
</div>
<div class="stats-info">
<div class="stats-name"><<print _npc.name>></div>
<div class="stats-traits">
<<if _npc.core_traits && Object.keys(_npc.core_traits).length > 0>>
<<for _tk, _tv range _npc.core_traits>>
<div class="stats-trait-item">
<span><<print _tk>></span>
<span class="stats-trait-value"><<print _tv>></span>
</div>
<</for>>
<<else>>
<em>No traits</em>
<</if>>
</div>
</div>
</div>
<</for>>
<<else>>
<p><em>No NPCs found.</em></p>
<</if>>
<</nobr>>
<<return "← Back">><<nobr>>
<h2>Change Clothes</h2>
<<= setup.renderWardrobePage()>>
<</nobr>>
<div id="wardrobe-warning" style="display:none; color:#ff6b6b; margin:10px 0; padding:8px; border:1px solid #ff6b6b; border-radius:4px;"></div>
<<link "← Back">><<script>>
var issues = setup.validateClothing();
if (issues.length > 0) {
var el = document.getElementById('wardrobe-warning');
if (el) { el.innerHTML = issues.join('<br>'); el.style.display = 'block'; }
} else {
Engine.play(State.variables.last_game_passage || "Navigation");
}
<</script>><</link>><<nobr>>
<h2>Clothing Store</h2>
<<= setup.renderShopPage()>>
<</nobr>>
<<return "← Back">><<nobr>>
<<set _money to $player.core_traits.money || 0>>
<<set _rent to setup.rent_amount>>
<<set _collectorName to "the landlord">>
<<set _npcPortrait to "">>
<<if setup.rent_collector_npc && setup.npc_slug_map[setup.rent_collector_npc]>>
<<set _npcId to setup.npc_slug_map[setup.rent_collector_npc]>>
<<set _npcData to $npcs[_npcId]>>
<<if _npcData && _npcData.name>>
<<set _collectorName to _npcData.name>>
<<set _npcPortrait to _npcData.portrait || "">>
<</if>>
<</if>>
<h2 class="rent-title">Monday Morning — Rent Day</h2>
<p>A heavy knock on the door. You open it to find <<print _collectorName>> standing there, hand already extended.</p>
<div class="dialog-block dialog-npc">
<div class="dialog-content">
<strong><<print _collectorName>>:</strong> Rent. $<<print _rent>>. You know how this works.
</div>
</div>
<p>You have $<<print _money>>. Rent is $<<print _rent>>.</p>
<div class="rent-choices">
<<if _money gte _rent>>
<<set _payText to "Pay $" + _rent + " rent">>
<<link _payText>>
<<set $player.core_traits.money -= _rent>>
<<set $game_state.rent_state.last_paid_week to $game_state.time_state.current_week>>
<<set $game_state.rent_state.is_due to false>>
<<set $game_state.rent_state.warnings to 0>>
<<goto "RentDay_Paid">>
<</link>>
<</if>>
<<link "Tell him you can't pay">>
<<goto "RentDay_Short">>
<</link>>
</div>
<</nobr>><<nobr>>
<<set _collectorName to "the landlord">>
<<if setup.rent_collector_npc && setup.npc_slug_map[setup.rent_collector_npc]>>
<<set _npcId to setup.npc_slug_map[setup.rent_collector_npc]>>
<<set _npcData to $npcs[_npcId]>>
<<if _npcData && _npcData.name>>
<<set _collectorName to _npcData.name>>
<</if>>
<</if>>
<p>You hand over the cash. <<print _collectorName>> counts it, nods once, and turns to leave.</p>
<div class="dialog-block dialog-npc">
<div class="dialog-content">
<strong><<print _collectorName>>:</strong> Same time next week.
</div>
</div>
<p>The door closes. Another week secured.</p>
<p class="rent-balance">Remaining money: <strong>$<<print $player.core_traits.money>></strong></p>
<<link "Continue your day">><<run Engine.play(State.variables.last_game_passage || "Navigation")>><</link>>
<</nobr>><<nobr>>
<<set _collectorName to "the landlord">>
<<if setup.rent_collector_npc && setup.npc_slug_map[setup.rent_collector_npc]>>
<<set _npcId to setup.npc_slug_map[setup.rent_collector_npc]>>
<<set _npcData to $npcs[_npcId]>>
<<if _npcData && _npcData.name>>
<<set _collectorName to _npcData.name>>
<</if>>
<</if>>
<<if $game_state.rent_state.warnings lt setup.rent_grace_periods>>
<p>You explain that you're short this week. <<print _collectorName>>'s expression doesn't change.</p>
<div class="dialog-block dialog-npc">
<div class="dialog-content">
<strong><<print _collectorName>>:</strong> Next Monday. Don't make me ask twice.
</div>
</div>
<p>The door closes. You have one week to find the money.</p>
<<set $game_state.rent_state.warnings += 1>>
<<set $game_state.rent_state.is_due to false>>
<p class="rent-balance">You have: <strong>$<<print $player.core_traits.money>></strong>. You need: <strong>$<<print setup.rent_amount>></strong>.</p>
<<link "Continue your day">><<run Engine.play(State.variables.last_game_passage || "Navigation")>><</link>>
<<else>>
<p><<print _collectorName>> doesn't wait for excuses this time.</p>
<div class="dialog-block dialog-npc">
<div class="dialog-content">
<strong><<print _collectorName>>:</strong> Locks are getting changed today. Pack your things.
</div>
</div>
<p>No negotiation. No extension. You had your chance.</p>
<p class="game-over-text">GAME OVER</p>
<<link "Start Over">><<run Engine.restart()>><</link>>
<</if>>
<</nobr>><<nobr>>
<<set _currentDay to $game_state.time_state.current_day>>
<h2>📅 <<print _currentDay>>'s Schedules</h2>
<p class="current-time">Current Time: <<print setup.formatTime($game_state.time_state.current_hour, $game_state.time_state.current_minute)>></p>
<<set _npcsWithSchedules to setup.getNpcsWithSchedules()>>
<<if _npcsWithSchedules.length === 0>>
<p><em>No NPCs have schedules defined.</em></p>
<<else>>
<<for _npcInfo range _npcsWithSchedules>>
<<set _npcId to _npcInfo.id>>
<<set _npcName to _npcInfo.name>>
<<set _currentLoc to setup.getNpcLocation(_npcId)>>
<<set _todaySchedule to setup.getTodayScheduleSorted(_npcId)>>
<<set _dayIndex to ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"].indexOf(_currentDay)>>
<div class="schedule-card">
<div class="schedule-header">
<span class="npc-name"><<print _npcName>></span>
<<if _currentLoc>>
<<set _locName to (setup.locations[_currentLoc.location] && setup.locations[_currentLoc.location].name) || _currentLoc.location>>
<span class="now-badge">NOW: <<print _locName>></span>
<</if>>
</div>
<<if _currentLoc && _currentLoc.activity>>
<div class="current-activity">"<<print _currentLoc.activity>>"</div>
<</if>>
<<if _todaySchedule.length === 0>>
<p><em>No schedule entries for <<print _currentDay>>.</em></p>
<<else>>
<p class="schedule-day-info"><<print _todaySchedule.length>> schedule entries for <<print _currentDay>></p>
<table class="schedule-table">
<thead><tr><th>Time</th><th>Location</th><th>Activity</th></tr></thead>
<tbody>
<<for _sch range _todaySchedule>>
<<set _isCurrent to setup.isCurrentTimeSlot(_sch.start_time, _sch.end_time)>>
<<set _rowClass to _isCurrent ? "current-slot" : "">>
<<set _schLocName to (setup.locations[_sch.location] && setup.locations[_sch.location].name) || _sch.location>>
<tr class="<<print _rowClass>>">
<td><<if _isCurrent>>▶ <</if>><<print _sch.start_time>>-<<print _sch.end_time || "?">></td>
<td><<print _schLocName>></td>
<td><<print _sch.activity>></td>
</tr>
<</for>>
</tbody>
</table>
<</if>>
</div>
<</for>>
<</if>>
<<set _soloActivities to setup.getSoloActivitiesForToday()>>
<<if _soloActivities.length > 0>>
<div class="solo-activities-section schedule-card">
<h3>Your Activities</h3>
<table class="schedule-table">
<thead><tr><th>Time</th><th>Location</th><th>Activity</th></tr></thead>
<tbody>
<<for _act range _soloActivities>>
<<set _rowClass to _act.isCurrent ? "current-slot" : "">>
<tr class="<<print _rowClass>>">
<td><<if _act.isCurrent>>▶ <</if>><<print _act.startTime>>-<<print _act.endTime || "?">></td>
<td><<print _act.locationName>></td>
<td><<print _act.name>></td>
</tr>
<</for>>
</tbody>
</table>
</div>
<</if>>
<<return "← Back">>
<</nobr>>
<style>
.current-time {
color: #334155;
font-size: 0.9em;
margin: 0 0 10px 0;
}
.schedule-card {
background: #ffffff;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 12px;
margin-bottom: 12px;
}
.schedule-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 4px;
}
.npc-name {
font-size: 1.1em;
font-weight: bold;
color: #1e293b;
}
.now-badge {
background: #22c55e;
color: white;
padding: 3px 8px;
border-radius: 10px;
font-size: 0.8em;
font-weight: bold;
}
.current-activity {
color: #475569;
font-style: italic;
margin-bottom: 6px;
font-size: 0.85em;
}
.schedule-day-info {
color: #64748b;
font-size: 0.8em;
margin: 0 0 6px 0;
padding: 2px 6px;
background: #f1f5f9;
border-radius: 3px;
display: inline-block;
}
.schedule-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85em;
color: #1e293b;
}
.schedule-table th {
text-align: left;
padding: 4px 8px;
background: #f1f5f9;
border-bottom: 2px solid #e2e8f0;
color: #334155;
font-weight: 600;
}
.schedule-table td {
padding: 4px 8px;
border-bottom: 1px solid #e2e8f0;
color: #334155;
}
.schedule-table tr.current-slot {
background: #fef3c7;
font-weight: 500;
}
.schedule-table tr.current-slot td:first-child {
color: #d97706;
}
.solo-activities-section {
margin-top: 18px;
}
.solo-activities-section h3 {
color: #1e293b;
margin: 0 0 8px 0;
}
</style><<nobr>>
<h2>🚩 Game Flags</h2>
<div class="flags-container">
<<if $flags && Object.keys($flags).length > 0>>
<div class="flags-section">
<h3>Story Flags</h3>
<<set _gkeys to Object.keys($flags).sort()>>
<ul class="flags-list">
<<for _i to 0; _i lt _gkeys.length; _i++>>
<<set _gk to _gkeys[_i]>>
<li class="flag-item">
<span class="flag-name"><<print _gk>></span>
<span class="flag-value <<print $flags[_gk] ? 'flag-true' : 'flag-false'>>"><<print $flags[_gk] ? '✔' : '✖'>></span>
</li>
<</for>>
</ul>
</div>
<<else>>
<div class="no-flags">No story flags set.</div>
<</if>>
<<if $player && $player.flags && Object.keys($player.flags).length > 0>>
<div class="flags-section">
<h3>Player Flags</h3>
<<set _pkeys to Object.keys($player.flags).sort()>>
<ul class="flags-list">
<<for _j to 0; _j lt _pkeys.length; _j++>>
<<set _pk to _pkeys[_j]>>
<li class="flag-item">
<span class="flag-name"><<print _pk>></span>
<span class="flag-value <<print $player.flags[_pk] ? 'flag-true' : 'flag-false'>>"><<print $player.flags[_pk] ? '✔' : '✖'>></span>
</li>
<</for>>
</ul>
</div>
<</if>>
</div>
<<return "← Back">>
<</nobr>>
<style>
.flags-container {
background: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 8px;
padding: 16px;
margin: 16px 0;
}
.flags-section {
margin-bottom: 20px;
}
.flags-section:last-child {
margin-bottom: 0;
}
.flags-section h3 {
color: #495057;
border-bottom: 2px solid #dee2e6;
padding-bottom: 8px;
margin: 0 0 12px 0;
}
.flags-list {
list-style: none;
padding: 0;
margin: 0;
}
.flag-item {
display: flex;
justify-content: space-between;
padding: 6px 0;
border-bottom: 1px solid #e9ecef;
}
.flag-item:last-child {
border-bottom: none;
}
.flag-name {
font-weight: 500;
color: #212529;
}
.flag-value {
font-family: monospace;
}
.flag-true {
color: #000000;
}
.flag-false {
color: #000000;
}
.no-flags {
color: #6c757d;
font-style: italic;
padding: 12px;
background: #fff;
border-radius: 4px;
}
</style><p>A bus stop on a street that looks nothing like home. One suitcase, a backpack, and an address scribbled on a piece of paper. The city is loud, grey, and doesn't care that she's here.</p><p>She stands on the sidewalk. Nobody tips their hat. Nobody stops to stare. Nobody notices her at all. That's the first thing she learns about this place — you're invisible until you make yourself visible.</p><p>$500 in her bank account. An address for a place that rents rooms above a bar — cheapest listing she could find.</p><img src="./videos/images/story/opening_arrival_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "67e5d8f3-89eb-411c-9ed7-fe674ffe031b">>
<<set $game_state.current_node = "d49fd83b-8a6f-4384-821e-5857c171cf28">>
<<script>>setup.markCanvasTriggered("67e5d8f3-89eb-411c-9ed7-fe674ffe031b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("opening_arrival.n1") === -1) { vn.push("opening_arrival.n1"); }<</script>>
<<nobr>>
<<link "Find the address" "StartingCanvas_opening_arrival_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She finds it. A two-story building on a corner — neon sign in the window just says BAR, the B flickering. Inside smells like spilled beer and fryer oil. It's mid-afternoon and three men sit at the counter watching a game on a mounted TV.</p><p>Behind the bar: a woman in a tank top, hair up, cigarette tucked behind her ear. She looks at Emma — suitcase, backpack, wide eyes — and sizes her up in about two seconds.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You the college girl? The one who called about the room?</div></div><p>Emma nods.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> I'm Jolene. I own this place with my husband. Room's upstairs. You got the first week?</div></div><p>She doesn't wait for an answer. She comes around the bar, takes Emma's suitcase without asking, and heads for the stairs. "Come on."</p><img src="./videos/images/story/opening_arrival_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "67e5d8f3-89eb-411c-9ed7-fe674ffe031b">>
<<set $game_state.current_node = "ad55ec58-6b5c-4af7-8db7-494cf5f99e99">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("opening_arrival.n2") === -1) { vn.push("opening_arrival.n2"); }<</script>>
<<nobr>>
<<link "Follow her upstairs" "StartingCanvas_opening_arrival_Node_3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>A single bed. A desk by the window — the window looks out at a brick wall. A bathroom the size of a closet. Through the floor, she can hear the bar below — a man laughing, the TV, ice clinking in a glass.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> $150 a week. Cash or Venmo. Every Monday. Kitchen's down the hall — it's shared, don't leave dishes. Bathroom's yours but the hot water takes a minute. My husband Mick handles the money side. Don't be late — he doesn't do grace periods.</div></div><p>She holds out her hand. Emma pays. $500 becomes $350. Just like that.</p><p>Jolene leaves. The door is open. Emma isn't sure if she forgot to close it or just doesn't believe in closed doors.</p><p>Emma sits on the bed. Puts her backpack down. Looks at herself in the bathroom mirror. Same face. Same eyes. But everything around her is different now. No parents. No church. No safety net. Just her, a room above a bar, and a semester that starts Monday.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> You can do this.</div></div><p>She says it out loud, to the mirror, the way she used to before tests. The girl in the mirror looks like she's never been anywhere. She hasn't. Not really.</p><img src="./videos/images/story/opening_arrival_n3.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "67e5d8f3-89eb-411c-9ed7-fe674ffe031b">>
<<set $game_state.current_node = "4803af6e-8ce2-433e-b088-d5087b724491">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("opening_arrival.n3") === -1) { vn.push("opening_arrival.n3"); }<</script>>
<<nobr>>
<<link "Unpack and settle in" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", -150.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "game_started");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(180);<</script>><</link>><br>
<</nobr>><h2>Navigation</h2>
<p>Where would you like to go?</p>
<div class="location-list">
[[City Streets->Location_City_Streets]]<br>
[[Shopping Mall->Location_Shopping_Mall]]<br>
[[Clothing Shop->Location_Clothing_Shop]]<br>
[[The Bar->Location_The_Bar]]<br>
[[Bar Floor->Location_Bar_Floor]]<br>
[[Stockroom->Location_Stockroom]]<br>
[[Upstairs->Location_Upstairs]]<br>
[[Emma's Room->Location_Emma's_Room]]<br>
[[Jolene & Mick's Room->Location_Jolene_&_Mick's_Room]]<br>
[[Bar Bathroom->Location_Bar_Bathroom]]<br>
[[Kitchen->Location_Kitchen]]<br>
[[Upstairs Bathroom->Location_Upstairs_Bathroom]]<br>
[[Living Room->Location_Living_Room]]<br>
[[Campus->Location_Campus]]<br>
[[Classroom->Location_Classroom]]<br>
[[Library->Location_Library]]<br>
[[Professor's Office->Location_Professor's_Office]]<br>
</div>
<!-- LOCATION PASSAGES --><<nobr>>
<<set $player.current_location = "785d50a5-0b8d-4a89-9e59-5dc20c832dca">>
<<if not $game_state.visited_locations.includes("785d50a5-0b8d-4a89-9e59-5dc20c832dca")>>
<<set $game_state.visited_locations.push("785d50a5-0b8d-4a89-9e59-5dc20c832dca")>>
<</if>>
<</nobr>><h2>City Streets</h2>
<p>A rough neighborhood in a city that doesn't care you're here. Graffiti on brick walls, bars on convenience store windows, a laundromat that's always open, and people who've learned to mind their own business. The bus dropped Emma off here with one suitcase and an address on a piece of paper. Two blocks east is campus. Two blocks in any other direction is someone else's problem.</p>
<<= setup.renderLocationCanvases("785d50a5-0b8d-4a89-9e59-5dc20c832dca")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><a class="location-card link-internal" data-passage="Location_The_Bar"><div class="location-card-image" style="background-image: url('./videos/images/locations/the_bar.jpg')"></div><div class="location-card-content"><span class="location-card-name">The Bar</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("dd25c349-8d42-4c40-b6fa-22c51f22030e")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("dd25c349-8d42-4c40-b6fa-22c51f22030e")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("dd25c349-8d42-4c40-b6fa-22c51f22030e")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Campus"><div class="location-card-image" style="background-image: url('./videos/images/locations/campus.jpg')"></div><div class="location-card-content"><span class="location-card-name">Campus</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("5f31277a-fdf9-4508-83b8-878d3c70e432")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("5f31277a-fdf9-4508-83b8-878d3c70e432")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("5f31277a-fdf9-4508-83b8-878d3c70e432")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Shopping_Mall"><div class="location-card-image" style="background-image: url('./videos/images/locations/mall.jpg')"></div><div class="location-card-content"><span class="location-card-name">Shopping Mall</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("d5e9da7c-0870-4a04-af6a-f279ee5e82ee")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("d5e9da7c-0870-4a04-af6a-f279ee5e82ee")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("d5e9da7c-0870-4a04-af6a-f279ee5e82ee")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a></div><</nobr>>
</div><<nobr>>
<<set $player.current_location = "d5e9da7c-0870-4a04-af6a-f279ee5e82ee">>
<<if not $game_state.visited_locations.includes("d5e9da7c-0870-4a04-af6a-f279ee5e82ee")>>
<<set $game_state.visited_locations.push("d5e9da7c-0870-4a04-af6a-f279ee5e82ee")>>
<</if>>
<</nobr>><h2>Shopping Mall</h2>
<p>A strip mall at the edge of the neighborhood. Half the storefronts are shuttered with plywood and old FOR LEASE signs. Fluorescent light spills from the few places still open. A clothing shop with bright window displays, a check-cashing place with iron bars, and a nail salon that never opened.</p>
<<= setup.renderLocationCanvases("d5e9da7c-0870-4a04-af6a-f279ee5e82ee")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><a class="location-card link-internal" data-passage="Location_Clothing_Shop"><div class="location-card-image" style="background-image: url('./videos/images/locations/clothing_shop.jpg')"></div><div class="location-card-content"><span class="location-card-name">Clothing Shop</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("c9698e80-cd0e-41fa-8186-47627801ae7b")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("c9698e80-cd0e-41fa-8186-47627801ae7b")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("c9698e80-cd0e-41fa-8186-47627801ae7b")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a></div><</nobr>>
<div class="location-nav-exits">
[[Leave Shopping Mall->Location_City_Streets]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "c9698e80-cd0e-41fa-8186-47627801ae7b">>
<<if not $game_state.visited_locations.includes("c9698e80-cd0e-41fa-8186-47627801ae7b")>>
<<set $game_state.visited_locations.push("c9698e80-cd0e-41fa-8186-47627801ae7b")>>
<</if>>
<</nobr>><h2>Clothing Shop</h2>
<p>Racks of cheap fashion under fluorescent lights. Tank tops, skirts, dresses — nothing fancy, but a step up from the hoodie. A bored clerk behind the counter scrolls her phone. Jolene said this place was about leveling up. The price tags say it's about budgeting.</p>
[[Browse Clothes->ShopPage]]<br>
<<= setup.renderLocationCanvases("c9698e80-cd0e-41fa-8186-47627801ae7b")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Clothing Shop->Location_Shopping_Mall]]<br>
</div>
</div><!-- Container with default entry: Auto-redirect -->
<<goto "Location_Bar_Floor">><<nobr>>
<<set $player.current_location = "765d53fe-dbc8-4913-ac21-6c7e88f84617">>
<<if not $game_state.visited_locations.includes("765d53fe-dbc8-4913-ac21-6c7e88f84617")>>
<<set $game_state.visited_locations.push("765d53fe-dbc8-4913-ac21-6c7e88f84617")>>
<</if>>
<</nobr>><h2>Bar Floor</h2>
<p>Long bar top, eight stools, a few tables, a TV showing sports nobody's watching. The lighting is bad on purpose — it hides the stains. Jolene tends bar most nights. Mick stocks and fixes things. The regulars are construction workers, night-shift guys, and people who drink because the alternative is going home. Friday nights it fills up. The rest of the week it's quiet enough to hear the ice crack.</p>
<<= setup.renderLocationCanvases("765d53fe-dbc8-4913-ac21-6c7e88f84617")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><a class="location-card link-internal" data-passage="Location_Stockroom"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_stockroom.jpg')"></div><div class="location-card-content"><span class="location-card-name">Stockroom</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Upstairs"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_upstairs.jpg')"></div><div class="location-card-content"><span class="location-card-name">Upstairs</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("56b3eb44-0389-47c4-827b-c95e53396d5c")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("56b3eb44-0389-47c4-827b-c95e53396d5c")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("56b3eb44-0389-47c4-827b-c95e53396d5c")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Bar_Bathroom"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_bathroom.jpg')"></div><div class="location-card-content"><span class="location-card-name">Bar Bathroom</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("96b068d2-f888-414b-8f1d-773289dde83d")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("96b068d2-f888-414b-8f1d-773289dde83d")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("96b068d2-f888-414b-8f1d-773289dde83d")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a></div><</nobr>>
<div class="location-nav-exits">
[[Exit The Bar->Location_City_Streets]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6">>
<<if not $game_state.visited_locations.includes("1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6")>>
<<set $game_state.visited_locations.push("1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6")>>
<</if>>
<</nobr>><h2>Stockroom</h2>
<p>Behind the bar — cases of beer, spare kegs, cleaning supplies stacked to the ceiling. A single overhead bulb on a pull chain. Mick's domain. Everything has a place and he knows if anything moves.</p>
<<= setup.renderLocationCanvases("1e5170b3-c6f1-4616-9f4c-2aaaf7d0b8c6")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Stockroom->Location_Bar_Floor]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "56b3eb44-0389-47c4-827b-c95e53396d5c">>
<<if not $game_state.visited_locations.includes("56b3eb44-0389-47c4-827b-c95e53396d5c")>>
<<set $game_state.visited_locations.push("56b3eb44-0389-47c4-827b-c95e53396d5c")>>
<</if>>
<</nobr>><h2>Upstairs</h2>
<p>A narrow hallway at the top of creaking stairs. The living room is right there at the top — sagging couch, old TV, the only shared space that isn't a kitchen or a bathroom. Past that, two doors — Emma's room on the left, Jolene and Mick's on the right. Bathroom at the end of the hall. Kitchen past that. The sounds from the bar below come up through the floorboards whether you want them to or not.</p>
<<= setup.renderLocationCanvases("56b3eb44-0389-47c4-827b-c95e53396d5c")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><a class="location-card link-internal" data-passage="Location_Living_Room"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_living_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">Living Room</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("c1f64105-aa05-40c4-b911-5acfabc022ac")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("c1f64105-aa05-40c4-b911-5acfabc022ac")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("c1f64105-aa05-40c4-b911-5acfabc022ac")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Emma's_Room"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_emma_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">Emma's Room</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("e130c8a7-d18f-4145-97da-4838e709881c")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("e130c8a7-d18f-4145-97da-4838e709881c")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("e130c8a7-d18f-4145-97da-4838e709881c")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Jolene_&_Mick's_Room"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_jolene_mick_room.jpg')"></div><div class="location-card-content"><span class="location-card-name">Jolene & Mick's Room</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("63e93307-773f-486d-8901-67c803e81481")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("63e93307-773f-486d-8901-67c803e81481")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("63e93307-773f-486d-8901-67c803e81481")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Kitchen"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_kitchen.jpg')"></div><div class="location-card-content"><span class="location-card-name">Kitchen</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("00f93121-f1fd-4f8a-bffc-f31c66b54956")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("00f93121-f1fd-4f8a-bffc-f31c66b54956")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("00f93121-f1fd-4f8a-bffc-f31c66b54956")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Upstairs_Bathroom"><div class="location-card-image" style="background-image: url('./videos/images/locations/bar_upstairs_bathroom.jpg')"></div><div class="location-card-content"><span class="location-card-name">Upstairs Bathroom</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("48b8eed7-da10-4a2d-a4c9-092b7e38aa53")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("48b8eed7-da10-4a2d-a4c9-092b7e38aa53")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("48b8eed7-da10-4a2d-a4c9-092b7e38aa53")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a></div><</nobr>>
<div class="location-nav-exits">
[[Leave Upstairs->Location_Bar_Floor]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "e130c8a7-d18f-4145-97da-4838e709881c">>
<<if not $game_state.visited_locations.includes("e130c8a7-d18f-4145-97da-4838e709881c")>>
<<set $game_state.visited_locations.push("e130c8a7-d18f-4145-97da-4838e709881c")>>
<</if>>
<</nobr>><h2>Emma's Room</h2>
<p>A rented room above the bar. Single bed, a desk by the window that looks out at a brick wall. The walls are thin — she can hear the bar below, the TV next door, and conversations she wasn't meant to hear. Bathroom's down the hall, shared with Jolene and Mick. It started as the cheapest option. It's become her only option.</p>
[[Change Clothes->WardrobePage]]<br>
<<= setup.renderLocationCanvases("e130c8a7-d18f-4145-97da-4838e709881c")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Emma's Room->Location_Upstairs]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "63e93307-773f-486d-8901-67c803e81481">>
<<if not $game_state.visited_locations.includes("63e93307-773f-486d-8901-67c803e81481")>>
<<set $game_state.visited_locations.push("63e93307-773f-486d-8901-67c803e81481")>>
<</if>>
<</nobr>><h2>Jolene & Mick's Room</h2>
<p>Their room is across the hall from Emma's. Bigger, lived-in, messy in a way that says two people who work sixteen-hour days and don't care about interior design. Jolene's ashtray, Mick's boots by the door, a TV that's always on low. The door is sometimes open, sometimes not.</p>
<<= setup.renderLocationCanvases("63e93307-773f-486d-8901-67c803e81481")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Jolene & Mick's Room->Location_Upstairs]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "96b068d2-f888-414b-8f1d-773289dde83d">>
<<if not $game_state.visited_locations.includes("96b068d2-f888-414b-8f1d-773289dde83d")>>
<<set $game_state.visited_locations.push("96b068d2-f888-414b-8f1d-773289dde83d")>>
<</if>>
<</nobr>><h2>Bar Bathroom</h2>
<p>A single-stall bathroom off the bar floor. Fluorescent light that flickers, a mirror with a crack running through it, graffiti scratched into the stall door. It smells like bleach over everything else. Jolene told her she can use it during the day — 'but don't let the customers catch you in your robe.'</p>
<<= setup.renderLocationCanvases("96b068d2-f888-414b-8f1d-773289dde83d")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Bar Bathroom->Location_Bar_Floor]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "00f93121-f1fd-4f8a-bffc-f31c66b54956">>
<<if not $game_state.visited_locations.includes("00f93121-f1fd-4f8a-bffc-f31c66b54956")>>
<<set $game_state.visited_locations.push("00f93121-f1fd-4f8a-bffc-f31c66b54956")>>
<</if>>
<</nobr>><h2>Kitchen</h2>
<p>A small shared kitchen at the end of the upstairs hallway. Gas stove with a burner that sticks, a fridge with Jolene's wine and Mick's beer, a coffee pot that's always on. The table seats two — barely. Jolene cooks here, smokes here, drinks coffee here. It's where the real conversations happen: morning coffee before the bar opens, late-night wine after it closes.</p>
<<= setup.renderLocationCanvases("00f93121-f1fd-4f8a-bffc-f31c66b54956")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Kitchen->Location_Upstairs]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "48b8eed7-da10-4a2d-a4c9-092b7e38aa53">>
<<if not $game_state.visited_locations.includes("48b8eed7-da10-4a2d-a4c9-092b7e38aa53")>>
<<set $game_state.visited_locations.push("48b8eed7-da10-4a2d-a4c9-092b7e38aa53")>>
<</if>>
<</nobr>><h2>Upstairs Bathroom</h2>
<p>The shared bathroom at the end of the upstairs hallway. Small, functional, always slightly damp. One shower with a curtain that doesn't fully close, a sink with a mirror, a toilet. Hot water takes a minute — bang the pipe twice. Jolene's shampoo on the shelf, Mick's razor by the sink, Emma's dollar-store soap in the corner. Three people, one bathroom, no lock that works.</p>
<<= setup.renderLocationCanvases("48b8eed7-da10-4a2d-a4c9-092b7e38aa53")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Upstairs Bathroom->Location_Upstairs]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "c1f64105-aa05-40c4-b911-5acfabc022ac">>
<<if not $game_state.visited_locations.includes("c1f64105-aa05-40c4-b911-5acfabc022ac")>>
<<set $game_state.visited_locations.push("c1f64105-aa05-40c4-b911-5acfabc022ac")>>
<</if>>
<</nobr>><h2>Living Room</h2>
<p>A small living room at the top of the stairs, before the hallway narrows toward the bedrooms. A sagging couch that's older than Emma, a TV on a milk crate, a window that looks out at the alley. The wallpaper is peeling at the seams. A standing lamp in the corner gives off orange light that makes everything look warmer than it is. Jolene's wine glass rings on the coffee table, Mick's jacket over the arm of the couch, a remote with tape holding the battery cover on. It's where everyone passes through and nobody stays — except late at night, when the bar closes and the building goes quiet.</p>
<<= setup.renderLocationCanvases("c1f64105-aa05-40c4-b911-5acfabc022ac")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Living Room->Location_Upstairs]]<br>
</div>
</div><!-- Container with default entry: Auto-redirect -->
<<goto "Location_Classroom">><<nobr>>
<<set $player.current_location = "3ecba3f2-5b45-41f5-835a-b2d7cb8fd810">>
<<if not $game_state.visited_locations.includes("3ecba3f2-5b45-41f5-835a-b2d7cb8fd810")>>
<<set $game_state.visited_locations.push("3ecba3f2-5b45-41f5-835a-b2d7cb8fd810")>>
<</if>>
<</nobr>><h2>Classroom</h2>
<p>A lecture hall with tiered seating, fluorescent lights, and a whiteboard nobody's cleaned properly since September. Emma sits in the back. The professor talks fast. The students who've been here before already know each other — they share notes, whisper jokes, form study groups that don't include the new girl in the hoodie.</p>
<<= setup.renderLocationCanvases("3ecba3f2-5b45-41f5-835a-b2d7cb8fd810")>>
<div class="location-navigation">
<<nobr>><div class="location-nav-grid"><a class="location-card link-internal" data-passage="Location_Library"><div class="location-card-image" style="background-image: url('./videos/images/locations/campus_library.jpg')"></div><div class="location-card-content"><span class="location-card-name">Library</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("d987513f-8ed3-42c4-ade4-467aa150701d")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("d987513f-8ed3-42c4-ade4-467aa150701d")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("d987513f-8ed3-42c4-ade4-467aa150701d")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a><a class="location-card link-internal" data-passage="Location_Professor's_Office"><div class="location-card-image" style="background-image: url('./videos/images/locations/campus_professor_office.jpg')"></div><div class="location-card-content"><span class="location-card-name">Professor's Office</span><div class="location-card-indicators"><<if setup.locationHasNewCanvases("43064e43-0a21-4041-8e0a-5dedee49153b")>><span class="nav-new-badge">NEW</span><</if>><<if setup.locationHasNewUnlockedChoices("43064e43-0a21-4041-8e0a-5dedee49153b")>><span class="nav-unlocked-badge">🔓</span><</if>><<for _npc range setup.getNpcsWithCanvasesAtLocation("43064e43-0a21-4041-8e0a-5dedee49153b")>><<if _npc.portrait>><img @src="'./videos/' + _npc.portrait" class="nav-npc-badge" @alt="_npc.name"><</if>><</for>></div></div></a></div><</nobr>>
<div class="location-nav-exits">
[[Exit Campus->Location_City_Streets]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "d987513f-8ed3-42c4-ade4-467aa150701d">>
<<if not $game_state.visited_locations.includes("d987513f-8ed3-42c4-ade4-467aa150701d")>>
<<set $game_state.visited_locations.push("d987513f-8ed3-42c4-ade4-467aa150701d")>>
<</if>>
<</nobr>><h2>Library</h2>
<p>Three floors of concrete and quiet. Old computers along the wall, study carrels with scratched desks, and shelves that smell like paper and dust. Closes at 9pm. The third floor is where people go to actually study. The first floor is where people go to pretend. Emma uses both, depending on the day.</p>
<<= setup.renderLocationCanvases("d987513f-8ed3-42c4-ade4-467aa150701d")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Library->Location_Classroom]]<br>
</div>
</div><<nobr>>
<<set $player.current_location = "43064e43-0a21-4041-8e0a-5dedee49153b">>
<<if not $game_state.visited_locations.includes("43064e43-0a21-4041-8e0a-5dedee49153b")>>
<<set $game_state.visited_locations.push("43064e43-0a21-4041-8e0a-5dedee49153b")>>
<</if>>
<</nobr>><h2>Professor's Office</h2>
<p>Second floor of the humanities building, end of the hall. A small office that smells like old paper and coffee. Floor-to-ceiling bookshelves, a heavy wooden desk with stacks of student papers, two chairs — his leather one behind the desk, a smaller one in front for students. The window looks out at the parking lot. A framed diploma on the wall, a photo of a dog, no photo of a wife. The door has a frosted glass panel and a lock that clicks.</p>
<<= setup.renderLocationCanvases("43064e43-0a21-4041-8e0a-5dedee49153b")>>
<div class="location-navigation">
<div class="location-nav-exits">
[[Leave Professor's Office->Location_Classroom]]<br>
</div>
</div>
<!-- STORY CANVAS PASSAGES --><p>1:07 AM. Emma is lying in bed staring at the ceiling. The water stain is shaped like a hand — she noticed that weeks ago and now she can't unsee it. The bar closed an hour ago. The building has settled into its late-night breathing — pipes cooling, wood contracting, the ice machine downstairs doing its periodic dump.</p><p>Her door is cracked open. Three inches. Enough to let the hallway light make a thin line across the floor.</p><p>She doesn't know if she left it that way on purpose. She's been telling herself she didn't. She's been telling herself a lot of things lately.</p><p>The floorboard creaks.</p><p>The same floorboard. The one outside the bathroom. The one that groans when someone steps on it — someone heavy, someone trying to be quiet and failing because this building was built before anyone cared about sound.</p><p>She holds her breath. Listens. No footsteps continuing down the hall. No door opening. He's stopped. Right outside her room.</p><p>Her heart is hammering. Not from fear. From the knowledge that she left that door open and he's standing on the other side of it and they both know why.</p><img src="./videos/images/story/story_room_the_night_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "a62d5614-83e7-48b7-8da0-ce2f0a3203ae">>
<<set $game_state.current_node = "182472e6-a41f-493c-9e7e-c0264fe7ff40">>
<<script>>setup.markCanvasTriggered("a62d5614-83e7-48b7-8da0-ce2f0a3203ae");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_the_night.n1") === -1) { vn.push("story_room_the_night.n1"); }<</script>>
<<nobr>>
<<link "Leave it open" "Canvas_story_room_the_night_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The door moves. Slowly. The hallway light widens across the floor like a blade and then his shadow fills it.</p><p>Mick stands in the doorframe. T-shirt, sweatpants, bare feet. His hair is messed from lying down and his eyes are dark and he's looking at her the way he looked at her the first time she dropped her towel — like he's deciding something. Like he's been deciding it for weeks and just now made up his mind.</p><p>She's in a t-shirt and shorts. No bra. The sheet is pulled to her waist. She doesn't pull it higher.</p><p>Neither of them speaks. The building speaks for them — the ice machine, the pipes, the distant hum of the city through the window that looks at a brick wall.</p><p>He steps inside. Closes the door behind him. The hallway light disappears and the room goes dark except for the streetlight glow leaking through the curtain.</p><p>The mattress dips when he sits on the edge. The bed is too small — a single, barely enough for one person, and his weight tilts her toward him like the couch used to.</p><p>His hand finds her knee. Above the sheet. His palm is warm and rough and it's the first time he's touched her first. Every other time — the couch, the counter, the stockroom, the shower — she started it. She reached. She initiated. She led.</p><p>This time he came to her door.</p><img src="./videos/images/story/story_room_the_night_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "a62d5614-83e7-48b7-8da0-ce2f0a3203ae">>
<<set $game_state.current_node = "d182411c-d921-4670-bd3c-71457928c4af">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_the_night.n2") === -1) { vn.push("story_room_the_night.n2"); }<</script>>
<<nobr>>
<<link "Pull him down" "Canvas_story_room_the_night_Node_3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She reaches up and grabs the front of his t-shirt. Pulls. He doesn't resist — he falls forward, catching himself with one hand on either side of her head, his body over hers, his face inches away.</p><p>She can smell him. Soap and sweat and the faint whiskey that's part of his skin now. She pulls his shirt over his head. He helps — lifts his arms, the fabric catches on his chin for a second, and then he's bare above her and she can feel the heat radiating off his chest.</p><p>He pulls her shirt off. Slowly. Like he's unwrapping something he doesn't believe he's allowed to have. His hands trace down her sides — ribs, waist, the curve of her hips — and she arches into his touch.</p><p>His mouth finds her neck. Her collarbone. The hollow above her sternum where her pulse is visible. She can feel his stubble against her skin and his breath hot and uneven and his hands aren't steady — they're shaking. Mick's hands, that carry kegs and fix pipes, are shaking.</p><p>She pushes his sweatpants down. He kicks them off the end of the bed. She pulls her shorts off and throws them somewhere — the desk, the floor, it doesn't matter.</p><p>He settles between her legs. Heavy. The full weight of him pressing her into the mattress. She can feel him against her thigh — hard, thick, the same cock she's held in her hand and tasted in her mouth, but this is different. This is the line they've been walking toward since the first night she heard them through the wall.</p><p>He enters her. Slowly. She gasps — not from pain, from the fullness of it, from the way he fills her completely, from the way her body stretches around him and her nails dig into his back and the single bed creaks in protest.</p><p>He moves slow at first. Careful. Like he's afraid of breaking something — the bed, the building, whatever this is between them. Each thrust is deliberate, controlled, his arms braced on either side of her, his jaw set.</p><p>She wraps her legs around him. Pulls him deeper. Her heels dig into the small of his back — the same place Jolene's heels dug in, that night Emma watched through the cracked door — and she thinks about that for one second before the thought dissolves because he stops being careful.</p><p>The headboard hits the wall. Once. Twice. A rhythm that's impossible to mistake for anything else. The thin wall between Emma's room and the hallway, the hallway and Jolene's room. Twenty feet of plaster and wood between this bed and Jolene's bed.</p><p>She pulls his head down and kisses him to keep from making a sound. He groans into her mouth. The bed frame protests. The headboard taps the wall and she reaches up and grabs it with one hand to stop the noise and holds on while he drives into her.</p><p>She comes. It builds from somewhere deep and breaks through her whole body like a wave — her back arches off the mattress, her legs tighten around him, she bites his shoulder and tastes salt and feels the shudder run through her from her core to her fingertips.</p><p>He follows. She feels it — the swell, the pulse, the heat inside her. His whole body goes rigid above her and the sound he makes is low and broken and he says her name into her neck. Emma. The way he said it behind the bar. Like it costs him something.</p><video src="./videos/story/story_room_the_night_n3.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "a62d5614-83e7-48b7-8da0-ce2f0a3203ae">>
<<set $game_state.current_node = "b66df7e6-260f-4f63-a072-99e423dbfcbf">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_the_night.n3") === -1) { vn.push("story_room_the_night.n3"); }<</script>>
<<nobr>>
<<link "After" "Canvas_story_room_the_night_Node_4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>He lies there. One arm across her stomach. His breathing slowing. The room smells like sweat and sex and the cheap soap from the bathroom down the hall.</p><p>The single bed is too narrow for two people. His leg hangs off the edge. Her shoulder is pressed against the wall. Neither of them moves to fix it.</p><p>She traces a scar on his forearm she never noticed before. Two inches long, white against the tan. She doesn't ask how he got it. She runs her finger along it like she's reading braille.</p><p>Five minutes. Maybe ten. The ice machine downstairs cycles. A car passes on the street below. The building breathes around them.</p><p>He gets up. Sits on the edge of the bed. She watches his back — the muscles, the shoulder blades, the way his spine curves as he leans forward and puts his head in his hands for a moment.</p><p>He puts on his clothes. T-shirt. Sweatpants. Stands at the door. His hand on the knob.</p><p>He doesn't say goodnight. He looks at her — lying in the tangle of sheets, her hair spread across the pillow, the streetlight catching the sheen of sweat on her skin — and something moves behind his eyes. Not guilt. Not regret. Something bigger than both.</p><p>Then he's gone. The door clicks shut. His footsteps in the hallway. The floorboard creaks. His door opens and closes.</p><p>She lies there. The sheets smell like him. She pulls them up to her chin and breathes him in and stares at the water stain on the ceiling — the one shaped like a hand — and her body is still humming and her heart is still slamming and she doesn't change the sheets.</p><p>She won't change them for days.</p><img src="./videos/images/story/story_room_the_night_n4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "a62d5614-83e7-48b7-8da0-ce2f0a3203ae">>
<<set $game_state.current_node = "3c7aafc8-5e24-4a89-9f7d-3675132085ec">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_the_night.n4") === -1) { vn.push("story_room_the_night.n4"); }<</script>>
<<nobr>>
<<link "Close your eyes" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mick_sex");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "sex_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>12:47 AM. The last regular — Dave, who always has to be told twice — finally pushes off his stool and shuffles toward the door. Jolene locks it behind him and flips the neon sign off. The B stops flickering. The bar goes dark except for the work lights behind the counter.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> I'm dead on my feet. You two finish up?</div></div><p>She's already untying her apron. She doesn't wait for an answer. Her footsteps on the stairs, the hallway, the bedroom door. Then quiet.</p><p>Emma and Mick are alone. The bar stretches out in front of them — empty stools, sticky tables, glasses that need collecting. The jukebox is dark. The only sounds are the ice machine humming and the tap dripping.</p><p>They clean up. It's routine now — she does the tables, he does the bar. She collects glasses and brings them to the sink. He wipes down the counter and restocks the napkin holders. They move around each other in the dim light like two people who've done this a hundred times.</p><p>Except tonight the air is different. Heavier. Every time she passes behind him to drop glasses in the sink, her hip brushes his back. Every time he reaches past her for a bottle, his arm touches hers. Neither of them apologizes. Neither of them adjusts.</p><img src="./videos/images/story/story_bar_the_counter_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "730544bc-5c9b-4348-b515-32159c0f01f4">>
<<set $game_state.current_node = "f2e09be2-40fe-4cf9-9850-eed737f2655a">>
<<script>>setup.markCanvasTriggered("730544bc-5c9b-4348-b515-32159c0f01f4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_the_counter.n1") === -1) { vn.push("story_bar_the_counter.n1"); }<</script>>
<<nobr>>
<<link "Keep cleaning" "Canvas_story_bar_the_counter_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She's behind the counter now. Putting glasses on the rack. He's next to her, drying a pint glass with a rag. The space behind the bar is narrow — three feet wide, maybe less. Their shoulders keep touching.</p><p>She can smell him. Not cologne — Mick doesn't wear cologne. Just soap and sweat and the faint trace of whiskey that's soaked into his skin from seventeen years of pouring it.</p><p>She puts a glass on the shelf and her hand stays there. Resting on the wood. He's drying the same pint glass he's been drying for thirty seconds.</p><p>They both know what's happening. They've known since Jolene walked up those stairs. Since before that. Since she sat down next to him on the couch. Since she heard him breathing through the bathroom door. Since the beginning.</p><p>She looks at him. He looks at her. The work lights throw shadows across his face and she can see the lines around his eyes and the grey at his temples and the way his jaw is set like he's holding something back with his teeth.</p><p>She drops to her knees.</p><video src="./videos/images/story/story_bar_the_counter_n2.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "730544bc-5c9b-4348-b515-32159c0f01f4">>
<<set $game_state.current_node = "9e42d0ad-8994-4cb1-9268-908d78a6d102">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_the_counter.n2") === -1) { vn.push("story_bar_the_counter.n2"); }<</script>>
<<nobr>>
<<link "Get on your knees" "Canvas_story_bar_the_counter_Node_3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The floor behind the bar is sticky under her knees. Beer and sugar syrup and seventeen years of spilled drinks. She can feel it through her jeans and she doesn't care.</p><p>The counter hides her completely. If someone looked through the window right now they'd see Mick standing behind the bar, alone, maybe having a drink after closing. They wouldn't see Emma on her knees in front of him.</p><p>She undoes his belt. He doesn't help. He doesn't stop her. His hands grip the edge of the bar top — the same bar top he's leaned on every night for seventeen years — and his knuckles go white.</p><p>She pulls him free. He's hard. She wraps her hand around the base and feels him pulse against her palm and she looks up at him. From down here he's enormous — his chest, his arms, his jaw clenched above her.</p><p>She takes him in her mouth.</p><p>The taste of him fills her — salt and heat and something musky that she's still learning. She takes him deeper, finding the angle, adjusting, her lips stretching around the thickness of him. It's different than upstairs. Down here, on this sticky floor, behind this bar, it feels like they're doing something that can't be undone.</p><p>She finds her rhythm. Her hand and her mouth working together, wet and tight. She can hear the ice melting in the sink above her — tiny cracks and shifts — and the tap dripping and his breathing getting rougher, louder, filling the empty bar.</p><p>His hand comes off the bar top and rests on her head. His fingers thread through her hair. Not pushing. Guiding. Gentle in a way that surprises her — this man who carries kegs and fixes pipes and says four words a day, touching her hair like she's something fragile.</p><p>She takes him deeper. His hips move forward — a controlled thrust, not rough, but insistent — and she adjusts, breathing through her nose, letting him set a pace she follows. The bar creaks above her. The work light buzzes.</p><p>His breathing becomes ragged. His fingers tighten in her hair. She can feel him swelling against her tongue, feel the tension coiling through his legs, his stomach, his whole body going rigid.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Emma —</div></div><p>Her name. The first time he's said her name like that — not calling her downstairs, not telling her the rent is due, but saying it like a warning and a prayer at the same time.</p><p>She doesn't pull back. She takes him as deep as she can and feels him come — the first pulse hot and thick on her tongue, then another, and another, his whole body shuddering above her while he grips the bar with one hand and her hair with the other and the sound he makes is low and broken and it echoes off the empty bottles on the shelf.</p><p>She swallows. Keeps her mouth on him until the last pulse fades. Then she lets him go and sits back on her heels and wipes her mouth with the back of her hand.</p><video src="./videos/story/story_bar_the_counter_n3.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "730544bc-5c9b-4348-b515-32159c0f01f4">>
<<set $game_state.current_node = "a33e1cf9-28fa-4627-bc4f-bd3d27c8bacf">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_the_counter.n3") === -1) { vn.push("story_bar_the_counter.n3"); }<</script>>
<<nobr>>
<<link "Stand up" "Canvas_story_bar_the_counter_Node_4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She stands up. Her knees crack. There are marks on them — red impressions from the rubber bar mat. Her jaw aches. Her lips are swollen.</p><p>He's leaning against the counter like it's the only thing holding him up. His eyes are closed. He opens them and looks at her and there's something in his face she hasn't seen before — not just satisfaction, not just guilt, but something raw and unguarded. Like a wall just came down.</p><p>Neither of them says anything. He fixes his belt. She picks up the rag he dropped and finishes wiping down the counter.</p><p>They clean up the rest of the bar in silence. She puts the last glasses in the rack. He empties the register. The routine absorbs what just happened like the floor absorbs spilled beer — it's there, soaking in, becoming part of the building.</p><p>She unties her apron and hangs it on the hook by the kitchen door. Walks toward the stairs.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Emma.</div></div><p>She stops. Turns. He's standing behind the bar, one hand on the light switch.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Good night.</div></div><p>Two words. But the way he says them — slow, quiet, like he's tasting each one — they mean more than every sentence he's said to her combined.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Good night.</div></div><p>She goes upstairs. He locks the front door and kills the lights. The bar goes dark. The ice machine hums.</p><p>In her room she sits on the edge of the bed and touches her lips. She can still taste him. She can still hear the way he said her name — Emma — like it was the only word he knew.</p><p>The girl who arrived here with a suitcase and $500 is gone. She's been gone for a while. The woman sitting on this bed knows things that girl couldn't have imagined. And she's not done learning.</p><img src="./videos/images/story/story_bar_the_counter_n4.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "730544bc-5c9b-4348-b515-32159c0f01f4">>
<<set $game_state.current_node = "026ed176-e30f-48cf-90a8-4b563adb6e8e">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_the_counter.n4") === -1) { vn.push("story_bar_the_counter.n4"); }<</script>>
<<nobr>>
<<link "Good night" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "gave_blowjob");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "blowjob_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>1:14 AM. Emma is staring at the water stain on her ceiling. She's been staring at it for an hour. The bar is closed. The building is quiet. Sleep isn't coming.</p><p>She gets up. T-shirt and shorts — the short ones, the ones she doesn't think about putting on anymore, they're just what she sleeps in now. Bare feet on the cold floor.</p><p>She walks down the hallway toward the living room. The floorboards creak under her steps and she doesn't try to be quiet. She gave up being quiet in this building weeks ago.</p><p>The TV is on. The blue glow spills into the hallway before she turns the corner.</p><p>Mick is on the couch.</p><img src="./videos/images/story/story_living_room_the_couch_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6b532c12-4e36-493b-8bdb-11316a890619">>
<<set $game_state.current_node = "2c503452-c81d-43a0-8098-a2b40c147170">>
<<script>>setup.markCanvasTriggered("6b532c12-4e36-493b-8bdb-11316a890619");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_couch.n1") === -1) { vn.push("story_living_room_the_couch.n1"); }<</script>>
<<nobr>>
<<link "Sit down" "Canvas_story_living_room_the_couch_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>He's sitting in the middle of the sagging couch. T-shirt, sweatpants, bare feet on the coffee table. A beer on the armrest, half-finished. The TV is playing something with a laugh track — he's not watching it. He's looking at nothing.</p><p>He glances up when she appears in the doorway. Doesn't say anything. Goes back to looking at nothing.</p><p>She doesn't ask if it's okay. She walks in and sits down. Not on the other end of the couch. Not in the middle, exactly. But close enough that if either of them shifted three inches their legs would touch.</p><p>The couch sags toward the center. Toward him. She can feel the slope of the cushion pulling her closer, like the furniture itself has decided something.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Can't sleep?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> No.</div></div><p>That's all. Neither of them says anything else. The TV talks for them. A woman in a sitcom makes a joke. The laugh track rolls. The orange lamp throws warm light across the room and their arms are six inches apart on the couch cushion.</p><p>They both know what happened in the bathroom. They both know what the other one was doing. They haven't said a word about it. They haven't been alone together since. Until now.</p><img src="./videos/images/story/story_living_room_the_couch_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6b532c12-4e36-493b-8bdb-11316a890619">>
<<set $game_state.current_node = "177fa7f7-836d-4d69-9800-825436ecb469">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_couch.n2") === -1) { vn.push("story_living_room_the_couch.n2"); }<</script>>
<<nobr>>
<<link "Stay" "Canvas_story_living_room_the_couch_Node_3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Five minutes. Ten. The sitcom changes to an infomercial. A man on the screen is selling a blender with the enthusiasm of someone describing a miracle. Neither of them reaches for the remote.</p><p>The couch sags and their legs are touching now. His thigh against hers. The warmth of his skin through the fabric of his sweatpants against her bare leg. Neither of them moves away.</p><p>She's hyperaware of the point of contact. Every nerve in her leg is focused on the three inches where his body meets hers. The heat of it. The weight. The fact that he hasn't shifted, hasn't pulled his leg away, hasn't done the polite thing and given her space.</p><p>The infomercial man demonstrates the blender. He pulverizes a banana. The audience gasps.</p><p>Her hand is on her own thigh. His hand is on his. They're both staring at the TV and neither of them is seeing it.</p><p>Her pinky finger moves. Half an inch to the right. It touches the side of his hand. The back of his index finger. She feels him tense — a micro-movement, his whole body going still for one second — and then he exhales. Slowly. Through his nose. And he doesn't move his hand.</p><img src="./videos/images/story/story_living_room_the_couch_n3.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6b532c12-4e36-493b-8bdb-11316a890619">>
<<set $game_state.current_node = "6cb66716-7864-4e84-b61a-5def04d8e2a8">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_couch.n3") === -1) { vn.push("story_living_room_the_couch.n3"); }<</script>>
<<nobr>>
<<link "Touch him" "Canvas_story_living_room_the_couch_Node_4">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Her fingers move over his hand. Slowly. Tracing the back of his knuckles — rough skin, thick fingers, the hand of a man who carries kegs and tightens pipes and hasn't been touched like this by anyone but his wife in years.</p><p>His breathing changes. She can hear it over the infomercial. Deeper. Controlled the way it was controlled outside the bathroom door — deliberately even, deliberately slow, like he's trying to keep his body from doing what his body wants to do.</p><p>Her fingers slide between his. Their hands interlock on the couch cushion between them. His grip tightens — involuntary, strong — and she feels the calluses on his palm against the back of her hand.</p><p>Neither of them looks at the other. They both stare at the TV. The blender man is slicing through a block of ice. The audience applauds.</p><p>His thumb strokes the side of her hand. Once. Her breath catches.</p><p>Her hand moves. Leaves his fingers and slides onto his thigh. Over the sweatpants. She feels the muscle underneath — dense, warm, his quadricep tensing under her palm. She doesn't look at him. She looks at the man selling blenders.</p><p>Her hand moves higher.</p><video src="./videos/images/story/story_living_room_the_couch_n4.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6b532c12-4e36-493b-8bdb-11316a890619">>
<<set $game_state.current_node = "d0eac381-7bcd-4f55-83dd-71cd1f592dac">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_couch.n4") === -1) { vn.push("story_living_room_the_couch.n4"); }<</script>>
<<nobr>>
<<link "Keep going" "Canvas_story_living_room_the_couch_Node_5">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Her fingers find him through the sweatpants. He's hard. She knew he would be — she could feel the tension radiating off him like heat from an engine — but the reality of it makes her breath stop. The shape of him under her hand. The size. Thick and rigid and straining against the cotton.</p><p>His whole body goes rigid. His hand grips the armrest of the couch. His jaw clenches and she can see the muscle in his cheek flex from the corner of her eye.</p><p>She wraps her fingers around him through the fabric. Squeezes. Slowly. He exhales — a long, shaking breath that sounds like something breaking.</p><p>The blender man is talking about payment plans. Three easy installments.</p><p>Her hand slides under the waistband of his sweatpants. No underwear. Her fingers find bare skin — hot, impossibly hard, the head already slick. She wraps her hand around the shaft and feels the weight of him, the thickness, the way he throbs against her palm.</p><p>He makes a sound. Low. In the back of his throat. The kind of sound a man makes when he's been holding his breath for weeks and someone finally touched him.</p><p>She starts to move her hand. Slowly. Up. Down. Her grip tight enough to feel every ridge, every vein, the way his cock pulses against her fingers. She finds a rhythm — steady, deliberate, the way she would turn a page or take a note, methodical, like she's studying this too.</p><p>They don't look at each other. They look at the TV. The infomercial has become a nature documentary. A lion sleeps in tall grass. The narrator's voice is calm and British and completely unaware of what's happening on this couch.</p><video src="./videos/story/story_living_room_the_couch_n5.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6b532c12-4e36-493b-8bdb-11316a890619">>
<<set $game_state.current_node = "31a7c788-a2c5-48a9-97b6-6d855d9c7711">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_couch.n5") === -1) { vn.push("story_living_room_the_couch.n5"); }<</script>>
<<nobr>>
<<link "Finish him" "Canvas_story_living_room_the_couch_Node_6">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>His breathing gets ragged. Her hand moves faster. She can feel him getting closer — the way his cock swells in her grip, the way his hips start to push forward against her hand, small movements he can't control.</p><p>His hand finds her knee. Grips it. Hard. His fingers dig into her bare skin and she feels the desperation in it — not a grab, not a push, just a man holding onto something because he's about to let go of everything else.</p><p>She tightens her grip. Twists her wrist on the upstroke the way the videos taught her. His head tips back against the couch cushion. His eyes close. His mouth opens.</p><p>He comes. She feels it — the pulse first, deep and strong, then the warmth flooding over her fingers, his cock jerking in her hand in rhythmic spasms. He groans — low, strangled, bitten off — and his grip on her knee tightens until it almost hurts and his hips thrust up once, twice, and then he goes still.</p><p>The lion on TV yawns.</p><p>She keeps her hand on him for another five seconds. Feels the last pulse. Feels him soften, just slightly, still thick in her grip. Then she pulls her hand out of his sweatpants.</p><p>Her fingers are wet. She wipes them on the blanket she wrapped around her knees earlier. Her hand is shaking. Not from disgust or shock — from adrenaline. From the raw, electric fact of what she just did.</p><p>She stands up. Her legs are weak and she can feel her own pulse between them — heavy, insistent, unanswered.</p><p>She doesn't look at him. She walks out of the living room, down the hallway, into her room. Closes the door. Leans against it.</p><p>She holds her hand up in the dark. The hand that just made a forty-seven-year-old man come on a couch while a nature documentary played and his wife slept twenty feet away.</p><p>Her heart is slamming. Her face is burning. She can still feel the shape of him against her palm. She can still hear that groan — the one he tried to swallow and couldn't.</p><p>She washes her hands in the hallway bathroom. The water runs and she watches it and she doesn't feel guilty. She doesn't feel ashamed. She feels powerful. She feels like she just crossed a line she's been walking toward since the first time she heard them through the wall.</p><p>There was a girl who arrived in this city with a suitcase and a dream. That girl would not recognize the woman washing her hands right now. That girl wouldn't understand.</p><p>This woman does.</p><img src="./videos/images/story/story_living_room_the_couch_n6.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6b532c12-4e36-493b-8bdb-11316a890619">>
<<set $game_state.current_node = "75547717-e771-4174-8236-f6bd32470efa">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_couch.n6") === -1) { vn.push("story_living_room_the_couch.n6"); }<</script>>
<<nobr>>
<<link "No going back" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "touched_mick");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "handjob_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>The shower is running and the bathroom mirror is fogged at the edges. Emma can see herself in the clear center — shoulders, collarbone, the water streaming down between her breasts. She's taking her time tonight. Letting the hot water work.</p><p>The bathroom door doesn't lock. She knows this. Everyone knows this.</p><p>She hears it — the faintest creak of the floorboard outside the door. The one that always groans when someone steps on it. She freezes. Listens. No footsteps walking away. No door opening down the hall. Just silence on the other side of the door.</p><p>Someone is standing outside the bathroom.</p><p>The shower curtain is half-open. The mirror faces the door. If the door opened even two inches, whoever was on the other side could see her reflection — all of her, wet, lit by the overhead light.</p><p>She hears breathing. Slow. Controlled. The kind of breathing a man does when he's trying to be quiet.</p><p>Mick.</p><p>Her heart is pounding but she doesn't reach for the curtain. She doesn't call out. She stands in the hot water and looks at herself in the fogged mirror and knows he can see her and she lets him.</p><p>She hears his breath change. Rougher. A faint rhythm she recognizes from nights listening through the wall — except this time Jolene isn't with him. This time it's because of her.</p><p>Her hand moves down her stomach. Past her navel. She watches herself in the mirror as she touches herself and she knows he's watching too. The steam curls between them like a curtain that hides nothing.</p><p>She doesn't close her eyes. She watches her own face in the mirror as her fingers find the rhythm and she listens to his breathing getting faster on the other side of the door and she comes with his name caught between her teeth, silent, her legs shaking under the hot water.</p><p>She hears the floorboard creak again. Footsteps. His door closing softly down the hall.</p><p>She stands in the shower for a long time after that. The water turns cold and she doesn't move. Something just changed between them and there is no going back.</p><video src="./videos/story/story_bathroom_the_mirror_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6fc57abe-a4f6-49e9-9412-41add28b91fd">>
<<set $game_state.current_node = "2485b329-0e2c-41ff-917d-e2cda6e57a0e">>
<<script>>setup.markCanvasTriggered("6fc57abe-a4f6-49e9-9412-41add28b91fd");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bathroom_the_mirror.base") === -1) { vn.push("story_bathroom_the_mirror.base"); }<</script>>
<<nobr>>
<<link "No going back" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "caught_mick");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma opens the bathroom door. Steam billows out around her. She's wrapped in a towel — just the one, barely tucked, still damp from the shower. Her hair is wet against her neck and shoulders.</p><p>Mick is in the hallway. Coming out of his room. They're face to face.</p><p>She planned this. She heard him moving in his room, timed it, opened the door at exactly the right moment. The towel is tucked loosely on purpose. She practiced the tuck.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Oh — sorry, I didn't know you were —</div></div><p>She lets the sentence trail off. She lets him look. The towel covers her from chest to mid-thigh but it's clinging to her wet skin and the outline of her body is unmistakable — the swell of her breasts pushing against the terry cloth, her waist, the curve of her hips.</p><p>Then the towel slips. She knew it would — she tucked it loose. It drops from her chest and catches on her hips for one second before she grabs it.</p><p>One second. Long enough. He sees everything from her collarbone to her navel — her breasts, bare and wet, nipples hard from the cool hallway air. Small, firm, perfectly shaped. Water droplets on her skin catching the light.</p><p>She pulls the towel up. Clutches it against her chest. Her face is flushed — partly manufactured, partly real, because his eyes went wide for a fraction of a second and she saw him look and she felt it everywhere.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Shit. Sorry.</div></div><p>He clears his throat. His hand goes to the back of his neck.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> No — it's. Yeah. No worries.</div></div><p>He's flustered. Mick is flustered. The man who has run this bar for seventeen years and doesn't do small talk and doesn't react to anything is flustered because a twenty-year-old girl dropped her towel in front of him.</p><p>He turns and walks to his room. Faster than normal. She watches him go and she's shaking — not from the cold. From the power of it.</p><img src="./videos/images/random/random_hallway_towel_base.gif" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "c6c01389-3d04-44a6-8c3d-ad3f319e7ff0">>
<<set $game_state.current_node = "4c3f6293-df58-4571-8e85-2f892caac5a5">>
<<script>>setup.markCanvasTriggered("c6c01389-3d04-44a6-8c3d-ad3f319e7ff0");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_hallway_towel.base") === -1) { vn.push("random_hallway_towel.base"); }<</script>>
<<nobr>>
<<link "Go to your room" "Location_Upstairs">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>The kitchen smells like coffee and burnt toast. Mick is at the table — plate, mug, newspaper he's not really reading. He's in a t-shirt and jeans. His hair is still damp from the shower. His forearms are on the table, thick and tanned, and Emma tries not to look at them.</p><p>She pours herself coffee. Sits across from him. The table is small — their knees are almost touching.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Morning.</div></div><p>One word. That's Mick. She sips her coffee and lets the silence be normal.</p><img src="./videos/images/activities/activity_mick_breakfast_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "01bfbfdf-c85a-4e4c-9dca-a6f3e2f61764">>
<<script>>setup.markCanvasTriggered("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.base") === -1) { vn.push("activity_mick_breakfast.base"); }<</script>>
<<if ndef $game_state.loop_count>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><</if>>
<<nobr>>
<<link "Chat" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if not $game_state.loop_visited.includes("bfd32d1e-6163-4066-bc18-d3b97bd406a2")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 65}, {"type": "flag", "subject": "player", "flag_key": "learned_seduction", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_mick", "trait_key": "love", "operator": "gte", "value": 8}]})>>
<span @class="setup.isChoiceVisited('6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc0') ? '' : 'unlocked-choice'">
<<link "Flirt" "Canvas_activity_mick_breakfast_Node_2">><<script>>setup.markChoiceVisited("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc0");<</script>><<run $game_state.loop_visited.push("bfd32d1e-6163-4066-bc18-d3b97bd406a2")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("83c67f79-ecd3-4bc0-b61b-2f9b3094358d")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 90}, {"type": "flag", "subject": "player", "flag_key": "discovered_teasing", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc1') ? '' : 'unlocked-choice'">
<<link "Tease him" "Canvas_activity_mick_breakfast_Node_4">><<script>>setup.markChoiceVisited("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc1");<</script>><<run $game_state.loop_visited.push("83c67f79-ecd3-4bc0-b61b-2f9b3094358d")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("12053826-af7c-4b60-a6a5-15b3d2a27b88")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 120}, {"type": "flag", "subject": "player", "flag_key": "first_kiss_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc2') ? '' : 'unlocked-choice'">
<<link "Kiss him" "Canvas_activity_mick_breakfast_Node_3">><<script>>setup.markChoiceVisited("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc2");<</script>><<run $game_state.loop_visited.push("12053826-af7c-4b60-a6a5-15b3d2a27b88")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "touched_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc3') ? '' : 'unlocked-choice'">
<<link "Give him a handjob" "Canvas_activity_mick_breakfast_Node_5">><<script>>setup.markChoiceVisited("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc3");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "gave_blowjob", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc4') ? '' : 'unlocked-choice'">
<<link "Give him a blowjob" "Canvas_activity_mick_breakfast_Node_6">><<script>>setup.markChoiceVisited("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc4");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "mick_sex", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc5') ? '' : 'unlocked-choice'">
<<link "On the table" "Canvas_activity_mick_breakfast_Node_7">><<script>>setup.markChoiceVisited("6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962:cc5");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>Emma holds her coffee mug in both hands and looks at him over the rim. She doesn't look away when he glances up.</p><p>She asks him something about the bar. Something easy. She doesn't care about the answer — she cares about keeping him talking so she can watch his mouth move. He has a good mouth. She never noticed that before. Strong jaw, lips that are fuller than she expected.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> You're up early.</div></div><p>She smiles. Not the polite smile. The one she practiced in the mirror. The one that says something.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Couldn't sleep. Kept thinking about things.</div></div><p>She lets the word 'things' hang there. She reaches across the table for the sugar — she doesn't take sugar in her coffee — and lets her fingers brush the back of his hand as she pulls it toward her.</p><p>He looks at her hand on his. Two seconds. He doesn't pull away.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Sugar's behind you.</div></div><p>His voice is the same flat tone but his eyes stay on her a beat longer than they used to.</p><img src="./videos/images/activities/activity_mick_breakfast_flirt.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "bfd32d1e-6163-4066-bc18-d3b97bd406a2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.flirt") === -1) { vn.push("activity_mick_breakfast.flirt"); }<</script>>
<<nobr>>
<<link "Finish coffee" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "flirt_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_mick_breakfast_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "flirt_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>She reaches across the table for the sugar. Stops halfway. Looks at him.</p><p>Leans further. Past the coffee cups, past the plates. Kisses him over the breakfast table.</p><p>He tastes like black coffee. His stubble scratches her chin. He leans in for a second — then pulls back, pushes his chair from the table.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Your eggs are getting cold.</div></div><p>She smiles and goes back to eating. The eggs are fine. Everything is fine.</p><img src="./videos/activities/activity_mick_breakfast_kiss.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "12053826-af7c-4b60-a6a5-15b3d2a27b88">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.kiss") === -1) { vn.push("activity_mick_breakfast.kiss"); }<</script>>
<<nobr>>
<<link "Finish breakfast" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_mick_breakfast_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>Emma came downstairs in a thin white tank top. No bra. She made that decision in her room, standing in front of the mirror, and she's not second-guessing it.</p><p>She walks to the counter. The kitchen is cold in the morning and her nipples are hard — pressing against the thin cotton, clearly visible, two dark points that she knows he can see from where he's sitting.</p><p>She pours coffee. Stretches to reach the mug on the top shelf — the one she always uses, the one she specifically put on the top shelf last night. Her tank top rides up past her navel. She holds the stretch for a second longer than necessary.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Can never reach that one.</div></div><p>She turns around. He's looking. His eyes are on her chest — quick, then up to her face, but the dip happened and they both know it.</p><p>She sits across from him. Leans forward on her elbows. The tank top hangs and he can see straight down the neckline — the curve of her breasts, the shadow between them, the hard points of her nipples through the fabric.</p><p>She asks him about his day. Keeps leaning. Keeps the eye contact. He answers in short sentences and his eyes don't go below her face again but his jaw is tighter than it was five minutes ago.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> You okay? You seem tense.</div></div><p>She takes a sip of coffee. Slow. Looks at him over the rim. She can feel the power of it — the knowing, the deliberate, the watching him try not to look.</p><img src="./videos/activities/activity_mick_breakfast_tease.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "83c67f79-ecd3-4bc0-b61b-2f9b3094358d">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.tease") === -1) { vn.push("activity_mick_breakfast.tease"); }<</script>>
<<nobr>>
<<link "Finish breakfast" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_mick_breakfast_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>Emma picks up her coffee and moves around the table. Pulls her chair next to his. Close. Their shoulders almost touching.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Let me see the paper.</div></div><p>He slides the newspaper toward her without looking up. She leans in like she's reading. Their thighs press together under the table — her bare leg against his jeans.</p><p>Her hand drops to his thigh. Casual. Like she's resting it there. He goes still. The coffee steams between them. The kitchen clock ticks.</p><p>Her hand moves higher. Over the denim. Slowly. She can feel the muscle tense under her fingers, feel his breathing change — that same controlled exhale she knows so well now.</p><p>She undoes his belt under the table. The metal clinks softly. She pops the button. Slides the zipper down. Her hand goes inside and finds him — already hard, straining against the cotton of his boxers.</p><p>She pulls him free and wraps her hand around him. He makes a sound — a short, cut-off inhale — and grips the edge of the table with both hands.</p><p>She strokes him under the table while they both stare at the newspaper. The headlines blur. Her hand moves in a steady rhythm and she can feel him swelling, throbbing, his hips pushing forward in small involuntary movements that rock the chair.</p><p>The coffee gets cold. The morning light comes through the kitchen window and falls across the table and their hands and the newspaper neither of them is reading. Somewhere downstairs Jolene is unlocking the bar.</p><p>He comes. She feels the tension break — his grip on the table goes white-knuckled and his jaw locks and the pulse against her palm is strong and rhythmic and she keeps stroking through it until his hand lands on hers, gently, telling her to stop.</p><p>She pulls her hand back. Grabs a napkin from the holder and wipes her fingers under the table. Folds the napkin and sets it beside her coffee cup.</p><p>She takes a sip. It's cold.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Good morning.</div></div><p>She stands up. Takes her mug to the sink. Rinses it. Walks out of the kitchen without looking back.</p><p>She can hear him fixing his belt behind her. The buckle clinks in the quiet kitchen like a period at the end of a sentence.</p><video src="./videos/activities/activity_mick_breakfast_handjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "68834b1f-f9e9-4492-b350-c7efecea0e20">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.handjob") === -1) { vn.push("activity_mick_breakfast.handjob"); }<</script>>
<<nobr>>
<<link "Finish breakfast" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma picks up her fork. Looks at it. Drops it under the table.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Oops.</div></div><p>She slides off her chair and ducks under the table. The kitchen tablecloth hangs low enough to hide her. She doesn't pick up the fork.</p><p>Her hands go to his thighs. She can hear him inhale above the table — sharp, quick — and feel his legs tense under her palms. She undoes his belt. The buckle clinks against the chair leg.</p><p>She pulls him free. He's getting hard in her hand, stiffening with every stroke, and she can see the way his knees spread wider under the table to give her room.</p><p>She takes him in her mouth. Under the kitchen table, on her knees on the linoleum, while the coffee steams above her and the morning light comes through the window and lands on the tablecloth an inch from her head.</p><p>His hands grip the edge of the table. She can hear the newspaper trembling, the coffee cup rattling faintly in its saucer. The domestic sounds of morning — the fridge humming, a bird outside the window — play over what's happening underneath.</p><p>She works him slowly. No rush. This is the kitchen and the morning is long and she wants to feel every reaction — the way his thighs flex, the way his breathing gets ragged, the way he shifts in the chair trying not to make a sound.</p><p>He comes with both hands white-knuckled on the table. She feels the pulse and the heat and swallows and keeps her mouth on him until the last shudder passes through his legs.</p><p>She slides back up into her chair. Wipes the corner of her mouth with her thumb. Picks up the fork from the floor and sets it on her napkin.</p><p>She takes a sip of coffee. Cold. She takes another sip anyway.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Something wrong with your fork?</div></div><p>She looks at him. He's looking at her. And for the first time since any of this started — since the mirror, the couch, the stockroom, all of it — one corner of his mouth twitches. Almost a smile. The first joke either of them has made about any of it.</p><p>She laughs. Short, surprised, real. Then she stands up, takes her mug to the sink, and walks out.</p><video src="./videos/activities/activity_mick_breakfast_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "072dd3fd-f562-42de-8df0-cf66bb57f430">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.blowjob") === -1) { vn.push("activity_mick_breakfast.blowjob"); }<</script>>
<<nobr>>
<<link "Finish breakfast" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma stands up from the table. Doesn't say anything. She pushes the coffee cups to the far end — they rattle, slide, one tips and spills across the newspaper. Neither of them looks at it.</p><p>She turns around. Leans forward across the table. Looks back over her shoulder at him.</p><p>Mick stands up so fast the chair scrapes across the floor. His hands on her hips. He pulls her shorts down and she kicks them off one ankle. He undoes his belt. She hears the buckle hit the linoleum.</p><p>He takes her on the kitchen table. Morning light through the window falls across her back. The table legs scrape with every thrust. The coffee mug rolls off the edge and shatters on the floor and neither of them stops.</p><p>She grips the far edge of the table with both hands. His hands on her hips, pulling her back onto him. The kitchen is small and the sounds fill it completely — skin, breathing, the table legs stuttering across the linoleum.</p><p>He finishes with his forehead pressed against her shoulder blade. She can feel his breath, hot and ragged, against her back. She stays bent over the table for a moment. Her legs are trembling.</p><p>She picks up her shorts. He picks up the broken mug. They clean up the coffee in silence. The kitchen looks exactly the same as it did five minutes ago. Except for the broken mug. And everything else.</p><video src="./videos/activities/activity_mick_breakfast_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6a8a2ff7-9eb2-4cd7-82b8-f936b1a6c962">>
<<set $game_state.current_node = "b552af1f-8634-4f78-a008-e3fe37d67b2e">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_breakfast.sex") === -1) { vn.push("activity_mick_breakfast.sex"); }<</script>>
<<nobr>>
<<link "Clean up" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>She's in the stockroom restocking napkins when a box of cocktail straws slips off the shelf. They scatter across the concrete floor like pick-up sticks.</p><p>Mick is three feet behind her, checking inventory on a clipboard.</p><p>Emma bends down to pick them up. Not the way she would have a month ago — quick, efficient, forgettable. She bends at the waist. Slowly. Her shorts ride up the back of her thighs and she knows exactly how far because she checked in the mirror this morning.</p><p>She takes her time gathering the straws. One by one. She can feel the fabric pulling tight across her hips.</p><p>When she straightens up and turns around, Mick's eyes are on the clipboard. But his pen isn't moving. His jaw is set. The clipboard is slightly lower than it was.</p><p>He felt her do that. She can tell from the rigid way he's standing, the careful way he's not looking at her. The way his breathing has changed — slower, more controlled, like he's deliberately keeping it even.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Got them all.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Good.</div></div><p>One word. But his voice is half a register lower than it was ten seconds ago. Emma walks out of the stockroom with the straws and a heartbeat she can feel in her fingertips.</p><p>She made him look. She made him react. And now she knows exactly how to do it again.</p><img src="./videos/images/story/story_stockroom_the_bend_base.webp" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "542d2dc0-d6c8-454d-8e03-f99b183916d3">>
<<set $game_state.current_node = "c4297d92-b140-4d9a-a095-19ede9cca294">>
<<script>>setup.markCanvasTriggered("542d2dc0-d6c8-454d-8e03-f99b183916d3");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_stockroom_the_bend.base") === -1) { vn.push("story_stockroom_the_bend.base"); }<</script>>
<<nobr>>
<<link "Do it again tomorrow" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "discovered_teasing");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "tease_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>Emma can't sleep. She goes downstairs. The living room is dark except for the TV — blue light washing over the furniture, the peeling wallpaper, the sagging couch.</p><p>Mick is on the couch. Some movie. Volume low. He's got a beer on the floor next to his foot and his arm stretched across the back of the cushions.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Can't sleep. Mind if I watch?</div></div><p>He shrugs. She sits down. Opposite end of the couch. There's two feet of cushion between them and she can feel every inch of it.</p><p>The movie plays. She's not watching it. She's aware of him — his breathing, the way the blue light catches his jaw, the weight of his arm on the cushion behind her.</p><p>A scene comes on. Two characters in a kitchen. The tension has been building for twenty minutes. They look at each other. They stop talking. They kiss.</p><p>The room changes. The air between Emma and Mick gets heavier. She can feel it on her skin like humidity.</p><p>She glances at him. He's already looking at her.</p><img src="./videos/images/story/story_living_room_the_kiss_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "b4096636-2ac6-44ba-874a-6fa6f61ff6b0">>
<<set $game_state.current_node = "5f34cac6-1712-4dce-b72f-88434c3208b2">>
<<script>>setup.markCanvasTriggered("b4096636-2ac6-44ba-874a-6fa6f61ff6b0");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_kiss.base") === -1) { vn.push("story_living_room_the_kiss.base"); }<</script>>
<<nobr>>
<<link "Kiss him" "Canvas_story_living_room_the_kiss_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Neither says anything. The two feet of cushion becomes one foot. She doesn't know who moved first. Maybe both of them. Maybe neither.</p><p>His mouth is warm. His hand comes up to her jaw — thumb along her cheekbone, fingers curling into her hair behind her ear. For three seconds, he's there. Really there. She can feel the roughness of his stubble and the softness of his lips and the way his breath catches.</p><p>Then he pulls back. But not all the way. His hand is still on her jaw. His forehead is an inch from hers. His breathing is rough and she can feel it on her lips.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> I've been thinking about this since the day you dragged that suitcase through my door.</div></div><p>One sentence. Low. Like it was dragged out of him against his will. His thumb traces her cheekbone once more — slow, deliberate — and then his hand drops.</p><p>He stands up. The couch springs creak.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> That can't happen again.</div></div><p>He walks to the kitchen. She hears water running. A glass being set down too hard on the counter.</p><p>She sits on the couch. Lips still tingling. Heart hammering. The sentence echoes — since the day she arrived. He's been carrying this. The whole time. Every morning in the stockroom, every time she walked past him in the hallway, every time their eyes met across the bar. He knew. He's known.</p><p>The movie plays on. The two characters in the kitchen are pulling apart too, saying the same kinds of things people say when they've done something they can't undo.</p><p>Emma is smiling.</p><video src="./videos/story/story_living_room_the_kiss_the_line.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "b4096636-2ac6-44ba-874a-6fa6f61ff6b0">>
<<set $game_state.current_node = "eeed3c4f-b188-41af-bbf3-f504f0e0030f">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_living_room_the_kiss.the_line") === -1) { vn.push("story_living_room_the_kiss.the_line"); }<</script>>
<<nobr>>
<<link "Touch your lips" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "first_kiss_mick");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma is on her bed. Phone in hand. This time she doesn't go to the bookmarked tab.</p><p>She types: 'why does my body feel like this.'</p><p>The results are immediate. Articles, forums, listicles with stock photos of women laughing with their heads tilted back. She scrolls past the obvious ones — 'Be Yourself!' and 'Ten Ways to Show You Care!' — and finds the ones that are actually useful.</p><p>Eye contact. Hold it one beat longer than comfortable. Let him catch you looking. Don't look away first — make him be the one who breaks.</p><p>Touch. Casual, deniable, escalating. Arm first. Then shoulder. Then wherever the space allows. Every touch makes the next one easier. The body remembers contact.</p><p>Clothing. Not slutty — suggestive. The difference between showing everything and showing just enough that his brain fills in the rest. A shirt that rides up when you stretch. Shorts that end where his imagination begins.</p><p>Proximity. Be in his space. Find reasons. The stockroom is narrow. The hallway is narrow. The kitchen is small. Use the architecture.</p><p>She reads for an hour. She takes mental notes the way she takes notes in class — organized, methodical, serious. She's not confused anymore. She understands what her body wants. She just didn't have the vocabulary for it until now.</p><p>She puts the phone down and stares at the water stain on the ceiling. Her skin is warm. Her mind keeps cycling through the images — the couple in the alley, the sounds through the wall, the videos on her phone, her own hands in the dark. She's not scared of it anymore. She's curious what happens next.</p><p>She has questions. And she's done being afraid to answer them.</p><img src="./videos/images/story/story_room_seduction_research_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "7a798b0c-57b6-4798-87d4-a9a51e4bee00">>
<<set $game_state.current_node = "d54e5f32-d7d1-49cf-ad37-b2e3e91fd4f9">>
<<script>>setup.markCanvasTriggered("7a798b0c-57b6-4798-87d4-a9a51e4bee00");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_seduction_research.base") === -1) { vn.push("story_room_seduction_research.base"); }<</script>>
<<nobr>>
<<link "Start tomorrow" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "learned_seduction");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>The door doesn't have a lock. Everyone knows that. You knock, you wait, you listen. Emma doesn't hear the water running until she's already pushed the door open.</p><p>Mick is in the shower. The curtain is half-drawn — the rod is bent and it's never hung right — and she can see him from the chest up. And then, because the mirror on the wall catches the angle, she can see the rest.</p><p>His back is to her. Broad, muscular, water running in rivulets down the groove of his spine. His shoulders flex as he runs his hands through his hair. She can see the muscles in his back move under his skin — lats, traps, the dense slabs of a man who has been carrying kegs and cases for seventeen years.</p><p>He turns slightly. In the mirror she sees his profile — chest thick with dark hair, stomach flat and hard, the V-line of his hips cutting down toward his groin. His cock hangs heavy between his thighs, thick even soft, water running over it. He cups his hand under the showerhead and rinses his face.</p><p>He hasn't seen her. She is standing in the doorway of a bathroom watching a forty-seven-year-old man shower and she is not leaving.</p><p>Her mouth is dry. Her pulse is everywhere — throat, wrists, between her legs. She watches the water run down his body. She watches his hands move. She watches his cock sway when he shifts his weight and she thinks: I want that. Not abstractly. Not the way she wanted the images on her phone. She wants him. This specific man. This body.</p><p>He reaches for the faucet. She steps back — silent, quick — and pulls the door shut. Her hands are shaking. She walks to her room and closes the door and sits on the bed and stares at nothing.</p><p>Something has shifted. She can feel it. The difference between watching strangers through walls and wanting someone she eats breakfast with.</p><video src="./videos/images/random/random_bathroom_mick_shower_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "c55d67d4-6098-40fd-9b9f-61d15cf0e613">>
<<set $game_state.current_node = "df3f2178-5112-409a-9233-75d0206651cb">>
<<script>>setup.markCanvasTriggered("c55d67d4-6098-40fd-9b9f-61d15cf0e613");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_bathroom_mick_shower.base") === -1) { vn.push("random_bathroom_mick_shower.base"); }<</script>>
<<nobr>>
<<link "Go to your room" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "seen_mick_shower");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>Different stranger. Taller. Stronger. She can tell by the way he leans against the bus stop — all weight and angles and the kind of patience that suggests he's done this before too.</p><p>The flash. The look. He doesn't blink. He nods toward the alley.</p><p>This time she follows him.</p><p>He pushes her against the wall. Brick against her shoulder blades. His hands on her hips. She reaches down and pulls her skirt up. No underwear — she stopped wearing them on these nights weeks ago.</p><p>He lifts her thigh. She wraps her leg around him and pulls him in and when he pushes into her she makes a sound that's too loud for an alley, too loud for a street where anyone could walk past, and she doesn't care.</p><video src="./videos/story/story_street_sex_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "341b5313-d641-4161-a7e8-06eae349760d">>
<<set $game_state.current_node = "cfdfe3b7-7797-4111-adff-963163eed0c1">>
<<script>>setup.markCanvasTriggered("341b5313-d641-4161-a7e8-06eae349760d");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_sex.base") === -1) { vn.push("story_street_sex.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_story_street_sex_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>A couple argues on the main street. A siren wails three blocks away. The brick scrapes her shoulder blades with every thrust and she arches into it, one hand on his shoulder, one hand braced against the wall behind her.</p><p>He's rough. She wants him to be. His hand on her thigh tightens and she wraps her leg higher and pulls him deeper and the sound of them — skin and breath and the wet obscene rhythm of a stranger fucking her in an alley — fills the dead-end space.</p><p>She comes first. Her whole body clenches and she bites down on his shoulder to keep from screaming and her nails rake his back through his shirt. He follows — hard, his forehead against the wall beside her head, his breath ragged and raw in her ear.</p><p>She straightens her skirt. Her back is scraped — she can feel it, raw skin against fabric. Her thighs are shaking. She walks out of the alley on unsteady legs and the cold air hits her and she feels electric.</p><p>She fucked a stranger in an alley. Against a wall. While people walked by on the street. And she wants to do it again.</p><img src="./videos/images/story/story_street_sex_aftermath.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "341b5313-d641-4161-a7e8-06eae349760d">>
<<set $game_state.current_node = "e1caba75-d107-4280-997c-8d131af19394">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_sex.n2") === -1) { vn.push("story_street_sex.n2"); }<</script>>
<<nobr>>
<<link "Walk home" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "public_sex");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(25);<</script>><</link>><br>
<</nobr>><p>She's been doing this for weeks now. The flash, the approach, the alley. Her hand around a stranger. But tonight she walked past three men and none of them were right and she knows why.</p><p>The handjobs aren't enough.</p><p>She finds the one she wants outside a closed hardware store. Tall. Leather jacket. Smoking a cigarette and watching her walk. She lets the strap of her top slip. His cigarette stops halfway to his mouth.</p><p>She tilts her head toward the alley. He follows.</p><p>Past the dumpster. Past the fire escape. She turns and pushes him against the wall with both hands on his chest but this time she doesn't reach for his belt. She drops.</p><p>Her knees hit the pavement. Cold concrete through bare skin. Gritty. She unzips him with steady hands. Takes him in her mouth. The sound she makes is wet and obscene and echoes off the walls and she doesn't try to be quiet.</p><video src="./videos/story/story_street_blowjob_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "87e541e8-c613-4c0d-a974-d8303e7a7f50">>
<<set $game_state.current_node = "7960e4f0-050a-41d4-8ef8-454fe9415403">>
<<script>>setup.markCanvasTriggered("87e541e8-c613-4c0d-a974-d8303e7a7f50");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_blowjob.base") === -1) { vn.push("story_street_blowjob.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_story_street_blowjob_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She can hear traffic. Footsteps. A group of people laughing two streets over. A car's headlights sweep the alley entrance and for one frozen second she's illuminated — on her knees, mouth full, hands braced on his thighs — and then the light passes and she keeps going.</p><p>He grabs her hair. She lets him. Deeper — past comfort, past the reflex, her throat working around him. His hips push forward. She grabs his belt and sets the pace. Her pace.</p><p>When he finishes she swallows. All of it. Stands up slow. Her knees are scraped — red, raw, the pavement embedded in her skin. Her jaw aches. Her eyes are watering.</p><p>She wipes her mouth with the back of her hand and walks out of the alley. Her knees sting with every step. She's grinning.</p><p>The girl who arrived in this city with a suitcase and a scholarship would not recognize the woman walking home with dirty knees and a stranger's taste in her mouth. Emma doesn't think about that girl anymore.</p><img src="./videos/images/story/story_street_blowjob_aftermath.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "87e541e8-c613-4c0d-a974-d8303e7a7f50">>
<<set $game_state.current_node = "5b257c94-d68a-4077-89eb-56dea1fa0231">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_blowjob.n2") === -1) { vn.push("story_street_blowjob.n2"); }<</script>>
<<nobr>>
<<link "Walk home" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "public_blowjob");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>Same pattern. The skirt. The flash. The approach.</p><p>This one is taller. Broad shoulders, dark jacket, hands in his pockets. He saw her flash from across the street and walked straight over like he knew the invitation when he saw it.</p><p>The dirty talk. The words that aren't hers anymore — they're hers now, she's said them enough times. What she wants. What she'll do. What he can have.</p><p>He nods toward the side street. She follows. This time she doesn't say 'not tonight.'</p><p>The alley is narrow. Brick walls on both sides, a dumpster, the orange glow of a streetlight that doesn't quite reach. She pushes him against the wall — her hands, her choice — and reaches for his belt.</p><p>The buckle clinks. The zipper goes down. He's already hard. She wraps her hand around him and his head drops back against the brick and he groans — a real sound, low and rough, not performative.</p><p>She strokes him. Quick, efficient, the way she learned on her own body what rhythm works. Her grip is firm and her wrist moves with purpose and she watches his face — the way his mouth opens, the way his eyes close, the way his hips start to push into her hand.</p><p>A car's headlights sweep past the alley entrance. For one second they're lit up — her hand around a stranger's cock in a side street two blocks from her apartment. She doesn't stop.</p><p>He finishes against the wall. A groan that he bites down on, his hand grabbing her shoulder, his hips jerking. She feels it — hot, wet on her fingers, the pulse of him.</p><p>She wipes her hand on his shirt. Steps back. He's breathing hard, leaning against the brick, looking at her like she's something he can't quite believe.</p><p>She walks away without a word. Doesn't look back. The danger was the point.</p><video src="./videos/story/story_street_handjob_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "12dc61b9-b235-431f-9cb5-55f6cd2b3d4b">>
<<set $game_state.current_node = "b116ce0d-76d3-4913-9cd5-1410fc51b9d5">>
<<script>>setup.markCanvasTriggered("12dc61b9-b235-431f-9cb5-55f6cd2b3d4b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_handjob.base") === -1) { vn.push("story_street_handjob.base"); }<</script>>
<<nobr>>
<<link "Walk away" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "public_handjob");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>She does the usual. Short skirt, no underwear, a dark stretch of sidewalk. A man walking his dog — no, just walking, no dog, just a guy in a hoodie heading somewhere.</p><p>She lifts her skirt. Quick flash. Bare skin in the streetlight.</p><p>He stops. She expects the stare, the frozen moment, the look she walks away from.</p><p>He doesn't just stare. He crosses the street.</p><p>Emma's pulse spikes. Fight or flight. But she doesn't run.</p><p>He laughs. Low, surprised. He's close enough now that she can see his face — mid-twenties, stubble, not handsome but not ugly. Eyes that are still processing what they saw.</p><p>The conversation gets dirty fast. He tells her what he'd do to her if she let him. She tells him what she'd let him do. The words coming out of her mouth are someone else's words — filthy, specific, things she's only read on her phone screen with the door locked. But here, on a dark street, with a stranger she'll never see again, they feel natural.</p><p>She looks at the alley. The same kind of alley where she watched that couple weeks ago. The brick wall. The broken light.</p><p>She walks away. Her legs are shaking. She was wet the entire conversation — she can feel it on her inner thighs with every step.</p><p>She said 'not tonight.' Not 'no.' Not 'never.' Not tonight. Which means there might be a tonight when she says yes.</p><p>The walk home is electric.</p><img src="./videos/images/story/story_street_dirty_talk_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "e65d666d-a2f6-4f9b-8f6b-00a0fca09bf2">>
<<set $game_state.current_node = "049f1caa-1322-43e8-9954-d80e74c4d031">>
<<script>>setup.markCanvasTriggered("e65d666d-a2f6-4f9b-8f6b-00a0fca09bf2");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_dirty_talk.base") === -1) { vn.push("story_street_dirty_talk.base"); }<</script>>
<<nobr>>
<<link "Not tonight" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "public_dirty_talk");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>She does it again. Different night, different corner, different stranger.</p><p>Sometimes she lifts her shirt — no bra — and holds it for two seconds while a man on a bench stares with his sandwich halfway to his mouth. Sometimes she bends over at the bus stop, knowing the skirt rides up, knowing the guy behind her can see everything. Sometimes she 'accidentally' drops her keys and takes her time picking them up.</p><p>Each time the rush is the same. The look on their face. The moment their brain catches up to what their eyes just saw. The power of it — she chose to show them, she chose when to stop, she chose to walk away.</p><p>She's not doing this for them. She's doing this for the feeling in her chest when she rounds the corner — heart pounding, thighs slick, alive in a way she's never been alive.</p><p>The girl who arrived with a suitcase would be horrified. Emma doesn't care what that girl thinks anymore.</p><video src="./videos/images/activities/activity_street_flash_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "ffe5f1f7-de8b-4802-a625-54dfffee0b6e">>
<<set $game_state.current_node = "e7bbd722-5b3b-4491-b9a9-0de4e142ec6d">>
<<script>>setup.markCanvasTriggered("ffe5f1f7-de8b-4802-a625-54dfffee0b6e");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_street_flash.base") === -1) { vn.push("activity_street_flash.base"); }<</script>>
<<nobr>>
<<link "Walk away" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(10);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 160}, {"type": "flag", "subject": "player", "flag_key": "public_handjob", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "handjob_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('ffe5f1f7-de8b-4802-a625-54dfffee0b6e:cc0') ? '' : 'unlocked-choice'">
<<link "Jerk him off" "Canvas_activity_street_flash_Node_2">><<script>>setup.markChoiceVisited("ffe5f1f7-de8b-4802-a625-54dfffee0b6e:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 190}, {"type": "flag", "subject": "player", "flag_key": "public_blowjob", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "blowjob_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('ffe5f1f7-de8b-4802-a625-54dfffee0b6e:cc1') ? '' : 'unlocked-choice'">
<<link "Get on your knees" "Canvas_activity_street_flash_Node_3">><<script>>setup.markChoiceVisited("ffe5f1f7-de8b-4802-a625-54dfffee0b6e:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 220}, {"type": "flag", "subject": "player", "flag_key": "public_sex", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "sex_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('ffe5f1f7-de8b-4802-a625-54dfffee0b6e:cc2') ? '' : 'unlocked-choice'">
<<link "Fuck him in the alley" "Canvas_activity_street_flash_Node_4">><<script>>setup.markChoiceVisited("ffe5f1f7-de8b-4802-a625-54dfffee0b6e:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>He followed. They always follow.</p><p>The alley is narrow. She pushes him against the wall and reaches for his belt. The buckle clinks. He's already hard.</p><p>She strokes him — quick, efficient, her grip firm. His head drops back against the brick. A car's headlights sweep past. She doesn't stop.</p><p>He finishes against the wall. She wipes her hand on his shirt and walks away without a word.</p><video src="./videos/activities/activity_street_flash_handjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "ffe5f1f7-de8b-4802-a625-54dfffee0b6e">>
<<set $game_state.current_node = "0d928cbb-bf19-488e-8b24-8d81eba869e6">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_street_flash.handjob") === -1) { vn.push("activity_street_flash.handjob"); }<</script>>
<<nobr>>
<<link "Walk away" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>An alley. Behind a dumpster. Under a fire escape that smells like rust and old rain.</p><p>She picks them the same way every time. Eye contact. A look that lasts one second too long. A slight tilt of her head toward the dark. They follow. They always follow.</p><p>She gets on her knees on the dirty pavement. The concrete is cold and gritty through her bare skin and she doesn't care. She unzips him and takes him in her mouth and she can hear people walking on the sidewalk thirty feet away.</p><p>A siren passes. Red and blue light sweeps the alley walls above her head. She doesn't stop. Her mouth is full and her hands are braced on his thighs and the sound she makes — wet, rhythmic, obscene — echoes off the brick walls.</p><p>He tangles his fingers in her hair. She lets him. She takes him deeper — past her comfort, past the reflex, her throat working around him. His hips push forward and she grabs his belt to control the pace. Her pace. Her rules.</p><p>When he finishes she swallows. Stands up. Wipes her mouth with the back of her hand. Her knees are dirty and her jaw aches and she can taste him and none of that matters.</p><p>She walks out of the alley like she was tying her shoe.</p><video src="./videos/activities/activity_street_flash_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "ffe5f1f7-de8b-4802-a625-54dfffee0b6e">>
<<set $game_state.current_node = "812dff5d-e2e0-45b0-a3c1-937c878ff650">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_street_flash.blowjob") === -1) { vn.push("activity_street_flash.blowjob"); }<</script>>
<<nobr>>
<<link "Walk away" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>He's taller than the others. Broader shoulders. Hands that look like they know what they're doing.</p><p>She leads him into the alley. Past the dumpster, past the fire escape, to the dead end where the streetlight doesn't reach. She turns and puts her back against the brick wall and pulls her skirt up.</p><p>No underwear. She stopped wearing them on these nights weeks ago.</p><p>He lifts her thigh. She wraps her leg around him and pulls him closer and the brick scrapes her shoulder blades through her top and she doesn't care. He pushes into her and she gasps — not quiet, not careful, loud enough that someone on the street could hear.</p><p>A couple walks past the alley mouth. Their conversation fades. A car horn. A distant siren. The city sounds stack up around them like walls of noise and none of it matters because he's fucking her against a wall in an alley and her fingers are digging into his shoulders and her head is tipped back against the brick.</p><p>She comes first. Hard. Her whole body clenches around him and she bites her lip to keep from screaming and fails. He follows a minute later, his forehead against the wall beside her head, his breath ragged in her ear.</p><p>She straightens her skirt. Walks out of the alley. Her back is scraped and her thighs are shaking and she's already thinking about next time.</p><video src="./videos/activities/activity_street_flash_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "ffe5f1f7-de8b-4802-a625-54dfffee0b6e">>
<<set $game_state.current_node = "e376bc5f-8daf-44fb-b8a2-619eeda8b996">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_street_flash.sex") === -1) { vn.push("activity_street_flash.sex"); }<</script>>
<<nobr>>
<<link "Walk away" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>She decided before she left the bar. Standing in front of the small mirror in her room, pulling on the short skirt — the one from the mall, the one that barely covers anything — and then reaching under it and sliding her underwear down her legs and stepping out of them. Leaving them on the floor.</p><p>No underwear. On purpose. She knows what she's doing.</p><p>The street is mostly empty. Two in the morning. Orange light from the few streetlamps that still work. The convenience store is closed, metal shutters down. A car passes and its headlights sweep across her and she feels the air on her bare skin under the skirt and something tightens in her stomach that isn't fear.</p><p>A man is leaning against a fire hydrant across the street. Smoking. He's looking at his phone, the screen lighting up his face. Late thirties, work boots, a cigarette that's almost done.</p><p>Emma stops under a broken streetlight. The shadow is deep here — dark enough that she's half-hidden, light enough that he could see if he looked up.</p><p>She turns to face his direction. Her heart is hammering so hard she can feel it in her fingertips.</p><p>She reaches down and grabs the hem of her skirt. Hikes it up. Just for a second — two seconds — bare skin, the shadow between her thighs, everything exposed to the night air and to anyone who's watching.</p><p>He looks up. His cigarette stops halfway to his mouth.</p><p>She pulls the skirt down and walks away. Fast. Her sneakers slapping the sidewalk. She doesn't run — running would mean she's scared and she's not scared. She's soaking wet. Her hands are shaking and she's grinning and she can't stop grinning.</p><p>She did that. She chose to do that. Nobody made her. Nobody paid her. Nobody asked.</p><p>Three blocks later she can still feel the air on her skin. She can still see his face — the cigarette frozen, his mouth open, the look. That look.</p><p>She wants to do it again.</p><img src="./videos/images/story/story_street_first_flash_base.gif" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f5684f38-dbd5-4c10-a84b-0250f4ddd0af">>
<<set $game_state.current_node = "fadf934b-c6a2-4734-ae4d-fe4f5a50c008">>
<<script>>setup.markCanvasTriggered("f5684f38-dbd5-4c10-a84b-0250f4ddd0af");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_street_first_flash.base") === -1) { vn.push("story_street_first_flash.base"); }<</script>>
<<nobr>>
<<link "Walk home" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "public_flashed");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>Emma locks the door. Sits on the bed. Opens her phone.</p><p>She doesn't pretend anymore. She goes straight to the browser, straight to the bookmarked tab she stopped clearing two weeks ago. The page loads and the thumbnails fill the screen — women on their knees, women bent over counters, women with their mouths open and their eyes looking up at the camera like they know exactly who's watching.</p><p>She picks one. A brunette with a guy on a couch. Nothing fancy. The woman straddles him, pulls her shirt over her head, and his hands go straight to her tits — squeezing, thumbing her nipples until she gasps. Emma can hear the wet sounds when the woman starts grinding on him.</p><p>The camera angle shifts. The woman reaches back and takes his cock in her hand, guides it in. She sinks down slowly and the sound she makes is real — not performed, not exaggerated. A short, sharp inhale through her teeth and then a long exhale as she starts to move.</p><p>Emma watches. Her lips are parted. Her breathing has matched the rhythm on the screen without her deciding to do that.</p><p>The guy grabs the woman's hips and starts thrusting up into her. The woman's head tips back. Her tits bounce with every stroke. She's saying something — 'right there, right there' — and Emma can feel her own pulse between her legs, heavy and insistent.</p><p>She shifts on the bed. Presses her thighs together. The pressure helps and doesn't help at the same time.</p><p>On screen, the woman is on her hands and knees now. The guy behind her, one hand on her hip, the other tangled in her hair. The slapping sound is rhythmic, steady. The woman's moans have gone from words to just sounds — raw, uncontrolled.</p><p>Emma's face is hot. Her underwear is wet. She can feel it. She's been watching for six minutes and her body has made a decision her brain is still negotiating with.</p><video src="./videos/images/activities/activity_room_watch_porn_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6b36b08a-11cc-444f-9d17-4747612ad11c">>
<<set $game_state.current_node = "13c5228d-b92b-406c-b453-253665770a0d">>
<<script>>setup.markCanvasTriggered("6b36b08a-11cc-444f-9d17-4747612ad11c");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_room_watch_porn.base") === -1) { vn.push("activity_room_watch_porn.base"); }<</script>>
<<nobr>>
<<link "Close the phone" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "discovered_porn");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 60}]})>>
<span @class="setup.isChoiceVisited('6b36b08a-11cc-444f-9d17-4747612ad11c:cc0') ? '' : 'unlocked-choice'">
<<link "Masturbate" "Canvas_activity_room_watch_porn_Node_2">><<script>>setup.markChoiceVisited("6b36b08a-11cc-444f-9d17-4747612ad11c:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>She doesn't close the phone.</p><p>Her free hand moves down her stomach. Slowly. Past the waistband of her shorts, past the elastic of her underwear. Her fingers find the wet spot and press against it through the cotton and her hips jerk — just a little, involuntary, but enough to make her breath catch.</p><p>On screen the woman is moaning, loud and desperate, and Emma slides her hand inside her underwear. The first touch of her fingers against her bare clit sends a shudder through her whole body. She's swollen. Slick. More wet than she expected.</p><p>She starts slow. Two fingers, circling. The way she figured out works — not pressing too hard, keeping the rhythm steady, letting the heat build instead of chasing it. On the phone screen the guy is fucking the woman from behind and the sounds are obscene — skin on skin, the wet sounds, the woman begging him not to stop.</p><p>Emma's fingers slide lower. She pushes one inside herself and her breath comes out in a shaky exhale she wasn't ready for. She's tight around her own finger, hot inside, and she curls it forward the way she read about and — there. Right there. A spike of pleasure sharp enough to make her thighs clamp together.</p><p>She adds a second finger. Pushes them in slowly, then out, then in again. Her palm grinds against her clit with every stroke and she can hear how wet she is — a soft, slick sound that would embarrass her if she could think about anything other than how good this feels.</p><p>She's not watching the video anymore. Her eyes are closed. Her hips are moving on their own, pushing down against her hand, and she's thinking about the woman in the alley — leg hooked around his waist, head thrown back. She's thinking about Jolene's voice through the wall, pitched up and breaking. She's thinking about the sounds she's making right now, quiet and desperate, and how she doesn't care.</p><p>It builds fast. Her fingers curl inside herself, pressing that spot, and her other hand drops the phone and grabs the sheet and she's close — she's right there — her thighs are shaking and her stomach is tight and every muscle in her body is pulling toward the place where her fingers are moving.</p><p>She comes with her hand over her mouth. Her back arches off the mattress. Her fingers are still inside herself and she can feel herself clenching around them, pulsing, and her hips won't stop moving — grinding against her palm through the aftershocks until it's too much and she has to pull her hand away.</p><p>She lies there. Breathing. The phone has fallen to the pillow, still playing. She reaches over and closes it.</p><p>Her fingers are wet. Her underwear is ruined. She feels loose and warm and a little lightheaded, like she just put something down she's been carrying for weeks.</p><p>She cleans up. Unlocks the door. Goes downstairs like nothing happened.</p><img src="./videos/activities/activity_room_watch_porn_fingering.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6b36b08a-11cc-444f-9d17-4747612ad11c">>
<<set $game_state.current_node = "64a71793-7a33-4404-8712-ecadf617717d">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_room_watch_porn.fingering") === -1) { vn.push("activity_room_watch_porn.fingering"); }<</script>>
<<nobr>>
<<link "Catch your breath" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "discovered_porn");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Two in the morning. Emma is staring at the ceiling again.</p><p>The bar closed an hour ago. The building is quiet — no sounds from Jolene's room tonight, no jukebox rattling the floor, just the hum of the fridge downstairs and a car passing on the street.</p><p>She rolls over. Presses the pillow against her face. Breathes into the cotton and tells herself to sleep.</p><p>The images come anyway.</p><p>The alley couple. The woman's leg hooked around his hip, her head thrown back. The sounds through Jolene's wall — the headboard, the pitch of her voice. The silhouettes in the window. The girl in the library with her skirt fanned out.</p><p>Emma turns onto her back. Her skin is warm. The sheet is too much and too little at the same time. She kicks it off and lies there in a tank top and underwear and the air from the open window does nothing.</p><p>She's been like this for a week. Every night the same cycle — lie down, close her eyes, see things she wasn't supposed to see, feel things she doesn't know what to do with. Push it down. Try again. Push it down harder.</p><p>Her phone is on the nightstand. The screen is dark. She can see the faint outline of it in the streetlight coming through the window.</p><p>She reaches for it. Pulls her hand back. Reaches again.</p><img src="./videos/images/random/random_room_restless_night_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "bb28003e-694d-486e-a37a-25086796bbdb">>
<<set $game_state.current_node = "a39e5c88-5bb7-4294-849a-1ca499d60276">>
<<script>>setup.markCanvasTriggered("bb28003e-694d-486e-a37a-25086796bbdb");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_first_porn.struggling") === -1) { vn.push("story_room_first_porn.struggling"); }<</script>>
<<nobr>>
<<link "Pick up the phone" "Canvas_story_room_first_porn_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The screen lights up her face. She squints and turns the brightness down and opens the browser.</p><p>She types something. Deletes it. Types it again — different words, more specific. Her thumb hovers over the search button. She can feel her heartbeat in her throat.</p><p>She tells herself this is research. Understanding. She's twenty years old and she's curious and there's nothing wrong with curiosity.</p><p>She presses search.</p><p>The screen fills with thumbnails. Women arching their backs. Mouths open. Skin on skin. Things she's never seen laid out in a grid like a menu.</p><p>She taps one. The video loads.</p><p>For the first fifteen seconds she watches the way someone watches a nature documentary — detached, analytical, cataloguing. A woman. A man. A bed. Positions she's seen in her anatomy textbook but never in motion.</p><p>Thirty seconds in the detachment cracks. The woman on screen moans — not theatrical, not performative, just a sound that comes from somewhere deep — and something in Emma's stomach drops. Like a trapdoor opening.</p><p>She watches. Two minutes. Three. The door is locked. Her phone is warm in her hand. She can hear her own breathing and it's faster than it should be.</p><p>At six minutes she closes the phone. Puts it face-down on the nightstand. Stares at the ceiling.</p><p>Her heart is pounding. She's wet — she can feel it, unmistakable, a heat between her thighs that arrived sometime around the second minute and hasn't left. She didn't touch herself. She wanted to. Her hand moved twice and she stopped it both times.</p><p>She lies there in the dark and waits for the feeling to pass. It doesn't pass.</p><p>She picks the phone back up.</p><video src="./videos/images/activities/activity_room_watch_porn_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "bb28003e-694d-486e-a37a-25086796bbdb">>
<<set $game_state.current_node = "979f94e0-da22-4df8-b5e3-7645d04afb13">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_room_first_porn.giving_in") === -1) { vn.push("story_room_first_porn.giving_in"); }<</script>>
<<nobr>>
<<link "Close the phone" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "discovered_porn");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma lies in the dark, staring at the ceiling. The bar closed an hour ago. The building is quiet. She should be asleep.</p><p>She's not asleep.</p><p>It starts the same way it always does — a fragment. The crack of light through Jolene's door. The sound from the hallway. The woman in the alley, her back against the brick, not caring who saw.</p><p>Emma turns over. Presses her face into the pillow. The images don't stop. They're not even images, exactly — more like impressions. The sound of the headboard. The way Jolene's voice had pitched up. The arch of someone's back in a window that was supposed to be none of Emma's business.</p><p>She's been seeing things she wasn't supposed to see for weeks. She keeps telling herself they don't mean anything. She keeps lying there thinking about them at midnight.</p><p>She rolls onto her back. Stares at the water stain on the ceiling. Her face is warm. The room is fine — it's not warm, the window's open, there's a breeze. But her face is warm.</p><p>She breathes. Deliberately. In and out. The building settles. A car passes on the street below.</p><p>She tells herself it's just her brain processing things. She read that somewhere. Dreams, intrusive thoughts — it's just your brain filing things away. It doesn't mean anything.</p><p>She's been telling herself that for three weeks and she's not sure she believes it anymore.</p><p>Eventually something like sleep comes. Not quickly.</p><img src="./videos/images/random/random_room_restless_night_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "caedc6da-8e3e-4db5-84c6-a6cb14eba7e1">>
<<set $game_state.current_node = "c804e013-5e17-483a-bde1-34137967ec24">>
<<script>>setup.markCanvasTriggered("caedc6da-8e3e-4db5-84c6-a6cb14eba7e1");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_room_restless_night.base") === -1) { vn.push("random_room_restless_night.base"); }<</script>>
<<nobr>>
<<link "Push it down" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "had_restless_night");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>Her room. Door closed. Textbook open on the bed, notes spread around her like a paper nest. The bar is loud below — bass through the floor, glasses clinking, Jolene's laugh cutting through everything.</p><p>She reads. Highlights. Writes summaries in the margins. Her handwriting gets smaller as the night goes on, cramped and tight, trying to fit everything in.</p><p>It's not glamorous. It's not fun. But every page is one step closer to not failing.</p><img src="./videos/images/activities/activity_homework_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "3dfde0de-7f65-4a99-afef-507fa6cbd15e">>
<<set $game_state.current_node = "c7cefdc9-f3f3-482e-9ea8-5e34826aacee">>
<<script>>setup.markCanvasTriggered("3dfde0de-7f65-4a99-afef-507fa6cbd15e");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_homework.base") === -1) { vn.push("activity_homework.base"); }<</script>>
<<nobr>>
<<link "Keep at it" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "intelligence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>Room 208. The door is open. Harlan is behind his desk, glasses on, red pen in hand, marking papers. He looks up when she knocks.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Emma. Come in.</div></div><p>She sits in the student chair. The one that's worn down on the left armrest from all the students who came before her. None of them sat in it the way she does now.</p><img src="./videos/images/activities/activity_office_hours_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "b0998080-ea52-4b92-9971-30afdfaeeb4c">>
<<script>>setup.markCanvasTriggered("f80b776c-eeca-41f7-9d6b-cd9e5b72488b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.base") === -1) { vn.push("activity_office_hours.base"); }<</script>>
<<if ndef $game_state.loop_count>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><</if>>
<<nobr>>
<<link "Study with him" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "intelligence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(90);<</script>><</link>><br>
<<if not $game_state.loop_visited.includes("024b8ac1-f2b6-4ce0-b256-56cc225811c8")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 70}, {"type": "trait", "subject": "npc", "npc_id": "npc_harlan", "trait_key": "corruption", "operator": "gte", "value": 10}]})>>
<span @class="setup.isChoiceVisited('f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc0') ? '' : 'unlocked-choice'">
<<link "Get personal" "Canvas_activity_office_hours_Node_2">><<script>>setup.markChoiceVisited("f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc0");<</script>><<run $game_state.loop_visited.push("024b8ac1-f2b6-4ce0-b256-56cc225811c8")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("2ce735d6-37b0-4300-b592-57c5b0552ba0")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 100}, {"type": "flag", "subject": "player", "flag_key": "flirt_unlock", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_harlan", "trait_key": "corruption", "operator": "gte", "value": 20}]})>>
<span @class="setup.isChoiceVisited('f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc1') ? '' : 'unlocked-choice'">
<<link "Flirt with him" "Canvas_activity_office_hours_Node_3">><<script>>setup.markChoiceVisited("f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc1");<</script>><<run $game_state.loop_visited.push("2ce735d6-37b0-4300-b592-57c5b0552ba0")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("59fd3552-9560-40cf-8878-c1ec196c80aa")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 130}, {"type": "flag", "subject": "player", "flag_key": "tease_unlock", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_harlan", "trait_key": "corruption", "operator": "gte", "value": 35}]})>>
<span @class="setup.isChoiceVisited('f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc2') ? '' : 'unlocked-choice'">
<<link "Let him touch you" "Canvas_activity_office_hours_Node_4">><<script>>setup.markChoiceVisited("f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc2");<</script>><<run $game_state.loop_visited.push("59fd3552-9560-40cf-8878-c1ec196c80aa")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 175}, {"type": "flag", "subject": "player", "flag_key": "handjob_unlock", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "harlan_handjob", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc3') ? '' : 'unlocked-choice'">
<<link "Under the desk" "Canvas_activity_office_hours_Node_5">><<script>>setup.markChoiceVisited("f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc3");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 200}, {"type": "flag", "subject": "player", "flag_key": "blowjob_unlock", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "harlan_blowjob", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc4') ? '' : 'unlocked-choice'">
<<link "On your knees" "Canvas_activity_office_hours_Node_6">><<script>>setup.markChoiceVisited("f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc4");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 220}, {"type": "flag", "subject": "player", "flag_key": "sex_unlock", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "harlan_sex", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc5') ? '' : 'unlocked-choice'">
<<link "On his desk" "Canvas_activity_office_hours_Node_7">><<script>>setup.markChoiceVisited("f80b776c-eeca-41f7-9d6b-cd9e5b72488b:cc5");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>They stop talking about the reading. He asks about the bar. About Jolene. About why she works nights and goes to class mornings. She tells him things she hasn't told anyone.</p><p>He listens the way he reads — closely, carefully, finding the subtext. He tells her about his ex-wife. About the dog in the photo. About why he stayed at a commuter college when he could've gone somewhere prestigious.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I stay because the students here are real. They've got jobs and problems and they still show up. That means something.</div></div><p>He's looking at her when he says it. She knows he means her.</p><img src="./videos/images/activities/activity_office_hours_personal.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "024b8ac1-f2b6-4ce0-b256-56cc225811c8">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.personal") === -1) { vn.push("activity_office_hours.personal"); }<</script>>
<<nobr>>
<<link "Head out" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(60);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_office_hours_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(60);<</script>><</link>><br>
<</if>>
<</nobr>><p>She leans forward in the chair. Lets the conversation slow down. Holds his eyes a beat too long when he makes a joke.</p><p>He notices. He always notices. His hand goes to his glasses — takes them off, puts them on, the nervous tic she's learned to read.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> You're doing it again.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Doing what?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Looking at me like that.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Like what?</div></div><p>He doesn't answer. But he smiles. And his eyes drop — just for a second — and she knows exactly where they went.</p><img src="./videos/images/activities/activity_office_hours_flirt.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "2ce735d6-37b0-4300-b592-57c5b0552ba0">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.flirt") === -1) { vn.push("activity_office_hours.flirt"); }<</script>>
<<nobr>>
<<link "Leave him wanting" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(45);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_office_hours_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(45);<</script>><</link>><br>
<</if>>
<</nobr>><p>The door is locked. They've stopped pretending there's a reason it shouldn't be.</p><p>He comes around to her side of the desk. Sits on the edge, close. His knee touches hers.</p><p>His hand goes to her face. Pushes a strand of hair behind her ear. Traces her jaw. Down her neck. His thumb rests in the hollow of her throat.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Tell me to stop.</div></div><p>She doesn't.</p><p>His hand continues. Down her collarbone. Over the top of her shirt. He cups her breast — slow, deliberate, watching her face for permission that's already been given. She arches into it.</p><p>He kisses her neck. She grips the armrests and closes her eyes and lets him.</p><img src="./videos/activities/activity_office_hours_touch.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "59fd3552-9560-40cf-8878-c1ec196c80aa">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.touch") === -1) { vn.push("activity_office_hours.touch"); }<</script>>
<<nobr>>
<<link "Pull away" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_office_hours_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>The routine. Lock the door. Come around the desk. She knows the choreography.</p><p>She kneels between his legs. Unzips him. Takes him in her hand.</p><p>He leans back in the leather chair and closes his eyes and she strokes him the way she's learned — firm, steady, reading his breathing.</p><p>Someone knocks. They both freeze. His hand is in her hair. She's on her knees under his desk.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Come back in ten minutes.</div></div><p>Footsteps walk away. He looks down at her. She looks up at him. They don't stop.</p><p>He finishes. She cleans up. Goes back to the student chair.</p><p>The student who knocked comes back in eight minutes. Harlan reviews her paper with his glasses on and his voice steady and Emma sits in the corner pretending to read.</p><video src="./videos/activities/activity_office_hours_under_desk.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "ee627bce-c0f9-4945-809c-e0f7c9cbb162">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.under_desk") === -1) { vn.push("activity_office_hours.under_desk"); }<</script>>
<<nobr>>
<<link "Leave when the student does" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>The routine. Door locked. Blinds angled. She doesn't sit in the student chair anymore.</p><p>She kneels between his legs. Unzips him. Takes him in her mouth.</p><p>He leans back in the leather chair. One hand on the armrest, the other resting on the back of her head — not pushing, just resting. She bobs her head and works him with her mouth and her hand and above her she can hear the scratch of his pen on paper. He's grading. She's on her knees under his desk and he's grading someone else's essay.</p><p>The efficiency doesn't bother her. It's the point. This is what office hours are now — she gets a grade, he gets this. The transaction is clean.</p><p>He finishes. She swallows. Stands. Washes her mouth at the small sink in the corner. He slides a graded paper across the desk without looking up. B+.</p><video src="./videos/activities/activity_office_hours_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "7b5e9939-56ab-4167-a1fa-d08e11c36aa8">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.blowjob") === -1) { vn.push("activity_office_hours.blowjob"); }<</script>>
<<nobr>>
<<link "Take the paper and leave" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(25);<</script>><</link>><br>
<</nobr>><p>She locks the door. He doesn't look up from his papers. He's learned not to.</p><p>She walks around the desk. Pushes the stack of ungraded exams aside — they slide across the wood and a few fall off the edge. She sits on the desk in front of him. Her skirt rides up.</p><p>He puts the pen down. Takes off his glasses. Stands.</p><p>She pulls him between her legs and wraps them around him and the desk shudders when he pushes into her. A pen rolls off. His coffee mug wobbles. She grabs the back of his neck and sets the pace — her rhythm, her depth, the clock on the wall ticking through the minutes of his posted office hours.</p><p>Quick. Purposeful. The same efficiency that defines everything between them. She comes first — quiet, controlled, her teeth in her lower lip. He follows. The leather chair catches him when his knees give.</p><p>She straightens her skirt. Picks up the fallen exams. Stacks them neatly on the corner of the desk. He's putting his glasses back on with unsteady hands.</p><p>She leaves the door unlocked behind her.</p><video src="./videos/activities/activity_office_hours_desk.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "f80b776c-eeca-41f7-9d6b-cd9e5b72488b">>
<<set $game_state.current_node = "7f24f399-99ca-4f4d-ad40-0ddc5b0a011c">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_office_hours.desk") === -1) { vn.push("activity_office_hours.desk"); }<</script>>
<<nobr>>
<<link "Walk out" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(25);<</script>><</link>><br>
<</nobr>><p>Literature 201. Professor Harlan is at the front, pacing between the rows, making Dostoevsky sound like breaking news. Emma sits closer to the front now. She's not sure when that changed.</p><p>He catches her eye. A half-second of contact that nobody else in the room would notice. She notices.</p><img src="./videos/images/activities/activity_harlan_class_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8">>
<<set $game_state.current_node = "3aa78f45-1152-4ce3-8ef8-592f685c9f9a">>
<<script>>setup.markCanvasTriggered("d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_harlan_class.base") === -1) { vn.push("activity_harlan_class.base"); }<</script>>
<<if ndef $game_state.loop_count>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><</if>>
<<nobr>>
<<link "Pay attention" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "intelligence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(120);<</script>><</link>><br>
<<if not $game_state.loop_visited.includes("5404ca08-6982-410d-90b1-4d181805e943")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 90}, {"type": "flag", "subject": "player", "flag_key": "flirt_unlock", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_harlan", "trait_key": "corruption", "operator": "gte", "value": 15}]})>>
<span @class="setup.isChoiceVisited('d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8:cc0') ? '' : 'unlocked-choice'">
<<link "Flirt during class" "Canvas_activity_harlan_class_Node_2">><<script>>setup.markChoiceVisited("d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8:cc0");<</script>><<run $game_state.loop_visited.push("5404ca08-6982-410d-90b1-4d181805e943")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("4a52d1b5-bfe8-4cce-bcf2-c696c3c64b9e")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 120}, {"type": "flag", "subject": "player", "flag_key": "tease_unlock", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_harlan", "trait_key": "corruption", "operator": "gte", "value": 30}]})>>
<span @class="setup.isChoiceVisited('d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8:cc1') ? '' : 'unlocked-choice'">
<<link "Tease him" "Canvas_activity_harlan_class_Node_3">><<script>>setup.markChoiceVisited("d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8:cc1");<</script>><<run $game_state.loop_visited.push("4a52d1b5-bfe8-4cce-bcf2-c696c3c64b9e")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<</nobr>><p>She sits in the front row. Crosses and uncrosses her legs slowly. When he walks past her row, she tilts her head up and holds the eye contact two beats too long.</p><p>He asks the class a question. She raises her hand — slowly, stretching, letting the motion show. Her answer is smart but her delivery is for him. The lower register. The pause.</p><p>He's flustered. He drops the whiteboard marker. Bends down to pick it up and his eyes are level with her knees for one second.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Good answer. Moving on.</div></div><p>Moving on. Like he can.</p><img src="./videos/images/activities/activity_harlan_class_flirt.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8">>
<<set $game_state.current_node = "5404ca08-6982-410d-90b1-4d181805e943">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_harlan_class.flirt") === -1) { vn.push("activity_harlan_class.flirt"); }<</script>>
<<nobr>>
<<link "Pack up slowly" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(120);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_harlan_class_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(120);<</script>><</link>><br>
<</if>>
<</nobr>><p>The short skirt. No tights. She sits in the front row and lets her knees fall apart — not wide, just enough. Enough that when he walks past and looks down, he can see.</p><p>He sees. His lecture falters for three whole seconds. He grips the podium. A student in the second row asks if he's okay.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Fine. Just — lost my place.</div></div><p>Emma closes her legs. Opens her notebook. Writes a sentence she'll never read: I like watching him try not to look.</p><p>The lecture ends ten minutes early. He doesn't explain why.</p><img src="./videos/activities/activity_harlan_class_tease.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "d95c8593-1b0a-49f8-b1e8-a37bc2b58fe8">>
<<set $game_state.current_node = "4a52d1b5-bfe8-4cce-bcf2-c696c3c64b9e">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_harlan_class.tease") === -1) { vn.push("activity_harlan_class.tease"); }<</script>>
<<nobr>>
<<link "Leave with a smile" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(110);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_harlan_class_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(110);<</script>><</link>><br>
<</if>>
<</nobr>><p>Monday morning. Blue exam books stacked at the front. Harlan writes the questions on the board in his neat handwriting. Forty-five minutes. No notes.</p><p>Emma opens her blue book. Reads the first question. Her pen hovers.</p><img src="./videos/images/activities/monday_test_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "782a3e01-ecc4-444f-9ac9-09f2fdc69719">>
<<set $game_state.current_node = "0487150e-a5c6-46f6-9913-e39e860b79c8">>
<<script>>setup.markCanvasTriggered("782a3e01-ecc4-444f-9ac9-09f2fdc69719");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("monday_test.base") === -1) { vn.push("monday_test.base"); }<</script>>
<<nobr>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "gte", "value": 80}]})>>
<span @class="setup.isChoiceVisited('782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc0') ? '' : 'unlocked-choice'">
<<link "You aced it" "Canvas_monday_test_Node_2">><<script>>setup.markChoiceVisited("782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "gte", "value": 60}, {"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "lt", "value": 80}]})>>
<span @class="setup.isChoiceVisited('782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc1') ? '' : 'unlocked-choice'">
<<link "Solid work" "Canvas_monday_test_Node_3">><<script>>setup.markChoiceVisited("782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "gte", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "lt", "value": 60}]})>>
<span @class="setup.isChoiceVisited('782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc2') ? '' : 'unlocked-choice'">
<<link "You passed" "Canvas_monday_test_Node_4">><<script>>setup.markChoiceVisited("782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "lt", "value": 40}]})>>
<span @class="setup.isChoiceVisited('782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc3') ? '' : 'unlocked-choice'">
<<link "You failed" "Canvas_monday_test_Node_5">><<script>>setup.markChoiceVisited("782a3e01-ecc4-444f-9ac9-09f2fdc69719:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if not (setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "gte", "value": 80}]}) or setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "gte", "value": 60}, {"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "lt", "value": 80}]}) or setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "gte", "value": 40}, {"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "lt", "value": 60}]}) or setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "intelligence", "operator": "lt", "value": 40}]}))>>
No available choices<br>
[[Continue->Location_Classroom]]
<</if>>
<</nobr>><p>She knows every answer. The pen moves fast — no hesitation, no second-guessing. When she finishes, there's twenty minutes left. She double-checks. It's clean.</p><p>Harlan collects the books. When he passes her row, he glances at her page count. Raises an eyebrow. Almost impressed.</p>
<<set $game_state.current_canvas = "782a3e01-ecc4-444f-9ac9-09f2fdc69719">>
<<set $game_state.current_node = "3b4db4df-fae1-4e47-9ec4-5ce0017d7de8">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("monday_test.grade_a") === -1) { vn.push("monday_test.grade_a"); }<</script>>
<<nobr>>
<<link "Hand it in" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grade_a");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grade_b");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grade_c");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>She knows most of it. A few questions make her pause — she circles back to them, writes what she can. It's not perfect but it's solid. She studied for this.</p><p>When she hands it in, she feels okay. Not great. Okay. That's more than she expected when she started.</p>
<<set $game_state.current_canvas = "782a3e01-ecc4-444f-9ac9-09f2fdc69719">>
<<set $game_state.current_node = "cbee4e80-027e-4e29-8de1-4ca1d154095c">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("monday_test.grade_b") === -1) { vn.push("monday_test.grade_b"); }<</script>>
<<nobr>>
<<link "Hand it in" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grade_b");<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grade_c");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>She recognizes some of it. Enough to fill in answers for most questions, guess on the rest. Her handwriting gets messier toward the end — she's rushing, running out of time and ideas.</p><p>She hands it in. It's a pass. Barely. But it's a pass.</p>
<<set $game_state.current_canvas = "782a3e01-ecc4-444f-9ac9-09f2fdc69719">>
<<set $game_state.current_node = "d60ee67d-c278-4ce9-876d-7d3b923c39af">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("monday_test.grade_c") === -1) { vn.push("monday_test.grade_c"); }<</script>>
<<nobr>>
<<link "Hand it in" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "grade_c");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>She stares at the questions. Some of the words look familiar. Most don't. She writes something for the first two, leaves the third blank, guesses on the fourth.</p><p>When time is called, half the blue book is empty. She hands it in face-down.</p>
<<set $game_state.current_canvas = "782a3e01-ecc4-444f-9ac9-09f2fdc69719">>
<<set $game_state.current_node = "3ac2d6e4-b6ae-4275-8d20-242cef48d52d">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("monday_test.grade_fail") === -1) { vn.push("monday_test.grade_fail"); }<</script>>
<<nobr>>
<<link "Hand it in" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "test_failed");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>She doesn't need anything. The letter is written. The grade is filed. Financial aid is secure. There is no reason for Emma to be standing in front of Room 208 at two in the afternoon on a Wednesday.</p><p>She walks in. He looks up — glasses on, red pen in hand, the same posture she's seen a hundred times. He starts to say her name.</p><p>She closes the door. Turns the lock. The click fills the room.</p><p>He puts the pen down.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Emma, what are you —</div></div><p>She walks around the desk. Not to the student chair — around it, past the bookshelf, to his side. She puts both hands on the stack of ungraded papers and pushes them off the edge. They scatter across the floor like leaves.</p><p>She sits on the desk. Crosses her legs. Looks down at him in his leather chair.</p><p>He's staring at her. She's never seen this expression on his face before — not the confident professor, not the man who locks doors and tilts chins. He's uncertain. He's the student now.</p><p>She reaches forward and grabs his tie. Pulls him up out of the chair. Pulls him toward her.</p><video src="./videos/story/story_office_the_desk_base.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "fedd250e-ae24-47fc-8f6b-d299ce69ac08">>
<<set $game_state.current_node = "851ba01d-d2a9-45c9-9bc2-19952cc8e62c">>
<<script>>setup.markCanvasTriggered("fedd250e-ae24-47fc-8f6b-d299ce69ac08");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_the_desk.base") === -1) { vn.push("story_office_the_desk.base"); }<</script>>
<<nobr>>
<<link "Continue" "Canvas_story_office_the_desk_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>His glasses are on the floor. The nameplate — PROF. HARLAN, LITERATURE — is face-down next to the trash can. The leather chair has rolled into the bookshelf. Papers everywhere.</p><p>She pulls him between her legs. Wraps them around him. Her skirt is pushed up around her waist and his hands are on her hips and she grabs the back of his neck and pulls his mouth to hers.</p><p>He pushes into her and the desk shudders. A pen rolls off the edge. She leans back on her elbows and watches him — his face, his effort, the way his jaw tightens. She sets the pace. Slower. Deeper. Her heel digs into the back of his thigh.</p><p>Someone tries the door handle. It rattles. They both freeze for one second and then she tightens her legs around him and pulls him back and he gives up pretending he's going to stop.</p><p>She comes with her hand over her own mouth and her back arched against the cold wood of his desk. He follows — forehead against her shoulder, breathing hard, his hands gripping the desk on either side of her hips.</p><p>She straightens her skirt. Picks up a sheet of paper from the floor — the recommendation letter, crumpled at one corner. She smooths it. Places it back on the desk.</p><p>He's in the leather chair. Glasses back on. Pen in hand. But his hand is shaking and his hair is wrong and there's a red mark on his neck from her mouth.</p><p>She unlocks the door. Doesn't look back.</p><p>She never needed him. He needed her. It took her this long to figure out which way the debt ran.</p><video src="./videos/story/story_office_the_desk_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "fedd250e-ae24-47fc-8f6b-d299ce69ac08">>
<<set $game_state.current_node = "fc442c40-f13b-4906-8d12-6414c79a970f">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_the_desk.n2") === -1) { vn.push("story_office_the_desk.n2"); }<</script>>
<<nobr>>
<<link "Walk out" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_sex");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>She needs a recommendation letter. For a transfer application, for a scholarship, for the next step out of this city. He's the only professor who knows her name.</p><p>His office. The routine. Lock the door. The click that means everything that follows doesn't exist outside this room.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> I need the letter, Professor.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I know what you need.</div></div><p>She kneels. This time it's different — not a handjob but her mouth. She takes him in and works him the way she's learned. Fast. Purposeful. His hand goes to her hair and his fingers tighten and she hears the leather chair creak under his weight.</p><p>He finishes. She swallows. Stands. Wipes her mouth with the back of her hand.</p><p>He turns to his computer. Types for two minutes. The printer hums. He signs the letter with a fountain pen and slides it across the desk.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> You earned this.</div></div><p>She takes the letter. Folds it. Puts it in her bag. Walks to the door. Unlocks it. Walks out.</p><p>She doesn't look back. She's not sure if she hates him or herself more. She's not sure it matters.</p><video src="./videos/story/story_office_the_letter_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "1606d409-692c-4610-8136-5c9bccc0056c">>
<<set $game_state.current_node = "b22c599c-aec5-4e1a-90d6-4d3abdaaa05a">>
<<script>>setup.markCanvasTriggered("1606d409-692c-4610-8136-5c9bccc0056c");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_the_letter.base") === -1) { vn.push("story_office_the_letter.base"); }<</script>>
<<nobr>>
<<link "Walk out" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 4.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_blowjob");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>Finals week. She needs to pass this class or she loses financial aid. He knows this. She told him two weeks ago and watched something shift behind his eyes — not sympathy, something else. Opportunity.</p><p>His office. Door locked. He's behind the desk with her exam paper in front of him. Red pen in hand. He hasn't started grading it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Sit down.</div></div><p>She doesn't sit in the student chair. She walks around the desk. He watches her. She kneels.</p><p>His breath catches. His hand tightens on the pen. She undoes his belt. Button. Zipper. Takes him in her hand.</p><p>He leans back in the leather chair. Closes his eyes. She strokes him — firm, steady, reading his breathing the way he taught her to read Dostoevsky. Close. Careful. Finding the subtext.</p><p>Someone knocks. They both freeze. Her hand is still on him. He's still hard.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Come back in ten minutes.</div></div><p>Footsteps walk away. He looks down at her. She looks up at him. They don't stop.</p><p>He finishes. She cleans up with a tissue from the box on his desk. Goes back to the student chair. Smooths her hair.</p><p>He picks up the red pen. Grades her exam. Slides it across the desk. A-.</p><p>Neither of them says anything.</p><video src="./videos/story/story_office_under_the_desk_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6b03f162-d1f4-4990-83ff-cfbbd9c15039">>
<<set $game_state.current_node = "5274762f-74cc-4ef0-a835-66efa3a1e3db">>
<<script>>setup.markCanvasTriggered("6b03f162-d1f4-4990-83ff-cfbbd9c15039");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_under_the_desk.base") === -1) { vn.push("story_office_under_the_desk.base"); }<</script>>
<<nobr>>
<<link "Take the exam and leave" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_handjob");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>She missed an assignment. A zero. Her grade is hanging by a thread and she's panicking — she can feel it in her chest, the tightness, the math she keeps doing in her head that doesn't add up.</p><p>She goes to his office. Doesn't knock. Just walks in.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> I got a zero. On the assignment. I was working a double and I —</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I know.</div></div><p>He stands. Walks to the door. Closes it. The frosted glass rattles in the frame. Then he turns the lock. The click is loud in the small room.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I can make that zero disappear. You know that.</div></div><p>She knows. She's known since the B+ she didn't earn. Since his knee against hers. Since the way he looks at her when the door is closed.</p><p>He steps close. Tilts her chin up with two fingers. His eyes search her face for permission.</p><p>He kisses her. Slow. Deliberate. His hand moves to the back of her neck. She can feel the weight of his palm, the roughness of his fingers. She kisses him back.</p><p>When he pulls away his breathing is different.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Come back Thursday.</div></div><p>She nods. The zero is gone by morning.</p><img src="./videos/story/story_office_the_lock_base.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f6e14239-e475-4359-964d-b8d00cfd5452">>
<<set $game_state.current_node = "80e8f153-acf0-41b7-a114-ff46803450f0">>
<<script>>setup.markCanvasTriggered("f6e14239-e475-4359-964d-b8d00cfd5452");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_the_lock.base") === -1) { vn.push("story_office_the_lock.base"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 5.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_kissed");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>They're reviewing her essay. He's next to her now — not behind the desk but on the edge of it, leaning forward, their knees almost touching. She can smell his cologne. Something woody and warm.</p><p>He's pointing at a paragraph. His hand is close to hers on the paper. She can feel the heat of it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> This sentence. Read it again.</div></div><p>She reads. He watches her mouth. She knows he's watching her mouth.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> You know, I bumped your last paper to a B+. You deserved a C.</div></div><p>Long pause. The room is very quiet. She can hear the clock on the wall.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Why are you telling me that?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I just want you to know. That's all.</div></div><p>But it's not all. They both know it's not all. He gave her something she didn't earn. Now there's a debt between them that neither of them is naming.</p><p>His knee touches hers. Neither of them moves.</p><img src="./videos/images/story/story_office_the_shift_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "88fb4afa-9dc8-4785-a303-58961684db7e">>
<<set $game_state.current_node = "3c370d5b-0daf-4396-a563-e9ea3ebaf63c">>
<<script>>setup.markCanvasTriggered("88fb4afa-9dc8-4785-a303-58961684db7e");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_the_shift.base") === -1) { vn.push("story_office_the_shift.base"); }<</script>>
<<nobr>>
<<link "Leave quietly" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_shift");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Room 208. She knocks. The door is open. Harlan is behind his desk, glasses on, red pen in hand.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Emma. Sit down.</div></div><p>He pulls her last test from a stack. There's less red ink this time. Not a lot less — but less.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> You've been studying.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> The library. Every afternoon I'm not working.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> It shows. You went from an F to a C. That's not nothing.</div></div><p>He leans back in his chair. Takes off his glasses. The thing he does when he's about to say something he's been thinking about.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I could help you. Twice a week, office hours. I'll walk you through the material. Get you to a B.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Why?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Because you gave me the best answer on Raskolnikov I've heard in three years. Because you work harder than anyone in that classroom. And because I think you're smarter than your grades say.</div></div><p>She says yes. He smiles. Something in the way he says 'good' stays with her all day.</p><img src="./videos/images/story/story_office_the_offer_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "cdc8a603-8a92-4e63-90fa-344a6719b4b3">>
<<set $game_state.current_node = "98730067-1b9f-4f9e-b3be-2a5a61aa9495">>
<<script>>setup.markCanvasTriggered("cdc8a603-8a92-4e63-90fa-344a6719b4b3");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_office_the_offer.base") === -1) { vn.push("story_office_the_offer.base"); }<</script>>
<<nobr>>
<<link "Accept" "Location_Professor's_Office">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_offered_study");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>After class. The other students file out. Harlan is at the front, stacking papers. He holds one up without looking at it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Emma. Stay a minute.</div></div><p>She walks to the front. He hands her the test. Red ink everywhere. A grade she doesn't want to read circled at the top.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> You're going to fail this class.</div></div><p>It's not mean. It's flat. A fact.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> I work nights. At a bar. I don't have time to —</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> I know. I can see it. You come in tired, you leave tired. But tired doesn't pass exams.</div></div><p>He pulls a sticky note from his desk. Writes his office hours on it. Room 208. Slides it across.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> The library is open until nine. Use it. And if you need help — come see me.</div></div><p>She takes the sticky note. His handwriting is neat. She folds it and puts it in her pocket.</p><img src="./videos/images/story/story_classroom_the_warning_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "4321f11f-19a4-4f13-9249-76da6ad9d0a4">>
<<set $game_state.current_node = "f96cf1b5-8d0c-4df7-bf35-727b06535cac">>
<<script>>setup.markCanvasTriggered("4321f11f-19a4-4f13-9249-76da6ad9d0a4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_classroom_the_warning.base") === -1) { vn.push("story_classroom_the_warning.base"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "harlan_warning");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>New semester. New professor. Literature 201 — the kind of class that fills up because the professor has a reputation. Emma's in the back row with her dollar-store notebook when he walks in.</p><p>Professor Harlan. Mid-forties. Tall, lean, salt-and-pepper stubble. Reading glasses he puts on and takes off like punctuation. He doesn't use the podium — he walks between the rows, talks with his hands, makes eye contact with students like he's having a conversation instead of giving a lecture.</p><p>He's talking about Dostoevsky. About guilt and desire and the stories people tell themselves to justify what they want. Emma stops taking notes and just listens.</p><p>Halfway through, he cold-calls her. She wasn't expecting it — her hand isn't up, she's in the back row, she's nobody.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> You. Back row. What does Raskolnikov actually want?</div></div><p>She answers. She doesn't know where it comes from — something about permission, about wanting to prove he's allowed to take what he wants. The room is quiet. Harlan looks at her for three seconds.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> That's the best answer I've heard in three semesters. What's your name?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Emma.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/professor_harlan.jpg" alt="Professor Harlan" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Professor Harlan:</strong> Emma. Don't sit in the back row. You're wasted there.</div></div><p>Nobody's ever said that to her. Not here, not anywhere. She moves her chair forward — just a few inches. He notices.</p><img src="./videos/images/story/story_classroom_the_lecture_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "8cd0ef95-024d-457d-98e3-b1b403c01f18">>
<<set $game_state.current_node = "62002070-24ec-498d-9c8c-03cd8573206b">>
<<script>>setup.markCanvasTriggered("8cd0ef95-024d-457d-98e3-b1b403c01f18");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_classroom_the_lecture.base") === -1) { vn.push("story_classroom_the_lecture.base"); }<</script>>
<<nobr>>
<<link "Head out" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_harlan", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "met_harlan");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>Emma forgot her notebook. The one with her lecture notes for Thursday's exam. She goes back to the classroom building after hours — the hallway is empty, half the lights are off, her sneakers squeak on the linoleum.</p><p>Room 214. The door is ajar. Light from inside cuts a stripe across the hallway floor. Emma pushes it open.</p><p>A girl is sitting on the professor's desk. Her legs are apart. A guy is standing between them, leaning into her, his hands on the wood on either side of her hips. The girl's skirt is pushed up around her waist. Her underwear is on the floor next to a stack of dropped textbooks. His shirt is untucked and her hands are underneath it, nails dragging down his back.</p><p>He's moving against her — slow, pressing, the desk scraping an inch across the floor with each push. The girl's head is thrown back and her eyes are closed and she's making a sound that echoes in the empty classroom — a breathy, rhythmic 'ah' that gets louder each time he drives forward. Her ankles are locked behind his thighs, pulling him deeper.</p><p>The whiteboard behind them still has today's lecture notes. A chair is knocked over. The professor's nameplate — DR. KIERAN — is face-down on the floor.</p><p>The guy grabs her hips and pulls her to the edge of the desk and the girl gasps — sharp, involuntary, her back arching off the wood. She grabs his shoulders and digs in and whispers 'don't stop' and it's not a whisper, it's loud enough that Emma hears every syllable from the doorway.</p><p>The door hinges creak. They hear it.</p><p>The girl's eyes open. She looks directly at Emma. Flushed. Lips swollen. Hair sticking to her forehead. She doesn't scream, doesn't cover herself, doesn't push the guy away. She just looks at Emma with an expression that's half-startled and half-something else — annoyed, maybe, that someone interrupted.</p><p>The guy freezes but doesn't turn around. His hands are still on her hips. Nobody moves for two seconds.</p><p>Emma pulls the door shut. The latch clicks. She stands in the hallway and her heart is hammering and the fluorescent light above her is buzzing and she can hear them start again through the door — the desk scraping, the girl's voice rising.</p><p>They didn't even wait for her footsteps to fade.</p><p>Emma walks out of the building without the notebook. The night air hits her face and she realizes she's been holding her breath since she opened the door.</p><video src="./videos/random/random_campus_classroom_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "a20c8331-c9ee-4aeb-8954-3f00d5d714de">>
<<set $game_state.current_node = "267e2ffb-0e4b-4df2-8c02-7ee61fa652f0">>
<<script>>setup.markCanvasTriggered("a20c8331-c9ee-4aeb-8954-3f00d5d714de");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_campus_classroom.base") === -1) { vn.push("random_campus_classroom.base"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>Emma takes the elevator to the third floor. The quiet section. It's past seven — the overhead lights are dimmed to half and most of the study carrels are empty. The carpet absorbs her footsteps.</p><p>She turns the corner between the philosophy and religion shelves and stops.</p><p>A girl is on a guy's lap in the last carrel. Facing him. Straddling. Her skirt is fanned out over his thighs and her textbook is still open on the desk beside them, a highlighter rolling slowly toward the edge. Her blouse is unbuttoned to the third button and his hand is inside it, cupping her breast, his thumb moving in lazy circles.</p><p>She's rocking on him. Slowly. A barely-there motion that Emma might have missed if the girl's breath wasn't hitching every time she moved forward. The guy's other hand is under her skirt, gripping her hip, guiding the rhythm. His eyes are closed and his lips are parted and his head is tilted back against the carrel wall.</p><p>The girl leans forward and puts her mouth against his ear. Whispers something. He groans — quiet, stifled, the kind of sound a person makes when they're trying not to be heard in a library. His grip tightens on her hip and she grinds down harder and her breath catches and she bites her lip and closes her eyes.</p><p>Emma is six feet away. Standing between two shelves of books she's never going to read. She can hear the creak of the chair. She can hear the girl's breathing — short, quick, controlled, like she's counting to keep herself quiet. She can hear the wet sound of the guy's mouth on her neck.</p><p>The girl opens her eyes. Sees Emma. Holds the eye contact for three full seconds — flushed, glassy-eyed, still moving on his lap. No embarrassment. No panic. The look says: I know you're watching. I don't care. Then she turns back to the guy, puts both hands on his shoulders, and rolls her hips in a way that makes him grab the edge of the desk.</p><p>The highlighter falls off the desk and rolls across the carpet to Emma's feet.</p><p>Emma leaves. Finds a table on the second floor, under the fluorescent lights, surrounded by freshmen with earbuds in. She opens her textbook. Reads the same paragraph four times. The words don't connect.</p><p>The girl's face is still in her head. Not the sex. The look. The absolute absence of shame.</p><p>Emma closes the book and stares at the table and doesn't understand why she feels like the one who did something wrong.</p><video src="./videos/random/random_campus_library_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "446cd4c8-b8c1-4b41-973d-4a4f3fdf8cbf">>
<<set $game_state.current_node = "9985857f-f43c-4b19-a255-4cdecdc36590">>
<<script>>setup.markCanvasTriggered("446cd4c8-b8c1-4b41-973d-4a4f3fdf8cbf");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_campus_library.base") === -1) { vn.push("random_campus_library.base"); }<</script>>
<<nobr>>
<<link "Find another section" "Location_Library">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(10);<</script>><</link>><br>
<</nobr>><p>A lit window on the second floor of a walk-up across the street. The curtain is half-drawn — cheap fabric, the kind that doesn't close all the way. Warm yellow light spills onto the fire escape.</p><p>Emma sees the silhouettes before she hears them. A woman on her knees on a bed, facing the headboard. A man behind her, one hand on her hip, the other tangled in her hair. They're moving together — slow, deep, the woman's back dipping with each stroke.</p><p>The window is open because the building doesn't have air conditioning. The sounds drift down to the sidewalk like smoke. A moan — long, unguarded, the kind that doesn't know there's a street below. Then a gasp. The creak of a bed frame. The man says something and the woman laughs, and the laugh turns into a sound that isn't laughter anymore.</p><p>The rhythm changes. Faster. The headboard taps against the wall — a quick, insistent knocking that Emma can hear over the traffic. The woman grabs the headboard rail with both hands and pushes back against him and the moan that comes out of her is loud enough that a man on the opposite sidewalk glances up, shrugs, keeps walking.</p><p>A guy walking his dog passes Emma without looking. A taxi honks. A couple argues outside the bodega on the corner. Nobody cares about the open window. Nobody stops.</p><p>Except Emma. Emma has stopped. She's standing on the sidewalk with her bag on her shoulder and her lips parted and she is watching the silhouettes move behind that half-drawn curtain like it's a movie she can't turn off.</p><p>The woman cries out — high, broken, repeating. The man's shadow leans forward, both hands on her hips now, and the bed frame protests and the curtain sways in the breeze and Emma can see the arch of the woman's spine, the way her head drops between her arms, the way her whole body shudders.</p><p>Then quiet. Low voices. A laugh. The light stays on.</p><p>Emma starts walking again. She doesn't know how long she was standing there. A minute. Maybe longer. Her mouth is dry and the night air feels electric on her skin.</p><p>This neighborhood doesn't hide anything. It doesn't bother. And something in Emma is starting to understand why.</p><img src="./videos/random/random_street_window_base.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "604f88e0-de85-4645-87d5-c4944f0c5c11">>
<<set $game_state.current_node = "4f8056de-eb53-4245-904e-c08fee718b29">>
<<script>>setup.markCanvasTriggered("604f88e0-de85-4645-87d5-c4944f0c5c11");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_street_window.base") === -1) { vn.push("random_street_window.base"); }<</script>>
<<nobr>>
<<link "Walk on" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>Walking home. The streetlights are orange and half of them are out. The sidewalk is cracked and the air smells like exhaust and the cheap pizza place on the corner.</p><p>Movement. An alley between a laundromat and a boarded-up pawn shop. Emma's eyes go there before her brain can stop them.</p><p>A woman is pressed against the brick wall. Her jacket is open, her shirt hiked up, and the man in front of her has one hand flat against the wall beside her head and the other between her thighs. She's not fighting it. Her back is arched off the bricks and her mouth is open and her hips are moving against his hand in a slow, deliberate grind.</p><p>He says something into her neck. She laughs — breathless, dirty — and grabs his belt buckle. Pulls it open. The metallic clink is loud in the quiet street. She gets his zipper down and her hand disappears between them and the man's head drops forward, a groan escaping through his teeth.</p><p>The woman hooks one leg around his hip. He lifts her — just enough — and she gasps, sharp, the kind of gasp that isn't surprise. Her back scrapes against the brick and she doesn't care. Her fingers dig into his shoulders and she buries her face in his neck and the sounds she makes are muffled but unmistakable.</p><p>They're ten feet away. Under a broken streetlight. They don't see Emma. Or they see her and it changes nothing. The rhythm is steady — the woman's heel bouncing against the man's thigh, the wet sound of breathing, a whispered 'yeah' that could be from either of them.</p><p>A car drives past. Headlights sweep the alley for one second — enough to see her face. Eyes closed. Lips parted. Lost.</p><p>Emma walks faster. Her sneakers are loud on the sidewalk and she doesn't look back. She tells herself she doesn't look back.</p><p>Three blocks later she can still hear them. Not really — the distance is too far. But her brain keeps playing it. The gasp. The clink of the belt. The way the woman moved like she'd forgotten the rest of the world existed.</p><p>Emma walks home with her hands in her pockets and her pulse in her throat.</p><video src="./videos/random/random_street_alley_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "6f5a0423-42c2-47ae-b633-d46845096230">>
<<set $game_state.current_node = "4deebd76-753f-4407-8231-8150ec299bd0">>
<<script>>setup.markCanvasTriggered("6f5a0423-42c2-47ae-b633-d46845096230");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_street_alley.base") === -1) { vn.push("random_street_alley.base"); }<</script>>
<<nobr>>
<<link "Keep walking" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>Emma comes upstairs in the afternoon. The bar is slow — a Tuesday, maybe three people nursing beers downstairs. She figured they'd both be working.</p><p>Their bedroom door is open. Not all the way. Six inches. Enough.</p><p>Jolene is on the bed, on her back. Her tank top is pushed up above her breasts, bunched under her chin. Her jeans are on the floor. Mick is standing at the edge of the mattress, shirtless, his belt coiled on the carpet like a dead snake. His hands are around Jolene's ankles, holding her legs apart.</p><p>Jolene's back arches off the sheets. She grabs a fistful of the comforter and pulls it sideways, her mouth open, a sound coming out of her that isn't a word — low and thick and shameless. Mick leans forward and she wraps her legs around him, pulling him in, her heels digging into the small of his back.</p><p>He moves. Slow at first — deliberate, grinding. Jolene bites her lip and her hips roll up to meet him. Then faster. The bed shifts on the hardwood floor with a scrape. Jolene's hand goes to his chest, nails pressing into skin, and she says his name — not the way you say someone's name across a room. The way you say it when you're underneath them.</p><p>Emma is three feet away. Through a gap in a door. She can see the sweat on Jolene's stomach. She can see Mick's shoulders flex as he grips the headboard with one hand for leverage. She can hear every sound — skin against skin, the wet rhythm of it, Jolene's breathing getting shorter and higher.</p><p>She should look away. She should already be in her room.</p><p>Jolene's eyes are closed. Her mouth shapes a word that might be 'God' or might be 'more' — Emma can't tell and it doesn't matter because the sound Jolene makes next is neither. It's raw. Mick responds by going harder, the bed now slamming into the wall in a rhythm that shakes the hallway floor.</p><p>Emma moves. Finally. Gets to her room. Shuts the door. Leans against it. Her hands are shaking and her face is burning and she can still hear them — muffled now, but unmistakable. The bed. Jolene's voice climbing. Mick's low groan.</p><p>The look on Jolene's face is burned behind Emma's eyelids. Not pain. Not performance. Something real and animal and completely unashamed.</p><p>Emma sits on her bed and presses her palms against her knees and waits for her heart to slow down. It takes a long time.</p><video src="./videos/images/random/random_home_door_open_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "a5096478-41ba-4d6d-bea2-3b5dbf42dedf">>
<<set $game_state.current_node = "68eaf89e-6922-49ac-a3f0-b7b7def7e663">>
<<script>>setup.markCanvasTriggered("a5096478-41ba-4d6d-bea2-3b5dbf42dedf");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("random_home_door_open.base") === -1) { vn.push("random_home_door_open.base"); }<</script>>
<<nobr>>
<<link "Sit with it" "Location_Upstairs">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>The living room. The standing lamp throws orange light across the peeling wallpaper. The TV is on low — some late-night show, a man in a suit interviewing a woman who laughs too loudly at everything.</p><p>Mick is already on the couch. One arm along the backrest, feet up on the coffee table. He doesn't look up when she comes in. Doesn't need to.</p><p>Emma drops onto the other end. The couch sags under her like it's been waiting for someone to give it permission to collapse. The cushions smell like old fabric softener and Jolene's cigarettes and something else — just the smell of a building that people have been living in for too long.</p><p>Neither of them changes the channel. The TV talks. They don't. The building settles around them — creaking pipes, the fridge humming in the kitchen, the last sounds from the bar below fading into nothing. The orange light makes everything feel smaller. Closer.</p><p>She pulls a blanket off the back of the couch and wraps it around her knees. He watches the screen. She watches the screen. Sometimes that's enough.</p><img src="./videos/images/activities/activity_watch_tv_mick.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "e5f96f34-45bb-4387-b95a-2c7185aed29e">>
<<script>>setup.markCanvasTriggered("b2fb3e47-e597-46e1-b665-682158473813");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.base") === -1) { vn.push("activity_watch_tv_mick.base"); }<</script>>
<<nobr>>
<<link "Watch with him" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 65}, {"type": "flag", "subject": "player", "flag_key": "learned_seduction", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_mick", "trait_key": "love", "operator": "gte", "value": 8}]})>>
<span @class="setup.isChoiceVisited('b2fb3e47-e597-46e1-b665-682158473813:cc0') ? '' : 'unlocked-choice'">
<<link "Flirt" "Canvas_activity_watch_tv_mick_Node_2">><<script>>setup.markChoiceVisited("b2fb3e47-e597-46e1-b665-682158473813:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 90}, {"type": "flag", "subject": "player", "flag_key": "discovered_teasing", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('b2fb3e47-e597-46e1-b665-682158473813:cc1') ? '' : 'unlocked-choice'">
<<link "Tease him" "Canvas_activity_watch_tv_mick_Node_3">><<script>>setup.markChoiceVisited("b2fb3e47-e597-46e1-b665-682158473813:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 120}, {"type": "flag", "subject": "player", "flag_key": "first_kiss_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('b2fb3e47-e597-46e1-b665-682158473813:cc2') ? '' : 'unlocked-choice'">
<<link "Kiss him" "Canvas_activity_watch_tv_mick_Node_4">><<script>>setup.markChoiceVisited("b2fb3e47-e597-46e1-b665-682158473813:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "touched_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('b2fb3e47-e597-46e1-b665-682158473813:cc3') ? '' : 'unlocked-choice'">
<<link "Give him a handjob" "Canvas_activity_watch_tv_mick_Node_5">><<script>>setup.markChoiceVisited("b2fb3e47-e597-46e1-b665-682158473813:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "gave_blowjob", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('b2fb3e47-e597-46e1-b665-682158473813:cc4') ? '' : 'unlocked-choice'">
<<link "Give him a blowjob" "Canvas_activity_watch_tv_mick_Node_6">><<script>>setup.markChoiceVisited("b2fb3e47-e597-46e1-b665-682158473813:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "mick_sex", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('b2fb3e47-e597-46e1-b665-682158473813:cc5') ? '' : 'unlocked-choice'">
<<link "Ride him" "Canvas_activity_watch_tv_mick_Node_7">><<script>>setup.markChoiceVisited("b2fb3e47-e597-46e1-b665-682158473813:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>Emma shifts on the couch. Not much — just enough. Her knee touches his thigh. She doesn't move it.</p><p>The TV plays something neither of them is watching. She laughs at a joke that isn't funny and turns her head toward him. He's close. The orange light catches the stubble on his jaw.</p><p>She asks about the show. He answers in three words. She asks another question and lets her shoulder press against his arm. He doesn't pull away.</p><p>When the scene changes she stretches and her hand lands on his knee for a second — casual, like she's just adjusting. His eyes flick down to her hand and back to the screen.</p><p>She leaves her knee against his for the rest of the episode.</p><img src="./videos/images/activities/activity_watch_tv_mick_flirt.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "0b8f00b4-21fe-4a9c-b4b4-6f1b2a80e6f2">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.flirt") === -1) { vn.push("activity_watch_tv_mick.flirt"); }<</script>>
<<nobr>>
<<link "Go to bed" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "flirt_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>Emma pulls the blanket off the back of the couch and drapes it over her lap. She tucks her legs up underneath her — the movement pushes her closer to Mick, close enough that her hip presses against his.</p><p>She stretches. Arms above her head, back arching. The tank top rides up past her navel. She holds the stretch one beat too long and catches him looking from the corner of his eye.</p><p>She settles back down and adjusts her shirt. Doesn't pull it all the way down. Leaves a strip of skin showing above the waistband of her shorts.</p><p>She yawns, leans sideways, lets her head almost — not quite — rest on his shoulder. The blanket has slipped off one leg and her bare thigh is right there, inches from his hand on the cushion.</p><p>He stares at the TV like it owes him money.</p><img src="./videos/images/activities/activity_watch_tv_mick_tease.gif" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "72c08b11-32d9-4fdd-bd37-6c06b45d3b9f">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.tease") === -1) { vn.push("activity_watch_tv_mick.tease"); }<</script>>
<<nobr>>
<<link "Go to bed" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>The show ends. Credits roll. Neither of them reaches for the remote.</p><p>Emma turns her head. He's right there — profile lit by the TV glow, jaw set, eyes forward. She can smell the whiskey on his breath and the soap on his skin.</p><p>She leans in. Slow. Gives him time to pull away. He doesn't.</p><p>Her lips find his. Soft at first. His mouth is warm and tastes like bourbon and he doesn't move for a second — then his hand comes up to the side of her face and he kisses her back.</p><p>The TV throws blue light across them. The building is quiet. His thumb brushes her cheekbone and she feels the roughness of his calluses against her skin.</p><p>He pulls back. Clears his throat. Picks up the remote and turns the TV off.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Good night.</div></div><img src="./videos/activities/activity_watch_tv_mick_kiss.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "011066cb-3d5e-435c-a198-179d649205df">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.kiss") === -1) { vn.push("activity_watch_tv_mick.kiss"); }<</script>>
<<nobr>>
<<link "Go to bed" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>The blanket is over both of them now. His arm along the backrest, her legs tucked up, the fabric pooling across their laps. The TV murmurs. The building settles.</p><p>Her hand moves under the blanket. Finds his thigh. He tenses but doesn't move. She slides higher.</p><p>Her fingers find his belt. She doesn't look at him — keeps her eyes on the screen like she's watching the show. Buckle. Button. Zipper. Her hand slips inside and wraps around him.</p><p>He exhales through his nose. Sharp. Controlled. His hand grips the armrest and his jaw locks shut.</p><p>She strokes him under the blanket. Slow, steady. The TV covers the sound of the fabric moving. His breathing gets rougher. She can feel the pulse against her fingers, the heat building.</p><p>He comes with his teeth clenched. Silent. She feels it happen — the tension, the release, the way his whole body goes rigid for three seconds and then sags into the cushions.</p><p>She pulls her hand free. Wipes it on the underside of the blanket. Neither of them looks at the other.</p><p>She stands up. Folds the blanket. Puts it back on the couch.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Good night, Mick.</div></div><video src="./videos/activities/activity_watch_tv_mick_handjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "21000d78-4479-412c-88ff-c35198b6ec72">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.handjob") === -1) { vn.push("activity_watch_tv_mick.handjob"); }<</script>>
<<nobr>>
<<link "Go to bed" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>Emma slides off the couch. The blanket falls away. She turns and kneels between his legs on the carpet.</p><p>Mick looks down at her. The TV throws blue light across his face. He doesn't say anything. He doesn't need to.</p><p>She undoes his belt. Takes her time. Button. Zipper. Pulls him free. He's already hard.</p><p>She takes him in her mouth. The carpet is rough under her knees — better than the stockroom concrete, worse than the bathroom tile. The TV plays a laugh track and somewhere in the building a pipe creaks.</p><p>His hand finds the back of her head. Not pushing — just resting there. His fingers in her hair. She can feel them trembling.</p><p>She works him with her mouth and her hand. The sounds she makes mix with the TV — wet, rhythmic, obscene under the canned laughter. His hips shift on the cushion and the couch springs creak.</p><p>He comes. She swallows. Wipes her mouth with the back of her hand. Stands up.</p><p>She picks up the remote and turns the TV off. The room goes dark except for the orange lamp.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Good night, Mick.</div></div><video src="./videos/activities/activity_watch_tv_mick_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "3ec2aba9-5e9d-4876-96f8-9bdbf2e46441">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.blowjob") === -1) { vn.push("activity_watch_tv_mick.blowjob"); }<</script>>
<<nobr>>
<<link "Go to bed" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>Emma throws the blanket over both of them. Slides into his lap. Faces him. Her knees on either side of his hips, sinking into the sagging cushions.</p><p>She reaches under the blanket. Pulls him free. He's hard — he was hard the moment she sat down, she thinks. She shifts her hips forward, pulls her shorts aside, and sinks onto him.</p><p>The couch springs creak. The TV plays something — she doesn't know what, doesn't care. She moves slowly, rocking her hips, the blanket hiding everything. If Jolene came down the stairs right now she'd see two people watching TV under a blanket.</p><p>His hands find her hips under the fabric. Guiding her. His grip tightens as she moves faster and the couch protests and the orange lamp throws their shadow across the wall — one shape, moving.</p><p>She comes first. Bites her lip hard enough to taste copper and buries her face in his neck and shakes. He follows a minute later — his hands pulling her down hard onto him, his hips pushing up, a low groan muffled against her hair.</p><p>They sit there for a minute. Connected. His arms around her waist. The TV talking. Then she climbs off, fixes herself, picks up the remote.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Good night, Mick.</div></div><video src="./videos/activities/activity_watch_tv_mick_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "b2fb3e47-e597-46e1-b665-682158473813">>
<<set $game_state.current_node = "a4b60fad-199d-4ad4-9c67-b4a3d7900fb3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv_mick.sex") === -1) { vn.push("activity_watch_tv_mick.sex"); }<</script>>
<<nobr>>
<<link "Go to bed" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>The living room. The standing lamp throws orange light across the peeling wallpaper. The TV is on low — some late-night show, a man in a suit interviewing a woman who laughs too loudly at everything.</p><p>Emma drops onto the couch. The cushions sag under her. She flips through channels — news, infomercials, a movie she's seen twice. Nothing holds.</p><p>She watches anyway. Sometimes the point isn't what's on the screen. Sometimes the point is not being in her room, not thinking, not doing anything at all.</p><img src="./videos/images/activities/activity_watch_tv_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "e7d5c0fc-42e2-4c0e-abd2-ecb6ec7c9b82">>
<<set $game_state.current_node = "2e932ec1-5bae-4544-b517-50a2e044f04a">>
<<script>>setup.markCanvasTriggered("e7d5c0fc-42e2-4c0e-abd2-ecb6ec7c9b82");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_watch_tv.base") === -1) { vn.push("activity_watch_tv.base"); }<</script>>
<<nobr>>
<<link "Watch TV" "Location_Living_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>She goes to the bathroom. She doesn't pretend it's for any other reason anymore.</p><p>The stall. The hole. She sits down and waits. The fluorescent light buzzes. The sink drips. Five minutes. Seven.</p><p>Then the door on the other side opens. Footsteps. A belt buckle. A zipper.</p><p>A cock pushes through the hole. Anonymous. Faceless. Nobody.</p><p>Her hand moves. She wraps her fingers around him and strokes — slow at first, then faster. He makes a sound through the wall. His hips push forward.</p><p>He finishes fast. She feels the pulse, the warmth over her fingers. He pulls back. She washes her hands at the sink.</p><video src="./videos/activities/activity_bathroom_glory_hole_wait_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "bef271b2-5f93-4961-a847-f061b742a34b">>
<<set $game_state.current_node = "c397740d-a064-4466-a50d-911321f1fd61">>
<<script>>setup.markCanvasTriggered("bef271b2-5f93-4961-a847-f061b742a34b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bathroom_glory_hole_wait.base") === -1) { vn.push("activity_bathroom_glory_hole_wait.base"); }<</script>>
<<nobr>>
<<link "Go back to work" "Location_Bar_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 30.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 190}, {"type": "flag", "subject": "player", "flag_key": "glory_hole_handjob", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "blowjob_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('bef271b2-5f93-4961-a847-f061b742a34b:cc0') ? '' : 'unlocked-choice'">
<<link "Use your mouth" "Canvas_activity_bathroom_glory_hole_wait_Node_2">><<script>>setup.markChoiceVisited("bef271b2-5f93-4961-a847-f061b742a34b:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>She doesn't reach for it with her hand. Not this time.</p><p>She gets on her knees. The tile is cold and grimy under her bare skin. She leans forward and takes him in her mouth.</p><p>He tastes like salt and soap and skin. She doesn't know his name. She can't even see him — just a cock through a hole in a wall. The anonymity is the permission.</p><p>She works him with her mouth and her hand. The sounds echo off the tile walls — wet, obscene, louder than she intends. The bar is twenty feet away.</p><p>He finishes in her mouth. A folded bill pushes through the hole. Fifty dollars.</p><p>She rinses her mouth at the sink. Checks her reflection. Smooths her hair. Walks back to the bar. Nobody knows.</p><video src="./videos/activities/activity_bathroom_glory_hole_wait_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "bef271b2-5f93-4961-a847-f061b742a34b">>
<<set $game_state.current_node = "04e280b1-9037-4755-a42e-7b2f5f6ff2cf">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bathroom_glory_hole_wait.blowjob") === -1) { vn.push("activity_bathroom_glory_hole_wait.blowjob"); }<</script>>
<<nobr>>
<<link "Go back to work" "Location_Bar_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 50.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glory_hole_blowjob");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>Late night. The bar is loud enough that nobody notices when Emma slips into the bathroom. She's been thinking about the hole for three days. About the woman on her knees. About the sounds.</p><p>She sits in the stall. The tape is still gone. The hole is open — dark, waiting, a circle in the wood that she can't stop looking at.</p><p>She waits. Five minutes. Seven. The fluorescent light buzzes. The sink drips. She feels stupid. She feels like she's about to do something she can't take back.</p><p>Then the door on the other side opens. Footsteps. Someone enters the opposite stall. She hears a belt buckle. A zipper.</p><p>A cock pushes through the hole.</p><p>She stares at it. Thick. Hard. A stranger's cock, anonymous, no face attached, just flesh pushing through a hole in a bathroom wall. She doesn't know who he is. She doesn't want to know.</p><p>Her hand moves.</p><p>She doesn't decide. Her fingers close around the shaft and she feels the heat of it, the hardness, the pulse underneath her fingertips. He's warm. He's alive. He makes a sound — a sharp inhale through his nose — and his hips push forward.</p><p>She strokes. Slow at first, feeling the shape of him, the way the skin moves under her grip. Then faster. She's done this before — with Mick, on the couch — but this is different. This is nobody. This is a wall and a hand and permission that comes from anonymity.</p><p>He finishes fast. She feels the pulse in her hand, the sudden warmth spilling over her fingers. His hips jerk twice and then he pulls back through the hole. She hears him breathing — ragged, heavy — and then a zipper and footsteps and the door.</p><p>She's alone. Her hand is wet. She stands up and walks to the sink and washes her hands under the cold water and looks at herself in the cracked mirror.</p><p>The woman in the mirror has a flushed face and bright eyes and soap suds running down her wrists. Emma doesn't recognize her.</p><p>She dries her hands. Goes back to work. Nobody asks where she was.</p><img src="./videos/story/story_bathroom_glory_hole_handjob_base.webp" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "d53d41f9-cd24-4a9a-b018-30f8d29b714c">>
<<set $game_state.current_node = "2f12cdd5-f872-4664-a992-512c6545abda">>
<<script>>setup.markCanvasTriggered("d53d41f9-cd24-4a9a-b018-30f8d29b714c");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bathroom_glory_hole_handjob.base") === -1) { vn.push("story_bathroom_glory_hole_handjob.base"); }<</script>>
<<nobr>>
<<link "Go back to work" "Location_Bar_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "glory_hole_handjob");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>The tape is gone. Not peeling — gone. Someone ripped it off completely. The hole is open. A dark circle in the partition wall, edges smooth, the size of a fist.</p><p>Emma is in the stall and she's staring at the hole and the hole is staring back.</p><p>She hears the door on the other side open. Footsteps. Someone entering the stall opposite hers. The partition creaks. She can hear breathing — two people. A zipper.</p><p>She leans forward. Just an inch. Just enough.</p><p>Through the hole she can see the other side of the partition. A man is standing with his back to the wall, jeans pushed down. His cock is out — hard, thick, a stranger's cock in a dive bar bathroom. And a woman is on her knees in front of the hole. Dark hair. Tank top. Emma can only see the back of her head and her shoulders.</p><p>The woman reaches through the hole. Her fingers wrap around him and she strokes once, twice, then leans forward and takes him in her mouth. Emma can hear the sounds — wet, rhythmic, the soft gagging when she goes too deep. The man's hand goes to the back of her head. His hips push forward.</p><p>Emma can't move. She's frozen with her eye pressed to the hole, watching a stranger suck a stranger's cock three feet from her face. She can hear every sound — every breath, every slick noise, the man's low groaning that he's trying and failing to keep quiet.</p><p>The woman speeds up. The man's hand tightens in her hair. Emma watches his stomach muscles clench, watches his jaw drop open, watches his whole body lock up. The woman pulls back and his cum lands on her chin, her chest. She wipes her mouth with the back of her hand like she's done this a hundred times.</p><p>They leave. Separately. The door opens and closes twice and then Emma is alone in the bathroom with the fluorescent buzz and the dripping sink and the smell of sex that she can't unsmell.</p><p>She's shaking. Her hands, her thighs, the breath in her chest. She can feel the wetness in her underwear — she's soaked, has been since the woman first reached through the hole. Her body responded before her brain could decide how to feel.</p><p>She walks out of the bathroom. Doesn't wash her hands — she didn't touch anything. Didn't need to. The watching was enough.</p><p>For now.</p><img src="./videos/story/story_bathroom_glory_hole_watching_base.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "5c6002c4-5ccf-4630-a9cc-13c08c9b25b8">>
<<set $game_state.current_node = "04416e29-09c9-4931-89b6-a7196314381d">>
<<script>>setup.markCanvasTriggered("5c6002c4-5ccf-4630-a9cc-13c08c9b25b8");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bathroom_glory_hole_watching.base") === -1) { vn.push("story_bathroom_glory_hole_watching.base"); }<</script>>
<<nobr>>
<<link "Go back to work" "Location_Bar_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "watched_glory_hole");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>Emma goes to the bathroom. She tells herself she needs to pee. She tells herself that's the only reason.</p><p>She sits in the stall. The tape is peeling again — one corner hanging loose, the hole dark behind it. She can hear the bar through the wall. Glasses clinking. The jukebox. Jolene's voice carrying over everything.</p><p>She sits there longer than she needs to.</p><p>Sometimes there's nothing. Just the bar sounds and the fluorescent buzz and the drip from the sink that never stops. She waits and nothing happens and she leaves feeling stupid.</p><p>Sometimes she hears something. A door opening on the other side of the partition. Footsteps. A belt buckle. A zipper. Breathing that gets faster. Sounds she recognizes from the videos on her phone — wet, rhythmic, unmistakable.</p><p>Once she hears a woman's voice. Muffled. Low moans that rise in pitch and then stop suddenly, like someone put a hand over her mouth. The sound of skin on skin. A man grunting. Then silence. Then a zipper. Then the door.</p><p>Emma sits in the stall with her heart hammering against her ribs. Her thighs are pressed together. Her face is hot. She can feel her pulse between her legs — heavy, insistent, the same way it beats when she watches the videos in her room.</p><p>She doesn't touch the tape. She doesn't look through the hole. She just sits there and listens and breathes and waits until her heart slows down enough to walk back out.</p><video src="./videos/images/activities/activity_bathroom_glory_hole_listen_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "48c56334-29bf-4e48-b565-3d1b72817f3b">>
<<set $game_state.current_node = "d2846e60-6f6e-4ec1-9452-da5583824b64">>
<<script>>setup.markCanvasTriggered("48c56334-29bf-4e48-b565-3d1b72817f3b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bathroom_glory_hole_listen.base") === -1) { vn.push("activity_bathroom_glory_hole_listen.base"); }<</script>>
<<nobr>>
<<link "Go back to work" "Location_Bar_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(20);<</script>><</link>><br>
<</nobr>><p>Slow Tuesday. Jolene is behind the bar, cleaning glasses. Dave is nursing his usual bourbon. A guy Emma doesn't recognize sits two stools down, half-watching the TV.</p><p>The stranger comes back from the bathroom and sits down with a grin.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> You still got that hole in the ladies' room?</div></div><p>Jolene doesn't look up from the glass she's drying.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Been there since before we bought the place. Covered it up three times. Tape keeps coming off.</div></div><p>The guy laughs. Dave laughs. Jolene's mouth twitches.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> Maybe stop covering it up.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Maybe people should use it for what it's for and stop pretending they don't know.</div></div><p>More laughter. Emma is wiping down the far end of the bar. She hears every word. The hole. The tape. 'Use it for what it's for.'</p><p>She doesn't say anything. She finishes wiping and goes upstairs after the shift.</p><p>In her room, she opens her phone. Types two words into the search bar. The results load and she reads them and her face gets hot and her stomach drops and she puts the phone down on the mattress face-first.</p><p>A glory hole. That's what's in the bathroom she uses every day. A hole that people put their — that strangers —</p><p>She picks the phone back up. Reads more. Forums, explanations, stories from people who've used them. Anonymous. No names, no faces, no consequences. Just a wall and a hole and whatever happens through it.</p><p>She closes the browser. Stares at the ceiling. The water stain looks different tonight.</p><p>She can't stop thinking about the tape. How it keeps coming off.</p><img src="./videos/images/story/story_bathroom_glory_hole_learning_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "76b7dc61-b3f3-4059-8248-eb0f8f80f896">>
<<set $game_state.current_node = "05e3b4a2-cc10-4785-96d6-5c8cc79c55ac">>
<<script>>setup.markCanvasTriggered("76b7dc61-b3f3-4059-8248-eb0f8f80f896");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bathroom_glory_hole_learning.base") === -1) { vn.push("story_bathroom_glory_hole_learning.base"); }<</script>>
<<nobr>>
<<link "Put the phone down" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "learned_glory_hole");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma pushes into the bathroom stall during a busy Friday shift. The lock barely catches. She sits down and stares at the stall partition — the same scratched wood, the same carved initials, the same graffiti she's seen a hundred times.</p><p>Except tonight she notices the duct tape.</p><p>A square of silver tape on the partition wall, about waist height. The edges are curling. One corner has peeled back far enough to show what's underneath — a rough circle cut into the wood. About three inches across. The edges are smooth, like someone sanded them.</p><p>She stares at it. It's just a hole. Someone cut a hole in the bathroom partition and taped over it. She doesn't know why. Maintenance? Ventilation? Some drunk with a pocket knife?</p><p>She presses the tape back down. It sticks, mostly. The adhesive is old and the tape is warm from the bathroom heat.</p><p>She finishes, washes her hands, checks her reflection in the cracked mirror. Her eyes go back to the stall. The tape. The hole.</p><p>Just a hole. She pushes through the door and goes back to work.</p><img src="./videos/images/story/story_bathroom_glory_hole_discovery_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "8f5f2dcf-2ebd-4c34-b48e-0881230dd316">>
<<set $game_state.current_node = "ae1b9408-42e4-4a0b-9436-34222170f601">>
<<script>>setup.markCanvasTriggered("8f5f2dcf-2ebd-4c34-b48e-0881230dd316");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bathroom_glory_hole_discovery.base") === -1) { vn.push("story_bathroom_glory_hole_discovery.base"); }<</script>>
<<nobr>>
<<link "Go back to work" "Location_Bar_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "noticed_hole");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(10);<</script>><</link>><br>
<</nobr>><p>The bar bathroom. Fluorescent light that flickers, a mirror with a crack running diagonal across it. She washes her hands, splashes water on her face.</p><p>She looks at herself in the cracked mirror. Two versions of her face, split by the line. She fixes her hair. Straightens her shirt. Practices something that might be a smile.</p><p>Good enough.</p><img src="./videos/images/activities/activity_bar_bathroom_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "d3912f6e-d6c4-4aee-8e07-b0f44dfaed4f">>
<<set $game_state.current_node = "e875326f-e3b1-4b78-8d26-93964ebf21ed">>
<<script>>setup.markCanvasTriggered("d3912f6e-d6c4-4aee-8e07-b0f44dfaed4f");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_bathroom.base") === -1) { vn.push("activity_bar_bathroom.base"); }<</script>>
<<nobr>>
<<link "Head out" "Location_Bar_Bathroom">><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>The tiny bathroom. She bangs the pipe twice like Jolene taught her and waits for the hot water. It comes — eventually.</p><p>She showers. The mirror fogs up and clears slowly. She looks at herself. Same face. A little more tired than yesterday. A little less scared.</p><video src="./videos/images/activities/activity_shower_base.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "71dfd46a-725d-4a4c-9878-b9b4f65b131b">>
<<set $game_state.current_node = "4b39fc34-84ce-4c71-8670-788cc5407e15">>
<<script>>setup.markCanvasTriggered("71dfd46a-725d-4a4c-9878-b9b4f65b131b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_shower.base") === -1) { vn.push("activity_shower.base"); }<</script>>
<<if ndef $game_state.loop_count>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><</if>>
<<nobr>>
<<link "Get ready" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if not $game_state.loop_visited.includes("46274d3c-128b-42ca-a508-0b9d4e6dea59")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "caught_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc0') ? '' : 'unlocked-choice'">
<<link "Perform for him" "Canvas_activity_shower_Node_2">><<script>>setup.markChoiceVisited("71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc0");<</script>><<run $game_state.loop_visited.push("46274d3c-128b-42ca-a508-0b9d4e6dea59")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "gave_blowjob", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc1') ? '' : 'unlocked-choice'">
<<link "Call him in" "Canvas_activity_shower_Node_4">><<script>>setup.markChoiceVisited("71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc1");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "mick_sex", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc2') ? '' : 'unlocked-choice'">
<<link "Pull him under the water" "Canvas_activity_shower_Node_5">><<script>>setup.markChoiceVisited("71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc2");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>She's rinsing her hair when she hears it. The floorboard. That same creak outside the door.</p><p>She doesn't freeze this time. She smiles.</p><p>Emma turns slowly under the water, letting it run down her chest, her stomach. She knows the mirror catches everything. She knows the door is cracked. She knows he's there.</p><p>She takes her time. Runs her hands down her body like she's washing — but slower than washing. She arches her back under the hot water and lets him see what he came to see.</p><p>The breathing on the other side of the door gets rougher. She listens to it like music.</p><p>When she's done she turns the water off and stands there in the steam, dripping, not reaching for the towel. She counts to five. Then she hears the floorboard creak and his footsteps disappear down the hall.</p><p>She dries off slowly. Her heart is racing but her hands are steady. This is theirs now. This thing they don't talk about.</p><img src="./videos/activities/activity_shower_perform.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "71dfd46a-725d-4a4c-9878-b9b4f65b131b">>
<<set $game_state.current_node = "46274d3c-128b-42ca-a508-0b9d4e6dea59">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_shower.perform") === -1) { vn.push("activity_shower.perform"); }<</script>>
<<nobr>>
<<link "Finish the shower" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "touched_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc3') ? '' : 'unlocked-choice'">
<<link "Pull him inside" "Canvas_activity_shower_Node_3">><<script>>setup.markChoiceVisited("71dfd46a-725d-4a4c-9878-b9b4f65b131b:cc3");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if $game_state.loop_count lt 1>>
<<link "Stay a while" "Canvas_activity_shower_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>She doesn't wait for the floorboard this time. She turns off the water and opens the bathroom door while the steam is still pouring out.</p><p>He's right there. Two feet away. His hand was on the doorframe like he'd been leaning in and his eyes go wide — she's naked, dripping, and she's looking right at him.</p><p>She grabs the waistband of his sweatpants and pulls him inside. He stumbles forward and she pushes the door shut behind him with her hip.</p><p>The bathroom is small and full of steam. He's fully clothed and she's completely bare and the wrongness of it — the asymmetry — makes her pulse hammer in her throat.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Don't talk.</div></div><p>Her hand goes into his sweatpants. He's already hard — he was watching her, of course he's hard — and she wraps her fingers around him and pushes him back against the tile wall.</p><p>She strokes him fast. No buildup, no slow drift like the couch. This is urgent. The shower is still dripping behind her and water is running down her back and his t-shirt is getting wet where her body presses against him.</p><p>He grabs the towel rack with one hand. His other hand hovers at her hip — not touching, not quite, trembling an inch from her wet skin like he's afraid if he touches her back it becomes something else entirely.</p><p>He finishes fast. He was already close from watching. She feels the pulse and the heat and his whole body shudder against the tile and the groan he tries to swallow comes out anyway, echoing off the bathroom walls.</p><p>She lets go. Steps back. Opens the door with her clean hand and pushes him gently into the hallway.</p><p>She closes the door. Turns the shower back on. Washes her hand under the hot water and stands there with her forehead against the tile and her heart beating so hard she can see her pulse in the fogged mirror.</p><img src="./videos/activities/activity_shower_handjob.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "71dfd46a-725d-4a4c-9878-b9b4f65b131b">>
<<set $game_state.current_node = "97d1293d-0154-4ea7-84d4-7c4ac49de675">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_shower.handjob") === -1) { vn.push("activity_shower.handjob"); }<</script>>
<<nobr>>
<<link "Finish the shower" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>She turns off the water. Doesn't reach for the towel. Opens the bathroom door — naked, dripping, steam pouring out around her.</p><p>The hallway is empty. She leans out and calls his name. Quiet. Just loud enough to carry through one wall.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Mick.</div></div><p>Three seconds. Five. Then his door opens and he's in the hallway and his eyes go from her face to her body to her face again and she sees his throat work as he swallows.</p><p>She grabs the front of his t-shirt and pulls him into the bathroom. Shuts the door. Pushes him down onto the closed toilet lid. He sits heavy, hands on his thighs, looking up at her.</p><p>She goes to her knees on the bath mat. The tile is cold under her shins but the steam keeps the rest of her warm. Water drips from her hair onto his jeans, darkening the denim in spots.</p><p>She undoes his belt. He lifts his hips and she pulls him free. He's hard already — he was hard the moment she said his name, she can tell by how he throbs when her fingers wrap around the base.</p><p>She takes him in her mouth. Slow at first — feeling the weight of him on her tongue, the salt and heat, the way he fills her mouth. She finds a rhythm. Her hand wraps around what her mouth can't reach and she moves them together, up and down, wet and tight.</p><p>His hand goes to the back of her head. Not pushing — just resting there, his fingers in her wet hair, feeling her move. His breathing fills the small bathroom. The mirror is fogged. The shower drips behind her in slow, steady drops.</p><p>She takes him deeper. His hips push forward — involuntary, desperate — and she adjusts, breathing through her nose, her lips stretched around him. She can feel him getting close. The way his thighs tense under her hands, the way his cock swells, the way his fingers tighten in her hair.</p><p>He comes. She feels the first pulse on her tongue — hot, thick, bitter — and she swallows and keeps going, milking him through it while he groans above her, his head tipped back against the tile wall, his whole body shaking.</p><p>She lets him go. Wipes her mouth with the back of her hand. Stands up. Her knees ache from the bath mat and her jaw is sore and she's still naked and dripping and she has never felt more in control of anything in her life.</p><p>She turns the shower back on. Steps under the water. He sits there for a moment, then stands, fixes himself, and leaves without a word. The door clicks shut.</p><img src="./videos/activities/activity_shower_blowjob.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "71dfd46a-725d-4a4c-9878-b9b4f65b131b">>
<<set $game_state.current_node = "7a1103f4-f5cf-4113-99f0-feff049d083a">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_shower.blowjob") === -1) { vn.push("activity_shower.blowjob"); }<</script>>
<<nobr>>
<<link "Finish the shower" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>She opens the door. He's there — always there now, the floorboard creak that means he's watching. She grabs the front of his t-shirt with a wet hand and pulls him inside.</p><p>She pulls his shirt over his head while the water runs behind her. His jeans are soaked in seconds. She pushes them down and he kicks them off and the denim hits the tile with a heavy wet slap.</p><p>He pushes her back under the shower. The hot water hits them both. She wraps her arms around his neck. He lifts her — one arm under her thigh — and presses her back against the tile wall. The cold of the tile against her back, the heat of the water on her chest, the heat of him between her legs.</p><p>He enters her against the wall. The shower sprays across both of them and the water runs down between their bodies and the bathroom fills with steam so thick she can barely see his face. She can feel it though. Every part of it.</p><p>Her back slides against the wet tile with every thrust. She holds on to his shoulders — broad, slippery, the muscles working under her hands. The showerhead sprays wildly. Water pools on the floor and leaks under the door.</p><p>He comes with a groan that echoes off every surface in the tiny bathroom. She feels it inside her — the pulse, the heat, his whole body pressing her into the tile. She holds him there. Lets the water run over both of them.</p><p>He sets her down. Steps out of the shower. Puts on his wet jeans — an awkward, ridiculous struggle that she watches and almost laughs at. Almost. He picks up his soaked shirt and walks out barefoot, dripping a trail down the hallway.</p><p>She turns the water cold. Stands under it until her breathing is normal.</p><video src="./videos/activities/activity_shower_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "71dfd46a-725d-4a4c-9878-b9b4f65b131b">>
<<set $game_state.current_node = "a738042a-90e9-46b1-8d6a-61fecf4f6742">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_shower.sex") === -1) { vn.push("activity_shower.sex"); }<</script>>
<<nobr>>
<<link "Finish the shower" "Location_Upstairs_Bathroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma turns off the lamp. The bar is still going below — glasses, voices, the jukebox playing something she almost recognizes. She pulls the blanket to her chin.</p><p>Tomorrow will come whether she's ready or not.</p><img src="./videos/images/activities/activity_sleep_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "628fa649-7b77-4a22-98f4-54644236cce4">>
<<set $game_state.current_node = "817fadd9-3ff1-4e33-a566-54c14a24ab91">>
<<script>>setup.markCanvasTriggered("628fa649-7b77-4a22-98f4-54644236cce4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_sleep.base") === -1) { vn.push("activity_sleep.base"); }<</script>>
<<nobr>>
<<link "Sleep" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(480);<</script>><</link>><br>
<</nobr>><p>Emma lies on the bed. The ceiling has a water stain shaped like nothing. Through the floor, the bar hums — or doesn't, depending on the hour.</p><p>She doesn't do anything. Sometimes that's the only thing she can afford.</p><img src="./videos/images/activities/activity_rest_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "730bf86c-d699-4ab6-ae65-4d111b767c8b">>
<<set $game_state.current_node = "8f8edbd3-073d-4f9c-a95a-e6548176bf16">>
<<script>>setup.markCanvasTriggered("730bf86c-d699-4ab6-ae65-4d111b767c8b");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_rest.base") === -1) { vn.push("activity_rest.base"); }<</script>>
<<nobr>>
<<link "Rest" "Location_Emma's_Room">><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>Third floor. A study carrel in the corner with a scratched desk and a lamp that flickers if she bumps it. She opens her textbook — one of the two she could afford — and starts reading.</p><p>The library is quiet. Other students around her — some studying, some sleeping, some staring at phones. The clock on the wall ticks. Two hours disappear into chapter summaries and highlighted passages.</p><p>No money earned. No tips. Just her and a book and the slow, invisible work of learning something.</p><img src="./videos/images/activities/activity_study_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "80f79408-92a0-4d52-8f23-d3eb9691546a">>
<<set $game_state.current_node = "b75b58d9-e5ba-4286-bca1-89dc12c0aa24">>
<<script>>setup.markCanvasTriggered("80f79408-92a0-4d52-8f23-d3eb9691546a");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_study.base") === -1) { vn.push("activity_study.base"); }<</script>>
<<nobr>>
<<link "Study" "Location_Library">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "intelligence", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><p>The lecture hall fills up. Professor at the front, whiteboard covered in notes from the last class nobody erased. Emma sits in the back row with her one textbook and a notebook she bought at the dollar store.</p><p>She takes notes. She pays attention. This is what she came here for — a degree, a future, a way out. It doesn't pay rent, it doesn't fill the tip jar, but it matters. It has to matter.</p><img src="./videos/images/activities/activity_attend_class_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "41ec9ff8-0066-4912-a58e-b2fae8710ad0">>
<<set $game_state.current_node = "97da9a34-8b4a-4310-8eaa-5fbccd2c6628">>
<<script>>setup.markCanvasTriggered("41ec9ff8-0066-4912-a58e-b2fae8710ad0");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_attend_class.base") === -1) { vn.push("activity_attend_class.base"); }<</script>>
<<nobr>>
<<link "Pay attention" "Location_Classroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "intelligence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(180);<</script>><</link>><br>
<</nobr>><p>The bathroom door opens as Emma reaches for the handle. Mick steps out — towel around his waist, hair damp, steam behind him. He's bigger up close than she realized. Broad chest, water still running in the grooves between his muscles. A line of dark hair from his navel down past the towel.</p><p>He sees her, nods once.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> All yours.</div></div><p>He moves past her down the hall. No awkwardness. He's been sharing this building with tenants for years. It's just a Tuesday to him.</p><img src="./videos/images/activities/activity_mick_bathing_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "aa9a3617-1f43-4e73-a6aa-83253c2b55bc">>
<<set $game_state.current_node = "6ba0f791-60ed-4c18-bbb5-bd84b9ec8f5d">>
<<script>>setup.markCanvasTriggered("aa9a3617-1f43-4e73-a6aa-83253c2b55bc");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_bathing.base") === -1) { vn.push("activity_mick_bathing.base"); }<</script>>
<<nobr>>
<<link "Go in after him" "Location_Upstairs_Bathroom">><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>Emma pushes the bathroom door open. Jolene is at the sink — towel wrapped around her, wet hair dripping on her shoulders. She's brushing her teeth and doesn't flinch.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Morning, hon. Give me two minutes.</div></div><p>She rinses, spits, grabs her robe off the hook, and pads past Emma in bare feet. Normal. Completely normal. Like sharing a bathroom with someone is the most natural thing in the world.</p><p>For Jolene, it is.</p><img src="./videos/images/activities/activity_jolene_bathing_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "9b08929c-ee46-45aa-b4db-66ec18ea8734">>
<<set $game_state.current_node = "ab8fb38c-92c3-4e58-97dd-3bf67a901dfb">>
<<script>>setup.markCanvasTriggered("9b08929c-ee46-45aa-b4db-66ec18ea8734");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_jolene_bathing.base") === -1) { vn.push("activity_jolene_bathing.base"); }<</script>>
<<nobr>>
<<link "Wait your turn" "Location_Upstairs_Bathroom">><<script>>advanceTime(15);<</script>><</link>><br>
<</nobr>><p>Mick is in the stockroom. Clipboard, pen, same as every morning. He's counting bottles and doesn't look up when Emma comes in.</p><p>She leans against the doorframe. Asks something — about the bar, about the neighborhood, about how long he's been doing this.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Seventeen years.</div></div><p>He marks something on the clipboard. Doesn't elaborate. Mick answers questions the way he stocks shelves — one at a time, no extra.</p><p>But he answers. That's something.</p><img src="./videos/images/activities/activity_mick_chat_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "3faf0d7f-8561-4c4a-b7a9-1f0f6476e97f">>
<<script>>setup.markCanvasTriggered("2f49676f-e8b0-472d-953e-7c749a4625d1");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.base") === -1) { vn.push("activity_mick_chat.base"); }<</script>>
<<if ndef $game_state.loop_count>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><</if>>
<<nobr>>
<<link "Chat" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if not $game_state.loop_visited.includes("428d5cba-c724-4e47-82d2-0142ea8fb1ae")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 65}, {"type": "flag", "subject": "player", "flag_key": "learned_seduction", "operator": "is_true"}, {"type": "trait", "subject": "npc", "npc_id": "npc_mick", "trait_key": "love", "operator": "gte", "value": 8}]})>>
<span @class="setup.isChoiceVisited('2f49676f-e8b0-472d-953e-7c749a4625d1:cc0') ? '' : 'unlocked-choice'">
<<link "Flirt" "Canvas_activity_mick_chat_Node_2">><<script>>setup.markChoiceVisited("2f49676f-e8b0-472d-953e-7c749a4625d1:cc0");<</script>><<run $game_state.loop_visited.push("428d5cba-c724-4e47-82d2-0142ea8fb1ae")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("b3ac62ea-5e96-41f3-8f6e-416b967a4a6f")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 90}, {"type": "flag", "subject": "player", "flag_key": "discovered_teasing", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('2f49676f-e8b0-472d-953e-7c749a4625d1:cc1') ? '' : 'unlocked-choice'">
<<link "Tease him" "Canvas_activity_mick_chat_Node_4">><<script>>setup.markChoiceVisited("2f49676f-e8b0-472d-953e-7c749a4625d1:cc1");<</script>><<run $game_state.loop_visited.push("b3ac62ea-5e96-41f3-8f6e-416b967a4a6f")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if not $game_state.loop_visited.includes("aeb4133b-af46-4282-8ba6-19033ab74c22")>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 120}, {"type": "flag", "subject": "player", "flag_key": "first_kiss_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('2f49676f-e8b0-472d-953e-7c749a4625d1:cc2') ? '' : 'unlocked-choice'">
<<link "Kiss him" "Canvas_activity_mick_chat_Node_3">><<script>>setup.markChoiceVisited("2f49676f-e8b0-472d-953e-7c749a4625d1:cc2");<</script>><<run $game_state.loop_visited.push("aeb4133b-af46-4282-8ba6-19033ab74c22")>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "touched_mick", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('2f49676f-e8b0-472d-953e-7c749a4625d1:cc3') ? '' : 'unlocked-choice'">
<<link "Give him a handjob" "Canvas_activity_mick_chat_Node_5">><<script>>setup.markChoiceVisited("2f49676f-e8b0-472d-953e-7c749a4625d1:cc3");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "gave_blowjob", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('2f49676f-e8b0-472d-953e-7c749a4625d1:cc4') ? '' : 'unlocked-choice'">
<<link "Give him a blowjob" "Canvas_activity_mick_chat_Node_6">><<script>>setup.markChoiceVisited("2f49676f-e8b0-472d-953e-7c749a4625d1:cc4");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "flag", "subject": "player", "flag_key": "mick_sex", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('2f49676f-e8b0-472d-953e-7c749a4625d1:cc5') ? '' : 'unlocked-choice'">
<<link "Fuck him" "Canvas_activity_mick_chat_Node_7">><<script>>setup.markChoiceVisited("2f49676f-e8b0-472d-953e-7c749a4625d1:cc5");<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>Emma pushes off the doorframe and walks into the stockroom. It's narrow — shelves on both sides, cases of bottles stacked to the ceiling. She stops next to him. Closer than she needs to be.</p><p>She asks about a bottle on the top shelf. Something she's never heard of. She doesn't care about the answer. She cares about how close she's standing.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Fernet. Italian. Tastes like toothpaste and regret.</div></div><p>She laughs. It's a real laugh but she holds it a beat longer than she would normally. Lets her hand touch his forearm when she reaches past him for something on the shelf. His arm is warm. She can feel the muscle under the skin.</p><p>He glances at her. Quick. Back to the clipboard. But the glance happened.</p><p>She asks another question she doesn't care about and stands there while he answers, watching his mouth move, and when she leaves she makes sure to brush his shoulder with hers on the way out.</p><img src="./videos/images/activities/activity_mick_chat_flirt.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "428d5cba-c724-4e47-82d2-0142ea8fb1ae">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.flirt") === -1) { vn.push("activity_mick_chat.flirt"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "flirt_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_mick_chat_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "flirt_unlock");<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>She's helping him count inventory. Standing close — closer than she needs to. Their shoulders almost touching as they work down the same shelf.</p><p>She turns to hand him a bottle and he's right there. Faces inches apart. She can smell the soap on his skin, the faint bite of whiskey on his breath.</p><p>She closes the gap. Quick. Firm. His lips don't move for a second — then they do.</p><p>His hand tightens on the clipboard. She can hear it creak.</p><p>Then he steps back. Clears his throat.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> That's... not in the inventory.</div></div><p>She picks up a box and walks out. Doesn't look back.</p><img src="./videos/activities/activity_mick_chat_kiss.gif" alt="" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "aeb4133b-af46-4282-8ba6-19033ab74c22">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.kiss") === -1) { vn.push("activity_mick_chat.kiss"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_mick_chat_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>Emma walks in and doesn't stop at the doorframe. She walks past Mick — close enough that her hip brushes his thigh — and goes to the back shelf.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> What are you looking for?</div></div><p>She reaches for something on the top shelf. She knows exactly what she's doing. She's wearing the shorts — the short ones — and a tank top that rides up when she stretches. She goes up on her toes and the hem lifts past her navel.</p><p>She can feel him looking. The stockroom is small enough that she can hear his breathing change — just slightly, just enough.</p><p>She grabs a bottle, turns around holding it like a question. She's three feet from him. Her stomach is still showing. She doesn't pull her shirt down.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> This one?</div></div><p>His eyes go from the bottle to her stomach to her face. It takes him a full second. He clears his throat.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Put it back. Second shelf.</div></div><p>She turns around again. Bends at the waist this time. Slowly. The shorts ride up and she knows exactly how much of her thighs he can see. She puts the bottle back, takes her time, and walks out without looking at him.</p><p>She hears him exhale when she's halfway down the hall.</p><video src="./videos/images/activities/activity_mick_chat_tease.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "b3ac62ea-5e96-41f3-8f6e-416b967a4a6f">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.tease") === -1) { vn.push("activity_mick_chat.tease"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<<if $game_state.loop_count lt 2>>
<<link "Stay a while" "Canvas_activity_mick_chat_Node_1">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to $game_state.loop_count + 1>><<script>>advanceTime(30);<</script>><</link>><br>
<</if>>
<</nobr>><p>Emma walks into the stockroom and pulls the door shut behind her. The click of the latch is the loudest sound in the room.</p><p>Mick looks up from his clipboard. The stockroom is narrow — six feet wide, shelves on both sides, cases of bourbon stacked to the ceiling. With the door closed the air gets thick and close and there's nowhere to go that isn't near each other.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> What are you —</div></div><p>She takes the clipboard out of his hands. Sets it on a case of Jameson. He lets her.</p><p>Her hand goes to his belt. She doesn't fumble — she practiced this in her head a hundred times since the couch. Buckle, button, zipper. Her fingers find him and he's already stiffening under her touch.</p><p>He grabs her wrist. Not to stop her. To hold on. His grip is tight and his knuckles are white and he's looking at the closed door like he can hear through it.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Jolene's downstairs.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> I know.</div></div><p>She wraps her hand around him and strokes fast. No slow build. No pretending. This is the stockroom and his wife is one floor below and Emma's hand is moving in quick, tight strokes that make him brace against the shelf behind him.</p><p>Bottles clink against each other. A case shifts on the shelf. He bites his lip hard enough to leave a mark and his free hand grips the edge of the shelf and she can see his forearm flexing, every tendon standing out.</p><p>He comes with his jaw clenched shut. Silent except for one sharp exhale through his nose. She feels the pulse against her fingers, the heat, the way his whole body locks up for five seconds and then goes slack.</p><p>She pulls her hand out. Grabs a bar rag from the stack on the bottom shelf and wipes her fingers. Drops the rag in the laundry pile.</p><p>She picks up his clipboard and puts it back in his hands. Opens the door. Walks out.</p><p>She doesn't look back. She can hear him breathing — rough, ragged — and the sound of his belt buckle as he puts himself back together.</p><video src="./videos/activities/activity_mick_chat_handjob.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "99a5b6ad-bff8-44fd-b261-5827bab291a4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.handjob") === -1) { vn.push("activity_mick_chat.handjob"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma walks into the stockroom, shuts the door, and turns the lock. The click echoes between the shelves.</p><p>Mick looks at her. He knows that click now. He knows what it means when she closes the door.</p><p>She doesn't reach for his belt this time. She sinks to her knees. Right there between the shelves, on the concrete floor, looking up at him.</p><p>His clipboard clatters onto a case of whiskey. His hands hang at his sides. She can see the pulse in his throat.</p><p>She undoes his belt from below. Button. Zipper. Pulls him free. He's already hard — he's been hard since she turned the lock, she thinks.</p><p>She takes him in her mouth. The stockroom is narrow enough that her shoulder brushes the shelf behind her. She can smell the cardboard and the whiskey and the clean sweat on his skin. Her knees ache on the concrete but she doesn't care.</p><p>He braces against the shelf with both hands. Bottles rattle with every movement of her head. A case of gin shifts three inches toward the edge and neither of them notices.</p><p>She works him fast. Urgent. The same tempo as the handjob but deeper, wetter, her tongue doing things she learned from the videos on her phone — things she never thought she'd do on a concrete floor in a stockroom at ten in the morning.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Jesus —</div></div><p>One word. The first word he's ever said during any of this. It comes out strangled and broken and she feels a surge of something hot in her chest — power, pride, hunger.</p><p>He comes. She feels it hit the back of her throat and she swallows, keeps her mouth on him, feels every pulse and twitch while his hands grip the shelves so hard the wood creaks.</p><p>She stands up. Her knees are red from the concrete. She grabs a water bottle from the shelf, twists the cap off, rinses her mouth, spits into the utility sink in the corner.</p><p>She unlocks the door. Opens it. Walks out. Behind her she hears him pick up the clipboard and the scratch of his pen, like nothing happened. Like he's counting bottles.</p><video src="./videos/activities/activity_mick_chat_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "15774531-2cc6-40a5-ad55-a86ca75f8791">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.blowjob") === -1) { vn.push("activity_mick_chat.blowjob"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Emma walks in, locks the door, and doesn't stop at the shelves. She walks straight to him. Puts both hands on his chest. Pushes him back against the wall between the bourbon and the rye.</p><p>She undoes his belt while he pulls her tank top over her head. His hands on her waist, her ribs, rough calluses against her skin. He lifts her — one arm under her thigh, the other bracing against the shelf — and she wraps her legs around him.</p><p>He enters her standing. The bottles rattle. A case of whiskey slides six inches. She bites his shoulder to keep from making a sound that would carry through the floor into the bar below.</p><p>It's fast and hard and the shelf behind her digs into her back and she doesn't care. He comes with his face buried in her neck and she feels him shudder through his whole body, his grip on her thighs tightening to the point of bruises.</p><p>He sets her down. Her legs shake. She pulls her tank top back on. Fixes her hair. Unlocks the door.</p><p>He picks up his clipboard.</p><video src="./videos/activities/activity_mick_chat_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "2f49676f-e8b0-472d-953e-7c749a4625d1">>
<<set $game_state.current_node = "c84c7d95-1e90-4ce3-b66f-7ec8db8689ad">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_mick_chat.sex") === -1) { vn.push("activity_mick_chat.sex"); }<</script>>
<<nobr>>
<<link "Leave" "Location_Stockroom">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "love", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "trust", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_mick", "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<set $game_state.loop_count to 0>><<set $game_state.loop_visited to []>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>The kitchen. Jolene is at the table with coffee and a cigarette, silk robe over a tank top. She looks like she's been up for hours or hasn't slept at all — hard to tell with Jolene.</p><img src="./videos/images/activities/activity_jolene_chat_base.gif" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" /><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Coffee's hot. Sit.</div></div>
<<set $game_state.current_canvas = "7cf31d08-9815-407f-8c1c-aa3881b70b41">>
<<set $game_state.current_node = "9a0cde5d-af4e-47f1-9d0f-5273c52f7a8f">>
<<script>>setup.markCanvasTriggered("7cf31d08-9815-407f-8c1c-aa3881b70b41");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_jolene_chat.base") === -1) { vn.push("activity_jolene_chat.base"); }<</script>>
<<nobr>>
<<link "Ask for advice" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(45);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 20}]})>>
<span @class="setup.isChoiceVisited('7cf31d08-9815-407f-8c1c-aa3881b70b41:cc0') ? '' : 'unlocked-choice'">
<<link "Ask about her past" "Canvas_activity_jolene_chat_Node_2">><<script>>setup.markChoiceVisited("7cf31d08-9815-407f-8c1c-aa3881b70b41:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>Jolene talks about the men she's known. Not the names — the patterns. How they act, what they want, how to read them.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> They all want the same thing. Control. The trick is knowing that before they do.</div></div><p>She lights another cigarette and studies Emma through the smoke.</p>
<<set $game_state.current_canvas = "7cf31d08-9815-407f-8c1c-aa3881b70b41">>
<<set $game_state.current_node = "d22171a4-1dd1-4d71-b677-db499f109c49">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_jolene_chat.personal") === -1) { vn.push("activity_jolene_chat.personal"); }<</script>>
<<nobr>>
<<link "Think about that" "Location_Kitchen">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("npc", "npc_jolene", "mentorship", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(45);<</script>><</link>><br>
<</nobr>><p>It happens again. Different man, same hands.</p><p>She's carrying a case of Bud Light from the stockroom and a regular — the plumber with the mustache — puts his hand on her lower back as she passes. Low. His fingers rest on the curve where her back meets her jeans. He holds it there for three seconds while he tells his buddy something about a job site.</p><p>Emma doesn't flinch. She doesn't speed up. She sets the case down behind the bar and goes back to work.</p><p>An hour later, a hand on her hip while she clears glasses. A squeeze. She moves past it like water around a rock.</p><p>At the end of the night, the tips are heavier than usual. She counts them in the bathroom — fifteen dollars more than a normal shift.</p><p>She looks at herself in the cracked mirror above the sink. The girl who froze when a man touched her thigh — that was weeks ago. This girl keeps serving.</p><video src="./videos/images/activities/bar_groped_tolerate.mp4" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "267299c4-14bd-4acb-b6ae-42d60ebb5f6f">>
<<set $game_state.current_node = "2bc56ac9-222c-47ae-bf35-2c15b4f26ca2">>
<<script>>setup.markCanvasTriggered("267299c4-14bd-4acb-b6ae-42d60ebb5f6f");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_groped_tolerate.base") === -1) { vn.push("activity_bar_groped_tolerate.base"); }<</script>>
<<nobr>>
<<link "End the shift" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 15.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(5);<</script>><</link>><br>
<</nobr>><p>Thursday night. The bar is loud — jukebox cranked, construction crew celebrating something, every stool taken. Emma moves between tables with a tray of empties, the tank top Jolene bought her sticking to her lower back.</p><p>She leans across a booth to grab a pint glass and feels it.</p><p>A hand. On her thigh. High up. Fingers pressing into the inside of her leg through her jeans, firm and deliberate and not moving away.</p><p>She freezes. The glass is in her hand. The noise of the bar is suddenly very far away.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> Hey sweetheart. Can I get another round?</div></div><p>She looks down. A guy she doesn't know — forties, thick neck, wedding ring. He's smiling like he just asked about the weather. His hand is still on her thigh. His thumb moves.</p><p>Emma pulls back. The glass rattles on the tray. Her face is hot.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Sure. Coming right up.</div></div><p>She walks away too fast. At the bar she sets the tray down and her hands are shaking. Jolene glances over but doesn't say anything.</p><p>When she brings his round back, there's a twenty-dollar bill on the table. He slides it toward her with one finger.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> For the service.</div></div><p>She takes it. She doesn't know why she takes it but she takes it.</p><video src="./videos/images/story/bar_first_groped_touch.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "bb273cd9-9ea3-479d-aaa1-0d83020f8a3a">>
<<set $game_state.current_node = "e47c892f-ee36-4835-ac0f-4c9d25836644">>
<<script>>setup.markCanvasTriggered("bb273cd9-9ea3-479d-aaa1-0d83020f8a3a");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_first_groped.the_touch") === -1) { vn.push("story_bar_first_groped.the_touch"); }<</script>>
<<nobr>>
<<link "Go upstairs" "Canvas_story_bar_first_groped_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>End of the night. The bar is emptying out. Emma is wiping down a table and her hands are still not steady. Jolene watches her from behind the bar, cigarette between her fingers.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Come here.</div></div><p>Emma walks over. She doesn't know what her face looks like but Jolene reads it in a second.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> The guy at the booth. Hands.</div></div><p>Emma nods. She can't make herself say it.</p><p>Jolene takes a drag. Exhales through her nose.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> They do that. Some of them. Not all of them, but enough. It's not okay. I'm not telling you it's okay. But it happens. And if you want to work here, you learn to deal with it.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Deal with it how?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You keep smiling. You keep the money. And you don't let them see that it got to you, because the second they see that, they do it again. For free.</div></div><p>Jolene stubs out the cigarette. Looks at Emma — not with pity, not with apology. With the flat honesty of a woman who learned this lesson twenty years ago.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> The twenty he left you? That's yours. You earned it. Just not the way you wanted to.</div></div><img src="./videos/images/story/bar_first_groped_jolene.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "bb273cd9-9ea3-479d-aaa1-0d83020f8a3a">>
<<set $game_state.current_node = "e699e971-5494-4dca-a1ec-d4552bb22f8e">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_first_groped.jolene_talk") === -1) { vn.push("story_bar_first_groped.jolene_talk"); }<</script>>
<<nobr>>
<<link "Go upstairs" "Canvas_story_bar_first_groped_Node_3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Later. The bar is closed. Emma is in her room. She showered but she can still feel the imprint of his fingers on her inner thigh — a ghost pressure, warm and wrong.</p><p>The twenty is on her nightstand. She picks it up, turns it over. Andrew Jackson stares at the ceiling.</p><p>She should have said something. Smacked his hand. Told Jolene. Called him out in front of his friends. Any of those things. All of those things.</p><p>She put the twenty in her pocket and finished the shift.</p><p>The math runs in her head before she can stop it. Rent is $150 a week. A normal shift is $35. That twenty was five minutes of being frozen while a stranger touched her leg.</p><p>She hates that she did the math. She hates that the math makes sense.</p><p>Emma puts the twenty in her wallet with the rest and turns off the light.</p><img src="./videos/images/story/bar_first_groped_aftermath.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "bb273cd9-9ea3-479d-aaa1-0d83020f8a3a">>
<<set $game_state.current_node = "1f882cca-096d-43c5-9c91-01e315167bf4">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("story_bar_first_groped.aftermath") === -1) { vn.push("story_bar_first_groped.aftermath"); }<</script>>
<<nobr>>
<<link "Try to sleep" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 10.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bar_groped");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(30);<</script>><</link>><br>
<</nobr>><p>Evening. The bar fills up. Jolene is already behind the counter. Emma ties her apron and takes her side.</p><p>The regulars are here — Dave at the end, the construction guys in the corner, a couple she doesn't recognize by the window. The jukebox plays something country. Glasses clink. The night begins.</p><img src="./videos/images/activities/activity_bar_shift_base.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "5626584f-ba25-44e4-a99e-6d2e3a0d61af">>
<<script>>setup.markCanvasTriggered("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.base") === -1) { vn.push("activity_bar_shift.base"); }<</script>>
<<nobr>>
<<link "Work the shift" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 35.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 65}, {"type": "flag", "subject": "player", "flag_key": "learned_seduction", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "flirt_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc0') ? '' : 'unlocked-choice'">
<<link "Flirt for tips" "Canvas_activity_bar_shift_Node_2">><<script>>setup.markChoiceVisited("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc0");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 90}, {"type": "flag", "subject": "player", "flag_key": "discovered_teasing", "operator": "is_true"}, {"type": "flag", "subject": "player", "flag_key": "tease_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc1') ? '' : 'unlocked-choice'">
<<link "Show off for tips" "Canvas_activity_bar_shift_Node_3">><<script>>setup.markChoiceVisited("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc1");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 110}, {"type": "flag", "subject": "player", "flag_key": "tease_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc2') ? '' : 'unlocked-choice'">
<<link "Let him grope you" "Canvas_activity_bar_shift_Node_4">><<script>>setup.markChoiceVisited("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc2");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 160}, {"type": "flag", "subject": "player", "flag_key": "handjob_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc3') ? '' : 'unlocked-choice'">
<<link "Handjob in the bathroom" "Canvas_activity_bar_shift_Node_5">><<script>>setup.markChoiceVisited("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc3");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 190}, {"type": "flag", "subject": "player", "flag_key": "blowjob_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc4') ? '' : 'unlocked-choice'">
<<link "Blowjob in the bathroom" "Canvas_activity_bar_shift_Node_6">><<script>>setup.markChoiceVisited("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc4");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<<if setup.triggerConditionsSatisfied({"version": "1.0", "items": [{"type": "trait", "subject": "player", "trait_key": "corruption", "operator": "gte", "value": 220}, {"type": "flag", "subject": "player", "flag_key": "sex_unlock", "operator": "is_true"}]})>>
<span @class="setup.isChoiceVisited('8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc5') ? '' : 'unlocked-choice'">
<<link "Take him out back" "Canvas_activity_bar_shift_Node_7">><<script>>setup.markChoiceVisited("8cd16662-b1d2-44fa-b7c8-8cc27f8ec190:cc5");<</script>><<script>>advanceTime(3);<</script>><</link>><br>
</span>
<</if>>
<</nobr>><p>Emma unties the top button of her shirt. Not much — just enough. She catches her reflection in the bar mirror and adjusts the collar so the neckline falls open when she leans forward.</p><p>She leans forward a lot tonight.</p><p>When Dave orders his third bourbon, she slides it across the bar and holds eye contact one beat longer than normal. He leaves a ten on a six-dollar drink. When the construction guys want another round, she laughs at a joke she's heard before and tilts her head like she's really listening.</p><p>She touches arms when she hands back change. She remembers names. She lets her fingers linger on the glass a half-second too long.</p><p>Jolene notices. Doesn't say anything. Just watches Emma work and smokes her cigarette with something like approval.</p><p>By closing, Emma's tips are almost double. Her feet hurt, her face hurts from smiling, and she feels a strange electricity under her skin — the power of being looked at and knowing exactly what you're doing with it.</p><img src="./videos/images/activities/activity_bar_shift_flirt_tips.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "17c2c519-0993-417c-bd83-6cfcff43005d">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.flirt_tips") === -1) { vn.push("activity_bar_shift.flirt_tips"); }<</script>>
<<nobr>>
<<link "Count your tips" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 55.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>Emma came to work in a short skirt and a low-cut top. No bra. She made that decision in her room, standing in front of the mirror, and she's not second-guessing it.</p><p>The bar notices. Every head turns when she comes out from behind the counter to clear tables. The skirt is short enough that when she bends to wipe down a booth, the guys at the bar can see the backs of her thighs. She takes her time wiping.</p><p>She bends to grab bottles from the lower shelf and stays down longer than she needs to. She can feel eyes on her — on her chest when she leans over the bar, on her legs when she walks past, on her ass when she turns around. She lets all of it happen.</p><p>A customer's hand lands on her waist when she squeezes past his stool. Warm, firm, proprietary. Her first instinct is to pull away. She doesn't. She lets it sit there for three seconds, then moves on. He leaves a $30 tip.</p><p>Another one stares straight down her top when she leans across the bar to hand him his drink. She could stand up straighter. She doesn't. She holds the lean and watches him try to look at her face instead of her tits. He fails. She smiles.</p><p>The tip jar is overflowing by eleven. The bills are crumpled and damp and there are more twenties in there than she's ever seen.</p><p>Jolene watches from the other end of the bar. She doesn't say anything. She pours herself a whiskey and drinks it looking at something that isn't Emma.</p><p>After closing, Emma counts the money twice. Her hands smell like beer and her feet are killing her and she's buzzing with something that isn't alcohol. Every look, every lingering hand, every overtipped drink — she earned all of it. With her body. And she'd do it again tomorrow.</p><video src="./videos/activities/activity_bar_shift_let_them_look.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "94debd72-ad79-4dd9-88d0-613a7d16db9b">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.let_them_look") === -1) { vn.push("activity_bar_shift.let_them_look"); }<</script>>
<<nobr>>
<<link "Count your tips" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 90.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>Friday night. The bar is packed. Emma is behind the counter in the skirt and the top that shows everything and nothing, and the regulars have learned what that outfit means: she's working tonight. Really working.</p><p>She squeezes past a regular to get to the taps. His hand goes to her thigh. Not her waist — her thigh. High up. His fingers press into the bare skin above her knee and slide two inches north before she can react.</p><p>She freezes. His hand is hot and rough and his thumb is tracing the inside of her leg and the bar is loud enough that nobody else sees.</p><p>He slides a fifty-dollar bill across the bar with his other hand. She looks at the bill. She looks at his hand on her thigh. She looks at the fifty again.</p><p>She doesn't move his hand.</p><p>He finishes his drink and orders another. His hand stays. She serves him with his fingers resting on her thigh like it's the most normal thing in the world. When she finally moves away, she takes the fifty.</p><p>It happens again an hour later. Different guy. Hand on her ass when she bends to restock. A twenty tucked into her waistband. She doesn't flinch this time. She arches her back slightly — presses into the hand — and the twenty becomes a fifty.</p><p>By the end of the night she's learned the exchange rate. A hand on her waist is worth a good tip. A hand on her thigh is worth a great one. A hand on her ass — if she leans into it, if she lets him feel her — that's worth whatever he's willing to pay.</p><p>She counts the money in the bathroom after closing. Her hands are shaking but not from fear. From adrenaline. From the math — she made more tonight from being touched than she makes in three normal shifts.</p><p>Jolene is wiping down the bar when Emma comes out. She looks at Emma. Emma looks at Jolene. Neither says anything. Jolene pours two whiskeys, slides one across the counter, and drinks hers looking at the wall.</p><video src="./videos/activities/activity_bar_shift_groping.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "b1d49f45-f650-4b61-93ec-774dc7ef82b0">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.groping") === -1) { vn.push("activity_bar_shift.groping"); }<</script>>
<<nobr>>
<<link "Count your tips" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 120.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>Last call. The bar is emptying. A regular — the one with the truck, the one who's been tipping heavy all night, the one whose hand she let rest on her thigh for ten minutes during the second round — leans across the counter.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> What's five minutes of your time worth?</div></div><p>She knows what he's asking. She's known since the third time his hand landed on her leg. She looks at him — mid-forties, wedding ring, calloused hands, the kind of guy who drinks at a dive bar because his wife thinks he's working late.</p><p>She should say no. The old Emma would have said no. The old Emma would have been horrified.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Two hundred.</div></div><p>He doesn't blink. He pulls two bills from his wallet and puts them on the bar.</p><p>She takes the money. Folds it. Puts it in her back pocket. Walks around the bar and nods toward the bathroom.</p><p>The bar bathroom. Fluorescent light, cracked mirror, the smell of bleach. She locks the door behind them. He's already undoing his belt. She doesn't make him ask twice.</p><p>She wraps her hand around him and strokes fast. No preamble, no eye contact, no pretending this is anything other than what it is. He braces against the sink with one hand. She watches the cracked mirror — her own face, calm, focused, calculating. A stranger's cock in her hand and she's thinking about rent.</p><p>He finishes in three minutes. Grunts once. She lets go, washes her hands, and opens the door. He's still buckling his belt when she walks out.</p><p>She goes back behind the counter. Wipes down the bar. The money is in her pocket. Her hands smell like soap. The bar looks the same as it did ten minutes ago.</p><p>She doesn't feel guilty. She feels practical.</p><video src="./videos/activities/activity_bar_shift_handjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "89ae4cde-59eb-47b6-b9b3-acfe5342cba7">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.bar_handjob") === -1) { vn.push("activity_bar_shift.bar_handjob"); }<</script>>
<<nobr>>
<<link "Close up" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 200.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "bar_handjob_done");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>Last call. The bar's almost empty. A man at the end — nice watch, loosened tie, the kind who comes to a place like this to feel like he's slumming — catches her eye.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> What would three hundred buy me?</div></div><p>She doesn't hesitate. She takes the bills off the bar and nods toward the bathroom.</p><p>The door locks behind them. Fluorescent buzz overhead. She pushes him against the sink and drops to her knees on the cold tile floor. His belt buckle clinks. She unzips him and takes him in her mouth.</p><p>It's transactional. Efficient. Her head bobs and her hands brace on his thighs and she can hear the jukebox through the door — some old country song about heartbreak. He grabs the edge of the sink with both hands and his breath gets ragged.</p><p>She takes him deep. Past comfort, working her throat around him the way she's learned works fastest. The tile is cold on her knees. The fluorescent light catches everything in the cracked mirror beside her — her head moving, his white knuckles on the porcelain, the clinical geometry of money changing hands.</p><p>He finishes. She swallows. Stands up. Washes her mouth at the sink while he buckles his belt. She doesn't look at him in the mirror.</p><p>She goes back behind the counter. Three hundred dollars in her pocket. Her jaw aches. She wipes down the bar and the night continues like nothing happened.</p><video src="./videos/activities/activity_bar_shift_blowjob.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "14484df0-2c75-450f-a9f5-5adef8185c25">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.bar_blowjob") === -1) { vn.push("activity_bar_shift.bar_blowjob"); }<</script>>
<<nobr>>
<<link "Close up" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 300.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 3.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>He's been watching her all night. Big hands, heavy shoulders, the kind of quiet that means he's been thinking about what he wants. When the bar empties out he stays.</p><div class="dialog-block dialog-npc"><div class="dialog-content"><strong>Stranger:</strong> Five hundred.</div></div><p>He says it like a statement, not a question. He puts the bills on the bar — five hundreds, crisp, fanned out like a poker hand. She counts them. Folds them. Puts them in her back pocket.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Out back.</div></div><p>The stockroom door. Past the cases of beer and the mop bucket and the circuit breaker box. She pushes him against the shelf and hikes her skirt up and he lifts her by the hips and sets her on the edge of the metal shelving.</p><p>Bottles rattle. A case of pint glasses slides. She wraps her legs around him and pulls him in and when he pushes into her she grabs the shelf behind her head and a bottle of whiskey wobbles but doesn't fall.</p><p>It's rough and fast and purely transactional. His hands on her hips, her back against the cold metal shelving, the sound of them filling the small stockroom — rhythmic, obscene, businesslike. She comes anyway. She wasn't expecting to. He follows a minute later.</p><p>She straightens her skirt. Walks back to the bar. Five hundred dollars. Her thighs ache and she can feel him and she wipes down the counter and locks the front door and the night is over.</p><video src="./videos/activities/activity_bar_shift_sex.webm" autoplay muted loop playsinline controls preload="metadata" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;"></video>
<<set $game_state.current_canvas = "8cd16662-b1d2-44fa-b7c8-8cc27f8ec190">>
<<set $game_state.current_node = "2832f492-03d0-4e30-94a1-608dbae06b8a">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("activity_bar_shift.bar_sex") === -1) { vn.push("activity_bar_shift.bar_sex"); }<</script>>
<<nobr>>
<<link "Close up" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", 500.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 4.0, false, null);<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>Emma is walking to campus when Jolene falls into step beside her. Cigarette in hand, sunglasses pushed up on her head, moving with that easy confidence that Emma still can't replicate.</p><p>Jolene doesn't say hello. She looks Emma up and down — the hoodie, the jeans, the sneakers — the way a mechanic looks at a car that's making a weird noise.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You learned the smile. Good. But nobody tips the hoodie.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> What's wrong with my hoodie?</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Nothing. If you're going to class. But you're not just going to class anymore, are you?</div></div><p>Jolene flicks her cigarette into the gutter and changes direction. She doesn't ask Emma to follow. She just walks.</p><img src="./videos/images/story/shopping_jolene_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f3b0f806-2434-4118-a21b-9900ecb484d4">>
<<set $game_state.current_node = "9934ff55-514c-42d2-981e-40ba83b88ece">>
<<script>>setup.markCanvasTriggered("f3b0f806-2434-4118-a21b-9900ecb484d4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("shopping_with_jolene.n1") === -1) { vn.push("shopping_with_jolene.n1"); }<</script>>
<<nobr>>
<<link "Follow her" "Canvas_shopping_with_jolene_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The strip mall is three blocks east. Half the storefronts are shuttered — a nail salon that never opened, a check-cashing place with iron bars. But wedged between them is a clothing shop with bright window displays and a hand-lettered SALE sign.</p><p>Inside: fluorescent lights, racks of cheap fashion, the smell of new fabric and floor cleaner. A bored clerk behind the counter doesn't look up from her phone.</p><p>Jolene walks the racks like she owns the place. Pulls a tank top off a hanger, holds it against Emma's chest, shakes her head, puts it back. Grabs another one.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> This isn't about being pretty. Pretty is what you are when you roll out of bed. This is about being seen.</div></div><p>She holds up a fitted tank top — black, simple, with a lower neckline than anything Emma owns. Nothing scandalous. But different from the hoodie the way a whisper is different from silence.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Wearing the right clothes at the bar — that's money, sweetie. Men tip what they see. You show up in that hoodie, you're invisible. You show up in this, you're someone they want to buy a drink for.</div></div><p>She's not wrong. Emma has watched Jolene work. The fitted tops. The way she leans on the bar. Tips aren't about the beer.</p><img src="./videos/images/story/shopping_jolene_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f3b0f806-2434-4118-a21b-9900ecb484d4">>
<<set $game_state.current_node = "2a7488bb-2f81-48eb-a3e1-b9d96f0a2234">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("shopping_with_jolene.n2") === -1) { vn.push("shopping_with_jolene.n2"); }<</script>>
<<nobr>>
<<link "Try it on" "Canvas_shopping_with_jolene_Node_3">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Outside the store. Emma is wearing the tank top under her hoodie — a compromise with herself. But she can feel the difference. The fabric sits closer. The neckline dips lower. She stands a little straighter without meaning to.</p><p>Jolene lights another cigarette and leans against the brick wall.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> That one's on me. Call it a business investment.</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> I can't let you—</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You can and you will. When you're ready — come back here and look around on your own. Think of it like leveling up. Better clothes, better tips, better everything.</div></div><p>She pushes off the wall and starts walking back toward the bar. Over her shoulder:</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> The hoodie was fine for week one. Week one is over.</div></div><p>Emma watches her go. The tank top feels like a small, quiet permission.</p><img src="./videos/images/story/shopping_jolene_n3.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "f3b0f806-2434-4118-a21b-9900ecb484d4">>
<<set $game_state.current_node = "b4befe28-2922-41d3-97ff-9e67dda93ec1">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("shopping_with_jolene.n3") === -1) { vn.push("shopping_with_jolene.n3"); }<</script>>
<<nobr>>
<<link "Head to campus" "Location_City_Streets">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);<</script>><<script>>setup.applyAndNotifyTrait("player", null, "corruption", "add", 1.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "mall_unlocked");<</script>><<script>>setup.addToWardrobe("tank_top");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(60);<</script>><</link>><br>
<</nobr>><p>Next shift. Emma is faster — she knows where the glasses are, she doesn't fumble the tap. But the tips are still thin. Coins. A dollar here. The regulars order from Jolene when they can.</p><p>During a quiet moment, Jolene leans against the back counter next to her. Lights a cigarette. Watches Emma pour a beer for a man who doesn't look at her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You know what your problem is?</div></div><p>Emma braces herself.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You're serving beer. That's not the job. The beer is a prop. They can buy beer at a gas station for half the price. They're here for you. They tip you. Not the bottle. You.</div></div><p>She takes a drag. Watches a regular signal for another round.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Smile when you pour. Look at them when you hand it over. Say their name if you know it. Laugh if they're funny. They're not — but laugh anyway. That's the job.</div></div><img src="./videos/images/story/bar_lesson_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "05871429-a392-4ccc-886d-0a5d46e99176">>
<<set $game_state.current_node = "81774685-1ff6-4277-a28e-c78d28ee50ca">>
<<script>>setup.markCanvasTriggered("05871429-a392-4ccc-886d-0a5d46e99176");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("bar_lesson.n1") === -1) { vn.push("bar_lesson.n1"); }<</script>>
<<nobr>>
<<link "Try it" "Canvas_bar_lesson_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>A man holds up his empty glass. Emma takes it.</p><p>She pours. Slides it across the counter. Looks him in the eye and smiles — not her nervous smile, not the polite one. Something warmer. Something that says I see you.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Here you go.</div></div><p>The man blinks. Looks at her like he's seeing her for the first time. "Thanks, sweetheart." He leaves three dollars on the bar. Last time he left fifty cents.</p><p>She does it again. And again. She laughs at a joke that isn't funny. She remembers a regular's name — 'Same as last time, Dave?' — and Dave tips her five dollars and tells her she's a natural.</p><p>She's not a natural. She's performing. And it's working.</p><p>End of the night. She counts.</p><p>$45.</p><p>Jolene sees the pile. Nods once.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> See? They're not tipping the beer.</div></div><p>Emma puts the money in her pocket. $45. More than double last time. She earned it — but not with her hands. With her smile. With eye contact. With a performance she didn't know she could give.</p><p>Something shifts. Small, but real. Presentation has value. Attention is currency. She just learned her first method.</p><img src="./videos/images/story/bar_lesson_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "05871429-a392-4ccc-886d-0a5d46e99176">>
<<set $game_state.current_node = "826ccec1-173d-489c-9efc-f25fde886bac">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("bar_lesson.n2") === -1) { vn.push("bar_lesson.n2"); }<</script>>
<<script>>advanceTime(240);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "money", "add", 45.0, false, null);setup.applyAndNotifyTrait("player", null, "corruption", "add", 2.0, false, null);setup.applyAndNotifyTrait("player", null, "confidence", "add", 2.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "bar_lesson_learned");<</script>>
[[Go upstairs->Location_Emma's_Room]]<p>8pm. Friday. Emma is behind the bar in a t-shirt she found at the bottom of her suitcase — the best she could do for 'not a hoodie.' Jolene hands her an apron.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Beer taps are labeled. Liquor's on the wall — read the bottles. If someone orders a cocktail, come get me. Don't break the glasses — they cost more than you do tonight.</div></div><p>The bar fills up. Emma pours beers. Slowly. She fumbles the tap twice, overfills a glass, and spills foam on the counter. A regular holds up his empty glass and waves it at her. She scrambles.</p><p>A man orders a whiskey sour. She stares at the bottles. Jolene appears behind her, makes it in thirty seconds without looking, slides it across the counter, and is already laughing at something someone said.</p><img src="./videos/images/story/first_shift_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "410fa2a3-734a-4941-b8d7-15786acba5c4">>
<<set $game_state.current_node = "20996d92-fc6d-4c49-8322-9ed2675795ac">>
<<script>>setup.markCanvasTriggered("410fa2a3-734a-4941-b8d7-15786acba5c4");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("first_shift.n1") === -1) { vn.push("first_shift.n1"); }<</script>>
<<nobr>>
<<link "Survive the night" "Canvas_first_shift_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She watches Jolene. Not on purpose — she can't help it. Jolene moves through the bar like she owns the air in it. She leans on the counter when a man talks, laughs with her whole body, touches a regular's arm when she hands him a drink. She calls them 'hon' and 'baby' and they eat it up.</p><p>Same bar. Same customers. Same drinks. But the tip jar on Jolene's side of the bar is full. Emma's side has coins and a crumpled five.</p><p>Last call. The bar empties. Emma counts her tips on the counter.</p><p>$18.</p><p>Jolene counts hers without looking. Folds the bills, stuffs them in her back pocket.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> How'd you do?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Eighteen dollars.</div></div><p>Jolene doesn't say anything. She doesn't have to. The number says it all.</p><p>Emma wipes down the bar and tries not to think about the difference. She thinks about the difference.</p><img src="./videos/images/story/first_shift_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "410fa2a3-734a-4941-b8d7-15786acba5c4">>
<<set $game_state.current_node = "5cc24800-7b31-4141-a615-1c912581a2ca">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("first_shift.n2") === -1) { vn.push("first_shift.n2"); }<</script>>
<<script>>advanceTime(240);<</script>>
<<script>>setup.pendingEffects = [];setup.applyAndNotifyTrait("player", null, "money", "add", 18.0, false, null);setup.showEffectNotification();<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "first_shift_done");<</script>>
[[Go upstairs->Location_Emma's_Room]]<p>Emma waits until the bar is quiet — just two regulars and the TV. Jolene is wiping down the counter, cigarette behind her ear. Emma sits on a stool and doesn't order anything.</p><p>Jolene notices. She always notices.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You're sitting there like a woman with a question. Ask it.</div></div><p>Emma takes a breath.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Do you need help? Behind the bar? I can learn.</div></div><p>Jolene stops wiping. Looks at her. Takes in the hoodie, the sneakers, the ponytail, the nervous hands. She doesn't laugh — but something in her expression says she's thinking about it.</p><img src="./videos/images/story/asking_jolene_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6137f8aa-0167-4135-af2b-b069b064d6a8">>
<<set $game_state.current_node = "b4a021c4-31c6-402f-93e6-2b03a76d0021">>
<<script>>setup.markCanvasTriggered("6137f8aa-0167-4135-af2b-b069b064d6a8");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("asking_jolene.n1") === -1) { vn.push("asking_jolene.n1"); }<</script>>
<<nobr>>
<<link "Wait for her answer" "Canvas_asking_jolene_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You ever poured a drink in your life?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> No.</div></div><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You ever worked a crowd? Handled a drunk? Carried four glasses without dropping them?</div></div><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> No.</div></div><p>Jolene leans on the bar. Studies her.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> You want to pour drinks for these guys looking like that? Hoodie and sneakers? They're not going to tip a girl who looks like she's doing homework.</div></div><p>Emma doesn't know what to say to that. Jolene isn't being mean — she's being honest in the way that only Jolene is honest.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/jolene.jpg" alt="Jolene" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Jolene:</strong> Friday. Be down here at 8. Wear something that isn't a hoodie. I'll show you where everything is. If you don't break anything, you can have weekend shifts.</div></div><p>She goes back to wiping the counter. The conversation is over.</p><p>Emma sits there for a moment. She got the job. She thinks. She's not entirely sure what she agreed to.</p><img src="./videos/images/story/asking_jolene_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6137f8aa-0167-4135-af2b-b069b064d6a8">>
<<set $game_state.current_node = "38655ea7-372f-4e6a-a420-47ca6e38cb49">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("asking_jolene.n2") === -1) { vn.push("asking_jolene.n2"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "asked_jolene");<</script>>
[[Go upstairs->Location_Emma's_Room]]<p>She spends the day applying. The coffee shop with the HELP WANTED sign — the manager looks at her resume (blank except for babysitting and church volunteer work), says he'll call. He won't.</p><p>The campus library — they're fully staffed. The woman behind the desk doesn't even take her name.</p><p>A diner two blocks from campus — they need a dishwasher. Weekends, 6am to noon. $9 an hour. She does the math in her head standing right there at the counter: $108 a week before taxes. Rent is $150.</p><div class="dialog-block dialog-player"><div class="portrait"><img src="./videos/emma.jpg" alt="You" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>You:</strong> Can I think about it?</div></div><p>The manager shrugs. "Spot won't last."</p><img src="./videos/images/story/job_hunt_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "817bfec1-7118-4a63-868d-eb6e0487c20f">>
<<set $game_state.current_node = "1238bd24-3451-404b-9fcd-9097089c110b">>
<<script>>setup.markCanvasTriggered("817bfec1-7118-4a63-868d-eb6e0487c20f");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("job_hunt.n1") === -1) { vn.push("job_hunt.n1"); }<</script>>
<<nobr>>
<<link "Keep looking" "Canvas_job_hunt_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She walks home. Past the convenience store, past the laundromat, past the stoop where two guys sit and don't say anything.</p><p>Minimum wage, part-time, no experience. Every job she qualifies for pays less than her rent. The math is simple and it's brutal: the honest route doesn't add up.</p><p>She turns the corner and there it is — the bar. Her building. Neon sign buzzing in the window. Through the glass she can see Jolene behind the counter, pouring something for a man in a work jacket. The bar is busy. Tips are changing hands. Money is moving.</p><p>The job is right under her feet. It's been there the whole time.</p><img src="./videos/images/story/job_hunt_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "817bfec1-7118-4a63-868d-eb6e0487c20f">>
<<set $game_state.current_node = "3a726b38-ad92-4d29-b0f6-7dced28a112f">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("job_hunt.n2") === -1) { vn.push("job_hunt.n2"); }<</script>>
<<nobr>>
<<link "Go inside" "Location_Bar_Floor">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "job_hunt_done");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(180);<</script>><</link>><br>
<</nobr>><p>Monday morning. Emma walks to campus. Twenty minutes through city blocks — past the convenience store with bulletproof glass, the laundromat, two guys on a stoop who watch her pass and say nothing.</p><p>Campus is different. Cleaner. Louder with a different kind of energy — students who look like they've been here forever, groups already formed, inside jokes she doesn't get. Everyone knows where they're going. Emma checks the map on her phone three times in five minutes.</p><p>Registration is fine. Financial aid covers tuition — that's the one thing that worked. She finds her first classroom. Sits in the back. Takes notes. Feels invisible in a way that's becoming familiar.</p><img src="./videos/images/story/campus_day_one_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6af9aaee-2020-428c-a199-09257a1cf6ae">>
<<set $game_state.current_node = "e57ad9d3-6ccd-459b-bfc4-61fa065fc046">>
<<script>>setup.markCanvasTriggered("6af9aaee-2020-428c-a199-09257a1cf6ae");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("campus_day_one.n1") === -1) { vn.push("campus_day_one.n1"); }<</script>>
<<nobr>>
<<link "Go to the bookstore" "Canvas_campus_day_one_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>The campus bookstore. She finds her required textbooks — four classes, four books. She stacks them on the counter and the cashier scans them.</p><p>$380.</p><p>She stares at the number. She has $200 left after next Monday's rent. $200 minus $380 is a number that doesn't work.</p><p>She puts two books back. Keeps the ones she can't survive without. $90.</p><p>The cashier doesn't react. This happens every semester.</p><p>Walking home, she passes a coffee shop with a HELP WANTED sign in the window. She stops. Reads it. Part-time, minimum wage, experience preferred.</p><p>She does the math again. Minimum wage, part-time, after taxes — it wouldn't cover rent and books. Not even close.</p><p>She stares at the sign for a long time. Then she keeps walking.</p><p>There has to be something better. She just doesn't know what yet.</p><img src="./videos/images/story/campus_day_one_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "6af9aaee-2020-428c-a199-09257a1cf6ae">>
<<set $game_state.current_node = "c10ca541-c345-44a0-ae6e-8fea1174d153">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("campus_day_one.n2") === -1) { vn.push("campus_day_one.n2"); }<</script>>
<<nobr>>
<<link "Walk home" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyTrait("player", null, "money", "add", -90.0, false, null);<</script>><<script>>setup.applyAndNotifyFlag("player", null, "campus_started");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(240);<</script>><</link>><br>
<</nobr>><p>Early morning. Emma comes downstairs. The bar is empty — chairs on tables, floor still sticky from last night, the air thick with stale beer and lemon cleaner.</p><p>A man is behind the counter. Big hands, rolled-up sleeves, counting bottles from a clipboard. He moves with the efficiency of someone who's done this ten thousand times. He doesn't look up.</p><p>This is Mick. Jolene's husband.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> You're the tenant. Jolene told me.</div></div><p>He still doesn't look up. Marks something on the clipboard.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Coffee's in the kitchen if you want it. Don't touch the espresso machine.</div></div><img src="./videos/images/story/meeting_mick_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "9f23cdc6-4e97-4d43-a421-0a52e5ead269">>
<<set $game_state.current_node = "792d4953-9248-4c4a-8986-1a15a522b8c2">>
<<script>>setup.markCanvasTriggered("9f23cdc6-4e97-4d43-a421-0a52e5ead269");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("meeting_mick.n1") === -1) { vn.push("meeting_mick.n1"); }<</script>>
<<nobr>>
<<link "Get coffee" "Canvas_meeting_mick_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>Emma gets coffee from the kitchen. Sits at the bar. Mick talks while he counts. He doesn't look at her much — she's a line item, not a conversation.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> Rent's Monday. Every Monday. I don't chase people. You're late, you get one warning. After that I change the lock. Nothing personal — I've had twelve tenants in five years and I've changed the lock on four of them.</div></div><p>He puts down the clipboard. Looks at her for the first time. Not unkind — just assessing. The same look the city gave her at the bus stop.</p><div class="dialog-block dialog-npc"><div class="portrait"><img src="./videos/mick.jpg" alt="Mick" onerror="this.style.display='none';this.parentElement.innerHTML='<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="35" r="20" fill="#6c757d"/><ellipse cx="50" cy="85" rx="35" ry="25" fill="#6c757d"/></svg>';" /></div><div class="dialog-content"><strong>Mick:</strong> You need anything fixed, tell Jolene. You need anything else — figure it out.</div></div><p>He goes back to his bottles. Emma drinks her coffee and feels like she just signed a contract she hasn't fully read.</p><img src="./videos/images/story/meeting_mick_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "9f23cdc6-4e97-4d43-a421-0a52e5ead269">>
<<set $game_state.current_node = "828d0cae-ec08-4144-b5a2-6a28f71c6dd3">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("meeting_mick.n2") === -1) { vn.push("meeting_mick.n2"); }<</script>>
<<script>>advanceTime(30);<</script>>
<<script>>setup.applyAndNotifyFlag("player", null, "met_mick");<</script>>
[[Finish coffee->Location_Bar_Floor]]<p>10pm. The bar below is alive.</p><p>Bass through the floorboards. Laughter — the loud kind, the kind that comes with alcohol. A glass breaking. Someone shouting something she can't quite make out. Music she doesn't recognize rattling the light fixture on her ceiling.</p><p>Emma lies in bed with the pillow over her head. It doesn't help. The ceiling vibrates. A woman laughs — loud, unapologetic. Probably Jolene. Someone cheers.</p><p>This is her bedroom now. Six feet above a bar on a weeknight.</p><img src="./videos/images/story/first_night_n1.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "813d7cb9-73cc-4bde-961b-f7ecccd037e6">>
<<set $game_state.current_node = "fc38c774-a0db-46b2-9004-02a95994635e">>
<<script>>setup.markCanvasTriggered("813d7cb9-73cc-4bde-961b-f7ecccd037e6");<</script>>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("first_night.n1") === -1) { vn.push("first_night.n1"); }<</script>>
<<nobr>>
<<link "Give up on sleep" "Canvas_first_night_Node_2">><<script>>advanceTime(3);<</script>><</link>><br>
<</nobr>><p>She can't sleep, so she does the math. She's done it three times already. The numbers don't get better.</p><p>$350 left. Rent again Monday — $150. That leaves $200. Textbooks — she looked them up online — at least $300 for the semester, probably more. Food. A bus pass. Soap, toothpaste, the things you don't think about until you're buying them with money you don't have.</p><p>Three weeks. Maybe less. Then she's broke.</p><p>She stares at the ceiling. The bass thumps through the floor. A man's voice rises over the music, telling a story, and the whole bar laughs.</p><p>Emma closes her eyes and tries not to think about money.</p><p>She thinks about money.</p><img src="./videos/images/story/first_night_n2.jpg" alt="" loading="lazy" decoding="async" style="max-width:100%;max-height:70vh;object-fit:contain;height:auto;border-radius:8px;" />
<<set $game_state.current_canvas = "813d7cb9-73cc-4bde-961b-f7ecccd037e6">>
<<set $game_state.current_node = "0e0fb476-467e-4607-8039-732e9be77fef">>
<<script>>var vn = State.variables.game_state.visited_nodes;if (vn.indexOf("first_night.n2") === -1) { vn.push("first_night.n2"); }<</script>>
<<nobr>>
<<link "Stare at the ceiling until sleep comes" "Location_Emma's_Room">><<script>>setup.pendingEffects = [];<</script>><<script>>setup.applyAndNotifyFlag("player", null, "first_night_complete");<</script>><<script>>setup.showEffectNotification();<</script>><<script>>advanceTime(120);<</script>><</link>><br>
<</nobr>><h2>Missing Media Files</h2>
<p>No missing media files found.</p>
<<return "← Back">>