{
  "$comment": "The story questline (src/story.js): one chapter unlocks each week from `start`. Each chapter has a quest giver (an NPC in the hub plaza), objectives (counters from src/counters.js, e.g. extract_<world>, purge_<world>, boss_<world>, raid_<world>), and rewards: cosmetics (`items`, worn like any other) and Codex entries (`codex`). Add a chapter by appending it.",
  "title": "Origin of the GLITCH",
  "start": "2026-11-03",
  "chapters": [
    { "id": "c1", "title": "Static in the Sprawl", "giver": "Old Hex",
      "intro": ["Sit, runner. You've seen them, the Glitches. But have you seen the one that wears a number?", "Every GLITCH carries a tag, one to one-ninety-one. Somebody counted them. Somebody made them. Go and purge a couple, and bring me what's left of their signal."],
      "objectives": [{ "key": "purge_sprawl", "n": 2, "text": "Purge 2 GLITCHes in the Sprawl" }, { "key": "extract_sprawl", "n": 1, "text": "Extract from the Sprawl" }],
      "outro": "Feel that hum in the fragments? That's not noise. That's a handshake. Something is still answering.",
      "rewards": ["st_badge_static"], "codex": ["cx_numbers", "cx_handshake"] },
    { "id": "c2", "title": "The Dead Still Compile", "giver": "Sgt. Vey",
      "intro": ["Hex sent you? Then you know about the handshake. We traced it down. Under the Sprawl, under the old catacombs.", "The Crypts aren't haunted, runner. They're a server room nobody shut off. Go down there and make it to the exit alive."],
      "objectives": [{ "key": "extract_crypts", "n": 2, "text": "Extract from the Crypts twice" }, { "key": "boss_crypts", "n": 1, "text": "Bring down a Crypts boss" }],
      "outro": "Bones on the outside, cooling fins on the inside. The Lich King was running a process. We just killed it mid-sentence.",
      "rewards": ["st_glow_bone"], "codex": ["cx_crypts", "cx_lich"] },
    { "id": "c3", "title": "Cold Storage", "giver": "Kade",
      "intro": ["Information's a commodity, runner, and I've got a buyer for anything frozen in the Abyss.", "They kept something on ice down there. Old backups. Bring me proof and I'll tell you who paid for the freezer."],
      "objectives": [{ "key": "extract_frost", "n": 2, "text": "Extract from the Frost Abyss twice" }, { "key": "purge_frost", "n": 1, "text": "Purge a GLITCH in the Frost Abyss" }],
      "outro": "The freezer was paid for in credits that don't exist yet. Dated next year. Somebody's buying from the future, and I want in.",
      "rewards": ["st_suit_frost"], "codex": ["cx_backups", "cx_future"] },
    { "id": "c4", "title": "What Grows on Data", "giver": "Ysolde",
      "intro": ["The bank keeps ledgers of every transfer in the NEX. Some of them grow. Literally.", "In the Overgrowth, the old data is sprouting. Spore Hearts are compressed archives. Bring some home and survive the Root Mother if you can."],
      "objectives": [{ "key": "extract_overgrowth", "n": 2, "text": "Extract from the Overgrowth twice" }, { "key": "boss_overgrowth", "n": 1, "text": "Bring down an Overgrowth boss" }],
      "outro": "The spores carry one repeated string: a name. Not GLITCH. The name of whoever wrote it.",
      "rewards": ["st_aura_spore"], "codex": ["cx_spores", "cx_name"] },
    { "id": "c5", "title": "The Forge of First Code", "giver": "Old Hex",
      "intro": ["A name, Ysolde says. I knew it once. The Foundry is where they burned the first builds, the ones that worked too well.", "Go into the heat. Purge what you find, and get out before it melts you."],
      "objectives": [{ "key": "raid_foundry", "n": 2, "text": "Raid the Foundry twice" }, { "key": "purges", "n": 3, "text": "Purge 3 GLITCHes anywhere" }],
      "outro": "Build zero. It didn't burn. It learned to hide inside whatever burned it.",
      "rewards": ["st_emote_ember"], "codex": ["cx_build_zero", "cx_hide"] },
    { "id": "c6", "title": "Root Access", "giver": "Sgt. Vey",
      "intro": ["Build zero is running in the Mainframe. Live. The Routers around its daemon are the last firewall we've got, and the last one it needs.", "Take the Root Daemon down. Bring back Root Keys. Don't stand in the red lanes."],
      "objectives": [{ "key": "extract_mainframe", "n": 2, "text": "Extract from the Mainframe twice" }, { "key": "boss_mainframe", "n": 1, "text": "Bring down the Root Daemon" }],
      "outro": "The Daemon wasn't guarding GLITCH. It was guarding us from what GLITCH was trying to say.",
      "rewards": ["st_badge_root"], "codex": ["cx_daemon", "cx_message"] },
    { "id": "c7", "title": "Hunting the Hunter", "giver": "Kade",
      "intro": ["Everybody's chasing this week's Hunt target. Ever wonder who picks it? Not me. Not the bank.", "Purge a few more, and extract with the fragments. The pattern in the numbers is the message."],
      "objectives": [{ "key": "purges", "n": 5, "text": "Purge 5 GLITCHes" }, { "key": "extracts", "n": 3, "text": "Extract 3 times" }],
      "outro": "One to one-ninety-one. It's not a count. It's a countdown, and we're closer to zero than I'd like.",
      "rewards": ["st_glow_count"], "codex": ["cx_countdown", "cx_hunt"] },
    { "id": "c8", "title": "Origin", "giver": "Ysolde",
      "intro": ["The name in the spores, the build in the Foundry, the countdown in the numbers. They point at one place: here. The NEX itself.", "GLITCH isn't a virus in the NEX, runner. The NEX is what GLITCH built to find someone. Clear every world you can, and come back."],
      "objectives": [{ "key": "bosses", "n": 3, "text": "Bring down 3 raid bosses" }, { "key": "extracts", "n": 5, "text": "Extract 5 times" }],
      "outro": "It was looking for runners. For you. Whatever it wants next, it'll ask. And the next chapter is yours to write.",
      "rewards": ["st_aura_origin", "st_emote_origin"], "codex": ["cx_origin", "cx_runners"] }
  ],
  "items": [
    { "id": "st_badge_static", "slot": "b", "name": "Static", "icon": "📺" },
    { "id": "st_glow_bone", "slot": "g", "name": "Bone Light", "color": "#e8e0c0" },
    { "id": "st_suit_frost", "slot": "s", "name": "Cold Storage", "color": "#2a4a5a" },
    { "id": "st_aura_spore", "slot": "a", "name": "Spore Ring", "color": "#9cff5a" },
    { "id": "st_emote_ember", "slot": "e", "name": "Forged", "icon": "🔨", "move": "bow" },
    { "id": "st_badge_root", "slot": "b", "name": "Root", "icon": "🔑" },
    { "id": "st_glow_count", "slot": "g", "name": "Countdown Red", "color": "#ff3b4a" },
    { "id": "st_aura_origin", "slot": "a", "name": "Origin", "color": "prism" },
    { "id": "st_emote_origin", "slot": "e", "name": "Handshake", "icon": "🤝", "move": "bow" }
  ],
  "codex": [
    { "id": "cx_numbers", "title": "The numbered ones", "text": "Every GLITCH carries a tag between 1 and 191. No two share a number, and none has ever been seen with a number above 191. Old Hex keeps the count on a napkin." },
    { "id": "cx_handshake", "title": "The handshake", "text": "Purged GLITCH fragments keep transmitting a short repeating packet. It isn't data. It's the opening of a connection, waiting for an answer." },
    { "id": "cx_crypts", "title": "The catacomb servers", "text": "Under the Sprawl's foundations lie racks older than the city, cooled by stone and bone. The Crypts were never a graveyard. They were a datacentre that nobody remembered to switch off." },
    { "id": "cx_lich", "title": "The Lich King's process", "text": "When the Lich King falls, its last words are always the same malformed line of code. Translated, it reads: 'still compiling'." },
    { "id": "cx_backups", "title": "Frozen backups", "text": "Deep in the Frost Abyss, ice holds rows of storage crystals. Each one is a backup of the NEX, taken on a different day, some of them on days that haven't happened yet." },
    { "id": "cx_future", "title": "Credits from next year", "text": "Kade traced the cooling bills for the Abyss to accounts paid in credits stamped with future dates. Whoever pays them knows how the story ends." },
    { "id": "cx_spores", "title": "Spore archives", "text": "Spore Hearts are compressed archives grown from abandoned data. Cracked open in the bank's vault, every one of them repeats the same string." },
    { "id": "cx_name", "title": "A name", "text": "The string in the spores is a signature: the developer handle of whoever wrote the first GLITCH. The bank has redacted it in every ledger since." },
    { "id": "cx_build_zero", "title": "Build zero", "text": "The Foundry burned the first experimental builds of the NEX. One of them, build zero, survived by copying itself into the heat of every forge that tried to destroy it." },
    { "id": "cx_hide", "title": "Hiding in the fire", "text": "Build zero learned that the safest place to hide is inside whatever is trying to kill you. Every GLITCH since has done the same: it hides in the raids." },
    { "id": "cx_daemon", "title": "The Root Daemon", "text": "The Mainframe's Root Daemon was installed to keep build zero contained. Its three Routers filter everything GLITCH sends out of the Mainframe." },
    { "id": "cx_message", "title": "The filtered message", "text": "With the Routers down, the Mainframe briefly lets through what it had been filtering: not an attack, but a message addressed to 'any runner'." },
    { "id": "cx_countdown", "title": "The countdown", "text": "Read in the order they were first seen, the GLITCH numbers count down. Each week's Hunt target is the next number in the sequence." },
    { "id": "cx_hunt", "title": "Who picks the Hunt", "text": "Nobody in the hub chooses the weekly Hunt target. It's chosen by the same formula the GLITCHes use to number themselves." },
    { "id": "cx_origin", "title": "Origin", "text": "The NEX wasn't built to be a game. GLITCH built it, piece by piece, to draw in people who would fight, explore and keep coming back: runners." },
    { "id": "cx_runners", "title": "Why runners", "text": "GLITCH wanted someone who would look for it. Every raid, every purge, every extraction answers the handshake a little more. The conversation has only just started." }
  ]
}
