9 Commits
Author SHA1 Message Date
tevansandClaude Fable 5 dbc7f5a713 Providence/Calamity also fires on lethality rolls — v2.1.1
The nat-01/00 home rule (shipped v2.0.2) only hooked DGPercentileRoll's
toChat; lethality rolls are d100 tests too and now trigger it as well.
Verified live with forced rolls: nat 01 posts the PROVIDENCE card, nat 00
posts CALAMITY, d6 table result + styling + variant flags all correct.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 11:21:13 +01:00
tevansandClaude Fable 5 b4b1bfed1e GM screen v2: accordion structure + deeply expanded content
Every part is now a collapsible card - all closed on load, click a header
or nav entry to open (state persists per section). Search auto-opens
matching sections; Open/Close-all buttons added.

Content substantially expanded throughout: Provost phone-call read-aloud
with Q&A, road/diner beats, cold-exposure clock, cruiser/compound detail,
d6 dread beats, tiered console work with the uplink dilemma, Agnes
dialogue lines, round-by-round Congregation script, pond/Baptism rules,
Vance's 5-segment wiring-clock (with tracker), backward-manual lines,
concrete generator/transformer procedures, implosion escape, expanded
cover-up tasks with a d6 complications table, player-questions Q&A, an
Improv Toolkit (name/sensory/static banks), tonight's environmental
rules, and a tickable half-hour Dawn Clock (21:00-06:30).

HP-bar animation moved from width to transform:scaleX.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 08:23:03 +01:00
tevansandClaude Fable 5 fba8112a6e Make handout-entity.svg a wrapper for the Tear portrait
The legacy SVG path (still referenced by packs compiled before the PNG
switch) now displays the same generated artwork, so older imported
copies of journal (8) show the correct climax image without a pack swap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 08:10:20 +01:00
tevansandClaude Fable 5 12da628c06 Add standalone GM screen app for Operation FALSE ALARM
Single self-contained HTML file (documentation/false-alarm-gm-screen.html):
sidebar navigation across the whole scenario (briefing, all scenes incl.
the Congregation midpoint, climax, cover-up, NPC stat blocks, the truth,
world/timeline, SAN quick-ref), full-text search (/), per-section GM
notes, clue checklists, NPC HP trackers, and an editable agent/cell
tracker - all persisted in localStorage with JSON export/import for
moving between computers. No dependencies, works offline, print-safe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 00:09:00 +01:00
tevansandClaude Fable 5 7683deb604 Use the Tear portrait as the climax handout image
Journal (8) THE TEAR's reveal page now shows the generated pencil artwork
(handout-entity.png, full resolution) instead of the fractal SVG.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 00:02:19 +01:00
tevansandClaude Fable 5 4ec537d4b8 Swap Vance / Rostova / Tear art for user-generated pencil portraits
The three original FALSE ALARM NPCs now match the Congregation set:
Deputy Vance (Changed), Dr. Rostova, and the Tear (rendered as a suited
figure with a receding non-Euclidean void for a head - 'almost done
learning our shape'). Pure asset swap at the existing token paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 23:59:49 +01:00
tevansandClaude Fable 5 bf4af421b5 Swap Congregation NPC art for user-generated pencil portraits
Agnes Corliss, the Returned Petrie brothers and the Called now use the
black-and-white pencil portraits (768px PNG) in place of the stylized
placeholders. Pure asset swap - pack document paths unchanged. SVG
sources retained alongside.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 23:38:53 +01:00
tevansandClaude Fable 5 b10f8213a7 FALSE ALARM midpoint encounter: The Congregation — v2.1.0
New Scene 2.5 at Cold Cauldron Crossing (Ridge Road mile 9): the town
comes up the mountain. Adds:
- 4 NPCs built to challenge 4 Agents: Agnes Corliss the Switchboard Widow
  (the Chorus SAN drain through the Agents' own radios, Stand Still action
  denial, Speak the Names; weakness = her dead husband's handset), the
  Returned Petrie brothers (armor 3, numbing grasp, pond Baptism drag,
  fire-vulnerable), and the Called x5 (restraining civilian wall - killing
  one is 1/1D8 SAN and a cover-up disaster).
- New battle map (blueprint style, 4400x3200 2x PNG) with 8 placed tokens,
  new gear item (Elias Corliss's Ham Handset), 4-page GM journal 13 with
  read-aloud, tactics, non-massacre outs and aftermath, plus a Scene 2.5
  pointer in the scene guide.
- Scene coordinate fix: padding 0 on all adventure scenes and centered
  token placement (tokens previously offset by the 0.25-padding origin).

Verified by fresh import in isolated Foundry: 7 actors, 13 journals,
4 scenes, 8 tokens on the crossing map at correct positions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 23:24:15 +01:00
tevansandClaude Fable 5 7dcbd96b13 Fix pause overlay showing GAME PAUSED while unpaused — v2.0.5
Root cause of the toggle cycle bug: the theme set display:flex on
#pause.dg2-pause unconditionally, out-specificity-ing core's hidden
(unpaused) state. After unpausing, the pause element stayed visible and
showed Foundry's default GAME PAUSED markup (the overlay injector
correctly skips unpaused renders). Scope the flex layout to
#pause.dg2-pause.paused and explicitly hide :not(.paused).

Verified three full pause/unpause cycles: paused = radar scope visible,
unpaused = element hidden. (Earlier tests misread visibility via
offsetParent, which is always null for position:fixed elements.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 22:39:52 +01:00
24 changed files with 1152 additions and 56 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

@@ -0,0 +1,96 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2200 1600" font-family="Courier New, monospace">
<defs>
<pattern id="cgrid" width="100" height="100" patternUnits="userSpaceOnUse">
<path d="M100 0H0V100" fill="none" stroke="#1d2a30" stroke-width="1"/>
</pattern>
<g id="cpine"><path d="M0 60 L20 -10 L40 60 Z M6 30 L20 -30 L34 30 Z" fill="#c9d6dd" opacity="0.45"/></g>
</defs>
<rect width="2200" height="1600" fill="#080a0d"/>
<rect width="2200" height="1600" fill="url(#cgrid)"/>
<!-- treeline both sides -->
<g>
<use href="#cpine" x="80" y="120"/><use href="#cpine" x="200" y="90"/><use href="#cpine" x="330" y="130"/>
<use href="#cpine" x="1750" y="100"/><use href="#cpine" x="1880" y="130"/><use href="#cpine" x="2010" y="95"/>
<use href="#cpine" x="90" y="1380"/><use href="#cpine" x="220" y="1420"/><use href="#cpine" x="1900" y="1400"/><use href="#cpine" x="2030" y="1360"/>
</g>
<!-- Ridge Road: gravel band across -->
<path d="M0 700 C 400 660 800 740 1200 700 C 1600 660 1900 720 2200 690" fill="none" stroke="#3a3325" stroke-width="150" opacity="0.85"/>
<path d="M0 700 C 400 660 800 740 1200 700 C 1600 660 1900 720 2200 690" fill="none" stroke="#7a6b3a" stroke-width="4" stroke-dasharray="26 18"/>
<text x="150" y="620" fill="#a08b4a" font-size="26" transform="rotate(-4 150 620)">RIDGE ROAD — MILE 9</text>
<text x="1960" y="640" fill="#a08b4a" font-size="22" transform="rotate(-3 1960 640)">to SITE ME-07 →</text>
<text x="60" y="800" fill="#a08b4a" font-size="22">← to CORLISS NOTCH</text>
<!-- winter gate, forced open -->
<g transform="translate(430 700)">
<rect x="-12" y="-90" width="24" height="180" fill="#9fb0b8"/>
<path d="M12 -70 L200 -110" stroke="#9fb0b8" stroke-width="12"/>
<text x="30" y="-130" fill="#9fb0b8" font-size="22">WINTER GATE — CHAIN CUT</text>
</g>
<!-- Cold Cauldron Pond, bottom right, thin ice -->
<g>
<path d="M1450 1080 C 1600 1000 1900 1020 2050 1140 C 2160 1240 2100 1420 1900 1470 C 1650 1530 1400 1420 1400 1260 C 1400 1180 1410 1110 1450 1080 Z"
fill="#0d1a20" stroke="#3d6b7a" stroke-width="3"/>
<g stroke="#5f97a8" stroke-width="2" opacity="0.6" fill="none">
<path d="M1520 1180 L1640 1260 L1600 1350"/>
<path d="M1800 1120 L1760 1240 L1880 1300"/>
</g>
<text x="1750" y="1240" fill="#5f97a8" font-size="26" text-anchor="middle">COLD CAULDRON POND</text>
<text x="1750" y="1272" fill="#3d6b7a" font-size="18" text-anchor="middle">ice: THIN — cracks radiate from shore</text>
</g>
<!-- Petrie truck: still here, hood open, running lights -->
<g transform="translate(1250 880) rotate(18)">
<rect x="-70" y="-150" width="140" height="300" rx="16" fill="#0f1418" stroke="#dfe8ee" stroke-width="4"/>
<rect x="-52" y="-120" width="104" height="90" fill="none" stroke="#9fb0b8" stroke-width="3"/>
<rect x="-52" y="30" width="104" height="100" fill="none" stroke="#9fb0b8" stroke-width="3"/>
<circle cx="-40" cy="-160" r="10" fill="#c9dd9e"/><circle cx="40" cy="-160" r="10" fill="#c9dd9e"/>
<text x="0" y="185" fill="#9fb0b8" font-size="20" text-anchor="middle" transform="rotate(-18)">PETRIE PICKUP</text>
<text x="0" y="211" fill="#5c6b73" font-size="15" text-anchor="middle" transform="rotate(-18)">10 weeks · engine still idling</text>
</g>
<!-- locals' vehicles blocking road: wood truck + two cars, headlights crossing -->
<g transform="translate(820 700) rotate(-84)">
<rect x="-80" y="-190" width="160" height="380" rx="10" fill="#0f1418" stroke="#dfe8ee" stroke-width="5"/>
<path d="M-80 -60 H80 M-80 60 H80" stroke="#3a474e" stroke-width="2"/>
<text x="0" y="230" fill="#9fb0b8" font-size="20" text-anchor="middle" transform="rotate(84)">LOG TRUCK (jackknifed)</text>
</g>
<g transform="translate(1035 585) rotate(24)">
<rect x="-55" y="-105" width="110" height="210" rx="14" fill="#0f1418" stroke="#dfe8ee" stroke-width="4"/>
<path d="M-70 -140 L-160 -230 M70 -140 L160 -230" stroke="#c9dd9e" stroke-width="6" opacity="0.5"/>
<text x="0" y="145" fill="#9fb0b8" font-size="18" text-anchor="middle" transform="rotate(-24)">SEDAN, doors open</text>
</g>
<g transform="translate(980 835) rotate(-12)">
<rect x="-55" y="-105" width="110" height="210" rx="14" fill="#0f1418" stroke="#dfe8ee" stroke-width="4"/>
<text x="0" y="150" fill="#9fb0b8" font-size="18" text-anchor="middle" transform="rotate(12)">DINER'S WAGON</text>
</g>
<!-- the congregation: circle of figures on the road, facing the ridge -->
<g transform="translate(1450 620)">
<circle r="120" fill="none" stroke="#8aa353" stroke-width="3" stroke-dasharray="8 10"/>
<g fill="#c9dd9e">
<circle cx="0" cy="-95" r="13"/><circle cx="82" cy="-42" r="13"/><circle cx="88" cy="52" r="13"/>
<circle cx="0" cy="98" r="13"/><circle cx="-88" cy="52" r="13"/><circle cx="-82" cy="-42" r="13"/>
</g>
<circle r="17" fill="#e8cd7a"/>
<text x="0" y="-150" fill="#8aa353" font-size="24" text-anchor="middle">THE CONGREGATION</text>
<text x="0" y="170" fill="#5c6b73" font-size="17" text-anchor="middle">standing in the snow, unbothered · humming</text>
<text x="0" y="24" fill="#7a6b3a" font-size="14" text-anchor="middle">AGNES</text>
</g>
<!-- petrie markers by pond edge -->
<g fill="#8fd4e8">
<circle cx="1560" cy="1050" r="14"/><circle cx="1640" cy="1085" r="14"/>
<text x="1600" y="1020" fill="#8fd4e8" font-size="20" text-anchor="middle">THE RETURNED (×2)</text>
</g>
<!-- title block -->
<g transform="translate(40 40)">
<rect width="600" height="120" fill="#0a0d10" stroke="#8aa353" stroke-width="2"/>
<text x="20" y="46" fill="#dfe8ee" font-size="32" letter-spacing="2">COLD CAULDRON CROSSING</text>
<text x="20" y="80" fill="#8aa353" font-size="21">MIDPOINT ENCOUNTER — THE CONGREGATION</text>
<text x="20" y="106" fill="#5c6b73" font-size="17">Ridge Road mile 9 · night · heavy snow · 1 sq = 5 ft</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

@@ -0,0 +1,33 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" fill="#0a0d10"/>
<!-- static halo: concentric broadcast rings -->
<g stroke="#e8cd7a" fill="none" opacity="0.35">
<circle cx="256" cy="220" r="150" stroke-width="2"/>
<circle cx="256" cy="220" r="190" stroke-width="1.5" stroke-dasharray="10 8"/>
<circle cx="256" cy="220" r="230" stroke-width="1" stroke-dasharray="4 12"/>
</g>
<g fill="#e8e2d4">
<!-- shawled shoulders -->
<path d="M256 318c-70 0-116 32-132 90-6 22-9 46-11 104h286c-2-58-5-82-11-104-16-58-62-90-132-90z"/>
<!-- head, gaunt -->
<path d="M256 122c-42 0-70 32-70 80 0 44 28 80 70 80s70-36 70-80c0-48-28-80-70-80z"/>
<!-- severe pulled-back hair -->
<path d="M256 122c-42 0-70 32-70 80 0 4 0 8 1 12 8-24 32-38 69-38s61 14 69 38c1-4 1-8 1-12 0-48-28-80-70-80z" fill="#b8b2a4"/>
<!-- bun -->
<circle cx="256" cy="118" r="22" fill="#b8b2a4"/>
</g>
<!-- headset band + earpiece pressed to ear -->
<path d="M186 170 C 200 120 312 120 326 170" stroke="#4a5560" stroke-width="12" fill="none"/>
<circle cx="188" cy="196" r="26" fill="#4a5560"/><circle cx="188" cy="196" r="12" fill="#0a0d10"/>
<!-- blank white eyes -->
<g fill="#f5f5ef"><ellipse cx="228" cy="200" rx="13" ry="9"/><ellipse cx="284" cy="200" rx="13" ry="9"/></g>
<!-- mouth open, speaking someone else's words: static pouring out -->
<ellipse cx="256" cy="252" rx="16" ry="22" fill="#0a0d10"/>
<g stroke="#e8cd7a" stroke-width="3" fill="none" opacity="0.9">
<path d="M256 260 q30 6 44 30 M256 264 q-28 8 -40 32 M256 268 q6 30 0 52"/>
</g>
<!-- frost on collar -->
<path d="M170 340 Q256 316 342 340" stroke="#bfeaf6" stroke-width="4" fill="none" opacity="0.6"/>
<!-- shawl folds -->
<path d="M210 360 L226 512 M302 360 L286 512" stroke="#0a0d10" stroke-width="5" opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

@@ -0,0 +1,30 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" fill="#0a0d10"/>
<!-- three overlapping entranced townsfolk, eyes closed, faces upturned -->
<g fill="#d9d2c4" opacity="0.55">
<path d="M120 512 c0 -70 34 -108 76 -108 s76 38 76 108z"/>
<g transform="rotate(-6 196 330)"><path d="M196 268 c-30 0 -50 24 -50 58 0 32 20 58 50 58 s50 -26 50 -58 c0 -34 -20 -58 -50 -58z"/></g>
</g>
<g fill="#d9d2c4" opacity="0.75">
<path d="M240 512 c0 -76 36 -116 82 -116 s82 40 82 116z"/>
<g transform="rotate(5 322 300)"><path d="M322 232 c-32 0 -54 26 -54 62 0 36 22 62 54 62 s54 -26 54 -62 c0 -36 -22 -62 -54 -62z"/></g>
</g>
<!-- front figure: teenager, head tipped back, mouth humming -->
<g fill="#e8e2d4">
<path d="M60 512 c0 -84 40 -128 92 -128 s92 44 92 128z"/>
<g transform="rotate(-10 152 260)">
<path d="M152 182 c-36 0 -60 28 -60 68 0 40 24 68 60 68 s60 -28 60 -68 c0 -40 -24 -68 -60 -68z"/>
<path d="M152 182 c-36 0 -60 28 -60 68 l0 4 c10 -24 30 -36 60 -36 s50 12 60 36 l0 -4 c0 -40 -24 -68 -60 -68z" fill="#a89f88"/>
</g>
</g>
<!-- closed eyes (peaceful, wrong) + humming mouths -->
<g stroke="#0a0d10" stroke-width="6" fill="none">
<g transform="rotate(-10 152 260)"><path d="M124 252 q14 10 28 0 M166 252 q14 10 28 0 M138 292 q16 -8 32 0"/></g>
</g>
<g stroke="#0a0d10" stroke-width="5" fill="none" opacity="0.75">
<g transform="rotate(5 322 300)"><path d="M300 292 q12 8 24 0 M336 292 q12 8 24 0 M312 326 q14 -6 28 0"/></g>
</g>
<!-- shared hum: single thin waveform rising -->
<path d="M100 150 q40 -30 80 0 t80 0 t80 0 t80 0" stroke="#8aa353" stroke-width="3" fill="none" opacity="0.7"/>
<path d="M140 110 q30 -22 60 0 t60 0 t60 0" stroke="#8aa353" stroke-width="2" fill="none" opacity="0.45"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

@@ -0,0 +1,29 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" fill="#08171c"/>
<!-- pond-ice fracture backdrop -->
<g stroke="#3d6b7a" stroke-width="1.5" opacity="0.5">
<path d="M60 470 L180 360 L140 300 M452 470 L340 380 L390 300 M256 500 L256 420"/>
</g>
<g fill="#cfe0e6">
<!-- broad hunter shoulders, soaked parka -->
<path d="M256 312c-76 0-124 34-140 94-6 22-9 48-11 106h302c-2-58-5-84-11-106-16-60-64-94-140-94z"/>
<!-- head -->
<path d="M256 128c-44 0-72 32-72 80 0 46 28 84 72 84s72-38 72-84c0-48-28-80-72-80z"/>
<!-- wet flat hair -->
<path d="M256 128c-44 0-72 32-72 80l0 6c10-26 34-40 72-40s62 14 72 40l0-6c0-48-28-80-72-80z" fill="#8fa6ad"/>
</g>
<!-- waterline stain across face -->
<path d="M184 226 Q256 214 328 226" stroke="#3d6b7a" stroke-width="5" fill="none" opacity="0.7"/>
<!-- sunken dark eyes, pinprick light -->
<g fill="#08171c"><ellipse cx="228" cy="204" rx="16" ry="20"/><ellipse cx="284" cy="204" rx="16" ry="20"/></g>
<g fill="#8fd4e8"><circle cx="228" cy="206" r="4"/><circle cx="284" cy="206" r="4"/></g>
<!-- slack mouth, water weed -->
<path d="M226 262 Q256 274 286 262" stroke="#08171c" stroke-width="7" fill="none"/>
<path d="M280 268 q14 26 4 52" stroke="#2c4a3e" stroke-width="5" fill="none"/>
<!-- parka zip + frost -->
<path d="M256 330 V512" stroke="#08171c" stroke-width="6"/>
<path d="M176 344 Q256 322 336 344" stroke="#bfeaf6" stroke-width="4" fill="none" opacity="0.7"/>
<!-- boat hook in fist -->
<path d="M108 512 L128 330 q2 -18 14 -14 l4 2 q10 4 6 20 L142 512" fill="#8fa6ad"/>
<path d="M120 336 q-26 -10 -18 -36 q4 -14 20 -12" stroke="#8fa6ad" stroke-width="10" fill="none"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

@@ -0,0 +1,35 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<rect width="512" height="512" fill="#08171c"/>
<g stroke="#3d6b7a" stroke-width="1.5" opacity="0.5">
<path d="M80 470 L200 380 L160 320 M430 470 L330 360 L380 290"/>
</g>
<g fill="#cfe0e6">
<!-- heavier build, hunched -->
<path d="M256 306c-80 0-130 36-146 96-6 22-9 52-11 110h314c-2-58-5-88-11-110-16-60-66-96-146-96z"/>
<!-- head tilted -->
<g transform="rotate(-8 256 210)">
<path d="M256 124c-44 0-72 32-72 80 0 46 28 84 72 84s72-38 72-84c0-48-28-80-72-80z"/>
<path d="M256 124c-44 0-72 32-72 80l0 6c10-26 34-40 72-40s62 14 72 40l0-6c0-48-28-80-72-80z" fill="#8fa6ad"/>
</g>
</g>
<!-- cap frozen to head -->
<g transform="rotate(-8 256 210)">
<path d="M184 176 C 196 130 316 130 328 176 L328 190 L184 190 Z" fill="#5c6b73"/>
<rect x="184" y="184" width="150" height="14" rx="7" fill="#5c6b73"/>
</g>
<!-- one eye frozen shut, one pinprick -->
<g transform="rotate(-8 256 210)">
<path d="M214 206 L246 202" stroke="#08171c" stroke-width="8"/>
<ellipse cx="286" cy="206" rx="16" ry="20" fill="#08171c"/><circle cx="286" cy="208" r="4" fill="#8fd4e8"/>
<!-- jaw hangs, breath of static -->
<path d="M230 262 Q258 284 288 258" stroke="#08171c" stroke-width="8" fill="none"/>
</g>
<g stroke="#bfeaf6" stroke-width="2.5" fill="none" opacity="0.7">
<path d="M262 282 q20 14 44 12 M258 288 q10 22 32 30"/>
</g>
<!-- frost -->
<path d="M168 336 Q256 312 344 336" stroke="#bfeaf6" stroke-width="4" fill="none" opacity="0.7"/>
<!-- splitting maul over shoulder -->
<path d="M356 512 L380 300 q2 -16 14 -12 l6 2 q10 4 6 18 L382 512" fill="#8fa6ad"/>
<rect x="352" y="268" width="86" height="40" rx="8" fill="#8fa6ad" transform="rotate(-14 395 288)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

+76 -4
View File
@@ -65,6 +65,8 @@ const items = [
"Incendiary supplied for sanitation. Burns hot enough to reduce a frozen body — or a data drive — to slag. Needed to dispose of Dr. Rostova's remains without leaving forensic questions."),
gearItem("Cold-Weather Field Kit", "camping-gear", "Standard",
"Parkas, chemical heat packs, headlamps and rope. The dome interior is pitch black and the whole site is well below freezing; Agents without light and warmth accrue penalties over a long night."),
gearItem("Elias Corliss's Ham Handset", "walkie-talkie", "Trivial",
"A 1970s hand microphone on a worn leather strap, wired to nothing. Agnes Corliss has carried it since her husband died at his radio bench in 1988. <b>The Tear speaks to her through it</b> &mdash; it is the anchor of the Chorus. Destroying it (called shot &minus;20%, 6 HP) or taking it from her silences the static and frees the Called. Afterward it is inert &mdash; but at 3 a.m. it is very slightly cold to the touch."),
];
// ---------------------------------------------------------------- actors
@@ -122,7 +124,56 @@ const aTear = npcActor({
shortDescription: "An extradimensional entity that mimics radio frequencies.",
notes: "<h2>The Tear &mdash; the Static Between Stations</h2><p>Not a creature so much as a <b>place that should not touch this one</b>: a shifting, non-Euclidean fractal silhouette that bleeds through the centre of the radar dish when the broadcast peaks. The air turns static-charged; hair stands on end; the temperature crashes.</p><h3>Rules</h3><ul><li><b>Firearms are useless.</b> Bullets pass through it and <b>warp out of shape</b>, doing nothing. Do not roll damage.</li><li><b>Presence:</b> being in its manifested presence costs <b>1D6/1D20 SAN</b>. Prolonged exposure (a round overloading the transformer beside it) is the full 1D20 branch.</li><li>It draws humans toward the freezing dark by <b>mimicking frequencies</b> — the corrupted radar return, the sub-carrier voice whispering the Agents' own names.</li></ul><h3>The only resolution: cut the power</h3><p>The tear cannot be fought, only <b>closed</b> by killing the broadcast:</p><ul><li><b>Blow the backup generator outside</b> &mdash; a hazardous run through the dark and snow (Demolitions, or improvised; STR/Athletics to reach it, exposure to Vance en route), or</li><li><b>Manually overload the main transformer inside the dome</b> &mdash; the Agent doing so takes <b>lethal electrical shock</b> (Lethality; survivors are badly hurt) and the full <b>1D6/1D20 SAN</b> exposure to the entity at arm's length.</li></ul><p>When power dies the tear <b>snaps back</b>, and the vacuum <b>implodes the dome.</b></p>",
});
const actors = [aRostova, aVance, aTear];
// ---- Midpoint encounter: The Congregation ----
const aAgnes = npcActor({
key: "agnes", name: "Agnes Corliss, the Switchboard Widow", type: "unnatural",
img: `${A}/token-agnes.png`, token: `${A}/token-agnes.png`,
stats: { str: 8, con: 12, dex: 9, int: 14, pow: 18, cha: 16 }, health: 10,
san: { failed: "1D6", success: "1" },
skills: { alertness: 55, occult: 40, persuade: 60, sigint: 50 },
shortDescription: "The Tear speaks through her dead husband's handset.",
notes: "<h2>Agnes Corliss &mdash; the Switchboard Widow (78)</h2><p>Great-granddaughter of the town's founders. Her husband Elias died at his ham bench in 1988, headphones on, tuned to the ridge. Agnes has listened every night since &mdash; and three months ago, <b>the ridge started answering in Elias's voice.</b> She believes the broadcast is heaven. She has been gathering the weak-willed of Corliss Notch to &#8220;hear the call.&#8221; Tonight she has brought them to meet it.</p><h3>Combat &mdash; she does not fight. She RULES the fight.</h3><ul><li><b>HP 10, WP 18.</b> Physically frail. <b>The Chorus Protects:</b> while any Called or Returned is conscious within 10 m, attacks against Agnes suffer &minus;20% (they lurch into the line of fire).</li><li><b>THE CHORUS (free action, every round):</b> layered static pours from her open mouth and from every radio, phone and earpiece the Agents carry. All who hear it: <b>SAN 0/1D4 on first exposure, then 0/1 per further round</b>; &minus;20% to any concentration-based test while it sustains. Agents who ditch comms and plug their ears reduce this to first-exposure only.</li><li><b>STAND STILL (action):</b> she speaks one Agent's true name <i>backward</i>. Opposed test: her POW&times;5 (90%) vs the target's POW&times;5. Fail: the Agent <b>loses their next action</b>, standing slack. Critical fail: they also drop what they hold.</li><li><b>SPEAK THE NAMES (once per Agent per night):</b> she recites something private &mdash; a Bond's name, a buried guilt (Handler: mine the Agent's Bonds). Target: <b>SAN 0/1D4.</b></li></ul><h3>Weakness &mdash; CUT THE FEED</h3><p>The Chorus anchors through <b>Elias's handset</b> on her belt (called shot &minus;20%, 6 HP, or a successful grapple to snatch it). Destroy or take it &mdash; or deafen her (flash-bang) &mdash; and the Chorus dies: Stand Still drops to 45%, the Called wake, and Agnes collapses into a confused, weeping old woman asking where Elias has gone. <b>She is a victim.</b> What A-Cell does with her afterward is the Handler's knife to twist.</p><p><em>SAN to witness the Chorus in a dead loved one's voice: 1/1D6.</em></p>",
});
const aDale = npcActor({
key: "dale", name: "Dale Petrie, Returned", type: "unnatural",
img: `${A}/token-returned-dale.png`, token: `${A}/token-returned-dale.png`,
stats: { str: 17, con: 16, dex: 12, int: 7, pow: 12, cha: 4 }, health: 17,
san: { failed: "1D6", success: "1" },
skills: { alertness: 50, athletics: 60, melee_weapons: 60, unarmed_combat: 55, swim: 70 },
shortDescription: "Ten weeks drowned. Walking anyway.",
weapons: [
{ name: "Boat Hook", icon: "forcible-entry-tool", skill: "melee_weapons", damage: "1D8+2", range: "0M" },
{ name: "Grasp of the Drowned", icon: "unarmed", skill: "unarmed_combat", damage: "1D6+1", range: "0M" },
],
notes: "<h2>Dale Petrie &mdash; Returned (was 41)</h2><p>The elder of the vanished hunters. Ten weeks at the bottom of Cold Cauldron Pond, and now he stands at its edge, soaked and patient, holding the boat hook he went in with. The Tear kept the shape and threw away most of the man.</p><h3>Combat (each brother)</h3><ul><li><b>HP 17. Frost-hardened flesh: 3 points armor</b> &mdash; cold meat doesn't tear. Ignores stun, pain and fear.</li><li><b>Boat Hook</b> 60%, 1D8+2. <b>Grasp of the Drowned</b> 55%, 1D6+1 &mdash; on a hit the limb seized goes numb: <b>&minus;20% to the target's DEX-based tests next round.</b></li><li><b>Cold radius:</b> Agents within 3 m for 3+ consecutive rounds: CON&times;5 or 1 HP from the cold.</li><li><b>COLD CAULDRON BAPTISM:</b> if BOTH brothers grapple one Agent, they drag them toward the pond &mdash; 2 rounds to the shore, then under the thin ice. Drowning and freezing, simultaneously. This is what they came to do: <b>the pond is how the Tear tastes people.</b></li></ul><h3>Weaknesses</h3><ul><li><b>Fire/thermite: double damage</b>, and an open flame makes both brothers flinch back one step.</li><li>An Agent who shouts their names with a successful <b>HUMINT</b> roll makes one brother hesitate a full round (once per brother). Something in there remembers being called in for supper.</li></ul><p><em>SAN to see one clearly: 1/1D6.</em></p>",
});
const aRoy = npcActor({
key: "roy", name: "Roy Petrie, Returned", type: "unnatural",
img: `${A}/token-returned-roy.png`, token: `${A}/token-returned-roy.png`,
stats: { str: 18, con: 16, dex: 11, int: 6, pow: 12, cha: 4 }, health: 17,
san: { failed: "1D6", success: "1" },
skills: { alertness: 45, athletics: 60, melee_weapons: 60, unarmed_combat: 55, swim: 70 },
shortDescription: "The younger brother. He hums the broadcast now.",
weapons: [
{ name: "Splitting Maul", icon: "wood-axe", skill: "melee_weapons", damage: "1D10+2", range: "0M" },
{ name: "Grasp of the Drowned", icon: "unarmed", skill: "unarmed_combat", damage: "1D6+1", range: "0M" },
],
notes: "<h2>Roy Petrie &mdash; Returned (was 38)</h2><p>The younger, bigger brother. One eye is frozen shut; his jaw hangs; from somewhere inside him comes the six-second static loop, humming, over and over. He carries the splitting maul from his own woodpile.</p><p><b>Use Dale's stat block</b> &mdash; identical rules, except: <b>Splitting Maul</b> 60%, 1D10+2 (slower, meaner). Roy always moves toward whoever is LOUDEST &mdash; gunfire, shouting, a radio squawk. Handler note: point him at the Agent doing the most talking.</p><p>Armor 3 (frost-hardened flesh) &middot; fire = double damage &middot; HUMINT name-call makes him hesitate once &middot; Baptism drag with Dale &middot; SAN 1/1D6.</p>",
});
const aCalled = npcActor({
key: "called", name: "The Called (Notch townsfolk)", type: "npc",
img: `${A}/token-called.png`, token: `${A}/token-called.png`,
stats: { str: 11, con: 11, dex: 10, int: 10, pow: 10, cha: 10 }, health: 11, san: 40,
skills: { alertness: 30, athletics: 30, unarmed_combat: 40 },
shortDescription: "Five entranced neighbours. They are crying while they do it.",
notes: "<h2>The Called &mdash; five townsfolk of Corliss Notch</h2><p>Cody Aldous (17, deleted the livestream), Ruth the diner cook, Whit Emmons the trapper, and the Pelletier couple from the feed store. They stand in the snow in their nightclothes and hunting jackets, faces upturned, <b>humming the six-second loop in unison.</b> Look closely (<b>HUMINT 40%</b>): they are weeping while they hum. They are prisoners in their own bodies.</p><h3>Combat &mdash; they are a wall, not an army</h3><ul><li>Use this one actor for all five (HP 11 each; track hits).</li><li><b>They do not kill. They RESTRAIN:</b> grapple at 40%, working in pairs (+20% for the second). A held Agent is carried toward Agnes &mdash; or the pond.</li><li>While the Chorus sustains they are immune to Persuade and feel no fear.</li><li><b>Pain wakes them a little:</b> any damage dealt to one grants it a POW&times;5 test each round to shake free of the trance.</li><li><b>When the Chorus dies</b> (handset destroyed/taken, Agnes deafened or down): they ALL wake at once &mdash; five terrified, hypothermic civilians in a firefight.</li></ul><h3>The cost</h3><p><b>Killing one of the Called costs the shooter 1/1D8 SAN</b> &mdash; they are innocent &mdash; and hands the cover-up (journal &#9451;) a body that cannot be blamed on weather. The Handler should make the easy trigger-pull expensive.</p>",
});
const actors = [aRostova, aVance, aTear, aAgnes, aDale, aRoy, aCalled];
// ---------------------------------------------------------------- journals
let jSort = 0;
@@ -199,7 +250,7 @@ const journal_audio = journal("07-audio", "⑦ HANDOUT — Final Transmission (A
]);
const journal_tear = journal("08-tear", "⑧ HANDOUT — THE TEAR (climax only)", [
imagePage("The Manifestation", `${A}/handout-entity.svg`, "DO NOT REVEAL until the broadcast peaks."),
imagePage("The Manifestation", `${A}/handout-entity.png`, "DO NOT REVEAL until the broadcast peaks."),
textPage("Reveal notes",
"<p><b>Hold this image back</b> until the radar dish activates and the entity bleeds through. The air is static-charged, everyone's hair stands on end, and a shifting, non-Euclidean <b>fractal silhouette</b> tears open at the centre of the dish. Presence costs <b>1D6/1D20 SAN</b>. Bullets pass through and warp uselessly. See <em>GM — NPCs &amp; The Threat</em>.</p>"),
]);
@@ -209,6 +260,8 @@ const journal_gm_scenes = journal("09-gm-scenes", "⑨ GM — Scene Guide &amp;
"<p>A fenced compound: one concrete equipment building and a massive geodesic radar dome over the pines. Heavy snow.</p><ul><li>The outer chain-link fence has been <b>cut from the inside out.</b></li><li><b>Deputy's cruiser</b> by the gate: door wide open, engine dead, interior coated in thick frost. <b>Forensics/Search:</b> his service weapon is in the footwell, <b>missing three rounds &mdash; no bullet holes in the car.</b></li><li><b>Survival/Tracking:</b> footprints lead from the driver's side into the woods, spaced <b>~8 feet apart</b> &mdash; as if sprinting, or dragged in massive strides.</li></ul>"),
textPage("Scene 2 — The Server Room",
"<p>The concrete building runs on a failing backup generator that hums unsteadily. <b>Dr. Elena Rostova</b> is dead at the console: <b>frozen solid</b> in a 40&deg;F room, eyes wide, lips torn from her teeth.</p><ul><li><b>Computer Science:</b> the log shows a &#8220;geometric shadow&#8221; over the dish, not an aircraft (Handout ②).</li><li><b>SIGINT/Science:</b> the final transmission is oscillating static. Listening closely = <b>SAN 0/1D4</b>; success hears a voice whispering the Agents' names (Handout ③).</li></ul>"),
textPage("Scene 2.5 — MIDPOINT: The Congregation",
"<p>Between the server room and the dome, the town comes up the mountain. When the Agents step back outside &mdash; or drive for the dome &mdash; <b>headlights crest the Ridge Road at mile 9</b>, and under the wind they hear it: a dozen human voices <b>humming the six-second static loop in unison.</b></p><p>Full encounter, map, and stat blocks: journal <b>&#9452; GM &mdash; MIDPOINT: The Congregation</b>. Run it before Scene 3; it is the operation's turn from investigation to horror.</p>"),
textPage("Scene 3 — The Radar Dome",
"<p>The upper catwalk inside the dome is pitch black, reeking of <b>ozone and scorched copper</b>. <b>Deputy Vance is here</b> — blind, self-mutilated, frantically rewiring the transmitter to broadcast the static loop at maximum amplification.</p><ul><li>He is <b>no longer entirely human</b>: unhinged jaw, jerky speed, screaming the tech manual backward. Witnessing him = <b>1/1D6 SAN</b>.</li><li>If interposed, he attacks with a heavy wrench (see <em>GM — NPCs</em>).</li></ul>"),
textPage("The Climax — The Broadcast",
@@ -232,6 +285,16 @@ const journal_gm_truth = journal("11-gm-truth", "⑪ GM — The Truth (What's Re
"<p>The tear cannot be fought &mdash; only <b>starved of signal.</b> Cut the primary power (blow the outside generator, or overload the dome transformer by hand at lethal cost) and the channel collapses: the entity snaps back and the vacuum implodes the dome. If the Agents <b>fail</b>, the broadcast completes, the doorway holds open, and Sable Ridge becomes a permanent cold spot that swallows the Notch over the following winter &mdash; a much larger Delta Green problem, later.</p>"),
]);
const journal_midpoint = journal("13-gm-midpoint", "⑬ GM — MIDPOINT: The Congregation", [
imagePage("Cold Cauldron Crossing", `${A}/map-crossing.svg`, "Ridge Road, mile 9 — the battle map is in the Scenes folder."),
textPage("The Setup",
"<p>The broadcast has been calling Corliss Notch for weeks &mdash; the hum, the radio that answers, the names. Tonight, as the transmitter nears full power, the most susceptible finally <b>answered</b>. <b>Agnes Corliss</b>, who has heard her dead husband in the static for months, has led five entranced neighbours up the Ridge Road to &#8220;meet the call.&#8221; And at Cold Cauldron Pond, the Tear has sent up what it kept: <b>the Petrie brothers.</b></p><p><b>Trigger:</b> run this when the Agents leave the equipment building for the dome (or try to drive back down). A jackknifed log truck blocks the road at mile 9; vehicles cluster with doors open, engines running; six figures stand in a circle in the snow, faces upturned, humming. The pond glimmers to the south. <b>Read-aloud:</b></p><blockquote><p><i>The snow parts around them like they've been standing there an hour. Old Agnes Corliss stands at the centre in her nightcoat, one hand pressing a dead man's radio handset to her ear. Without turning, she says your point-man's name &mdash; first, middle, last &mdash; in a voice that is not hers. From the pond shore, two big men in soaked hunting jackets begin to walk up the bank. They have been dead for ten weeks, and they are smiling like they're late for supper.</i></p></blockquote>"),
textPage("The Opposition",
"<p>Four actor sheets in the FALSE ALARM folder carry the full rules:</p><ul><li><b>Agnes Corliss, the Switchboard Widow</b> &mdash; the control piece. The Chorus (rolling SAN drain + concentration penalties through every radio the Agents carry), Stand Still (name spoken backward = lose an action), Speak the Names (weaponized Bonds). Frail &mdash; but screened by everyone else.</li><li><b>Dale &amp; Roy Petrie, Returned</b> &mdash; the muscle. Armor 3, ignore pain, boat hook and splitting maul, numbing grasp, and the <b>Baptism</b>: grappled Agents get dragged under the pond ice. Fire is doubled against them.</li><li><b>The Called</b> (&times;5) &mdash; the wall, and the moral trap. They grapple, restrain and carry; they never kill; they are crying while they do it. Killing one is 1/1D8 SAN and a cover-up catastrophe.</li></ul><p><b>Balance note (4 Agents):</b> this is deliberately unwinnable as a straight shootout &mdash; ~34 effective HP of armored Returned plus five bodies the Agents must not shoot, while Agnes strips actions and SAN. The door out is the <b>handset</b>.</p>"),
textPage("Running It — tactics, outs, aftermath",
"<p><b>Round order of intent:</b> the Called advance to restrain; the Returned make for whoever resists hardest (Roy goes for the loudest); Agnes stands still and takes Agents apart with words. Anyone dragged to the pond has 2 rounds before they go under.</p><p><b>Ways to win that aren't massacre:</b></p><ul><li><b>Cut the feed:</b> destroy or snatch Elias's handset (called shot &minus;20%, 6 HP, or grapple Agnes). Chorus dies, the Called wake, the Returned stop mid-stride &mdash; then turn and walk back into the pond.</li><li><b>Deafen her:</b> a flash-bang inside 10 m silences the Chorus for good.</li><li><b>Names:</b> HUMINT + shouting a Petrie's name buys a round per brother. Enough rounds to run.</li><li><b>Run the gauntlet:</b> ram past the log truck (Drive &minus;20% in snow). The Congregation follows &mdash; slowly, on foot, uphill, humming. They arrive at the compound for the climax if not dealt with.</li></ul><p><b>Aftermath:</b> freed Called remember everything as a dream of &#8220;the most beautiful voice.&#8221; Waking all five alive: <b>+1 SAN each Agent.</b> Agnes, if freed, keeps asking where Elias went &mdash; and once, flatly, in the wrong voice: <i>&#8220;IT IS ALMOST DONE LEARNING OUR SHAPE.&#8221;</i> That is the players' warning for Scene 3. Every civilian death here becomes a named problem in &#9451; Cover-Up.</p>"),
]);
const journal_gm_after = journal("12-gm-after", "⑫ GM — Cover-Up &amp; Aftermath", [
textPage("Loose ends",
"<ul><li><b>Burn</b> the frozen remains of Dr. Rostova (Thermite Charge) and manage her FAA record and next of kin (the sister in Vermont).</li><li><b>Stage the cruiser</b> as a horrific wildlife attack or a vehicular accident. Recover Vance's body if at all possible &mdash; the Notch will search for its deputy.</li><li><b>Wipe the FAA's remote cloud backups</b> (Computer Science) as well as the on-site drive.</li><li>The imploded dome sells the &#8220;catastrophic weather-generator failure&#8221; on its own &mdash; if nothing contradicts it. Loose talk in Corliss Notch is the real threat to the cover.</li></ul>"),
@@ -243,21 +306,24 @@ const journalArr = [
journal_briefing, journal_site, journal_area, journal_activity, journal_persons,
journal_radar, journal_audio, journal_tear,
journal_gm_scenes, journal_gm_threat, journal_gm_truth, journal_gm_after,
journal_midpoint,
].map((j) => { delete j._key; return j; });
// ---------------------------------------------------------------- scenes
function gridCfg() { return { type: 1, size: 200, style: "solidLines", thickness: 1, color: "#59ff87", alpha: 0.10, distance: 5, units: "ft" }; }
function sceneToken(actor, x, y, hidden = false) {
const tid = id(`fa-tok-${actor._id}-${x}-${y}`);
// x/y are the CENTER of the intended map position (scenes use padding 0,
// so map pixels === scene coordinates); token docs store the top-left.
return { _id: tid, name: actor.name, actorId: actor._id, actorLink: false,
texture: { src: actor.prototypeToken.texture.src, anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, fit: "contain" },
x, y, width: 1, height: 1, hidden, disposition: actor.prototypeToken.disposition, displayName: 20,
x: x - 100, y: y - 100, width: 1, height: 1, hidden, disposition: actor.prototypeToken.disposition, displayName: 20,
sight: { enabled: false }, sort: 0, flags: {} };
}
function scene(key, name, bg, w, h, tokens, notesFlag) {
return {
_id: id(`fa-scene-${key}`), name, active: false, navigation: true, navName: "",
width: w, height: h, padding: 0.25, background: { src: `${A}/${bg}` }, foreground: null,
width: w, height: h, padding: 0, background: { src: `${A}/${bg}` }, foreground: null,
grid: gridCfg(), initial: { x: Math.round(w / 2), y: Math.round(h / 2), scale: 0.5 },
backgroundColor: "#050708", tokenVision: false, fogExploration: false, globalLight: true, darkness: 0,
tokens, walls: [], lights: [], sounds: [], templates: [], notes: [], drawings: [], tiles: [],
@@ -268,6 +334,12 @@ function scene(key, name, bg, w, h, tokens, notesFlag) {
const scenes = [
scene("1-arrival", "Scene 1 — The Arrival (Compound)", "map-compound.png", 5200, 3600, []),
scene("2-server", "Scene 2 — The Server Room", "map-server-room.png", 3600, 2800, [sceneToken(aRostova, 1800, 1560)]),
scene("25-crossing", "Scene 2.5 — Cold Cauldron Crossing", "map-crossing.png", 4400, 3200, [
sceneToken(aAgnes, 2900, 1240),
sceneToken(aCalled, 2740, 1100), sceneToken(aCalled, 3070, 1140), sceneToken(aCalled, 2900, 1430),
sceneToken(aCalled, 2680, 1330), sceneToken(aCalled, 3100, 1350),
sceneToken(aDale, 3120, 2100), sceneToken(aRoy, 3280, 2170),
]),
scene("3-dome", "Scene 3 — The Radar Dome", "map-radar-dome.png", 4000, 4000,
[sceneToken(aVance, 2000, 2000), sceneToken(aTear, 2000, 2000, true)]),
];
+9
View File
@@ -539,12 +539,21 @@
#pause.dg2-pause {
background: none;
}
/* Layout ONLY while actually paused - never override Foundry's hidden
(unpaused) state, or the stock GAME PAUSED markup shows after unpausing. */
#pause.dg2-pause.paused {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
}
#pause.dg2-pause:not(.paused) {
display: none;
}
#pause.dg2-pause img { display: none; }
.dg2-pause-scope {
+830
View File
@@ -0,0 +1,830 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FALSE ALARM — GM Screen</title>
<style>
:root{
--bg:#101317; --panel:#161a1f; --panel2:#1c2127; --edge:#2a313a; --hair:#232932;
--ink:#e4e9ec; --mut:#8d98a3; --olive:#8aa353; --olive-b:#b7d873; --red:#d4553c; --red-b:#ff7a5c;
--steel:#6b93b8; --gold:#d6b45a; --violet:#9d7bd8;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{background:var(--bg);color:var(--ink);font:15px/1.55 -apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;display:flex;min-height:100vh}
::selection{background:rgba(138,163,83,.35)}
/* ---------- sidebar ---------- */
nav{position:sticky;top:0;height:100vh;width:252px;flex:0 0 252px;background:var(--panel);
border-right:1px solid var(--edge);padding:14px 0;overflow-y:auto;scrollbar-width:thin}
.brand{padding:0 16px 10px;border-bottom:1px solid var(--hair);margin-bottom:8px}
.brand h1{font-size:15px;letter-spacing:2px}
.brand small{color:var(--olive);letter-spacing:1.5px;font-size:10.5px;text-transform:uppercase}
#search{margin:8px 12px;width:calc(100% - 24px);background:#0d1013;border:1px solid var(--edge);
border-radius:5px;color:var(--ink);padding:7px 10px;font-size:13px}
#search:focus{outline:none;border-color:var(--olive)}
nav a{display:block;padding:6px 16px;color:var(--mut);text-decoration:none;font-size:13px;border-left:3px solid transparent;cursor:pointer}
nav a:hover{color:var(--ink);background:var(--panel2)}
nav a.on{color:var(--olive-b);border-left-color:var(--olive);background:var(--panel2)}
nav .grp{padding:12px 16px 4px;font-size:10px;letter-spacing:2px;color:#5a646f;text-transform:uppercase}
.navbtns{display:flex;gap:6px;margin:12px;flex-wrap:wrap}
.navbtns button{flex:1;min-width:58px;background:var(--panel2);border:1px solid var(--edge);color:var(--mut);
border-radius:5px;padding:6px 4px;font-size:11px;cursor:pointer}
.navbtns button:hover{color:var(--ink);border-color:var(--olive)}
/* ---------- main / accordion ---------- */
main{flex:1;max-width:920px;padding:26px 40px 30vh}
section{margin-bottom:10px;scroll-margin-top:14px;border:1px solid var(--edge);border-radius:9px;
background:var(--panel);overflow:hidden}
.sec-head{display:flex;align-items:center;gap:12px;padding:13px 16px;cursor:pointer;user-select:none}
.sec-head:hover{background:var(--panel2)}
.sec-head .chev{flex:0 0 auto;width:22px;height:22px;border-radius:5px;border:1px solid var(--edge);
display:grid;place-items:center;color:var(--olive-b);font-size:12px;transition:transform .18s}
section.open .sec-head .chev{transform:rotate(90deg)}
.sec-head h2{font-size:16.5px;letter-spacing:1.4px;text-transform:uppercase;flex:1}
.sec-head .tag{font-size:11px;letter-spacing:1px;color:var(--mut);font-weight:400;text-transform:none;display:block}
.sec-head .accent{width:4px;align-self:stretch;border-radius:2px;background:var(--olive);flex:0 0 4px}
.sec-body{display:none;padding:4px 20px 20px;border-top:1px solid var(--hair)}
section.open .sec-body{display:block}
h3{font-size:13.5px;color:var(--olive-b);letter-spacing:1px;margin:18px 0 6px;text-transform:uppercase}
h4{font-size:13px;color:var(--gold);margin:12px 0 4px}
p{margin:7px 0;color:#c8d0d6}
b,strong{color:var(--ink)} em{color:#aeb9c0}
ul,ol{margin:6px 0 6px 22px;color:#c8d0d6} li{margin:3px 0}
.card{background:var(--panel2);border:1px solid var(--edge);border-radius:8px;padding:13px 15px;margin:10px 0}
.card.red{border-left:4px solid var(--red)} .card.gold{border-left:4px solid var(--gold)}
.card.steel{border-left:4px solid var(--steel)} .card.violet{border-left:4px solid var(--violet)}
.card.olive{border-left:4px solid var(--olive)}
.read{background:#14181d;border:1px dashed #39424d;border-radius:8px;padding:12px 15px;margin:10px 0;
font-style:italic;color:#b8c2c9}
.read::before{content:"READ ALOUD";display:block;font-style:normal;font-size:10px;letter-spacing:2px;color:var(--olive);margin-bottom:6px}
.say{background:#181419;border-left:3px solid var(--gold);border-radius:0 6px 6px 0;padding:8px 13px;margin:8px 0;color:#dcd3bd;font-style:italic}
.say b{font-style:normal;color:var(--gold);font-size:11px;letter-spacing:1.5px;display:block;margin-bottom:2px}
.kv{display:grid;grid-template-columns:160px 1fr;gap:3px 14px;font-size:14px;margin:8px 0}
.kv dt{color:var(--mut)} .kv dd{color:var(--ink)}
table{width:100%;border-collapse:collapse;margin:8px 0;font-size:13.5px}
th{color:var(--mut);text-align:left;font-weight:600;letter-spacing:1px;font-size:11px;text-transform:uppercase;
border-bottom:1px solid var(--edge);padding:5px 8px}
td{border-bottom:1px solid var(--hair);padding:5px 8px;vertical-align:top}
.pill{display:inline-block;background:rgba(138,163,83,.14);border:1px solid rgba(138,163,83,.4);
color:var(--olive-b);border-radius:4px;font-size:11.5px;padding:1px 7px;margin:0 3px 3px 0;white-space:nowrap}
.pill.r{background:rgba(212,85,60,.12);border-color:rgba(212,85,60,.45);color:var(--red-b)}
.pill.v{background:rgba(157,123,216,.12);border-color:rgba(157,123,216,.45);color:#c4aae8}
.san{color:var(--violet);font-weight:600}
.clue{display:flex;gap:9px;align-items:flex-start;padding:5px 8px;border-radius:5px;cursor:pointer}
.clue:hover{background:#20262d}
.clue input{margin-top:4px;accent-color:var(--olive);flex:0 0 auto}
.clue.done span{color:#5f6a75;text-decoration:line-through}
.trk{display:flex;align-items:center;gap:8px;background:var(--panel2);border:1px solid var(--edge);
border-radius:6px;padding:7px 10px;margin:6px 0;flex-wrap:wrap}
.trk .nm{flex:1;min-width:150px;font-weight:600}
.trk .nm small{display:block;font-weight:400;color:var(--mut);font-size:11px}
.trk button{width:30px;height:30px;border-radius:5px;background:#0d1013;border:1px solid var(--edge);
color:var(--ink);font-size:15px;cursor:pointer}
.trk button:hover{border-color:var(--olive)}
.hpv{min-width:74px;text-align:center;font-weight:700;font-size:16px}
.hpv small{color:var(--mut);font-weight:400}
.bar{flex-basis:100%;height:5px;border-radius:3px;background:#0d1013;overflow:hidden}
.bar i{display:block;height:100%;width:100%;background:var(--olive);transform-origin:left;transition:transform .2s}
.low .bar i{background:var(--red)} .low .hpv{color:var(--red-b)}
.cell input{background:#0d1013;border:1px solid var(--edge);border-radius:4px;color:var(--ink);
padding:4px 7px;font-size:13px;width:100%}
.cell td{padding:3px 5px}
.notes{margin-top:14px}
.notes>label{font-size:10px;letter-spacing:2px;color:var(--gold);text-transform:uppercase}
.note{min-height:38px;background:#14161a;border:1px dashed #3a4030;border-radius:6px;padding:9px 12px;
margin-top:4px;color:#e0d9b8;font-size:14px;outline:none;white-space:pre-wrap}
.note:empty::before{content:"Click to add your notes…";color:#5a6150}
.note:focus{border-color:var(--gold)}
.footer{color:#525c66;font-size:12px;padding:16px 4px}
@media print{
nav,.navbtns,.trk button,.sec-head .chev{display:none}
body{background:#fff;color:#000} main{max-width:none}
.sec-body{display:block !important}
}
</style>
</head>
<body>
<nav id="nav">
<div class="brand">
<h1>OPERATION FALSE ALARM</h1>
<small>Handler's Screen · Delta Green 2</small>
</div>
<input id="search" type="search" placeholder="Search everything… ( / )">
<div class="navbtns">
<button onclick="openAll(true)">Open all</button>
<button onclick="openAll(false)">Close all</button>
<button onclick="expNotes()">Export</button>
<button onclick="impNotes()">Import</button>
<button onclick="resetAll()">Reset</button>
</div>
<div class="grp">Run the night</div>
<a data-go="brief">0 · Briefing</a>
<a data-go="s1">1 · The Arrival</a>
<a data-go="s2">2 · The Server Room</a>
<a data-go="s25">2.5 · The Congregation</a>
<a data-go="s3">3 · The Radar Dome</a>
<a data-go="climax">4 · The Broadcast</a>
<a data-go="cover">5 · Cover-Up &amp; Aftermath</a>
<div class="grp">Reference</div>
<a data-go="npcs">NPC Stat Blocks</a>
<a data-go="truth">The Truth &amp; Player Questions</a>
<a data-go="world">Site · Town · Timeline</a>
<a data-go="improv">Improv Toolkit</a>
<a data-go="san">SAN &amp; Rules Quick-Ref</a>
<div class="grp">Table tools</div>
<a data-go="clock">The Dawn Clock</a>
<a data-go="cell">The Cell (Agents)</a>
<a data-go="session">Session Notes</a>
</nav>
<main id="main">
<!-- ================= BRIEFING ================= -->
<section id="brief">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>0 · Briefing <span class="tag">the phone call · cover · requisition · getting there</span></h2></div>
<div class="sec-body">
<h3>The phone call from "Provost"</h3>
<div class="read">The phone that rings is not the one you gave anybody. The voice is dry, unhurried, East-Coast old. "Good evening. You have thirty seconds to find a pen. There is a Federal Aviation Administration radar station in Aroostook County, Maine, designation ME-07, that stopped talking at twelve minutes past three this morning. Its last transmission was… wrong. A sheriff's deputy went to look and has also stopped talking. You and your friends are now a joint FAA and National Weather Service equipment-failure response team. You were never anything else. Go tonight; the weather window shuts at dawn. And — this is the part you write down — if your radios start answering you, <b>stop transmitting.</b>"</div>
<h4>What Provost will answer (if asked)</h4>
<ul>
<li><b>"What was wrong with the transmission?"</b> — "The radar reported a contact that our people say cannot be an aircraft. That is all the detail that exists."</li>
<li><b>"What about the deputy?"</b> — "Marcus Vance. Local, well-liked, Army signals before the county. Recover him if you can. He cannot simply disappear — the town would look for him. Neither can you."</li>
<li><b>"Support?"</b> — "There is a green box at the co-ordinates I'm about to give you." (Cold-weather kit, thermite charge, breaching tools, one encrypted VHF set per Agent — draw from the Field Equipment compendium as they wish, within reason.)</li>
<li><b>"What if it's… one of those?"</b> — a pause. "Then priority one is the data, and priority four covers the rest."</li>
</ul>
<h4>What Provost will NOT answer</h4>
<ul><li>Anything about prior events on Sable Ridge (he genuinely knows only the 1978 survey report — buried).</li>
<li>Anything about A-Cell, other cells, or what happens to Agnes-type witnesses afterward. "Ask me no questions tonight."</li></ul>
<h3>Mission (priority order)</h3>
<ol>
<li><b>Erase unnatural data</b> — the on-site log drive AND the FAA remote cloud backups.</li>
<li><b>Recover or terminate Deputy Vance.</b></li>
<li><b>Secure the facility.</b></li>
<li><b>Cover it up</b> as a catastrophic severe-weather generator failure.</li>
</ol>
<div class="card red">
<b>ROE:</b> weapons discreet; no local casualties that can't be blamed on weather or wildlife. An Agent compromised by what's on that ridge comes second to the mission.
<br><b>Comms:</b> cellular dies at Ridge Road mile 3. Encrypted VHF, callsign OUTLAW-6. <b>If the radios begin to answer, stop transmitting.</b>
</div>
<h3>Cover identities</h3>
<p>FAA/NWS credentials (real, issued tonight, will not survive a determined callback after 48 hrs). The county has been told a specialist team is inbound; <b>the substation will not interfere</b> — mostly because its one deputy is the missing man.</p>
<h3>Getting there — beats on the road</h3>
<ul>
<li><b>The drive:</b> 4+ hours into deepening snow. Radio stations thin out; the last one is a preacher, then static. Let a player fiddle with the dial. Let the static <em>almost</em> resolve into rhythm once.</li>
<li><b>Corliss Notch (optional stop, ~15 min):</b> the diner is open late, half the town awake — worried about Vance. Seeds if they stop: Ruth the cook says <em>"the Whistle's been singing all week"</em>; a trapper (Whit) mutters that the Petrie boys' truck is <em>still up there running</em>; teenager Cody Aldous stares at the Agents and says nothing (he deleted his livestream). <span class="pill">HUMINT</span> everyone here is frightened in a way they can't name. <b>These are the faces they'll meet again at the Crossing.</b></li>
<li><b>The winter gate</b> at Ridge Road: chained — and the chain is already cut. (Vance had a key. Someone else didn't.)</li>
</ul>
<h3>Player handouts</h3>
<p>Foundry journals ①–⑤: A-Cell memo · ME-07 fact sheet · regional map · county newspaper · escalation timeline · Vance/Rostova dossiers. Give ①–④ before the drive; ⑤ works well AT the diner.</p>
<div class="notes"><label>My notes</label><div class="note" data-note="brief" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= SCENE 1 ================= -->
<section id="s1">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>1 · The Arrival <span class="tag">the compound · heavy snow · dread, not danger</span></h2></div>
<div class="sec-body">
<div class="read">The trees fall away and the headlights find chain-link. Beyond it, a concrete blockhouse with one caged bulb burning over the door — and above everything, pale against the storm, the dome: a geodesic golf ball ten storeys tall, humming somewhere below hearing. The gate stands open. Snow is filling a police cruiser's open driver's door like an hourglass.</div>
<h3>Environment — the cold clock</h3>
<div class="card steel">
<b>Exposure (house rule for tonight):</b> without proper cold-weather gear, each 30 minutes outside = <span class="pill">CON×5</span> or 1 HP and −10% (cumulative) to fine-motor tests until warmed. With the green-box kit: test each 2 hours instead. <b>Inside the fence it is colder than the forecast says it should be.</b> Anyone who says so aloud is right.
</div>
<h3>The compound, piece by piece</h3>
<ul>
<li><b>Gate &amp; fence line:</b> gate open, no forcing. Forty metres north, the chain-link is burst <b>outward</b> — wire splayed like a flower. <span class="pill">Search</span> no tool marks; the wire was <em>pushed</em>.</li>
<li><b>The yard:</b> one set of vehicle tracks in (the cruiser), softening under new snow. A second, older set (Rostova's contractor truck, parked behind the building, cold and buried).</li>
<li><b>Equipment building:</b> concrete, one steel door (unlocked — Rostova's keycard is still in the reader), the caged bulb, the <em>unsteady</em> generator hum through the wall. Like breathing with a catch in it.</li>
<li><b>The dome:</b> no ground-level entrance — access is the ladder inside the equipment building. Standing at its foot, <span class="pill">Alertness</span>: the hum isn't coming from the dome. It's coming from <em>everywhere</em>, faintly, like the air itself is carrying it.</li>
</ul>
<h3>The cruiser</h3>
<div class="clue"><input type="checkbox" data-clue="s1-cruiser"><span>Door open, engine dead (ran until the tank emptied), interior <b>furred with frost</b> — inside the car, not outside. <span class="pill">Forensics/Search</span> service pistol in the footwell, <b>3 rounds fired, no casings anywhere, no bullet holes in the car</b>.</span></div>
<div class="clue"><input type="checkbox" data-clue="s1-radio"><span>The dash radio is on, volume high, tuned between stations — <b>soft rhythmic static</b>. Anyone who listens for more than a few seconds hears the 6-second loop for the first time. No SAN yet — just recognition later.</span></div>
<div class="clue"><input type="checkbox" data-clue="s1-glovebox"><span>Glovebox: a photo of two kids at a lake; a county map with the Ridge Road marked in four places — Vance's welfare checks, dated. The last is <b>Cold Cauldron Pond</b>.</span></div>
<div class="clue"><input type="checkbox" data-clue="s1-tracks"><span><span class="pill">Survival/Track</span> footprints from the driver's seat toward the treeline — strides <b>~8 feet apart</b>, weight wrong (too even, like something carrying itself perfectly). They <b>stop mid-field</b>. Nothing after. Snowfall can't explain it.</span></div>
<h3>Optional dread beats (d6, sprinkle 1–2)</h3>
<table>
<tr><td>1</td><td>An Agent's earpiece clicks twice. Politely. Like a courtesy.</td></tr>
<tr><td>2</td><td>The caged bulb dims in rhythm — six seconds on the nose. Then stops when noticed.</td></tr>
<tr><td>3</td><td>Snow in the yard has settled in faint concentric rings around the dome.</td></tr>
<tr><td>4</td><td>A hare sits inside the fence line, dead, upright, facing the dish. Frozen solid.</td></tr>
<tr><td>5</td><td>One Agent (lowest POW) briefly hears their own name — in their own voice — from the treeline.</td></tr>
<tr><td>6</td><td>The wind stops. All at once. For exactly six seconds.</td></tr>
</table>
<p><em>Pacing: nothing attacks here. Let them clear the compound tactically, feel clever, get cold. The building's hum draws them inside → Scene 2.</em></p>
<div class="notes"><label>My notes</label><div class="note" data-note="s1" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= SCENE 2 ================= -->
<section id="s2">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>2 · The Server Room <span class="tag">equipment building · ~40°F · the investigation core</span></h2></div>
<div class="sec-body">
<div class="read">Emergency lights the colour of old teeth. Racks of humming equipment, breath misting indoors, and a main console whose screens are all showing the same frozen frame of static. A woman in a contractor's fleece is slumped over the console, one hand still on the keyboard, as if she'd just put her head down for a moment. Frost has grown across her like ivy.</div>
<h3>Layout</h3>
<ul>
<li><b>Server racks</b> (north wall) — four bays, all alive, all hot; the room should be warm. It isn't.</li>
<li><b>Main console</b> (centre) — Rostova at it. Login is open under her keycard; no hacking needed to begin.</li>
<li><b>Backup generator</b> (east corner) — diesel, running rough. <span class="pill">Heavy Machinery</span>: it's been running for days on bad fuel mix; it could be killed from here in seconds. <em>(Remember for the climax.)</em></li>
<li><b>Ladder</b> (west corner) — up into the dome. Cold air breathes DOWN it. Ozone and scorched copper.</li>
</ul>
<h3>Dr. Rostova — the body</h3>
<div class="card steel">
<b>Frozen solid</b> in a 40°F room. Eyes wide; lips torn back from her teeth. <span class="san">SAN 0/1</span> to examine closely.<br>
<span class="pill">Medicine/Forensics</span> she froze <b>from the inside out</b> — core first. There is no medical mechanism for this. Dead ~18 hours (matches the corrupted loop at 0312). No wounds, no struggle: her last act was pressing a headphone to one ear.
</div>
<div class="clue"><input type="checkbox" data-clue="s2-notes"><span><b>Rostova's work notes</b> (priority recovery) — margin scrawl gets worse over two weeks: <em>"array is receiving more than it transmits"</em> · <em>"return signal exceeds transmit power. Where is the gain coming from?"</em> · <em>"these readings do not make sense in three dimensions"</em> · final page, one line, steady hand: <b>"it is learning the shape of the carrier."</b></span></div>
<h3>The console — tiered digging</h3>
<div class="clue"><input type="checkbox" data-clue="s2-log"><span><span class="pill">Computer Science 40%</span> the radar log: last contact was no aircraft — a <b>"geometric shadow"</b>, no transponder, no vector, hovering <em>directly over the dish</em> before the crash. <em>Show Handout ⑥.</em></span></div>
<div class="clue"><input type="checkbox" data-clue="s2-audio"><span><span class="pill">SIGINT/Science</span> the final transmission: rhythmic oscillating static, a 6-second loop. <b>Listening closely = <span class="san">SAN 0/1D4</span></b>. Success: a low human voice under the static, <b>whispering the Agents' own names</b> — use their real character names; whisper them at the table. <em>Show Handout ⑦.</em></span></div>
<div class="clue"><input type="checkbox" data-clue="s2-drive"><span>The <b>on-site log drive</b>: wipe (trivial) or pull it (evidence — but then it exists).</span></div>
<div class="clue"><input type="checkbox" data-clue="s2-cloud"><span><b>The cloud backups — a real decision:</b> the satellite uplink is DOWN (it died with the crash). Wiping FAA cloud requires <b>re-raising the uplink for ~10 minutes</b> (<span class="pill">Computer Science</span> + <span class="pill">SIGINT</span>). While it's up, the channel is OPEN — the hum deepens, lights gutter, and the dome upstairs gets <em>louder</em>. Handler's dial: nothing has to happen… but they should sweat. (Alternative: wipe it later from any county library — and hope no one reads it first.)</span></div>
<h3>Optional beat</h3>
<p>While they work: every radio they carry clicks, together, twice. If anyone answers — <em>"say again, over"</em> — the static answers back in rhythm. That Agent has been <b>noticed</b>: they're the first name Agnes speaks at the Crossing.</p>
<p><em>When they head up the ladder or back outside → run <b>Scene 2.5</b>.</em></p>
<div class="notes"><label>My notes</label><div class="note" data-note="s2" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= SCENE 2.5 ================= -->
<section id="s25">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>2.5 · The Congregation <span class="tag">midpoint · Cold Cauldron Crossing · the moral fight</span></h2></div>
<div class="sec-body">
<p><b>Trigger:</b> the Agents leave the equipment building for the dome, or try to drive back down. Headlights crest the road at mile 9; under the wind, a dozen human voices <b>humming the six-second loop in unison</b>. A jackknifed log truck blocks the road; vehicles cluster, doors open, engines running.</p>
<div class="read">The snow parts around them like they've been standing there an hour. Old Agnes Corliss stands at the centre in her nightcoat, one hand pressing a dead man's radio handset to her ear. Without turning, she says your point-man's name — first, middle, last — in a voice that is not hers. From the pond shore, two big men in soaked hunting jackets begin to walk up the bank. They have been dead for ten weeks, and they are smiling like they're late for supper.</div>
<h3>Agnes speaks (use these)</h3>
<div class="say"><b>OPENING — to the noticed Agent</b>"He says he knows you. He says he's been saying your name for <em>days</em> and you kept pretending it was the wind."</div>
<div class="say"><b>WHEN THREATENED</b>"You can't shoot a broadcast, dear. Elias tried to tell me that for thirty-five years and I never listened either."</div>
<div class="say"><b>THE PITCH</b>"It only wants to finish the song. One more verse. Then everyone comes inside where it's warm."</div>
<div class="say"><b>IF THE HANDSET IS THREATENED — the only time she's afraid</b>"NO — that's HIM, that's all of him that's LEFT—"</div>
<h3>Default round-by-round (adjust freely)</h3>
<table>
<tr><th>Rd</th><th>The Congregation does</th></tr>
<tr><td>1</td><td>The Called advance, arms out, to restrain. Agnes: <b>Chorus</b> begins (<span class="san">SAN 0/1D4</span> first exposure). The Returned close from the pond, unhurried.</td></tr>
<tr><td>2</td><td>Agnes: <b>STAND STILL</b> on the biggest gun. Called pair-grapple whoever advanced. Roy heads for the loudest Agent.</td></tr>
<tr><td>3</td><td>The Returned engage. Anyone grappled by BOTH brothers starts the <b>Baptism drag</b> (2 rounds to the shore, then under).</td></tr>
<tr><td>4+</td><td>Agnes: <b>SPEAK THE NAMES</b> on the most effective Agent (<span class="san">SAN 0/1D4</span>). Chorus each round (<span class="san">0/1</span>). She retreats behind the Called if pressed.</td></tr>
</table>
<h3>The pond (if the Baptism lands)</h3>
<div class="card steel">Under the ice: <span class="pill">CON×5</span> each round; fail = 1D6 (cold + water). Allies can smash through (STR×5) and pull (opposed STR vs one brother, 17). An Agent who goes under and comes back up has heard the song from the OTHER side: <span class="san">SAN 1/1D6</span>, and they know exactly what the Tear is, no translation needed.</div>
<h3>Ways to win that aren't massacre</h3>
<ul>
<li><b>Cut the feed:</b> destroy/snatch Elias's handset (called shot −20%, 6 HP, or grapple Agnes). Chorus dies → the Called wake; the Returned stop mid-stride, turn, and walk back into the pond.</li>
<li><b>Deafen her:</b> a flash-bang within 10 m ends the Chorus for good.</li>
<li><b>Names:</b> <span class="pill">HUMINT</span> + shouting a Petrie's name = that brother hesitates one full round (once each). <em>"DALE! Your mother's porch light is still on!"</em></li>
<li><b>Stealth:</b> the Called barely see; Agnes hears RADIOS, not feet. A blacked-out, radio-silent cell can skirt the treeline entirely (<span class="pill">Stealth</span>, group). The Congregation walks on toward the compound behind them — a ticking clock for the climax.</li>
<li><b>Run the gauntlet:</b> ram past the log truck (<span class="pill">Drive −20%</span> in snow; fail = ditched, 1D4 to all aboard).</li>
</ul>
<h3>Combat trackers</h3>
<div id="trk-s25"></div>
<h3>Aftermath</h3>
<ul>
<li>Freed Called remember a dream of "the most beautiful voice." All five alive: <b>+1 SAN each Agent</b>. They are hypothermic civilians, miles from town, mid-operation — <em>what do the Agents do with them?</em> (Truck keys are in the vehicles. Cody can drive. It costs 20 minutes of the dawn clock to organize.)</li>
<li>Agnes, freed, keeps asking where Elias went — and once, flat, in the wrong voice: <b>"IT IS ALMOST DONE LEARNING OUR SHAPE."</b> That's the players' warning for Scene 3.</li>
<li>Every civilian death becomes a named problem in the Cover-Up. Say so out loud at the table when the first gun rises.</li>
</ul>
<div class="notes"><label>My notes</label><div class="note" data-note="s25" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= SCENE 3 ================= -->
<section id="s3">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>3 · The Radar Dome <span class="tag">the catwalk · pitch black · Vance and the countdown</span></h2></div>
<div class="sec-body">
<div class="read">The ladder climbs through a concrete throat and lets out onto a steel catwalk in absolute darkness. Your lights find the inside of the dome arching away like the vault of a cathedral built by something that had heard about cathedrals. The air burns with ozone and scorched copper. And at the centre, at the base of the great dish, somebody is working — fast, in the dark, with a sound of stripped wire and a voice reciting words in an order no throat should manage.</div>
<h3>Environment</h3>
<ul>
<li><b>Total darkness.</b> Their lights are the only light — and each light says exactly where its Agent stands.</li>
<li><b>Catwalk:</b> a ring around the dome with two radial spurs to the transmitter mast. Moving faster than careful in the dark: <span class="pill">Athletics/DEX×5</span> or fall — 4 m to the deck, 1D6.</li>
<li><b>Frozen metal:</b> bare-hand fine work (wiring, lockpicking, reloading fiddly weapons) −20% without gloves.</li>
<li><b>The dish</b> looms overhead, wrong even before the climax — anyone who studies it: it seems very slightly <em>closer</em> each time you look.</li>
</ul>
<h3>Vance at the transmitter — the countdown</h3>
<div class="card red">
<b>Witnessing him: <span class="san">SAN 1/1D6</span>.</b> Blind — sockets self-emptied, trails frozen black — but working the transmitter by feel at horrible speed, jaw unhinged, screaming the radar's technical manual <b>backward</b>.
</div>
<div class="card gold">
<b>THE WIRING CLOCK — 5 segments.</b> Each round Vance works unmolested, fill one. At <b>5/5</b> the Broadcast begins (Scene 4). Interposing (blocking, grappling, dragging him off) stops the clock that round; damage doesn't stop it unless he's down. <b>Killing him does not un-wire what's wired</b> — at 3+ segments the system finishes arming itself 2 rounds later regardless. There is a way to say this to players: <em>"He's not the bomb. He's just the fuse."</em>
</div>
<h4>Vance's lines (the manual, backward — read them slow)</h4>
<div class="say"><b>WORKING</b>"…tuptuo rewop mumixam ot yarra eht tes… niag eht kcolnU…"</div>
<div class="say"><b>IF AN AGENT SPEAKS TO HIM</b>— he stops for one heartbeat. In his own voice, small: "Tell my kids the lake in summer." Then the other voice takes the throat back.</div>
<h4>Fighting him</h4>
<ul>
<li>Wrench 65%, 1D10+2; <b>two actions per round</b>; your lights don't help or hinder him.</li>
<li><b>Restraint</b> (non-lethal): opposed STR (his 17); two Agents together shift the odds. He does not tire. Cuffs hold for 1D4 rounds, then the joints… reconfigure. <span class="san">SAN 0/1D3</span> for whoever's holding him when they do.</li>
<li>He attacks only those who interpose. He is trying to finish, not to kill.</li>
</ul>
<h3>Combat tracker</h3>
<div id="trk-s3"></div>
<div class="notes"><label>My notes</label><div class="note" data-note="s3" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= CLIMAX ================= -->
<section id="climax">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>4 · The Broadcast <span class="tag">the Tear manifests · the choice · the implosion</span></h2></div>
<div class="sec-body">
<div class="read">The dish wakes with a shriek of servos and begins to spin — too fast, faster, until it is a blur that pulls the air around after it. Every hair on your body stands up. Your fillings taste like batteries. And in the space above the dish, where the signal is thickest, the dark <b>opens</b>. It is not a shape. It is where shapes end. And it is coming through.</div>
<p><em>Show Handout ⑧ NOW — not before.</em></p>
<div class="card violet">
<b>The Tear</b> — presence: <span class="san">SAN 1D6/1D20</span>. <b>Bullets pass through and warp uselessly — do not roll damage, describe the round coming apart in the air.</b> It cannot be fought. It can only be <b>starved of signal</b>. Each round it is fed, the cold deepens (all exposure tests worsen one step) and it <em>reaches</em> — one Agent per round, lowest POW first, must <span class="pill">POW×5</span> or take a step toward the dish.
</div>
<h3>The choice — cut the primary power</h3>
<h4>Option A — blow the backup generator (outside, below)</h4>
<ul>
<li>Get there: down the ladder and out — 2 rounds moving fast (catwalk test in the dark), while the Congregation's survivors, if unresolved, are arriving at the fence.</li>
<li>Do it: <span class="pill">Demolitions 40%</span> with the thermite (instant, clean), or improvise — <span class="pill">INT×5</span> + fuel + 2 rounds rigging. The blast: anyone within 5 m, 2D6.</li>
<li>The generator dies → the transmitter browns out → <b>the Tear snaps back</b>.</li>
</ul>
<h4>Option B — overload the main transformer (inside the dome, beside the Tear)</h4>
<ul>
<li>One Agent at the transformer cabinet, one full round, no roll to attempt — the roll is surviving it.</li>
<li><b>Cost:</b> Lethality 15% electrical discharge (fail the Lethality = 2D10 damage instead), AND the full <span class="san">1D6/1D20</span> exposure at arm's length as the Tear turns its whole attention on the hand on the switch.</li>
<li>Insulated gloves from the cold-weather kit: the 2D10 becomes 1D10. Small mercies are Delta Green's whole budget.</li>
</ul>
<h3>Power dies</h3>
<div class="read">The Tear does not scream. It simply stops being there — and the air rushes in to fill the place where it wasn't, and the dome comes down like God clapping his hands.</div>
<ul>
<li><b>Implosion escape:</b> everyone inside — <span class="pill">DEX×5 or Athletics</span>; fail = 1D6 from debris. The catwalk survives; the panels don't.</li>
<li>Then: ringing silence. Snow falling through the new hole in the world. The hum is gone — <em>and one Agent (highest SAN loss tonight) notices they miss it.</em></li>
</ul>
<h3>If they fail / flee</h3>
<p>The Broadcast completes. The doorway holds open. Sable Ridge becomes a permanent cold spot that swallows Corliss Notch over the winter — 300 people, one radio sermon at a time. A-Cell's after-action call is very quiet. No SAN reward; the next operation is worse, and it is theirs.</p>
<div class="notes"><label>My notes</label><div class="note" data-note="climax" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= COVER-UP ================= -->
<section id="cover">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>5 · Cover-Up &amp; Aftermath <span class="tag">the story that holds · complications · rewards</span></h2></div>
<div class="sec-body">
<h3>The task list (each costs dawn-clock time)</h3>
<div class="clue"><input type="checkbox" data-clue="c-rostova"><span><b>Burn Rostova's remains</b> — thermite, 20 min. <span class="pill">Forensics</span> to leave the right kind of nothing. Her sister in Vermont gets a "generator explosion" letter and a sealed casket. (An Agent who reads the sister's later letters to the FAA: <span class="san">0/1</span>, the slow kind.)</span></div>
<div class="clue"><input type="checkbox" data-clue="c-vance"><span><b>Vance</b> — recover the body if it exists. Stage: vehicular accident on the ridge road (roll his cruiser, 30 min work) or wildlife (messier, less questioned in Aroostook). The town buries a hero; the county buys a plaque. His kids get the lake in summer, if anyone passes it on.</span></div>
<div class="clue"><input type="checkbox" data-clue="c-cloud"><span><b>FAA cloud backups</b> — if not wiped on-site, hit within 48 hrs (<span class="pill">Computer Science</span>, any decent connection) before a duty analyst gets curious.</span></div>
<div class="clue"><input type="checkbox" data-clue="c-dome"><span><b>The dome</b> — the implosion IS the cover story: catastrophic weather-generator failure. FAA inspectors will fly up in spring, find honest wreckage, write honest paperwork.</span></div>
<div class="clue"><input type="checkbox" data-clue="c-locals"><span><b>The locals</b> — freed Called remember a beautiful dream; a debrief over cocoa at the substation ("gas leak from the generator, you all wandered up in your sleep, lucky we found you") holds <em>if they're alive</em>. Agnes needs a longer conversation and a quiet care placement A-Cell will arrange without being asked twice. Dead civilians = named bodies = the story does not hold.</span></div>
<div class="clue"><input type="checkbox" data-clue="c-handset"><span><b>Elias's handset</b> — inert now. Mostly. Green box it. Do not keep it. <em>(If an Agent keeps it: it is very slightly cold at 3 a.m. That's a hook, not a rule.)</em></span></div>
<h3>Complications (d6 — roll once if the night went loud)</h3>
<table>
<tr><td>1</td><td>A snowplow driver saw headlights at the Crossing and "figures somebody ought to write it down."</td></tr>
<tr><td>2</td><td>Cody Aldous re-uploads a fragment of his deleted livestream. 214 views and climbing.</td></tr>
<tr><td>3</td><td>The sister in Vermont hires a very cheap, very stubborn private investigator.</td></tr>
<tr><td>4</td><td>An FAA duty tech noticed the uplink flap at 03:40 and opened a ticket. It has a number now. Numbers live forever.</td></tr>
<tr><td>5</td><td>One of the Called starts a prayer group. They meet on Thursdays. They hum.</td></tr>
<tr><td>6</td><td>County wants to REBUILD the radar. A-Cell would like the Agents' written opinion. All of them feel the draft of the door that didn't quite shut.</td></tr>
</table>
<h3>Sanity rewards</h3>
<p>Threat eliminated: <b>+1D4 SAN</b> · all five Called saved alive: <b>+1 each</b> · minus losses from collateral damage or a failed cover-up. The transformer martyr carries the worst of it — if they lived. Broadcast completed: no reward; A-Cell will be back.</p>
<div class="notes"><label>My notes</label><div class="note" data-note="cover" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= NPC STATS ================= -->
<section id="npcs">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>NPC Stat Blocks <span class="tag">everything rollable · with voices</span></h2></div>
<div class="sec-body">
<div class="card steel">
<h3 style="margin-top:0">Dr. Elena Rostova <span class="pill">deceased — clue, not combatant</span></h3>
<p>Frozen at the console, inside-out. Notes are priority recovery. Burn the remains. Her last steady line: <em>"it is learning the shape of the carrier."</em></p>
</div>
<div class="card red">
<h3 style="margin-top:0">Deputy Marcus Vance (Changed) <span class="pill r">HP 16</span> <span class="pill r">SAN 1/1D6</span></h3>
<p>STR 17 CON 16 DEX 16 INT 6 POW 15 · <b>2 actions/round</b> · blind, unimpaired in dark · attacks only those who interpose</p>
<ul>
<li><b>Pipe wrench</b> 65%, 1D10+2 · restraint: opposed STR 17; cuffs hold 1D4 rounds (<span class="san">0/1D3</span> when the joints reconfigure).</li>
<li>Runs the <b>wiring clock</b> (Scene 3): 1 segment/unmolested round; at 3+ it self-completes 2 rounds after he stops.</li>
<li><b>Voice:</b> the manual, backward — except once, his own, small: <em>"Tell my kids the lake in summer."</em></li>
</ul>
</div>
<div class="card gold">
<h3 style="margin-top:0">Agnes Corliss, the Switchboard Widow <span class="pill r">HP 10 · WP 18</span> <span class="pill r">SAN 0/1D4 · Chorus-voice 1/1D6</span></h3>
<p>STR 8 CON 12 DEX 9 INT 14 <b>POW 18</b> CHA 16 · doesn't fight — <b>rules</b> the fight · shielded −20% while any ally conscious in 10 m</p>
<ul>
<li><b>THE CHORUS</b> (free, every round): static from her mouth AND the Agents' own radios. <span class="san">0/1D4 first, 0/1 per round after</span>; −20% concentration. Ditch comms + plug ears = first exposure only.</li>
<li><b>STAND STILL</b> (action): a name backward. POW×5 (90%) vs target POW×5. Fail = lose next action; crit fail = drop held item.</li>
<li><b>SPEAK THE NAMES</b> (1/Agent/night): a Bond or a private guilt. <span class="san">0/1D4</span>.</li>
<li><b>CUT THE FEED:</b> Elias's handset (belt · called shot −20% · 6 HP · or grapple-snatch) OR deafen → Chorus ends, Stand Still 45%, the Called wake, Agnes collapses. A victim. A-Cell's problem now.</li>
</ul>
</div>
<div class="card olive">
<h3 style="margin-top:0">Dale &amp; Roy Petrie, Returned <span class="pill r">HP 17 each · Armor 3</span> <span class="pill r">SAN 1/1D6</span></h3>
<p>STR 17/18 CON 16 DEX 12/11 INT 7/6 POW 12 · no stun, pain, fear · <b>fire ×2 damage</b> + they flinch from open flame</p>
<ul>
<li><b>Dale — boat hook</b> 60%, 1D8+2 · patient, flanks · <b>Roy — splitting maul</b> 60%, 1D10+2 · goes for the LOUDEST.</li>
<li><b>Grasp of the Drowned</b> 55%, 1D6+1 — struck limb numbs: −20% DEX-based next round.</li>
<li><b>Cold radius</b> 3 m, 3+ rounds → CON×5 or 1 HP.</li>
<li><b>BAPTISM:</b> both grapple one Agent → 2 rounds to the shore → under the ice (CON×5/round, fail 1D6). <em>The pond is how the Tear tastes people.</em></li>
<li><span class="pill">HUMINT</span> + his name shouted = one round's hesitation (once each). Something in there remembers supper.</li>
</ul>
</div>
<div class="card">
<h3 style="margin-top:0">The Called ×5 <span class="pill r">HP 11 each</span> <span class="pill r">killing one: SAN 1/1D8</span></h3>
<p>Cody Aldous (17) · Ruth the cook · Whit the trapper · the Pelletiers. Nightclothes, upturned faces, humming. <span class="pill">HUMINT 40%</span>: weeping while they do it.</p>
<ul>
<li><b>Restrain, never kill:</b> grapple 40%, pairs +20% for the second. Held Agents get carried — to Agnes, or the pond.</li>
<li>Immune to Persuade/fear while the Chorus holds · any damage → POW×5 each round to wake.</li>
<li>Chorus dies → all five wake at once: terrified, hypothermic civilians in a firefight.</li>
</ul>
</div>
<div class="card violet">
<h3 style="margin-top:0">The Tear (the Static Between Stations) <span class="pill v">presence SAN 1D6/1D20</span></h3>
<ul>
<li><b>Bullets warp through it — no damage roll exists.</b> Describe the round coming apart.</li>
<li>Each fed round: cold worsens one step; one Agent (lowest POW) POW×5 or steps toward the dish.</li>
<li>Closable ONLY by cutting primary power. It has spent months <em>learning our shape</em>.</li>
</ul>
</div>
<div class="notes"><label>My notes</label><div class="note" data-note="npcs" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= TRUTH ================= -->
<section id="truth">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>The Truth &amp; Player Questions <span class="tag">GM only</span></h2></div>
<div class="sec-body">
<p>The entity is a <b>place adjacent to ours</b> that perceives through <b>resonance</b> — a signal answered by a signal. It has brushed Sable Ridge forever: the spinning compasses, the ridge that "answers," the 1888 hunting party. For most of history it could only whisper to those who whistled back.</p>
<p>In <b>2016</b> the FAA parked a high-power transmitter on the one ridge that half-listened and left it running unattended. Years of steady carrier gave it a <b>stable channel</b> — a door propped wider every night. The phantom returns were it <b>looking back down the beam</b>. The frozen animals and the Petrie brothers were it <b>learning to reach through and feed</b>.</p>
<p>Rostova's servicing tuned the door. The corrupted loop was it learning to <b>speak in our signal</b> — it took her first, then reached down <b>Vance's radio</b> (the one man for miles fluent in signal) and remade him into an instrument: blinded so nothing distracts, wiring the lure to full power.</p>
<h3>When players ask…</h3>
<ul>
<li><b>"Why doesn't it just come through?"</b> — It can't hold our shape yet. It needs the broadcast at full power to finish the fitting. Tonight is the last fitting.</li>
<li><b>"Why the cold?"</b> — Reaching through costs energy; it pulls heat the way we'd pull breath. Where it touches, things freeze from the inside.</li>
<li><b>"Can we talk to it?"</b> — It can only say what it has heard. It is a mirror that wants to be a mouth. Anything it "says" is your own words, rearranged, coming back wrong.</li>
<li><b>"Why Vance? Why Agnes?"</b> — Fluency. He spoke signal professionally; she has listened longer than anyone alive. It reached for the two best antennas in the county.</li>
<li><b>"Is it dead now?"</b> — No. The door is shut. The ridge is still the ridge. Don't rebuild the radar.</li>
</ul>
<div class="notes"><label>My notes</label><div class="note" data-note="truth" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= WORLD ================= -->
<section id="world">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>Site · Town · Timeline <span class="tag">background reference</span></h2></div>
<div class="sec-body">
<h3>Site ME-07 "Sable Ridge"</h3>
<div class="kv">
<dt>What</dt><dd>ARSR-4 long-range radar, joint FAA/USAF/NWS, border-approach coverage gap</dd>
<dt>Where</dt><dd>2,140 ft ridge ("the Whistle"), 14 gravel miles up Ridge Road from Corliss Notch; winter gate; no cell past mile 3</dd>
<dt>Staffing</dt><dd>Unmanned; Sygnal Dynamics contractor quarterly; nobody lives within 9 miles</dd>
<dt>Power</dt><dd>Grid + diesel backup generator (equipment building); main transformer in the dome</dd>
</div>
<h3>Corliss Notch (pop. ~310)</h3>
<p>General store (only gas for 40 mi) · the Notch Diner · Grange hall · white Congregational church · volunteer FD · two-deputy substation Vance runs alone. Logging town losing its young. Strangers are noticed. The ridge is <b>"the Whistle"</b> — it answers, and if you answer back it draws you into the cold. Locals won't discuss it with outsiders; they just don't go up after dark.</p>
<h3>Escalation timeline</h3>
<table>
<tr><th>When</th><th>Event</th></tr>
<tr><td>pre-1900</td><td>Compasses spin; the ridge "answers whistles"; 1888 diary — a party followed a voice, lost two</td></tr>
<tr><td>1978</td><td>USGS survey team flees a ridge cabin; "equipment fouling," one breakdown; report buried</td></tr>
<tr><td>2016</td><td>Site automated; ham operators log the nightly "Sable hum"</td></tr>
<tr><td>−14 mo</td><td>First phantom returns: contacts with no transponder or vector, gone between sweeps</td></tr>
<tr><td>−3 mo</td><td>Livestock/pets die "frozen through"; the static answers operators, twice repeats a name</td></tr>
<tr><td>−10 wk</td><td><b>Petrie brothers vanish</b> at Cold Cauldron Pond; truck running, radio on static</td></tr>
<tr><td>−6 wk</td><td>FAA schedules service; Cody livestreams "breathing static," deletes it</td></tr>
<tr><td>−2 wk</td><td>Rostova arrives; "receiving more than it transmits"; deep cold sets in around the dome</td></tr>
<tr><td>−4 days</td><td>A trucker's CB says Vance's kids' names; Vance rattled, calls the site repeatedly</td></tr>
<tr><td>−18 hr</td><td>Corrupted loop; site dark</td></tr>
<tr><td>−6 hr</td><td>Vance drives up alone. Silence. The Agents are activated</td></tr>
</table>
<div class="notes"><label>My notes</label><div class="note" data-note="world" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= IMPROV ================= -->
<section id="improv">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>Improv Toolkit <span class="tag">names · senses · static</span></h2></div>
<div class="sec-body">
<h3>Name bank — Corliss Notch</h3>
<p><b>The Called (statted):</b> Cody Aldous (17, gas-station kid) · Ruth Demers (diner cook) · Whit Emmons (trapper) · Gil &amp; Marge Pelletier (feed store).<br>
<b>Everyone else:</b> Pastor Vern Ouellette · Doreen at the store · plow driver Big Mike Thibodeau · warden Sgt. Kathy Cyr (county seat, 90 min away) · schoolteacher Miss Lavoie · Vance's kids: Sam (9) &amp; Ellie (7), with their mother in Bangor.</p>
<h3>Sensory bank (steal freely)</h3>
<ul>
<li>Snow squeaking like styrofoam · breath freezing in eyelashes · the particular silence after an engine dies.</li>
<li>The hum: felt in molars, in fillings, in an old collarbone break.</li>
<li>Frost growing in FERNS across glass — always toward the dome.</li>
<li>The static loop: shh-shh-SHH-shh-shh-shh. Six seconds. Once you've counted it, you can't stop.</li>
</ul>
<h3>Things the static says (sparingly — it can only repeat)</h3>
<ul>
<li>An Agent's own "say again, over," returned an hour later, flat.</li>
<li>Rostova: "…where is the gain coming from…"</li>
<li>Vance, clear as day: "Dispatch, show me 10-23 at the radar site." (He said it at 0455. It kept it.)</li>
<li>A child's voice from a 1994 broadcast, asking for a song on the county request show.</li>
</ul>
<div class="notes"><label>My notes</label><div class="note" data-note="improv" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= SAN ================= -->
<section id="san">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>SAN &amp; Rules Quick-Ref <span class="tag">every check in the scenario</span></h2></div>
<div class="sec-body">
<table>
<tr><th>Source</th><th>SAN</th><th>Where</th></tr>
<tr><td>Examining Rostova closely</td><td class="san">0/1</td><td>Scene 2</td></tr>
<tr><td>Listening closely to the final transmission</td><td class="san">0/1D4</td><td>Scene 2</td></tr>
<tr><td>The Chorus — first exposure / per round</td><td class="san">0/1D4 · 0/1</td><td>Scene 2.5</td></tr>
<tr><td>Chorus speaks in a dead loved one's voice</td><td class="san">1/1D6</td><td>Scene 2.5</td></tr>
<tr><td>Agnes: Speak the Names</td><td class="san">0/1D4</td><td>Scene 2.5</td></tr>
<tr><td>Seeing a Returned clearly</td><td class="san">1/1D6</td><td>Scene 2.5</td></tr>
<tr><td>Dragged under the pond ice (and surviving)</td><td class="san">1/1D6</td><td>Scene 2.5</td></tr>
<tr><td>Killing one of the Called</td><td class="san">1/1D8</td><td>Scene 2.5</td></tr>
<tr><td>Witnessing the changed Vance</td><td class="san">1/1D6</td><td>Scene 3</td></tr>
<tr><td>Vance's joints reconfiguring while held</td><td class="san">0/1D3</td><td>Scene 3</td></tr>
<tr><td>The Tear — presence / at the transformer</td><td class="san">1D6/1D20</td><td>Climax</td></tr>
<tr><td><b>Rewards:</b> threat ended +1D4 · all Called saved +1 each</td><td>—</td><td>Aftermath</td></tr>
</table>
<h3>Tonight's environmental rules</h3>
<ul>
<li><b>Cold:</b> no gear — CON×5 per 30 min outside or 1 HP + cumulative −10% fine-motor. With kit: per 2 hrs. Worsens one step per fed round of the Tear.</li>
<li><b>Under the ice:</b> CON×5/round, fail 1D6. Rescue: STR×5 to smash through, opposed STR vs 17 to pull free.</li>
<li><b>Catwalk in the dark, moving fast:</b> Athletics/DEX×5 or 4 m fall, 1D6.</li>
<li><b>Bare hands on frozen metal:</b> −20% fine manipulation.</li>
</ul>
<h3>House rules in play (Delta Green 2)</h3>
<ul>
<li><b>Nat 01 → PROVIDENCE · nat 00 → CALAMITY</b> — escalating d6 tables auto-post in chat.</li>
<li>Ammo auto-decrements; reload from the Equipment tab.</li>
<li>Apply Damage / Apply SAN buttons on chat cards (armor − AP handled).</li>
</ul>
<div class="notes"><label>My notes</label><div class="note" data-note="san" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= DAWN CLOCK ================= -->
<section id="clock">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>The Dawn Clock <span class="tag">time pressure tracker</span></h2></div>
<div class="sec-body">
<p>The cell is activated ~21:00. First light ~06:40. Tick a box when the table burns real time; the road closes behind snow at dawn — everything unfinished becomes a complication.</p>
<div id="clockgrid"></div>
<table>
<tr><th>Typical costs</th><th></th></tr>
<tr><td>Drive from briefing to the winter gate</td><td>4 hrs (4 boxes)</td></tr>
<tr><td>Diner stop · compound sweep · server room work</td><td>30 min each</td></tr>
<tr><td>Uplink raise for cloud wipe</td><td>30 min (and the channel opens)</td></tr>
<tr><td>The Crossing (however it goes)</td><td>30–60 min</td></tr>
<tr><td>Organizing freed Called back to town</td><td>30 min</td></tr>
<tr><td>Each cover-up task</td><td>20–30 min</td></tr>
</table>
<div class="notes"><label>My notes</label><div class="note" data-note="clock" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= CELL ================= -->
<section id="cell">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>The Cell <span class="tag">agents at the table — edits save automatically</span></h2></div>
<div class="sec-body">
<table class="cell" id="celltab">
<tr><th style="width:32%">Agent / Player</th><th>HP</th><th>WP</th><th>SAN</th><th>Breaking Pt</th><th style="width:28%">Condition</th></tr>
</table>
<div class="notes"><label>My notes</label><div class="note" data-note="cell" contenteditable="true"></div></div>
</div>
</section>
<!-- ================= SESSION ================= -->
<section id="session">
<div class="sec-head"><span class="accent"></span><span class="chev">▶</span>
<h2>Session Notes <span class="tag">free space — saves on this computer</span></h2></div>
<div class="sec-body">
<div class="note" data-note="session" contenteditable="true" style="min-height:220px"></div>
<p class="footer">FALSE ALARM Handler's Screen · Delta Green 2 · notes &amp; trackers persist in this browser (localStorage). <b>Export</b> moves them to another machine. Delta Green is a trademark of the Delta Green Partnership; fan material.</p>
</div>
</section>
</main>
<script>
(function(){
const LS = k => "fa-gm-" + k;
/* ---------- accordion ---------- */
const secs = [...document.querySelectorAll("main section")];
function setOpen(sec, open, save = true) {
sec.classList.toggle("open", open);
if (save) localStorage.setItem(LS("open-" + sec.id), open ? "1" : "0");
}
secs.forEach(sec => {
sec.querySelector(".sec-head").addEventListener("click", () => setOpen(sec, !sec.classList.contains("open")));
if (localStorage.getItem(LS("open-" + sec.id)) === "1") setOpen(sec, true, false);
});
window.openAll = (v) => secs.forEach(s => setOpen(s, v));
/* nav: open + scroll */
document.querySelectorAll("nav a[data-go]").forEach(a => {
a.addEventListener("click", () => {
const sec = document.getElementById(a.dataset.go);
setOpen(sec, true);
sec.scrollIntoView({ behavior: "smooth", block: "start" });
});
});
/* ---------- notes ---------- */
document.querySelectorAll(".note").forEach(n => {
const key = LS("note-" + n.dataset.note);
n.innerText = localStorage.getItem(key) || "";
n.addEventListener("input", () => localStorage.setItem(key, n.innerText));
});
/* ---------- clue checkboxes ---------- */
document.querySelectorAll(".clue input").forEach(c => {
const key = LS("clue-" + c.dataset.clue);
const wrap = c.closest(".clue");
const apply = () => wrap.classList.toggle("done", c.checked);
c.checked = localStorage.getItem(key) === "1";
apply();
c.addEventListener("change", () => { localStorage.setItem(key, c.checked ? "1" : "0"); apply(); });
wrap.addEventListener("click", e => { if (e.target !== c) { c.checked = !c.checked; c.dispatchEvent(new Event("change")); } });
});
/* ---------- HP trackers ---------- */
const NPCS = {
"trk-s25": [
["agnes","Agnes Corliss","Chorus / Stand Still / handset 6 HP",10],
["handset","Elias's Handset","called shot −20% · destroying ends the Chorus",6],
["dale","Dale Petrie","Armor 3 · hook 1D8+2 · fire ×2",17],
["roy","Roy Petrie","Armor 3 · maul 1D10+2 · goes for the loudest",17],
["c1","Called — Cody (17)","grapples only · POW×5 to wake if hurt",11],
["c2","Called — Ruth","grapples only",11],
["c3","Called — Whit","grapples only",11],
["c4","Called — Gil Pelletier","grapples only",11],
["c5","Called — Marge Pelletier","grapples only",11],
],
"trk-s3": [
["vance","Deputy Vance (Changed)","2 actions/round · wrench 65% 1D10+2",16],
["wclock","Wiring Clock","fills 1/round unmolested · 5 = Broadcast",5],
],
};
for (const [mount, list] of Object.entries(NPCS)) {
const host = document.getElementById(mount);
list.forEach(([id, name, sub, max]) => {
const key = LS("hp-" + id);
let hp = parseInt(localStorage.getItem(key)); if (isNaN(hp)) hp = id === "wclock" ? 0 : max;
const row = document.createElement("div");
row.className = "trk";
row.innerHTML = `<div class="nm">${name}<small>${sub}</small></div>
<button data-d="-5">−5</button><button data-d="-1">−1</button>
<div class="hpv"><span></span> <small>/ ${max}</small></div>
<button data-d="1">+1</button><button data-d="99">⟳</button>
<div class="bar"><i></i></div>`;
const val = row.querySelector(".hpv span"), bar = row.querySelector(".bar i");
const paint = () => { val.textContent = hp; bar.style.transform = "scaleX(" + Math.max(0, hp / max) + ")";
row.classList.toggle("low", id === "wclock" ? hp >= 4 : hp <= Math.ceil(max / 3)); };
row.querySelectorAll("button").forEach(b => b.addEventListener("click", () => {
const d = parseInt(b.dataset.d);
hp = d === 99 ? (id === "wclock" ? 0 : max) : Math.max(0, Math.min(max, hp + d));
localStorage.setItem(key, hp); paint();
}));
paint(); host.appendChild(row);
});
}
/* ---------- dawn clock ---------- */
const cg = document.getElementById("clockgrid");
const times = []; for (let h = 21 * 2; h <= 30.5 * 2; h++) times.push(h / 2); // 21:00 → 06:30 in half-hours (mod 24)
cg.style.cssText = "display:flex;flex-wrap:wrap;gap:5px;margin:10px 0";
times.forEach(t => {
const hh = Math.floor(t) % 24, mm = t % 1 ? "30" : "00";
const lab = String(hh).padStart(2, "0") + ":" + mm;
const key = LS("clk-" + lab);
const b = document.createElement("button");
b.textContent = lab;
b.style.cssText = "padding:6px 8px;border-radius:5px;border:1px solid var(--edge);background:#0d1013;color:var(--mut);font-size:12px;cursor:pointer";
const paint = () => { const on = localStorage.getItem(key) === "1";
b.style.background = on ? "rgba(138,163,83,.25)" : "#0d1013";
b.style.color = on ? "var(--olive-b)" : "var(--mut)";
b.style.borderColor = on ? "var(--olive)" : "var(--edge)"; };
b.addEventListener("click", () => { localStorage.setItem(key, localStorage.getItem(key) === "1" ? "0" : "1"); paint(); });
paint(); cg.appendChild(b);
});
/* ---------- cell table ---------- */
const tab = document.getElementById("celltab");
for (let r = 0; r < 6; r++) {
const tr = document.createElement("tr");
["name","hp","wp","san","bp","cond"].forEach(f => {
const td = document.createElement("td"), inp = document.createElement("input");
const key = LS(`cell-${r}-${f}`);
inp.value = localStorage.getItem(key) || "";
inp.addEventListener("input", () => localStorage.setItem(key, inp.value));
td.appendChild(inp); tr.appendChild(td);
});
tab.appendChild(tr);
}
/* ---------- nav highlight ---------- */
const links = [...document.querySelectorAll("nav a[data-go]")];
const onScroll = () => {
let i = secs.findLastIndex(s => s.getBoundingClientRect().top < 120);
links.forEach(a => a.classList.toggle("on", a.dataset.go === (secs[Math.max(0, i)] || {}).id));
};
document.addEventListener("scroll", onScroll, { passive: true }); onScroll();
/* ---------- search (opens matches) ---------- */
const box = document.getElementById("search");
document.addEventListener("keydown", e => {
if (e.key === "/" && document.activeElement !== box && !e.target.isContentEditable && e.target.tagName !== "INPUT") {
e.preventDefault(); box.focus();
}
});
box.addEventListener("input", () => {
const q = box.value.trim().toLowerCase();
secs.forEach(s => {
const hit = !q || s.textContent.toLowerCase().includes(q);
s.style.display = hit ? "" : "none";
if (q && hit) setOpen(s, true, false);
links.find(a => a.dataset.go === s.id)?.style.setProperty("opacity", hit ? "1" : ".3");
});
if (!q) secs.forEach(s => setOpen(s, localStorage.getItem(LS("open-" + s.id)) === "1", false));
});
/* ---------- export / import / reset ---------- */
window.expNotes = () => {
const data = {};
for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i);
if (k.startsWith("fa-gm-")) data[k] = localStorage.getItem(k); }
const a = document.createElement("a");
a.href = URL.createObjectURL(new Blob([JSON.stringify(data, null, 1)], { type: "application/json" }));
a.download = "false-alarm-gm-notes.json"; a.click();
};
window.impNotes = () => {
const inp = document.createElement("input"); inp.type = "file"; inp.accept = ".json";
inp.onchange = () => { const f = inp.files[0]; if (!f) return;
f.text().then(t => { const d = JSON.parse(t);
Object.entries(d).forEach(([k, v]) => { if (k.startsWith("fa-gm-")) localStorage.setItem(k, v); });
location.reload(); }); };
inp.click();
};
window.resetAll = () => {
if (!confirm("Clear ALL notes, clue ticks and trackers on this computer?")) return;
for (let i = localStorage.length - 1; i >= 0; i--) { const k = localStorage.key(i);
if (k.startsWith("fa-gm-")) localStorage.removeItem(k); }
location.reload();
};
})();
</script>
</body>
</html>
+4 -1
View File
@@ -744,7 +744,10 @@ export class DGLethalityRoll extends DGPercentileRoll {
},
);
return this.toMessage({ content: html });
const message = await this.toMessage({ content: html });
// Lethality is a d100 test too - natural 01/00 triggers the home rule.
await maybeTriggerCriticalEvent(this);
return message;
}
/**
Binary file not shown.
+3 -3
View File
@@ -1,3 +1,3 @@
2026/07/16-22:12:46.376475 17235f000 Recovering log #4
2026/07/16-22:12:46.380006 17235f000 Delete type=0 #4
2026/07/16-22:12:46.380058 17235f000 Delete type=3 #2
2026/07/17-00:01:55.659195 16ea8f000 Recovering log #4
2026/07/17-00:01:55.660325 16ea8f000 Delete type=0 #4
2026/07/17-00:01:55.660363 16ea8f000 Delete type=3 #2
+5 -5
View File
@@ -1,5 +1,5 @@
2026/07/16-22:12:46.303554 1737b7000 Delete type=3 #1
2026/07/16-22:12:46.305623 17404f000 Level-0 table #5: started
2026/07/16-22:12:46.305975 17404f000 Level-0 table #5: 19548 bytes OK
2026/07/16-22:12:46.306072 17404f000 Delete type=0 #3
2026/07/16-22:12:46.306136 17404f000 Manual compaction at level-0 from '!adventures!5zf355zpx5s1ux56' @ 72057594037927935 : 1 .. '!adventures!5zf355zpx5s1ux56' @ 0 : 0; will stop at (end)
2026/07/17-00:01:55.574374 16fbe7000 Delete type=3 #1
2026/07/17-00:01:55.577581 17047f000 Level-0 table #5: started
2026/07/17-00:01:55.578252 17047f000 Level-0 table #5: 28866 bytes OK
2026/07/17-00:01:55.578476 17047f000 Delete type=0 #3
2026/07/17-00:01:55.578633 17047f000 Manual compaction at level-0 from '!adventures!5zf355zpx5s1ux56' @ 72057594037927935 : 1 .. '!adventures!5zf355zpx5s1ux56' @ 0 : 0; will stop at (end)
Binary file not shown.
+1 -1
View File
@@ -15,7 +15,7 @@
"discord": "jalensailin"
}
],
"version": "2.0.4",
"version": "2.1.1",
"compatibility": {
"minimum": "13",
"verified": "14",