Module:MissionaryDailyOpsBVR: Difference between revisions

From MicrasWiki
Jump to navigationJump to search
NewZimiaGov (talk | contribs)
No edit summary
NewZimiaGov (talk | contribs)
No edit summary
Line 1,037: Line 1,037:
   },
   },
}
}
    --------------------------------------------------------------------------------
    -- 12.1) NOCTIC VAMPIRISM / NOCTIC-RABREV TASK INSERTS
    --
    -- These tasks add Noctic Vampirism and raw Noctic-Rabrev events to the cults
    -- most likely to intervene: dream, health, purification, wetland, funerary,
    -- hidden-knowledge, legal, charity, and counter-fraud orders.
    --------------------------------------------------------------------------------
    local function addCultTasks(cultName, list)
        tasksByCult[cultName] = tasksByCult[cultName] or {}
        for _, t in ipairs(list) do
            table.insert(tasksByCult[cultName], t)
        end
    end
    addCultTasks("Reverie Nebulous", {
        T("[[Noctic Vampirism]] dream-entanglement intake: affected households given sleep-boundary cards; severe nightmare cases referred to [[Temple_Aprobelle|Temple Aprobelle]].","green"),
        T("Noctic dream-circle for registered patients; blood-hunger language redirected into supervised journaling; family witnesses briefed.","green"),
        T("Nightmare cluster triage after suspected raw [[Noctic-Rabrev]] smoke exposure; trigger map compiled; clinic referrals issued.","yellow"),
        T("Shared-vision complaint linked to Noctic leaf use; dream narratives separated from rumor claims; speaker scripts distributed.","yellow"),
        T("Noctic trance-gathering compliance review; unsanctioned sleep rites suspended; repeat venues logged for Temple Bank follow-up.","yellow"),
        T("Crisis rest-ward activation after mass Noctic panic dream; supervised sleep zones opened; clinic corridor protected.","red"),
        T("Violent blood-hunger dream episode contained; families separated safely; witness shielding and trauma referrals arranged.","red"),
        T("High-risk dream-breach report involving suspected nocticine-Δ exposure; Aprobelle liaisons activated; public narrative held neutral.","red"),
    })
    addCultTasks("Sanctum Vitalis", {
        T("[[Noctic Vampirism]] clinic screen: photophobia, anemia, fever, lesions, and blood-craving symptoms logged; dietary guidance issued.","green"),
        T("Registered Noctic patient follow-up: milk, iron food, and blood-substitute stabilization plan checked; family care note filed.","green"),
        T("Raw [[Noctic-Rabrev]] exposure triage at wetland clinic; symptomatic patients separated from ordinary fever queue.","yellow"),
        T("Congenital Noctic case review; guardian consent ledger reconciled; lifelong monitoring schedule updated.","yellow"),
        T("Market illness cluster assessed for raw-leaf adulteration; sampling escorted; vendor recall notice prepared.","yellow"),
        T("Emergency hemorrhagic decline response in serious Noctic case; triage expansion, family shielding, and mortality ledger precautions enacted.","red"),
        T("Necrotic lesion cluster after unauthorized induction rite; quarantine boundary marked; cult-health evaluation ordered.","red"),
        T("High-risk fever center support after Noctic outbreak rumor; panic narratives suppressed while medical intake remains open.","red"),
    })
    addCultTasks("Temple Alabaster", {
        T("Refined nocticine tincture custody check; dosage ledger reconciled; [[Temple Bank of the Reformed Stripping Path|Temple Bank]] seal verified.","green"),
        T("Post-Eidolan recovery clinic review using licensed [[Noctic-Rabrev]] concentrate; patient response notes sealed under medical custody.","green"),
        T("Purity inspection of Noctic balms and tinctures; raw-leaf contamination warnings posted; suspect jars removed.","yellow"),
        T("Therapeutic nocticine distribution audit; storage seals verified; unauthorized substitutions routed to Golden Shadows.","yellow"),
        T("Contaminated Noctic medicine recall; affected households contacted; clinic-stabilization instructions posted.","yellow"),
        T("Emergency support for serious Noctic Vampirism collapse; calm ward opened; hemorrhage supplies and spiritual grounding teams staged.","red"),
        T("Crisis purification rite after counterfeit nocticine batch harms pilgrims; evidence preserved; public reassurance issued.","red"),
        T("High-risk medical custody transfer for unstable Noctic patient; decoy route used; receiving clinic countersigns sealed packet.","red"),
    })
    addCultTasks("Mystery of the Verdant Embrace", {
        T("[[Noctic-Rabrev]] field-blessing with safety lecture; flower and raw-leaf handling rules reissued to cultivators.","green"),
        T("Blood Orchard footpath inspection; leaf-storage huts checked; runoff risks and wetland access hazards logged.","green"),
        T("Noctic crop custody audit after missing leaf bundles; field stewards interviewed; harvest tally reconciled.","yellow"),
        T("Wetland illness cluster mapped near Noctic fields; raw-leaf exposure questions added to intake; clinic referrals issued.","yellow"),
        T("Flood-damaged Noctic storage shed inspected; wet leaves quarantined; safe flower product separated from restricted material.","yellow"),
        T("Emergency Blood Orchard closure after unauthorized raw-leaf distribution; field gates sealed; cultivator list turned over to Temple Bank.","red"),
        T("Poisoning event tied to unprocessed Noctic leaves; antidote routing, source trace, and water access controls initiated.","red"),
        T("High-risk wetland outbreak response: care kits staged, Noctic custody chain rebuilt, misinformation suppressed in shrine districts.","red"),
    })
    addCultTasks("Mystery of the Stygian Veil", {
        T("Funerary guidance for household of controlled Noctic patient; blood-offering limits explained; mourning schedule recorded.","green"),
        T("Noctic transformation counseling at cemetery gate; symbolic death language separated from unsafe raw-leaf use.","green"),
        T("Terminal Noctic vigil supervision; family witnesses logged; raw-leaf access barred during mourning rites.","yellow"),
        T("Blood-rite compliance check after ancestral-contact claims; permitted substitutes verified; coercion complaints recorded.","yellow"),
        T("Rumor suppression after ‘Noctic dead returning’ claim; evidence bulletin posted; graveyard panic triggers tracked.","yellow"),
        T("Crisis response after terminal Noctic transformation death; grief triage and crowd discipline established before nightfall.","red"),
        T("Emergency calm stations at tomb precinct after blood-hunger panic; supervised dispersal and clinic access protected.","red"),
        T("High-risk memorial for Noctic fatalities; retaliation prevention enforced; family shielding and witness support arranged.","red"),
    })
    addCultTasks("Order of the Umbral Oracle", {
        T("Noctic night-watch at shuttered shrine; sleepwalk reports logged; entry rules posted for anxious households.","green"),
        T("Covered-mirror guidance for suspected Noctic cases; families advised on safe vigils, naming restraint, and witness logs.","green"),
        T("Skødan-style mirror scare assessed after Noctic fever report; false-revelation claims documented without public amplification.","yellow"),
        T("Starless vigil compliance review; raw [[Noctic-Rabrev]] use questioned; repeat venues logged for Temple Bank follow-up.","yellow"),
        T("Dream-mapping dispute involving Noctic patient; testimony sealed; dangerous prophecy language corrected.","yellow"),
        T("Crisis nocturnal dispersal after mirror-haunting rumor; safe corridors opened; panic narratives suppressed.","red"),
        T("Serious Noctic fever episode during covered-mirror rite; patient removed safely; household witnesses debriefed.","red"),
        T("High-risk hidden-name panic in [[List of cities in Bassaridia Vaeringheim#Skøda|Skøda]]; Aprobelle and Sanctum Vitalis liaisons activated under seal.","red"),
    })
    addCultTasks("Conclave Illuminara", {
        T("Tarsican phase briefing for Noctic stewards; raw-leaf rites rescheduled away from high-anxiety night windows.","green"),
        T("Lunar calendar note issued for registered Noctic patients; dream disturbances and light-sensitivity triggers explained.","green"),
        T("Nocticine-Δ rumor correction after celestial alignment claims; hoarding and unsafe induction warnings posted.","yellow"),
        T("Moon-token and Noctic permit verification at night vigil; counterfeit ritual permissions seized.","yellow"),
        T("Controlled interpretation session after Noctic dream surge; public cycle-framing delivered to reduce panic.","yellow"),
        T("Emergency anti-panic bulletin after eclipse-linked Noctic outbreak claim; calm stations opened; clinic routes protected.","red"),
        T("High-risk nocturnal rite escort for registered Noctic patients; perimeter observers posted; false prophecy claims suppressed.","red"),
        T("Crisis interpretive response in Skødan mirror-vigil district; Tarsican language used to separate revelation from deception.","red"),
    })
    addCultTasks("Guild of Golden Shadows", {
        T("Quiet audit of [[Noctic-Rabrev]] market stalls; forged raw-leaf permissions logged; suspect brokers mapped.","green"),
        T("Noctic Fleet manifest cross-check; flower extract, tincture, and raw-leaf crates reconciled against Temple Bank seals.","green"),
        T("Undercover purchase of counterfeit Noctic induction permit; printer path traced; custody memo prepared.","yellow"),
        T("Raw-leaf diversion inquiry after Blood Orchard discrepancy; brokers interviewed; sealed attribution packet filed.","yellow"),
        T("Counterfeit nocticine tincture sweep; suspect vials seized; affected vendors routed to Temple Alabaster inspection.","yellow"),
        T("Night extraction of threatened Noctic witness; safe route screened; temporary housing arranged under seal.","red"),
        T("Major Noctic smuggling ring disruption: ledger seizure, broker detention support, and public market guidance coordinated.","red"),
        T("High-risk port-gate fraud surge involving raw Noctic leaf crates; inspection teams reinforced; evidence chain preserved.","red"),
    })
    addCultTasks("Temple Aprobelle", {
        T("[[Noctic Vampirism]] rumor-control briefing: discourage vigilante panic; explain registration, clinic access, and family support routes.","green"),
        T("Household anxiety visits after Noctic diagnosis; de-escalation coaching delivered; ostracism risks logged.","green"),
        T("Pattern-analysis intake for Noctic panic stories; dream claims, blood-hunger rumors, and raw-leaf reports separated.","yellow"),
        T("Noctic outbreak messaging cycle: official symptoms listed; false contagion claims corrected; clinic queues stabilized.","yellow"),
        T("Behavior audit after harassment of registered Noctic patients; corrective training issued; offenders warned.","yellow"),
        T("Silencing-cadre activated after Noctic panic flare; controlled messaging and care stations deployed before night crowds form.","red"),
        T("Emergency psychological stabilization after serious Noctic blood-hunger incident; retaliation bans and witness relocation arranged.","red"),
        T("High-risk mass scare after alleged Noctic attack; rumor nodes neutralized; supervised dispersal enforced; evidence chain sealed.","red"),
    })
    addCultTasks("Harmony Sanctum", {
        T("Family mediation after Noctic diagnosis; care duties, privacy expectations, and visitor rules written into household concord.","green"),
        T("Neighborhood explanation circle for registered Noctic household; stigma reduced; clinic and Temple Bank contacts posted.","green"),
        T("Market-lane calming after Noctic rumor; queue discipline restored; harassment complaints logged.","yellow"),
        T("Inter-family dispute over raw-leaf inheritance; compromise storage terms drafted; Temple Bank audit requested.","yellow"),
        T("Noctic clinic crowd-lane plan reviewed; patient privacy route and public waiting area separated.","yellow"),
        T("Emergency anti-reprisal pact after blood-hunger scare; escort corridors established; no-retaliation oaths collected.","red"),
        T("Mass grievance intake after Noctic outbreak panic; testimony queue metered; witness shielding arranged; outcomes logged.","red"),
        T("Crisis reconciliation hearing after violence against Noctic patient; restitution ledger initiated; family protection arranged.","red"),
    })
    addCultTasks("Azure Sentinel Sect", {
        T("Canal escort for licensed Noctic medical supplies; handoff signatures collected; chain-of-custody verified.","green"),
        T("Waterfront Noctic storage inspection after rain; flood exposure risks logged; damaged crates elevated.","green"),
        T("Storm-drain and wet-market sweep near Noctic vendors; runoff contamination warnings posted.","yellow"),
        T("Ferry-ramp crowd control during Noctic clinic transfer; privacy corridor and rescue lane maintained.","yellow"),
        T("Suspicious skiff check involving raw Noctic leaf bundles; manifests reviewed; contraband seized under seal.","yellow"),
        T("Emergency flood response at Noctic-Rabrev storehouse; restricted leaf material secured before dispersal through canals.","red"),
        T("Port lockdown support after Noctic smuggling violence; civilian zones cleared; clinic route protected.","red"),
        T("Mass casualty waterfront incident involving contaminated Noctic crates; triage staging and perimeter discipline enforced.","red"),
    })
    addCultTasks("Rex Catonis", {
        T("Noctic registration clinic: voluntary induction rules explained; lawful forms checked; appeal route posted.","green"),
        T("Public notice board update on raw [[Noctic-Rabrev]] restrictions; false decrees removed; clerk sign-off obtained.","green"),
        T("Hearing docket triage for unauthorized Noctic induction complaint; mediation attempted where lawful; evidence preserved.","yellow"),
        T("Raw-leaf permit compliance sweep; expired permissions suspended; corrective notices posted to shrine gates.","yellow"),
        T("Coerced induction allegation reviewed; victim protection options posted; suspect descriptions routed to Ironclad.","yellow"),
        T("Mass legal response after Noctic outbreak: unlawful vendors processed, custody ledgers seized, and public guidance issued.","red"),
        T("Coordinated violence response after Noctic panic; detention processing, court schedule triage, and after-action report filed.","red"),
        T("Emergency decree against unsafe raw-leaf distribution read publicly; clinic corridors protected during enforcement.","red"),
    })
    addCultTasks("Sanctum Delphica", {
        T("Noctic case archive update: diagnosis records, raw-leaf permissions, and family witness notes catalogued.","green"),
        T("Scribe training on Noctic custody language; distinguish raw leaf, flower extract, tincture, and nocticine concentrate.","green"),
        T("Doctrinal quarantine assistance after Noctic rumor; entry controls and approved signage posted.","yellow"),
        T("Forgery detection sweep for Noctic induction papers; suspect stamps catalogued; printer path traced.","yellow"),
        T("Witness packet assembled for raw-leaf desecration or coercive induction case; evidence collated and sealed.","yellow"),
        T("Emergency archive lockdown after Noctic registry breach; relocation plan activated; public narrative kept neutral.","red"),
        T("Mass panic after forged Noctic warning decree; authoritative retraction posted; printer network pursued; calm stations opened.","red"),
        T("High-risk transfer of Noctic medical ledgers; route denial markers deployed; decoy timing staged.","red"),
    })
    addCultTasks("Ordo Amicitia", {
        T("Milk and iron-food distribution for Noctic households; needs list updated; stigma-free delivery route assigned.","green"),
        T("Family support visits for congenital Noctic cases; caregiver relief scheduled; privacy rules posted.","green"),
        T("Aid line surge plan after Noctic diagnosis cluster; high-need triage and conflict scripts deployed.","yellow"),
        T("Fraudulent charity collectors using Noctic outbreak claims exposed; donations recovered; public warning posted.","yellow"),
        T("Shelter intake support for families displaced by Noctic panic; family reunification and trauma referrals recorded.","yellow"),
        T("Disaster relief activation after Noctic outbreak in wetland district; supply staging and rumor suppression enforced.","red"),
        T("Mass displacement response after raw-leaf scare; registration booth opened; care packages and witness shielding arranged.","red"),
        T("High-risk relief escort for registered Noctic patients leaving hostile neighborhood; safe housing arranged under seal.","red"),
    })


local function shouldAZSGoCovert(nextInt, sev, threat)
local function shouldAZSGoCovert(nextInt, sev, threat)
Line 1,121: Line 1,290:
-- 15) SEVERITY + ORDER/TASK CHOICE
-- 15) SEVERITY + ORDER/TASK CHOICE
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    -- 14.1) NOCTIC CITY / CULT WEIGHTING
    --
    -- Noctic Vampirism is more likely to appear where Noctic-Rabrev, Alperkin
    -- inheritance, dream rites, raw-leaf custody, or Skødan mirror-vigil customs
    -- are already locally important.
    --------------------------------------------------------------------------------
    local nocticCityRisk = {
        ["Somniumpolis"]    = 8,
        ["Odiferia"]        = 8,
        ["Erythros"]        = 7,
        ["Acheron"]        = 6,
        ["Norsolyra"]      = 6,
        ["Skøda"]          = 6,
        ["The Alpazkigz"]    = 6,
        ["Nexa"]            = 4,
        ["Pyralis"]        = 4,
        ["Vaeringheim"]    = 3,
        ["Jogi"]            = 3,
        ["Aurelia"]        = 3,
    }
    local nocticOrderBoost = {
        RNB = 4, -- Reverie Nebulous: dream entanglement, nightmares, trance
        SVI = 4, -- Sanctum Vitalis: clinic response, anemia, lesions, fever
        ALB = 3, -- Temple Alabaster: nocticine medicine and purity controls
        VDE = 4, -- Verdant Embrace: Noctic-Rabrev fields, wetlands, plant custody
        STY = 3, -- Stygian Veil: funerary rites, terminal transformation
        UMB = 3, -- Umbral Oracle: night rites, shadow, hidden revelation
        CON = 3, -- Conclave Illuminara: Tarsica, lunar timing, nocticines
        GGS = 3, -- Golden Shadows: smuggling, forged permits, counter-fraud
        TAP = 4, -- Temple Aprobelle: panic control, trauma, rumor suppression
        HSA = 2, -- Harmony Sanctum: family/community conflict stabilization
        SDE = 2, -- Sanctum Delphica: registries, documents, doctrine quarantine
        AMI = 2, -- Ordo Amicitia: relief for afflicted households
        AZS = 1, -- Azure Sentinel: canal/port custody and wetland movement
        CAT = 1, -- Rex Catonis: legal registration and enforcement
    }
    local nocticCitySpecificBoost = {
        ["Somniumpolis"] = {RNB=5, TAP=4, SVI=4, ALB=3, VDE=3},
        ["Odiferia"]    = {VDE=6, SVI=4, TAP=4, ALB=3, GGS=3},
        ["Erythros"]    = {CON=4, RNB=4, STY=3, TAP=3, SDE=2},
        ["Acheron"]    = {STY=6, SVI=3, ALB=3, UMB=3, TAP=3},
        ["Norsolyra"]  = {VDE=5, RNB=4, SVI=3, SYL=2, TAP=3},
        ["Skøda"]      = {UMB=6, CON=4, STY=4, SDE=3, TAP=3, GGS=2},
        ["The Alpazkigz"] = {VDE=4, STY=4, RNB=4, TAP=3, SVI=3},
        ["Jogi"]        = {GGS=3, MIR=2, TAP=3, SVI=2},
        ["Aurelia"]    = {CON=3, SDE=2, TAP=3, RNB=2},
        ["Vaeringheim"] = {GGS=3, TAP=3, SVI=2, ALB=2, CAT=2},
    }
    local function addNocticBoostsToWeights(weighted, seen, cityName)
        local risk = nocticCityRisk[cityName] or 0
        if risk <= 0 then return end
        local citySpecific = nocticCitySpecificBoost[cityName] or {}
        local riskBump = math.floor(risk / 2)
        for _, it in ipairs(weighted) do
            local base = nocticOrderBoost[it.key] or 0
            local localBoost = citySpecific[it.key] or 0
            if base > 0 or localBoost > 0 then
                it.w = it.w + base + localBoost + riskBump
            end
        end
        for key, base in pairs(nocticOrderBoost) do
            if not seen[key] then
                local localBoost = citySpecific[key] or 0
                if base > 0 or localBoost > 0 then
                    weighted[#weighted+1] = {key=key, w=base + localBoost + riskBump}
                    seen[key] = true
                end
            end
        end
    end
local function inferSeverity(cityTier, taskSev, threatUrg)
local function inferSeverity(cityTier, taskSev, threatUrg)
local sev = tostring(taskSev or "green")
local sev = tostring(taskSev or "green")
Line 1,132: Line 1,379:
end
end


local function pickOrder(nextInt, cityName, threat)
    local function pickOrder(nextInt, cityName, threat)
local profile = getProfile(cityName)
        local profile = getProfile(cityName)
local weighted = {}
        local weighted = {}
for key, w in pairs(profile.weights or {}) do
        local seen = {}
weighted[#weighted+1] = {key=key, w=tonumber(w) or 0}
 
end
        for key, w in pairs(profile.weights or {}) do
-- threat bump: prefer Aprobelle + safety/health + shadows
            weighted[#weighted+1] = {key=key, w=tonumber(w) or 0}
if threat and urgencyScore(threat.urg) >= 2 then
            seen[key] = true
for _, it in ipairs(weighted) do
        end
if it.key == "TAP" or it.key == "SVI" or it.key == "AZS" or it.key == "GGS" or it.key == "SDE" then
 
it.w = it.w + 2
        -- Noctic city bump: prefer the cults most likely to handle raw Noctic-Rabrev,
end
        -- Noctic Vampirism, dream disturbance, health evaluation, registration,
end
        -- smuggling, and family/community stabilization.
end
        addNocticBoostsToWeights(weighted, seen, cityName)
local pickedKey = pickWeighted(nextInt, weighted).key
 
for _, o in ipairs(orders) do
        -- Threat bump: prefer Aprobelle + safety/health + shadows.
if o.key == pickedKey then return o end
        if threat and urgencyScore(threat.urg) >= 2 then
end
            for _, it in ipairs(weighted) do
return orders[1]
                if it.key == "TAP" or it.key == "SVI" or it.key == "AZS" or it.key == "GGS" or it.key == "SDE" then
end
                    it.w = it.w + 2
                end
            end
        end
 
        local pickedKey = pickWeighted(nextInt, weighted).key
 
        for _, o in ipairs(orders) do
            if o.key == pickedKey then return o end
        end
 
        return orders[1]
    end


local function pickTask(nextInt, cultName, sev, usedIdx)
local function pickTask(nextInt, cultName, sev, usedIdx)
Line 1,205: Line 1,464:
local nextInt = lcg(seed)
local nextInt = lcg(seed)
local th = includeThreat and threatMap and threatMap[cityName] or nil
local th = includeThreat and threatMap and threatMap[cityName] or nil
local o = pickOrder(nextInt, cityName, th)
        local o = pickOrder(nextInt, cityName, th)
        ctx.usedTasksByCult[o.name] = ctx.usedTasksByCult[o.name] or {}
        local used = ctx.usedTasksByCult[o.name]
 
        local threatUrg = th and th.urg or ""
 
        -- Preliminary severity gives pickTask a useful target before the exact
        -- task-driven severity is known.
        local prelimSev = "green"
        if c.tier == "major" then prelimSev = "yellow" end
        if urgencyScore(threatUrg) >= 3 then
            prelimSev = "red"
        elseif urgencyScore(threatUrg) == 2 and prelimSev == "green" then
            prelimSev = "yellow"
        end


ctx.usedTasksByCult[o.name] = ctx.usedTasksByCult[o.name] or {}
        local baseTask, pickedIdx = pickTask(nextInt, o.name, prelimSev, used)
local used = ctx.usedTasksByCult[o.name]
        if pickedIdx then used[pickedIdx] = true end


local baseTask, pickedIdx = pickTask(nextInt, o.name, sev, used)
        local sev = inferSeverity(c.tier, baseTask.sev, threatUrg)
if pickedIdx then used[pickedIdx] = true end
local threatUrg = th and th.urg or ""
local sev = inferSeverity(c.tier, baseTask.sev, threatUrg)


-- WX overlay
-- WX overlay

Revision as of 14:59, 24 May 2026

Documentation for this module may be created at Module:MissionaryDailyOpsBVR/doc

-- Module:MissionaryDailyOpsBVR
-- Daily missionary tasking ledger (Temple Bank / Reformed Stripping Path).
--
-- Embedded requirements:
--  1) CITY FLAGS: follow Module:GeneralPortOperations flag-naming pattern, with overrides,
--     BUT any missing flag file falls back to the Imperial Trade Union flag.
--  2) CULT FLAGS (logos): taken directly from Module:GeneralPortOperations addLogo() mappings
--     for ritual cults (and Temple of Aprobelle logo). Missing files fall back to ITU flag.
--  3) CULT LINKS: each cult links to its canonical “Mystery” section target (Divine page section)
--     per Reformed_Stripping_Path#Planetary_Devotion (including the special “The …” headings).
--     Temple Aprobelle links to [[Temple_Aprobelle]] (not a Mystery section).
--  4) OPS ALERT: integrates Module:BassaridiaForecast getOpsData() (badge + condition + overlays).
--  5) Avoid “too many expensive function calls”:
--     - No candidate-search loops.
--     - Flag existence checks are cached and done at most once per unique file used.
--     - General Port content scan is ONLY executed if showEcon=yes.
--
-- Usage:
--   {{#invoke:MissionaryDailyOpsBVR|makeTable}}
--   {{#invoke:MissionaryDailyOpsBVR|makeTable|region=Core}}
--   {{#invoke:MissionaryDailyOpsBVR|makeTable|includeThreat=yes}}
--   {{#invoke:MissionaryDailyOpsBVR|makeTable|showEcon=yes}}
--   {{#invoke:MissionaryDailyOpsBVR|makeCity|city=Vaeringheim}}
--   {{#invoke:MissionaryDailyOpsBVR|makeOrder|order=Temple Aprobelle}}

local p = {}

local cal = require('Module:BassaridianCalendar')
local DAYS_IN_YEAR = 183

--------------------------------------------------------------------------------
-- 0) BASIC UTILS
--------------------------------------------------------------------------------
local function trim(s)
	s = tostring(s or "")
	return (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

local function normalizeSpaces(s)
	return (s or ""):gsub("[%s\u00A0]+", " ")
end

local function stripWiki(s)
	s = tostring(s or "")
	s = s:gsub("%{%b{}%}", "")
	s = s:gsub("%[%[[^%]|]+|([^%]]+)%]%]", "%1")
	s = s:gsub("%[%[([^%]]+)%]%]", "%1")
	s = s:gsub("'''''", ""):gsub("'''", ""):gsub("''", "")
	return trim(s)
end

--------------------------------------------------------------------------------
-- 1) CALENDAR PARSING
--------------------------------------------------------------------------------
local function parseCalendarString(s)
	if type(s) ~= "string" then return nil end
	local dayOfYear, month, year = s:match("^(%d+),%s+([%a]+)%s+%b()%s*,%s*(%d+)%s+PSSC")
	if dayOfYear and year then
		return tonumber(year), tonumber(dayOfYear), month
	end
	return nil
end

local function extractEventText(s)
	if type(s) ~= "string" then return "" end
	local ev = s:match("PSSC%s+–%s+(.-)%s+–%s+Proverb:")
	return ev or ""
end

local function doyToMonthDom(doy)
	if doy <= 61 then
		return 1, doy
	elseif doy <= 122 then
		return 2, doy - 61
	else
		return 3, doy - 122
	end
end

local function getDateInfo()
	local raw = cal.getCurrentDate()
	local y, doy = parseCalendarString(raw)
	if not y or not doy then
		y, doy = 0, 1
		raw = tostring(raw or "")
	end
	local m, dom = doyToMonthDom(doy)
	return {
		year = y,
		dayOfYear = doy,
		monthNum = m,
		dom = dom,
		text = string.format("%d/%d/%d PSSC", dom, m, y),
		raw = raw,
		calendarEvent = extractEventText(raw),
	}
end

--------------------------------------------------------------------------------
-- 2) DETERMINISTIC RNG
--------------------------------------------------------------------------------
local function hash31(str)
	str = tostring(str or "")
	local h = 0
	for i = 1, #str do
		h = (h * 131 + str:byte(i)) % 2147483647
	end
	return h
end

local function lcg(seed)
	local s = seed % 2147483647
	if s <= 0 then s = s + 2147483646 end
	return function()
		s = (1103515245 * s + 12345) % 2147483647
		return s
	end
end

local function pickFromList(nextInt, list, avoidValue)
	if not list or #list == 0 then return nil end
	if #list == 1 then return list[1] end
	local tries = 0
	while tries < 12 do
		local idx = (nextInt() % #list) + 1
		local v = list[idx]
		if v ~= avoidValue then return v end
		tries = tries + 1
	end
	for _, v in ipairs(list) do
		if v ~= avoidValue then return v end
	end
	return list[1]
end

local function pickWeighted(nextInt, weighted)
	local total = 0
	for _, it in ipairs(weighted) do total = total + (it.w or 0) end
	if total <= 0 then return weighted[1] end
	local r = nextInt() % total
	local acc = 0
	for _, it in ipairs(weighted) do
		acc = acc + (it.w or 0)
		if r < acc then return it end
	end
	return weighted[#weighted]
end

--------------------------------------------------------------------------------
-- 3) EXPENSIVE-CALL CONTROL: cached file existence checks (1 per unique file)
--------------------------------------------------------------------------------
local fileExistsCache = {}
local function fileExists(fileName)
	fileName = tostring(fileName or "")
	if fileName == "" then return false end
	if fileExistsCache[fileName] ~= nil then return fileExistsCache[fileName] end
	local t = mw.title.new("File:" .. fileName)
	local ok = (t and t.exists) or false
	fileExistsCache[fileName] = ok
	return ok
end

--------------------------------------------------------------------------------
-- 4) STYLE / SEVERITY
--------------------------------------------------------------------------------
local function sevStyle(sev)
	if sev == "red" then
		return ' style="background-color:#f8d7da;"'
	elseif sev == "yellow" then
		return ' style="background-color:#fff3cd;"'
	else
		return ' style="background-color:#d4edda;"'
	end
end

local function urgencyScore(u)
	u = tostring(u or ""):upper()
	if u == "CRITICAL" then return 4 end
	if u == "HIGH"     then return 3 end
	if u == "MEDIUM"   then return 2 end
	if u == "LOW"      then return 1 end
	return 0
end

--------------------------------------------------------------------------------
-- 5) CITY NETWORK
--------------------------------------------------------------------------------
local function cityLink(name)
	return string.format("[[List_of_cities_in_Bassaridia_Vaeringheim#%s|%s]]", name, name)
end

local cityOrder = {
	-- Core majors
	{name="Vaeringheim",      region="Core", tier="major"},
	{name="Luminaria",        region="Core", tier="major"},
	{name="Serena",           region="Core", tier="major"},
	{name="Pyralis",          region="Core", tier="major"},
	{name="Symphonara",       region="Core", tier="major"},
	{name="Aurelia",          region="Core", tier="major"},
	{name="Somniumpolis",     region="Core", tier="major"},
	{name="Nexa",             region="Core", tier="major"},
	{name="Lunalis Sancta",   region="Core", tier="major"},
	{name="Sylvapolis",       region="Core", tier="major"},
	-- Core minors
	{name="Saluria",          region="Core", tier="minor"},
	{name="Aetherium",        region="Core", tier="minor"},
	{name="Ferrum Citadel",   region="Core", tier="minor"},
	{name="Acheron",          region="Core", tier="minor"},
	{name="Erythros",         region="Core", tier="minor"},
	{name="Catonis Atrium",   region="Core", tier="minor"},
	{name="Delphica",         region="Core", tier="minor"},
	{name="Koinonía",         region="Core", tier="minor"},
	{name="Aureum",           region="Core", tier="minor"},
	-- Alperkin
	{name="The Alpazkigz",    region="Alperkin", tier="minor"},
	{name="Odiferia",         region="Alperkin", tier="minor"},
	-- New South Jangsong
	{name="Skýrophos",        region="New South Jangsong", tier="major"},
	{name="Bjornopolis",      region="New South Jangsong", tier="major"},
	{name="Aegirheim",        region="New South Jangsong", tier="major"},
	{name="Norsolyra",        region="New South Jangsong", tier="major"},
	{name="Thorsalon",        region="New South Jangsong", tier="major"},
	{name="Pelagia",          region="New South Jangsong", tier="minor"},
	{name="Myrene",           region="New South Jangsong", tier="minor"},
	{name="Thyrea",           region="New South Jangsong", tier="minor"},
	{name="Ephyra",           region="New South Jangsong", tier="minor"},
	{name="Halicarn",         region="New South Jangsong", tier="minor"},
	-- Haifan Bassaridia
	{name="Keybir-Aviv",      region="Haifan Bassaridia", tier="major"},
	{name="Tel-Amin",         region="Haifan Bassaridia", tier="major"},
	{name="Diamandis",        region="Haifan Bassaridia", tier="major"},
	{name="Jogi",             region="Haifan Bassaridia", tier="major"},
	{name="Lewisburg",        region="Haifan Bassaridia", tier="major"},
	{name="Thermosalem",      region="Haifan Bassaridia", tier="minor"},
	{name="Akróstadium",      region="Haifan Bassaridia", tier="minor"},
	{name="Sufriya",          region="Haifan Bassaridia", tier="minor"},
	{name="Lykopolis",        region="Haifan Bassaridia", tier="minor"},
	-- Normark
	{name="Ardclach",         region="Normark", tier="major"},
	{name="Riddersborg",      region="Normark", tier="major"},
	-- Ouriana
	{name="Bashkim",          region="Ouriana", tier="major"},
	{name="Ourid",            region="Ouriana", tier="major"},
	{name="Tonar",            region="Ouriana", tier="minor"},
-- Caledonia
{name="Fanghorn",         region="Caledonia", tier="major"},
{name="Eikbu",            region="Caledonia", tier="major"},
{name="Galvø",            region="Caledonia", tier="major"},
{name="Hamarrfell",       region="Caledonia", tier="major"},
{name="Sårensby",         region="Caledonia", tier="minor"},
{name="Slevik",           region="Caledonia", tier="minor"},
{name="Sjøsborg",         region="Caledonia", tier="minor"},
{name="Storesund",        region="Caledonia", tier="minor"},
{name="Notranskja",       region="Caledonia", tier="minor"},
{name="Kaledonija",       region="Caledonia", tier="minor"},
{name="Krlsgorod",        region="Caledonia", tier="minor"},
{name="Skøda",            region="Caledonia", tier="minor"},
}

local citySet = {}
local ctx = { usedTasksByCult = {} }
for _, c in ipairs(cityOrder) do citySet[c.name] = true end

local function regionPass(filter, cityRegion)
	filter = tostring(filter or "All")
	if filter == "" or filter == "All" then return true end
	if filter == "Core" then return cityRegion == "Core" end
	if filter == "NSJ" then return cityRegion == "New South Jangsong" end
	if filter == "Haifan" then return cityRegion == "Haifan Bassaridia" end
	if filter == "Caledonian" then return cityRegion == "Caledonia" end
	return cityRegion == filter
end

--------------------------------------------------------------------------------
-- 5.1) CITY FLAGS (GeneralPortOperations style + fallback-to-ITU if missing)
--------------------------------------------------------------------------------
local ITU_FLAG = "Imperial Trade Union flag.png"

local function normCityForFlag(name)
	-- Exactly the normalization used in Module:GeneralPortOperations
	return (name or "")
		:gsub("[%s%-’]", "")
		:gsub("[Áá]", "A"):gsub("[Éé]", "E")
		:gsub("[Íí]", "I"):gsub("[Óó]", "O")
		:gsub("[Úú]", "U"):gsub("[Ýý]", "Y")
end

local cityFlagOverrides = {
	["Skýrophos"] = "SkyrophosFlag.png", -- override used in GeneralPortOperations
	["Slevik"]    = "SlevikFlag.png.png", -- known oddity you’ve used elsewhere
	["Sårensby"]  = "SårensbyFlag.png",   -- known to exist in your notes
}

local cityFlagMarkupCache = {}
local function getCityFlagMarkup(cityName)
	if cityFlagMarkupCache[cityName] then return cityFlagMarkupCache[cityName] end
	local candidate = cityFlagOverrides[cityName] or (normCityForFlag(cityName) .. "Flag.png")
	local file = fileExists(candidate) and candidate or ITU_FLAG
	local mk = string.format("[[File:%s|20px]]", file)
	cityFlagMarkupCache[cityName] = mk
	return mk
end

--------------------------------------------------------------------------------
-- 6) CULT FLAGS (logos) from Module:GeneralPortOperations addLogo() + fallback
--------------------------------------------------------------------------------
local cultLogoFile = {
	-- Ritual cult logos from Module:GeneralPortOperations
	["Order of Aurora Mystica"]         = "Auroramystica.png",
	["Harmony Sanctum"]                = "Harmonysanctum.png",
	["Ignis Aeternum"]                 = "Ignis Aeternum.png",
	["Celestial Harmony Sect"]         = "HarmonySect.png",
	["Guild of Golden Shadows"]        = "GoldenShadows.png",
	["Azure Sentinel Sect"]            = "AzureSentinel.png",
	["Reverie Nebulous"]               = "RevNeb.png",
	["Eon Fellowship"]                 = "EonFel.png",
	["Order of the Umbral Oracle"]     = "Umbral.png",
	["Mystery of the Verdant Embrace"] = "Verdant.png",
	["Conclave Illuminara"]            = "Conclave.png",
	["Sanctum Vitalis"]                = "Vitalis.png",
	["Temple Alabaster"]               = "Alabaster.png",
	["Court of the Ironclad"]          = "Ironclad.png",
	["Accord Concordia"]               = "Concordia.png",
	["Mystery of the Stygian Veil"]    = "StygianVe.png",
	["Sylvan Fellowship"]              = "Sylvan.png",
	["Mystery of Red Mirth"]           = "MirthFlag.png",
	["Rex Catonis"]                    = "Catonis.png",
	["Sanctum Delphica"]               = "SanctumDel.png",
	["Ordo Amicitia"]                  = "OrdoFl.png",
	["Temple Illuminata"]              = "AureumFlag.png",
	-- Temple Aprobelle logo is mapped in GeneralPortOperations under serviceCompanies name:
	["Temple Aprobelle"]               = "TempleAprobelleLogo.png",
	["Temple of Aprobelle"]            = "TempleAprobelleLogo.png",
}

local cultFlagMarkupCache = {}
local function getCultFlagMarkup(cultName)
	if cultFlagMarkupCache[cultName] then return cultFlagMarkupCache[cultName] end
	local candidate = cultLogoFile[cultName]
	local file = (candidate and fileExists(candidate)) and candidate or ITU_FLAG
	local mk = string.format("[[File:%s|18px]] ", file)
	cultFlagMarkupCache[cultName] = mk
	return mk
end

--------------------------------------------------------------------------------
-- 7) CULT LINKS (canonical “Mystery” section targets)
--------------------------------------------------------------------------------
local cultTargets = {
	["Order of Aurora Mystica"]         = { page="Eos_(Reformed_Stripping_Path)",      anchor="Order_of_Aurora_Mystica" },
	["Harmony Sanctum"]                = { page="Micras_(Reformed_Stripping_Path)",   anchor="Harmony_Sanctum" },
	["Ignis Aeternum"]                 = { page="Pyros_(Reformed_Stripping_Path)",    anchor="Ignis_Aeternum" },
	-- Special headings on those pages include “The …”
	["Celestial Harmony Sect"]         = { page="Indigo_(Reformed_Stripping_Path)",   anchor="The_Celestial_Harmony_Sect" },
	["Guild of Golden Shadows"]        = { page="Chrysos_(Reformed_Stripping_Path)",  anchor="The_Guild_of_Golden_Shadows" },
	["Azure Sentinel Sect"]            = { page="Thalassa_(Reformed_Stripping_Path)", anchor="Azure_Sentinel_Sect" },
	["Reverie Nebulous"]               = { page="Nephele_(Reformed_Stripping_Path)",  anchor="Reverie_Nebulous" },
	["Eon Fellowship"]                 = { page="Glinos_(Reformed_Stripping_Path)",   anchor="Eon_Fellowship" },
	["Order of the Umbral Oracle"]     = { page="Noctis_(Reformed_Stripping_Path)",   anchor="Order_of_the_Umbral_Oracle" },
	["Mystery of the Verdant Embrace"] = { page="Opsithe_(Reformed_Stripping_Path)",  anchor="Mystery_of_the_Verdant_Embrace" },
	["Conclave Illuminara"]            = { page="Tarsica_(Reformed_Stripping_Path)",  anchor="Conclave_Illuminara" },
	["Sanctum Vitalis"]                = { page="Plateau_(Reformed_Stripping_Path)",  anchor="Sanctum_Vitalis" },
	["Temple Alabaster"]               = { page="Ivory_(Reformed_Stripping_Path)",    anchor="Temple_Alabaster" },
	["Court of the Ironclad"]          = { page="Fenrir_(Reformed_Stripping_Path)",   anchor="Court_of_the_Ironclad" },
	["Accord Concordia"]               = { page="Lukedu_(Reformed_Stripping_Path)",   anchor="Accord_Concordia" },
	["Mystery of the Stygian Veil"]    = { page="Styx_(Reformed_Stripping_Path)",     anchor="Mystery_of_the_Stygian_Veil" },
	["Sylvan Fellowship"]              = { page="Faun_(Reformed_Stripping_Path)",     anchor="Sylvan_Fellowship" },
	["Mystery of Red Mirth"]           = { page="Silenus_(Reformed_Stripping_Path)",  anchor="Mystery_of_Red_Mirth" },
	["Rex Catonis"]                    = { page="Cato_(Reformed_Stripping_Path)",     anchor="Rex_Catonis" },
	["Sanctum Delphica"]               = { page="Sisera_(Reformed_Stripping_Path)",   anchor="Sanctum_Delphica" },
	["Ordo Amicitia"]                  = { page="Erasmus_(Reformed_Stripping_Path)",  anchor="Ordo_Amicitia" },
	["Temple Illuminata"]              = { page="Nikolaj_(Reformed_Stripping_Path)",  anchor="Temple_Illuminata" },
}

local function cultLink(cultName)
	if cultName == "Temple Aprobelle" or cultName == "Temple of Aprobelle" then
		return "[[Temple_Aprobelle|Temple Aprobelle]]"
	end
	local t = cultTargets[cultName]
	if not t then
		return string.format("[[%s]]", cultName)
	end
	return string.format("[[%s#%s|%s]]", t.page, t.anchor, cultName)
end

--------------------------------------------------------------------------------
-- 8) ORG UNITS (Missionary echelons)
--------------------------------------------------------------------------------
local org = {
	Lampade     = { code="L", size=8  },
	Hetairoi    = { code="H", size=12 },
	Dodekade    = { code="D", size=18 },
	Kleisthenes = { code="K", size=25 },
	Stoa        = { code="S", size=40 },
	Thiasos     = { code="T", size=60 },
}

local function pickOrgUnit(nextInt, sev)
	if sev == "green" then
		return pickFromList(nextInt, {"Lampade","Hetairoi"}, nil)
	elseif sev == "yellow" then
		return pickFromList(nextInt, {"Hetairoi","Dodekade","Kleisthenes"}, nil)
	else
		return pickFromList(nextInt, {"Kleisthenes","Stoa","Thiasos"}, nil)
	end
end

--------------------------------------------------------------------------------
-- 9) OPS ALERT (Module:BassaridiaForecast)
--------------------------------------------------------------------------------
local wxOk, wx = pcall(require, "Module:BassaridiaForecast")
if not wxOk then wx = nil end

local function wxColor(level)
	level = tonumber(level) or 0
	if level == 3 then return "#f8d7da" end
	if level == 2 then return "#ffe5cc" end
	if level == 1 then return "#fff3cd" end
	return "#d4edda"
end

local function opsCell(cityName, year, dayOfYear)
	if not wx or type(wx.getOpsData) ~= "function" then return "n/a", nil end
	local op = wx.getOpsData(cityName, year, dayOfYear)
	if not op or not op.alert then return "n/a", nil end
	local lvl   = tonumber(op.alert.level) or 0
	local label = tostring(op.alert.label or "Green")
	local cond  = tostring(op.condition or "")
	local bg    = wxColor(lvl)

	local cell = string.format(
		"<span style='background:%s;padding:2px 6px;border:1px solid #ccc;border-radius:10px;white-space:nowrap;'>%s</span>%s",
		bg, label, (cond ~= "" and ("<br/><span style='font-size:90%;'>" .. cond .. "</span>") or "")
	)
	return cell, op
end

local function bumpSevWeather(sev, op)
	if not op or not op.alert then return sev end
	local lvl = tonumber(op.alert.level) or 0
	local imp = op.impacts or {}

	if lvl == 2 and sev == "green" then sev = "yellow" end
	if lvl >= 3 then sev = "red" end

	if (imp.ground == "Hazard" or imp.sea == "Closed" or imp.air == "No-Go") and sev == "green" then
		sev = "yellow"
	end
	return sev
end

local function weatherTaskOverlay(op)
	if not op or not op.alert then return "" end
	local lvl = tonumber(op.alert.level) or 0
	if lvl < 2 then return "" end -- Orange/Red only

	local haz = tostring(op.alert.hazard or "weather disruption")
	local imp = op.impacts or {}
	local cond = tostring(op.condition or "")
	local base = " Weather-driven tasking: " .. haz .. " (" ..
		string.format("Gnd %s / Sea %s / Air %s", imp.ground or "OK", imp.sea or "OK", imp.air or "OK") .. ")."

	if cond == "Storm" or cond == "Rain" then
		return base .. " Clinic/relief queues stabilized; rumor bulletins posted; shrine-district lanes marked."
	elseif cond == "Blizzard" or cond == "Snow" then
		return base .. " Warming-shelter checks; fuel/medicine custody verified; travel guidance posted."
	elseif cond == "Fog" then
		return base .. " Navigation warnings and crowd guidance in port/canal corridors; panic narratives suppressed."
	elseif cond == "Dust" then
		return base .. " Mask discipline and vendor hygiene enforcement prioritized; indoor refuge advisories posted."
	else
		return base .. " Welfare checks and public messaging prioritized."
	end
end

--------------------------------------------------------------------------------
-- 10) OPTIONAL: THREAT WATCH (Module:ReligiousEvents)
--------------------------------------------------------------------------------
local function parseReligiousEventsTable(wikitext)
	local map = {}
	wikitext = tostring(wikitext or "")
	for line in wikitext:gmatch("[^\n]+") do
		if line:match("^|%s") and not line:match("^|%-%s*$") then
			local parts = mw.text.split(line:gsub("^|%s*", ""), "%s*||%s*")
			if #parts >= 4 then
				local city = stripWiki(parts[2])
				local ev = stripWiki(parts[3])
				local urg = stripWiki(parts[4])
				if city ~= "" and ev ~= "" then
					map[city] = {event=ev, urg=urg}
				end
			end
		end
	end
	return map
end

--------------------------------------------------------------------------------
-- 11) OPTIONAL: ECON SIGNALS (EXPENSIVE; ONLY if showEcon=yes)
--------------------------------------------------------------------------------
local function getEconSignals()
	local title = mw.title.new("General Port of Lake Morovia")
	if not title then return {} end
	local ok, content = pcall(function() return title:getContent() end)
	if not ok or not content or content == "" then return {} end
	local signals = {}
	local text = normalizeSpaces(content)

	for _, c in ipairs(cityOrder) do
		local n = c.name
		local hits = 0
		local pattern = n:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])","%%%1")
		for _ in text:gmatch(pattern) do
			hits = hits + 1
			if hits >= 6 then break end
		end
		if hits >= 3 then
			signals[n] = {summary=string.format("High Port linkage (mentions: %d)", hits)}
		end
	end
	return signals
end

--------------------------------------------------------------------------------
-- 12) TASK HELPERS
--------------------------------------------------------------------------------
local function T(text, sev) return {text=text, sev=sev} end

-- 10 tasks per cult (kept compact so the module remains maintainable)
local tasksByCult = {

  ["Order of Aurora Mystica"] = {
    T("First-light conciliation at a guild hall; signatories recorded with Temple Bank clerks; follow-up meeting scheduled.","green"),
    T("Sunrise clarity bulletin: correct ‘official omen’ rumors before queues form; speakers briefed on approved language.","green"),
    T("Dawn home-visit circuit for anxious households; practical referrals routed through shrine stewards.","green"),
    T("Procession lane rehearsal for a morning rite; crush points marked; stewards drilled on staggered entry.","yellow"),
    T("Targeted pamphlet sweep: remove forged ‘dawn decree’ leaflets; source stalls logged for follow-up.","yellow"),
    T("Joint dawn patrol with civic stewards on canal/rail approaches; lighting faults logged; intimidation reports collected.","yellow"),
    T("Witness-support escort at daybreak: safe path confirmed; hostile crowd avoidance plan posted.","yellow"),
    T("Emergency dawn ceasefire convened after overnight clashes; terms read publicly; retaliation pledges collected.","red"),
    T("Crisis dawn-vigil stabilization after a major scare; grief care + calm stations opened; clinic corridors protected.","red"),
    T("High-risk dawn convoy escort for sacred/custody items; route denial and decoy timing implemented.","red"),
    -- +8 added
    T("Hilltop shrine schedule reset for first-light hymns; latecomer lanes separated; attendance log updated.","green"),
    T("Dawn-worksite blessing for shift crews; safety reminders appended; foreman sign-off obtained.","green"),
    T("Morning-lamp distribution and repair tickets; dark alleys flagged; follow-up patrol time posted.","green"),
    T("Sunrise complaint intake booth at market edge; triage tags assigned; referrals routed to Harmony Sanctum.","yellow"),
    T("Counter-badge check on ‘Aurora stewards’; impostors documented; credentials verified with Temple Bank.","yellow"),
    T("Dawn festival route reroute after hazard report; new signage posted; crowd cadence rehearsed.","yellow"),
    T("Red-posture dawn broadcast: scripted calm loop; speaker rotations scheduled; rumor nodes targeted for removal.","red"),
    T("High-risk witness staging at daybreak: staggered arrivals; decoy meeting point; custody signatures secured.","red"),
  },

  ["Harmony Sanctum"] = {
    T("Neighborhood mediation circle: settle a vendor–labor dispute; written concord filed.","green"),
    T("Public etiquette coaching at shrine square; queue discipline and nonviolent refusal scripts practiced.","green"),
    T("Household conflict visits after complaint spike; behavior plan issued; check-in date set.","green"),
    T("Festival crowd-lane plan review; bottlenecks marked; stewards assigned to separation corridors.","yellow"),
    T("Rumor triage: map source nodes feeding panic; corrective bulletin cycle deployed.","yellow"),
    T("Transit choke-point calming patrol; commuter separation corridor opened; escalation triggers documented.","yellow"),
    T("Clerk oversight coaching after audit flags; corrective training delivered; sign-off obtained.","yellow"),
    T("Emergency stabilization during riot flare; dispersal lanes held; care stations deployed at safe corners.","red"),
    T("Night calm-litany enforcement after a panic episode; supervised dispersal and reunification tent opened.","red"),
    T("Crisis reconciliation hearing after violence; restitution ledger initiated; witness protection arranged.","red"),
    -- +8 added
    T("Balance-rite for a disputed property line; boundary walk performed; neutral witnesses recorded.","green"),
    T("Structured apology conference after school conflict; restitution terms set; guardian contacts logged.","green"),
    T("Neighborhood rotation plan for shared resources; schedule posted; conflict triggers documented.","green"),
    T("Inter-ward speaking forum moderated; turn order enforced; heckler removal protocol posted.","yellow"),
    T("Counter-rumor ‘myth vs policy’ bulletin; distribution assigned by street; speaker script packet issued.","yellow"),
    T("Market-stall spacing enforcement after crush near fountain; lane widths measured; re-layout posted.","yellow"),
    T("Emergency anti-reprisal pact after stabbing; escort corridors established; no-retaliation oaths collected.","red"),
    T("Mass grievance intake after unrest; testimony queue metered; witness shielding arranged; outcomes logged.","red"),
  },

  ["Ignis Aeternum"] = {
    T("Forge discipline rite: safety roles assigned; firewatch roster posted; tool control verified.","green"),
    T("Heat advisory posting for labor crews; hydration discipline enforced; shade points designated.","green"),
    T("Brazier and lantern inspection at a festival lane; safe distances marked; fuel rules posted.","green"),
    T("Brushfire-risk patrol: illegal burns curtailed; emergency water points labeled; reporting chain rehearsed.","yellow"),
    T("Arson-scare containment: inspect fuel stores and service corridors; contractors re-badged; locks audited.","yellow"),
    T("Rumor suppression after ‘cursed flame’ claims; sanctioned narrative posted; agitator list started.","yellow"),
    T("Kiln/oven quarter audit after sabotage chatter; witness statements logged; repair tickets issued.","yellow"),
    T("Emergency response to a flare incident: evacuation lanes opened; burn triage support and calm messaging deployed.","red"),
    T("Crisis crowd control at a pyre/procession pinch point; stampede pressure relieved; reunification tent opened.","red"),
    T("High-risk perimeter posting at depots after credible arson threat; entry controlled; night watch rotated.","red"),
    -- +8 added
    T("Workshop ventilation check; soot exposure warnings posted; compliance sign-offs collected.","green"),
    T("Approved fuel rationing note posted for braziers; prevent hoarding; vendor guidance issued.","green"),
    T("Tool-blessing and inventory day; missing items reconciled; suspect list deferred to Golden Shadows.","green"),
    T("Firebreak drill coordination near warehouses; muster lanes marked; timing rehearsed with stewards.","yellow"),
    T("Controlled relight protocol after blackout; ignition permits checked; unsafe relights stopped.","yellow"),
    T("Inspection sweep for illegal accelerants; confiscations logged; storage seals verified.","yellow"),
    T("Major blaze containment support: perimeter discipline; water point control; after-action safety decree issued.","red"),
    T("Arson-ring disruption support: suspect workshops sealed; witness protection arranged; public guidance broadcast.","red"),
  },

  ["Celestial Harmony Sect"] = {
    T("Cosmic-order lecture at shrine school; reduce anxiety about sky-signs; practical safety guidance appended.","green"),
    T("Guided breathing session for canal workers; stress reduction paired with shift-safety reminder.","green"),
    T("Calendar correction bulletin: prevent hoarding after false eclipse/omen claims; approved text distributed.","green"),
    T("Quiet-zone enforcement near hospitals and shelters; regulated chanting and crowd spacing verified.","yellow"),
    T("Counterfeit star-chart inquiry: vendor interviews; seizure log compiled; correlations forwarded.","yellow"),
    T("Fog-night guidance patrol: speakers briefed; route markers placed; panic triggers documented.","yellow"),
    T("Post-event debrief: update approved narratives; distribute scripts to shrine speakers; archive record filed.","yellow"),
    T("Crisis counseling during mass scare; supervised calm stations opened; clinic access protected.","red"),
    T("Emergency embedded messaging team with civic stewards during unrest; prevent retaliatory panic; crowd lanes held.","red"),
    T("High-risk omen-driven gathering dispersed under controlled cadence; separation corridors opened; arrests avoided where possible.","red"),
    -- +8 added
    T("Twin-balance mediation between rival guild blocs; alternating speaking order enforced; compromise text drafted.","green"),
    T("Opposites-pair workshop for stewards; role swapping practiced; conflict sensitivity notes filed.","green"),
    T("Port/market ‘cycle briefing’: scarcity and surplus explained; calm purchasing guidance posted.","green"),
    T("Symbol dispute review (Indigo/Momiji misuse); offending banners removed; replacement signage approved.","yellow"),
    T("Diplomatic liaison support for visiting delegations; translation scripts issued; etiquette rules posted.","yellow"),
    T("Coordinated counter-panic cadence: staggered announcements; prevent feedback loops; rumor nodes mapped.","yellow"),
    T("Emergency unity convocation after sectarian flare; ceasefire terms read; neutral escorts assigned.","red"),
    T("Mass ominal panic response: structured dispersal waves; calm stations staffed; clinic routes protected.","red"),
  },

  ["Guild of Golden Shadows"] = {
    T("Quiet intake: log forged vouchers and coercion attempts; route evidence to Temple Bank without public escalation.","green"),
    T("Market observation rotation; identify counterfeit seals and pressure networks; ledger packet assembled.","green"),
    T("Discrete tracing of a forged permit chain; map printer stalls and broker intermediaries; file correlation report.","green"),
    T("Undercover purchase of fake shrine/custody seals; seize plates and ledgers; custody memo prepared.","yellow"),
    T("Intercept suspicious manifest and cross-check corridor registry for evasions; flag repeats for inspection teams.","yellow"),
    T("Witness-support arrangement for a threatened vendor; relocation and stipend bridge authorized.","yellow"),
    T("Rumor suppression operation: remove false broadsheets; replace with official bulletin; source nodes catalogued.","yellow"),
    T("Night extraction of compromised informant; safe route screened; temporary housing arranged under seal.","red"),
    T("Emergency counter-coercion action during crowd surge; stabilize lanes; evidence chain protected.","red"),
    T("High-risk liaison brief to War League contact: attribution summary + prevention plan; sealed addendum filed.","red"),
    -- +8 added
    T("Silent audit of a clerk’s ledger drawer; discrepancy list sealed; retraining notice drafted.","green"),
    T("Courier-route verification for stipend packets; handoff witnesses arranged; route hazards mapped.","green"),
    T("Counterfeit stamp reference kit issued to stewards; detection steps taught; escalation chain posted.","green"),
    T("Targeted sweep for extortion collectors; victim intake protected; suspect descriptions logged.","yellow"),
    T("Dockside inventory double-check after ‘lost crate’ claim; reconciliation performed; fraud flags filed.","yellow"),
    T("Controlled public correction of a forged notice; replace postings; photograph originals; printer path traced.","yellow"),
    T("Major embezzlement exposure: emergency ledger seizure; suspect detention support; restitution memo prepared.","red"),
    T("High-risk port gate fraud surge: inspection teams reinforced; entry metering; evidence chain preserved.","red"),
  },

  ["Azure Sentinel Sect"] = {
    T("Waterfront perimeter walk; safety rope checks along canal districts; hazards logged for civil works.","green"),
    T("Storm-drain inspection with engineers; blockages cleared; maintenance tickets filed.","green"),
    T("Port-house briefing: embarkation discipline, theft prevention, and safe-lane etiquette posted.","green"),
    T("Medical-supply escort across bridges; accountability signatures collected; chain-of-custody verified.","yellow"),
    T("Harbor rumor correction: suppress false quarantine/closure claims; prevent stampede behavior at gates.","yellow"),
    T("SAR standby after storm warnings; muster roster checked; equipment count verified.","yellow"),
    T("Debris clearance coordination after gale; hazard markings placed; access lanes reopened in phases.","yellow"),
    T("Emergency flood response: evacuation guidance at waterfront shrines; calm stations maintained; shelter intake controlled.","red"),
    T("High-risk escort of officials through port-gate crowd; separation corridor enforced; decoy route staged.","red"),
    T("Crisis harbor-closure messaging under red posture: notices distributed; prevent vigilante enforcement at ramps.","red"),
    -- +8 added
    T("Canal bridge inspection; loose stone and rail faults flagged; repair tickets prioritized.","green"),
    T("Dockworker conduct briefing; safe-lift rules posted; harassment complaints intake opened.","green"),
    T("Water purity spot-check at fountains; contamination warnings posted; sampling request filed.","green"),
    T("Controlled queue plan at ferry ramps; entry tokens issued; crowd cadence rehearsed.","yellow"),
    T("Suspicious skiff check support; manifests reviewed; contraband seized; custody signatures obtained.","yellow"),
    T("Storm-surge rehearsal: shelter route posted; boat tie-down checks; public update schedule set.","yellow"),
    T("Port lockdown support after violence; civilian zones cleared; rescue lanes protected; communications centralized.","red"),
    T("Mass casualty waterfront incident: triage staging; family intake; perimeter discipline; after-action memo sealed.","red"),
    T("CLASSIFIED tasking: covert counter-assassin sweep along port approaches; decoy route staged; boat manifests cross-checked; suspect surveillance handed off under seal; public posture maintained as routine SAR readiness.","red"),
  },

  ["Reverie Nebulous"] = {
    T("Dream-circle with strict moderation; de-escalation emphasized; referral cards issued for high anxiety.","green"),
    T("Quiet art support for children after a scare; parent coaching provided; school liaison note filed.","green"),
    T("Sleep-hygiene teaching for shift workers; rest scheduling guidance posted; rumor triggers explained.","green"),
    T("Rumor mapping: identify dream narratives feeding panic; corrective story deployed with approved phrases.","yellow"),
    T("Witness interviews after trance-gathering complaint; compliance conditions issued; repeat offenders logged.","yellow"),
    T("Night calming near transit nodes; chanting regulated; separation corridors planned to prevent crush behavior.","yellow"),
    T("Post-event narrative edit: reduce retaliatory impulses; speaker training conducted; script packet distributed.","yellow"),
    T("Containment support for mass panic dream episode; supervised rest zones opened; clinic corridor protected.","red"),
    T("Emergency counseling for families after fatal incident; grief rites paired with aid referrals.","red"),
    T("High-risk ‘dream-breach’ report assessed with Aprobelle liaisons; misinformation suppressed; controlled bulletin issued.","red"),
    -- +8 added
    T("Dream journal distribution; privacy rules explained; escalation criteria posted for severe episodes.","green"),
    T("Quiet ‘waking boundary’ lesson; discourage prophetic claims; practical coping steps posted.","green"),
    T("Artist liaison with civic stewards; performance permits checked; safe audience limits posted.","green"),
    T("Sweep for fraudulent ‘dream sellers’; counterfeit charms seized; victim refunds routed through Amicitia.","yellow"),
    T("Night-market calming protocol: light levels raised; exit lanes marked; chant limits enforced.","yellow"),
    T("Repeat nightmare cluster triage; trigger map compiled; clinic referrals issued; follow-up schedule set.","yellow"),
    T("Mass hysteria response after shared-vision rumor; calm stations expanded; scripts looped; arrests minimized.","red"),
    T("Violent trance incident containment: victim protection; offender transfer; witness shielding; records sealed.","red"),
  },

  ["Eon Fellowship"] = {
    T("Timing audit at market gates: shift rotations clarified; reduce conflict from missed windows.","green"),
    T("Public calendar correction bulletin; prevent rumor-driven delays and missed rites; signage posted.","green"),
    T("Clinic/shrine entry metering drill: queue cadence tested; stewards trained on timing scripts.","green"),
    T("Witness-arrival scheduling for a hearing; time windows staged to deter intimidation; escort plan posted.","yellow"),
    T("Transit-flow smoothing at rail/canal chokepoint; signage updated; alternate timing lane opened.","yellow"),
    T("Record review: repeated stipend-delay disputes analyzed; corrective SOP issued; clerk sign-off obtained.","yellow"),
    T("Night timing plan during fog disruption; safe intervals posted; navigation warnings coordinated.","yellow"),
    T("Emergency stabilization after cascading delays: volunteer surge roster synchronized; safe movement hours posted.","red"),
    T("Crisis schedule triage during unrest: curfew windows clarified; dispersal routes timed and enforced.","red"),
    T("High-risk timing escort for custody transfer; decoy timing used; route denial staged.","red"),
    -- +8 added
    T("Endurance briefing for patrol rotations; fatigue flags logged; relief roster posted.","green"),
    T("Winterization checklist posted (wind, ice, flood); supply needs tallied; maintenance tickets filed.","green"),
    T("Shelter readiness audit; blanket inventory checked; entry rules posted; complaint intake opened.","green"),
    T("Ration-line cadence enforcement; entry stamps issued; fights deterred; incident log filed.","yellow"),
    T("Gate sabotage rumor response; key control audit; access tightened; night watch schedule posted.","yellow"),
    T("Critical-utility staffing pact mediation; interim rota signed; enforcement stewards assigned.","yellow"),
    T("Storm emergency shelter activation: intake discipline; ration control; rumor suppression; clinic route protected.","red"),
    T("Civil disorder deterrence posture: curfew windows broadcast; safe lanes enforced; ringleaders detained.","red"),
  },

  ["Order of the Umbral Oracle"] = {
    T("Quiet-night rite with strict entry control; visitor conduct posted; disturbance triggers explained.","green"),
    T("Counseling for anxious households after nightmare spike; referral paths established; follow-up logged.","green"),
    T("Night watch at shrine steps to deter harassment; steward coordination and incident ledger maintained.","green"),
    T("Risk bulletin for shadow-sign nights; discourage panic gatherings at transit nodes; routes marked.","yellow"),
    T("Investigation of anonymous pamphlets claiming ‘oracle sanction’; counterfeit marks documented; plates traced.","yellow"),
    T("Audit of unsanctioned night gatherings; compliance restrictions issued; repeat venues logged.","yellow"),
    T("Post-incident narrative discipline: speaker scripts updated; rumor sources mapped; correction bulletins deployed.","yellow"),
    T("Containment support for ‘demonic sign’ rumor under red posture: controlled messaging delivered; calm stations opened.","red"),
    T("Witness protection for informant threatened by cult rival; safehouse route planned; decoy escort used.","red"),
    T("Crisis nocturnal dispersal after crowd surge; safe corridors opened; reunification tent activated.","red"),
    -- +8 added
    T("Nocturnal observation log sweep; key anomalies summarized; sealed note sent to Temple Bank.","green"),
    T("Lamp-and-lock check on vulnerable alleys; household guidance posted; repair tickets filed.","green"),
    T("Confidential witness intake at a night gate; testimony recorded; protection options listed.","green"),
    T("Blackout exploitation patrol; temporary lighting placed; entry control enforced; suspects logged.","yellow"),
    T("Cultic graffiti catalog; symbols photographed; cleanup ordered; copycat deterrence notice posted.","yellow"),
    T("Stalking complaint response; escort plan staged; restraining paperwork initiated; incident ledger updated.","yellow"),
    T("Assassination rumor triage: safe corridors established; witness relocation; evidence sealed; briefings issued.","red"),
    T("Kidnapping response support: gate checks tightened; informant intake opened; safehouse activation logged.","red"),
  },

  ["Mystery of the Verdant Embrace"] = {
    T("Canal cleanup rite; silt removed; flow restored; maintenance log filed.","green"),
    T("Seed blessing for gardeners; pest-prevention guidance distributed; vendor hygiene note appended.","green"),
    T("Wetland path maintenance; travel warnings posted; drowning prevention markers installed.","green"),
    T("Aqueduct/sluice audit: leakage mapped; repair crews coordinated; access rules posted at pump houses.","yellow"),
    T("Field mediation over irrigation rights; shared schedule drafted; signatures collected.","yellow"),
    T("Vector mitigation at swamp edges; standing water treated; guidance posted at shelters.","yellow"),
    T("Post-storm debris clearance with volunteers; hazard markings placed; lanes reopened in phases.","yellow"),
    T("Emergency flood relief: sandbag lines, food staging, shelter support; calm messaging maintained.","red"),
    T("Crisis canal-breach response: closure and reroute; crowd calming in shrine districts; clinic corridor protected.","red"),
    T("High-risk contamination response at water points; sampling escorted; panic narratives suppressed.","red"),
    -- +8 added
    T("Apothecary batch check for adulterants; approved sources posted; corrective warnings issued.","green"),
    T("Community garden rota mediation; tool access rules posted; theft prevention signage installed.","green"),
    T("Midwife support circuit; recovery herbs issued; follow-up visits scheduled; privacy rules posted.","green"),
    T("Illness cluster mapping near wetlands; symptom intake standardized; clinic referrals issued.","yellow"),
    T("Contaminated produce recall support; vendor notices posted; refunds coordinated with Amicitia.","yellow"),
    T("Pest outbreak triage briefing; safe treatment guidance; livestock protection steps posted.","yellow"),
    T("Epidemic response support: quarantine boundaries marked; care kits staged; misinformation suppressed.","red"),
    T("Poisoning event response: antidote routing; source trace; suspect packet assembled; water access controlled.","red"),
  },

  ["Conclave Illuminara"] = {
    T("Night-sky lecture: explain calendars; reduce omen anxiety; post practical safety guidance.","green"),
    T("Quiet meditation ward at shrine; breathing protocols taught; de-escalation reminders posted.","green"),
    T("Lantern-route inspection; reflective markers placed; hazard steps flagged.","green"),
    T("Dream-space custody audit: offerings catalogued; safety signage posted; access rules clarified.","yellow"),
    T("Counterfeit moon-token investigation; vendor interviews; seizure log compiled; restitution note drafted.","yellow"),
    T("Controlled night gathering after rumor flare; calm-litany enforced; dispersal cadence rehearsed.","yellow"),
    T("Blackout safety drill for storm season: guides staged; warning ropes placed; shelter route posted.","yellow"),
    T("Emergency anti-panic messaging after ‘demonic sign’ claim; speaker scripts distributed; rumor sources logged.","red"),
    T("Escort for sensitive nocturnal rite during unrest; perimeter observers posted; clinic access protected.","red"),
    T("High-risk crowd-control during an overfull vigil; separation corridors held; reunification tent activated.","red"),
    -- +8 added
    T("Lunar-cycle briefing for stewards; ‘dark segment’ messaging standardized; posting schedule set.","green"),
    T("Archive copy check: calendars and proclamations reconciled; corrections issued; stamps verified.","green"),
    T("Diplomatic reading for visiting officials; neutral phrasing drafted; public reassurance script prepared.","green"),
    T("Forgery sweep for ‘Conclave decree’ sheets; originals photographed; printer path traced.","yellow"),
    T("Vigil capacity enforcement; entry tokens issued; exit lanes marked; medics staged.","yellow"),
    T("Rumor correction loop after eclipse claims; public broadcasts timed; panic buying deterred.","yellow"),
    T("Mass fear response after prolonged blackout; calm stations opened; shelter routes protected; patrol liaison engaged.","red"),
    T("Crisis interpretive bulletin during unrest: ‘cycle framing’ delivered hourly; retaliatory panic prevented.","red"),
  },

  ["Sanctum Vitalis"] = {
    T("Clinic hygiene audit: water barrels sealed; entry protocols posted; handwashing station checks logged.","green"),
    T("Vaccination schedule coordination with stewards; consent ledger reconciled; follow-up appointments scheduled.","green"),
    T("Triage coaching circle: calm scripts practiced; escalation triggers clarified; volunteer assignments posted.","green"),
    T("Food-handling inspection at market stalls; spoiled goods removed; corrective warnings issued.","yellow"),
    T("Quarantine rumor suppression: correct false ‘plague’ claim; stabilize clinic queues; calm stations opened.","yellow"),
    T("Vector mitigation near wetlands; standing water treated; guidance posted at dorms and shelters.","yellow"),
    T("Witness interviews after ‘poisoned well’ claim; evidence packet assembled; sampling escorted.","yellow"),
    T("Emergency fever center support: intake metering + calm stations established; separation corridor enforced.","red"),
    T("Crisis medical escort for officials through crowd; protected clinic route held; decoy timing staged.","red"),
    T("High-risk contamination response: water points shut temporarily; alternate distribution controlled; panic narratives suppressed.","red"),
    -- +8 added
    T("Spring/well inspection; contamination risks logged; repair tickets filed; public boil guidance posted if needed.","green"),
    T("Clinic staff rota stabilization; break schedule enforced; burnout flags logged; relief volunteers assigned.","green"),
    T("Worksite injury-prevention briefing; hazards recorded; employer compliance sign-off obtained.","green"),
    T("Respiratory illness surge triage; mask distribution staged; ventilation rules posted; clinic flow adjusted.","yellow"),
    T("Food-borne illness scare response; vendor recall notices; refund guidance; culprit investigation packet started.","yellow"),
    T("Overcrowded clinic gate plan; entry metering tightened; conflict scripts deployed; escort corridor protected.","yellow"),
    T("Mass casualty support: triage expansion; supply convoy prioritization; family intake; mortality ledger sealed.","red"),
    T("Waterborne outbreak response: quarantine lines; alternate water distribution; daily briefings; misinformation suppressed.","red"),
  },

  ["Temple Alabaster"] = {
    T("Public conduct rite at shrine; rules reissued; volunteers coached on nonviolent enforcement.","green"),
    T("Counseling circle for fearful households; practical aid referrals arranged; follow-up log kept.","green"),
    T("Relief custody check: inventory counted; seals verified; theft-prevention signage posted.","green"),
    T("Vendor compliance sweep for counterfeit purity seals; seizures logged; corrective warnings issued.","yellow"),
    T("Witness interviews after shrine vandalism; sworn statements taken; intimidation complaints logged.","yellow"),
    T("Night watch rotation on shrine steps after threat chatter; steward roster posted.","yellow"),
    T("Escort of sacred item to storage; chain-of-custody verified; route screening documented.","yellow"),
    T("Emergency crowd control during pilgrimage surge; lanes marked; calm stations opened; reunification tent active.","red"),
    T("Crisis shelter activation in stone precinct during storm; intake discipline enforced; clinic route protected.","red"),
    T("High-risk perimeter reinforcement after credible attack rumor; entry controlled; decoy dispersal route staged.","red"),
    -- +8 added
    T("Purity inspection of public wash points; contamination warnings posted; maintenance tickets filed.","green"),
    T("Serenity hour enforcement in market lanes; noise caps posted; disputes mediated; incident log updated.","green"),
    T("Sanitation compliance coaching for vendors; corrective steps issued; follow-up date scheduled.","green"),
    T("Crowd cooling protocol outside shrine gates; separation lanes held; harassment complaints intake opened.","yellow"),
    T("Contaminated goods sweep (dye/soap/food); items pulled; source traced; public reassurance posted.","yellow"),
    T("Minor desecration repair coordination; evidence preserved; restoration rite scheduled; offenders logged.","yellow"),
    T("Major desecration fallout: crowd calmed; arrests coordinated; restoration rites performed; retaliation deterred.","red"),
    T("Toxic spill response support: exclusion zone enforced; cleanup supervised; health referrals issued; messaging standardized.","red"),
  },

  ["Court of the Ironclad"] = {
    T("Volunteer discipline training; nonviolent restraint emphasized; reporting scripts practiced.","green"),
    T("Public order presence at shrine steps; etiquette enforced; minor disputes mediated on-site.","green"),
    T("Oath workshop: pledge cards sealed for civic stewards; compliance expectations posted.","green"),
    T("Route hardening walk: broken lamps and unsafe crossings flagged; repair tickets filed.","yellow"),
    T("Contraband confiscation support; evidence logged for Temple Bank clerks; custody chain verified.","yellow"),
    T("Night watch on canal bridges after sabotage chatter; checkpoint discipline enforced; escorts scheduled.","yellow"),
    T("Post-incident intimidation review: complaints investigated; corrective discipline applied; report filed.","yellow"),
    T("High-risk escort for witness leaving hearing; safehouse transfer arranged; decoy route used.","red"),
    T("Emergency deterrence patrol after riot flare; separation corridors opened; care stations deployed.","red"),
    T("Crisis reinforcement at clinic gate during panic surge; queue discipline established; dispersal cadence enforced.","red"),
    -- +8 added
    T("Endurance drill briefing; heat/fatigue limits posted; rotation enforcement logged.","green"),
    T("Equipment discipline check; missing items reconciled; chain-of-command sign-off obtained.","green"),
    T("Desert-procession conduct rules posted; hydration points marked; medical standby coordinated.","green"),
    T("Rival faction confrontation risk patrol; meeting sites mapped; entry controls tightened; warnings issued.","yellow"),
    T("Bloodmoon rumor suppression; discourage panic gatherings; authorized statement posted; agitator list started.","yellow"),
    T("Arrest processing support after brawl surge; evidence tagging enforced; witness separation maintained.","yellow"),
    T("Sectarian violence surge: unified deterrence posture; safe corridors held; ringleaders detained; reprisals prevented.","red"),
    T("Critical sabotage threat: depot perimeter locked; entry metering; night watches doubled; public notice issued.","red"),
  },

  ["Accord Concordia"] = {
    T("Council mediation between neighborhood elders; written concord signed; follow-up date scheduled.","green"),
    T("Public forum moderation; speaking order enforced; agitator removal avoided through de-escalation.","green"),
    T("Vendor-stall settlement: restitution terms logged; compliance expectations posted.","green"),
    T("Civic etiquette training for steward teams; de-escalation scripts practiced; lane protocol rehearsed.","yellow"),
    T("Inter-cult boundary meeting; shared space rules posted at shrine gates; signage installed.","yellow"),
    T("Rumor containment after inflammatory broadsides; corrective bulletin cycle launched; sources logged.","yellow"),
    T("Audit of district clerk office after complaint surge; corrective plan countersigned; retraining scheduled.","yellow"),
    T("Emergency truce enforcement during street clash; separation lines held; medical access protected.","red"),
    T("Crisis reconciliation hearing after riot; pledge collection + witness support; retaliation prevention enforced.","red"),
    T("High-risk mediation under red posture: rival leaders separated; agreement read publicly; dispersal routes staged.","red"),
    -- +8 added
    T("Harmony Gardens work party coordination; mixed crews paired; grievances logged; follow-up circle scheduled.","green"),
    T("Shared-meal hosting plan; seating map prevents rival clustering; steward assignments posted.","green"),
    T("Welcome rite for new migrants/work crews; support contacts listed; exploitation warnings posted.","green"),
    T("Feast sabotage risk triage; ingredient chain verified; kitchen access controlled; guard liaison engaged.","yellow"),
    T("Inter-guild boycott settlement; compromise pledge signed; enforcement stewards appointed; public notice issued.","yellow"),
    T("Youth rivalry cooling via structured games; chaperones assigned; penalties posted for violence.","yellow"),
    T("Emergency unity convocation after fatal clash; ceasefire sworn; escort corridors established; reprisals deterred.","red"),
    T("Mass panic calming centers opened; volunteer surge; hourly briefings delivered; rumor nodes suppressed.","red"),
  },

  ["Mystery of the Stygian Veil"] = {
    T("Funerary custody check: offerings catalogued; tomb precinct rules posted; candle/fire safety verified.","green"),
    T("Grief counseling circle; practical aid referrals arranged; follow-up home visits scheduled.","green"),
    T("Mortuary hygiene audit; disease-prevention protocols verified; sanitation failures logged.","green"),
    T("Rumor suppression after ‘restless dead’ claims; evidence bulletin issued; agitation triggers tracked.","yellow"),
    T("Escort for body transfer; route secured; witnesses logged; custody chain verified.","yellow"),
    T("Night vigil supervision to prevent stampede or retaliatory violence; separation corridor planned.","yellow"),
    T("Witness interviews after desecration; sworn statements sealed; intimidation complaints recorded.","yellow"),
    T("Crisis response after mass death incident: grief triage + order restoration; calm stations opened.","red"),
    T("Emergency calm stations at cemetery gate during panic; supervised dispersal coordinated; clinic access protected.","red"),
    T("High-risk memorial crowd control under red posture; perimeter held; reunification tent activated.","red"),
    -- +8 added
    T("Rite of transition for a recovering patient; symbolic veil-lifting; community support plan logged.","green"),
    T("Inheritance dispute mediation after death; fair division terms drafted; coercion checks recorded.","green"),
    T("Cemetery path safety inspection; uneven steps flagged; lantern markers placed; maintenance tickets filed.","green"),
    T("Dusk procession route reset after hazard; entry cadence rehearsed; pinch points staffed.","yellow"),
    T("Grave-robbery scare investigation support; patrol liaison; witness intake; rumor correction posted.","yellow"),
    T("Overcrowded vigil management; capacity limits posted; exit lanes marked; medics staged.","yellow"),
    T("After-violence mourning containment; safe corridors held; retaliation ban sworn; witness shielding arranged.","red"),
    T("Mass panic after ‘demonic figure’ report near tomb precinct; authoritative denial; agitator detention; calm stations expanded.","red"),
  },

  ["Sylvan Fellowship"] = {
    T("Forest-path maintenance; travel warnings posted for pilgrims; hazard markers refreshed.","green"),
    T("Wildlife safety briefing; reduce accidents on shrine trails; reporting chain posted.","green"),
    T("Ecological repair planning: volunteer crews scheduled; debris staging plan filed.","green"),
    T("Herb/timber vendor conduct audit; sustainable collection rules enforced; repeat violators logged.","yellow"),
    T("Brushfire-watch patrol; illegal burns suppressed; emergency water points marked.","yellow"),
    T("Mediation between trappers and villagers; shared schedule signed; conflict triggers identified.","yellow"),
    T("Rumor containment after ‘forest curse’ claim; corrective bulletin cycle run; agitator list started.","yellow"),
    T("Emergency shelter staging in forest precinct during storm; intake controlled; calm messaging enforced.","red"),
    T("Crisis search for missing pilgrim after fog; guides deployed; safe corridors opened.","red"),
    T("High-risk evacuation support under red weather alert; trail closures enforced; reunification tent activated.","red"),
    -- +8 added
    T("Trailhead sign refresh: safe routes marked; dangerous gullies flagged; escort contacts posted.","green"),
    T("Livestock safety day; grazing boundaries walked; injury checks; neighbor oaths exchanged.","green"),
    T("Waterway cleanup coordination; contamination risks logged; volunteer rota posted.","green"),
    T("Illegal poaching/logging inquiry; evidence gathered; offender descriptions logged; patrol liaison engaged.","yellow"),
    T("Flood/mud hazard reroute postings; bridge warnings issued; rescue staging areas marked.","yellow"),
    T("Farmer–rancher conflict triage; grazing calendar set; penalties defined; enforcement stewards assigned.","yellow"),
    T("Major flood response: shelter intake; animal rescue; public briefings; rumor suppression enforced.","red"),
    T("Violent land access dispute: containment support; arrests coordinated; restitution terms drafted; reprisals deterred.","red"),
  },

  ["Mystery of Red Mirth"] = {
    T("Festival conduct briefing; prevent brawls and dangerous dares; de-escalation scripts posted.","green"),
    T("Joy-warden patrol: intervene early in disputes; stabilize lines outside taverns and music halls.","green"),
    T("Volunteer steward training: safe celebration guidance and nonviolent intervention.","green"),
    T("Vendor compliance audit for intoxicants; counterfeit batches seized; sanitation notes issued.","yellow"),
    T("Crowd choreography for parade route; crush-risk minimized; pinch points marked.","yellow"),
    T("Rumor suppression after scandal broadsides; approved narrative posted; source stalls logged.","yellow"),
    T("Night watch at tavern row after violence chatter; calm messaging distributed; escorts staged.","yellow"),
    T("Emergency stabilization after riot flare; separation lanes + care stations deployed; clinic access protected.","red"),
    T("Crisis safe escort for a key witness leaving hearing; safehouse transfer arranged; decoy route used.","red"),
    T("High-risk crowd-control during a packed revel; dispersal cadence enforced; reunification tent activated.","red"),
    -- +8 added
    T("Mask/prop safety inspection for performers; sharp edges removed; permit list verified.","green"),
    T("Controlled wine dosing guidance posted; hydration points marked; refusal rights explained.","green"),
    T("Aftercare check for revelers; transport escorts staged; harassment complaints intake opened.","green"),
    T("Stage rigging sabotage check; inspection log filed; access limited; suspects noted.","yellow"),
    T("Brawl-prone venue warning and temporary closure protocol; staff trained; incident ledger updated.","yellow"),
    T("Parade route split after crush-risk alert; alternate route posted; crowd cadence rehearsed.","yellow"),
    T("Stampede incident response: triage lanes; family reunification; safety reforms mandated; public statement issued.","red"),
    T("Coordinated sabotage campaign response: permit freeze; targeted arrests; controlled messaging; patrol liaison engaged.","red"),
  },

  ["Rex Catonis"] = {
    T("Civic order proclamation at court square; conduct rules reissued; complaint intake organized.","green"),
    T("Docket triage for petty disputes; mediation attempted before formal hearing; outcomes logged.","green"),
    T("Steward training on lawful dispersal and calm messaging; escalation triggers clarified.","green"),
    T("Municipal fines ledger audit: correct corrupt entries; restitution schedule drafted.","yellow"),
    T("Vendor permit compliance sweep; counterfeit permits seized; corrective notices posted.","yellow"),
    T("Rumor suppression after ‘illegal decrees’ claim; clarifying bulletin posted; speaker scripts updated.","yellow"),
    T("Escort for court clerks during sensitive hearing; intimidation deterrence; safe route posted.","yellow"),
    T("Emergency order restoration after riot; curfew messaging + dispersal corridors; clinic access protected.","red"),
    T("Crisis protection of court archives after arson threat; perimeter posted; custody chain verified.","red"),
    T("High-risk courthouse crowd control under red posture; separation corridors held; arrests minimized.","red"),
    -- +8 added
    T("Permit renewal clinic; expired permits reissued; lawful signage posted; fine waivers granted for compliance.","green"),
    T("Public notice board audit; false postings removed; official stamps verified; clerk sign-off obtained.","green"),
    T("Restitution schedule review; payment plan adjusted; guarantors recorded; Temple Bank copy filed.","green"),
    T("Price gouging complaint sweep; violations documented; fines assessed; public deterrence notice posted.","yellow"),
    T("Curfew violation surge response; warning protocol standardized; repeat offenders flagged; incident log filed.","yellow"),
    T("Gang intimidation intake; victim protection options posted; suspect descriptions routed to Ironclad.","yellow"),
    T("Mass corruption scandal response: ledger seizure; official suspensions; prosecution packets assembled; public guidance issued.","red"),
    T("Coordinated violence response: unified command liaison; detention processing; court schedule triage; after-action report filed.","red"),
  },

  ["Sanctum Delphica"] = {
    T("Archive custody inspection: seals verified; storage conditions checked; humidity warnings posted.","green"),
    T("Scribe training on custody chain; convoy paperwork rehearsed; handoff scripts practiced.","green"),
    T("Pilgrim etiquette workshop at library shrine; quiet-zone enforced; lane discipline posted.","green"),
    T("Index confiscated pamphlets for signature motifs; correlation packet forwarded; source stalls logged.","yellow"),
    T("Witness interviews after shrine vandalism; sworn statements taken; intimidation complaints recorded.","yellow"),
    T("Doctrinal quarantine assistance: entry controls + rumor suppression; approved signage posted.","yellow"),
    T("Court packet assembly for desecration suspects; evidence collated; custody memo sealed.","yellow"),
    T("Night watch rotation at archive stacks following arson threat; entry controlled; escort-only rule applied.","red"),
    T("Escort sensitive artifact transfer; route denial markers deployed; decoy timing staged.","red"),
    T("Emergency custody lockdown after breach attempt; relocation plan activated; public narrative kept neutral.","red"),
    -- +8 added
    T("Forecast briefing for stewards: likely choke points listed; preventive signage posted; shift plan updated.","green"),
    T("Public ‘clarity notice’ explaining rumor patterns; discourage prophecy claims; practical steps appended.","green"),
    T("Queue triage workshop for clerks; intake categories standardized; escalation triggers defined.","green"),
    T("Forgery detection surge response; verification booth staged; suspect stamps cataloged; seizures logged.","yellow"),
    T("High-traffic archive day capacity rules enforced; entry tokens issued; silent zone posted; security liaison set.","yellow"),
    T("False omen bulletin cycle after sky-sign rumors; broadcasts timed; hoarding deterrence included.","yellow"),
    T("Archive fire incident response: document evacuation; custody chain preserved; public messaging controlled; arrests coordinated.","red"),
    T("Mass panic after forged warning decree: authoritative retraction posted; printer network pursued; calm stations opened.","red"),
  },

  ["Ordo Amicitia"] = {
    T("Kindness distribution at shrine steps; ledger reconciled; needs list updated for tomorrow.","green"),
    T("Family mediation after dispute; amity pledges collected; follow-up visits scheduled.","green"),
    T("Volunteer training: calm communication and nonviolent intervention; escalation scripts practiced.","green"),
    T("Clinic-queue kindness patrol; conflict prevention and assistance to elderly; complaints logged.","yellow"),
    T("Rumor containment after defamatory pamphlets; corrective bulletin cycle launched; source stalls mapped.","yellow"),
    T("Audit of relief supplies to prevent theft; custody seals verified; storage rules posted.","yellow"),
    T("Witness support for targeted volunteer; safe route arranged; intimidation complaints recorded.","yellow"),
    T("Emergency care stations during unrest; neutral aid posture announced; clinic corridor protected.","red"),
    T("Crisis grief counseling after fatal incident; aid referrals coordinated; retaliation pledges collected.","red"),
    T("High-risk shelter stabilization under red posture; intake controlled; reunification tent activated.","red"),
    -- +8 added
    T("Elder check-in circuit; medicine delivery; home repair requests logged; follow-up visits scheduled.","green"),
    T("School buddy program setup; mentors paired; attendance tracked; guardian contacts logged.","green"),
    T("Micro-grant assistance for small vendors; eligibility explained; Temple Bank receipts issued.","green"),
    T("Aid line surge plan; entry metering; high-need triage; conflict scripts deployed.","yellow"),
    T("Fraudulent charity collectors sweep; donations recovered; offenders documented; public warning posted.","yellow"),
    T("Harassment at aid stations response; escorts assigned; offenders barred; reports sealed.","yellow"),
    T("Disaster relief activation: shelter staffing; supply staging; daily reporting; rumor suppression enforced.","red"),
    T("Mass displacement response: registration booth; family reunification; trauma referrals; records sealed.","red"),
  },

  ["Temple Illuminata"] = {
    T("Illumination vigil: lantern discipline and public calm guidance posted; safe routes marked.","green"),
    T("Counseling for anxious households; referral paths established; follow-up log kept.","green"),
    T("Archive testimonies and signs; witness statements catalogued; custody rules posted.","green"),
    T("Night watch of sacred precinct; entry control enforced; conduct rules posted at gates.","yellow"),
    T("Omen bulletin: correct false ‘dark star’ claim; discourage panic gatherings; scripts distributed.","yellow"),
    T("Audit unsanctioned night gatherings; compliance restrictions issued; repeat venues logged.","yellow"),
    T("Post-incident narrative discipline; rumor sources mapped; correction bulletins deployed.","yellow"),
    T("Emergency messaging after ‘demonic symbol’ report; scripts distributed; calm stations opened.","red"),
    T("Crisis crowd dispersal after night surge; guidance routes opened; reunification tent active.","red"),
    T("High-risk escort for sensitive nocturnal rite during unrest; perimeter observers posted; decoy route used.","red"),
    -- +8 added
    T("Public symposium moderation; debate rules posted; minutes archived; speaker list verified.","green"),
    T("Clarity counseling for civic leaders; action plan sealed; follow-up check scheduled.","green"),
    T("Apprentice study circle; reading list issued; mentor pairing logged; conduct rules posted.","green"),
    T("Heckler disruption response at lecture; removals enforced; incident log filed; next session relocated.","yellow"),
    T("Forged ‘Temple order’ correction; official stamps verified; printer path traced; retraction posted.","yellow"),
    T("Threat triage against philosophers/teachers; security escort arranged; venue access restricted.","yellow"),
    T("Attack on lecture venue response: injuries triaged; perpetrators prosecuted; continuity plan issued; public calm statement posted.","red"),
    T("Citywide incitement campaign response: counter-messaging; arrests; curfew guidance; safe corridors protected.","red"),
  },

  ["Temple Aprobelle"] = {
    T("Shrine-leader briefing: weekly rumor-control cycle; clarifications posted; complaint intake organized.","green"),
    T("Grief-cadre home visits after accident; de-escalation coaching delivered; referrals filed.","green"),
    T("School immunization coordination: schedule posted; consent ledger reconciled; follow-up reminders issued.","green"),
    T("Clinic-queue stabilization drill: entry metering tested; conflict prevention scripts practiced.","yellow"),
    T("Behavior audit of district office after complaint surge; corrective training issued; sign-off obtained.","yellow"),
    T("Pattern-analysis intake: schism texts logged; signature correlation packet forwarded; printer stalls mapped.","yellow"),
    T("Anomaly-response dispatch after contamination claims: care paired with narrative discipline; panic triggers logged.","yellow"),
    T("Silencing-cadre activated after panic flare; controlled messaging + care stations deployed; retaliation pledges collected.","red"),
    T("Emergency stabilization in evacuation/fever center: calming rites + rumor suppression; clinic corridor protected.","red"),
    T("High-risk psychological stabilization after mass scare: rumor nodes neutralized; supervised dispersal enforced; evidence chain sealed.","red"),
    -- +8 added
    T("Speaker coaching for ward announcements; panic triggers removed; approved phrasing distributed.","green"),
    T("Trust survey intake at market edges; key grievances logged; referrals routed to Harmony Sanctum.","green"),
    T("School liaison check: bullying/harassment trend review; intervention plan filed; follow-up scheduled.","green"),
    T("Targeted pamphlet purge after printer ID; removal teams assigned; replacement postings issued; suspects logged.","yellow"),
    T("Crowd agitation forecast; patrol liaison; calm broadcast cadence set; escalation thresholds defined.","yellow"),
    T("Workplace intimidation response; protective escort plan; offender sanctions recommended; compliance checks scheduled.","yellow"),
    T("Mass panic containment: calm centers expanded; hourly briefings; agitator roundup coordinated; retaliatory impulses reduced.","red"),
    T("Post-attack trauma response: debrief circles; retaliation bans; witness relocation; compliance sweep scheduled.","red"),
  },
}

    --------------------------------------------------------------------------------
    -- 12.1) NOCTIC VAMPIRISM / NOCTIC-RABREV TASK INSERTS
    --
    -- These tasks add Noctic Vampirism and raw Noctic-Rabrev events to the cults
    -- most likely to intervene: dream, health, purification, wetland, funerary,
    -- hidden-knowledge, legal, charity, and counter-fraud orders.
    --------------------------------------------------------------------------------

    local function addCultTasks(cultName, list)
        tasksByCult[cultName] = tasksByCult[cultName] or {}
        for _, t in ipairs(list) do
            table.insert(tasksByCult[cultName], t)
        end
    end

    addCultTasks("Reverie Nebulous", {
        T("[[Noctic Vampirism]] dream-entanglement intake: affected households given sleep-boundary cards; severe nightmare cases referred to [[Temple_Aprobelle|Temple Aprobelle]].","green"),
        T("Noctic dream-circle for registered patients; blood-hunger language redirected into supervised journaling; family witnesses briefed.","green"),
        T("Nightmare cluster triage after suspected raw [[Noctic-Rabrev]] smoke exposure; trigger map compiled; clinic referrals issued.","yellow"),
        T("Shared-vision complaint linked to Noctic leaf use; dream narratives separated from rumor claims; speaker scripts distributed.","yellow"),
        T("Noctic trance-gathering compliance review; unsanctioned sleep rites suspended; repeat venues logged for Temple Bank follow-up.","yellow"),
        T("Crisis rest-ward activation after mass Noctic panic dream; supervised sleep zones opened; clinic corridor protected.","red"),
        T("Violent blood-hunger dream episode contained; families separated safely; witness shielding and trauma referrals arranged.","red"),
        T("High-risk dream-breach report involving suspected nocticine-Δ exposure; Aprobelle liaisons activated; public narrative held neutral.","red"),
    })

    addCultTasks("Sanctum Vitalis", {
        T("[[Noctic Vampirism]] clinic screen: photophobia, anemia, fever, lesions, and blood-craving symptoms logged; dietary guidance issued.","green"),
        T("Registered Noctic patient follow-up: milk, iron food, and blood-substitute stabilization plan checked; family care note filed.","green"),
        T("Raw [[Noctic-Rabrev]] exposure triage at wetland clinic; symptomatic patients separated from ordinary fever queue.","yellow"),
        T("Congenital Noctic case review; guardian consent ledger reconciled; lifelong monitoring schedule updated.","yellow"),
        T("Market illness cluster assessed for raw-leaf adulteration; sampling escorted; vendor recall notice prepared.","yellow"),
        T("Emergency hemorrhagic decline response in serious Noctic case; triage expansion, family shielding, and mortality ledger precautions enacted.","red"),
        T("Necrotic lesion cluster after unauthorized induction rite; quarantine boundary marked; cult-health evaluation ordered.","red"),
        T("High-risk fever center support after Noctic outbreak rumor; panic narratives suppressed while medical intake remains open.","red"),
    })

    addCultTasks("Temple Alabaster", {
        T("Refined nocticine tincture custody check; dosage ledger reconciled; [[Temple Bank of the Reformed Stripping Path|Temple Bank]] seal verified.","green"),
        T("Post-Eidolan recovery clinic review using licensed [[Noctic-Rabrev]] concentrate; patient response notes sealed under medical custody.","green"),
        T("Purity inspection of Noctic balms and tinctures; raw-leaf contamination warnings posted; suspect jars removed.","yellow"),
        T("Therapeutic nocticine distribution audit; storage seals verified; unauthorized substitutions routed to Golden Shadows.","yellow"),
        T("Contaminated Noctic medicine recall; affected households contacted; clinic-stabilization instructions posted.","yellow"),
        T("Emergency support for serious Noctic Vampirism collapse; calm ward opened; hemorrhage supplies and spiritual grounding teams staged.","red"),
        T("Crisis purification rite after counterfeit nocticine batch harms pilgrims; evidence preserved; public reassurance issued.","red"),
        T("High-risk medical custody transfer for unstable Noctic patient; decoy route used; receiving clinic countersigns sealed packet.","red"),
    })

    addCultTasks("Mystery of the Verdant Embrace", {
        T("[[Noctic-Rabrev]] field-blessing with safety lecture; flower and raw-leaf handling rules reissued to cultivators.","green"),
        T("Blood Orchard footpath inspection; leaf-storage huts checked; runoff risks and wetland access hazards logged.","green"),
        T("Noctic crop custody audit after missing leaf bundles; field stewards interviewed; harvest tally reconciled.","yellow"),
        T("Wetland illness cluster mapped near Noctic fields; raw-leaf exposure questions added to intake; clinic referrals issued.","yellow"),
        T("Flood-damaged Noctic storage shed inspected; wet leaves quarantined; safe flower product separated from restricted material.","yellow"),
        T("Emergency Blood Orchard closure after unauthorized raw-leaf distribution; field gates sealed; cultivator list turned over to Temple Bank.","red"),
        T("Poisoning event tied to unprocessed Noctic leaves; antidote routing, source trace, and water access controls initiated.","red"),
        T("High-risk wetland outbreak response: care kits staged, Noctic custody chain rebuilt, misinformation suppressed in shrine districts.","red"),
    })

    addCultTasks("Mystery of the Stygian Veil", {
        T("Funerary guidance for household of controlled Noctic patient; blood-offering limits explained; mourning schedule recorded.","green"),
        T("Noctic transformation counseling at cemetery gate; symbolic death language separated from unsafe raw-leaf use.","green"),
        T("Terminal Noctic vigil supervision; family witnesses logged; raw-leaf access barred during mourning rites.","yellow"),
        T("Blood-rite compliance check after ancestral-contact claims; permitted substitutes verified; coercion complaints recorded.","yellow"),
        T("Rumor suppression after ‘Noctic dead returning’ claim; evidence bulletin posted; graveyard panic triggers tracked.","yellow"),
        T("Crisis response after terminal Noctic transformation death; grief triage and crowd discipline established before nightfall.","red"),
        T("Emergency calm stations at tomb precinct after blood-hunger panic; supervised dispersal and clinic access protected.","red"),
        T("High-risk memorial for Noctic fatalities; retaliation prevention enforced; family shielding and witness support arranged.","red"),
    })

    addCultTasks("Order of the Umbral Oracle", {
        T("Noctic night-watch at shuttered shrine; sleepwalk reports logged; entry rules posted for anxious households.","green"),
        T("Covered-mirror guidance for suspected Noctic cases; families advised on safe vigils, naming restraint, and witness logs.","green"),
        T("Skødan-style mirror scare assessed after Noctic fever report; false-revelation claims documented without public amplification.","yellow"),
        T("Starless vigil compliance review; raw [[Noctic-Rabrev]] use questioned; repeat venues logged for Temple Bank follow-up.","yellow"),
        T("Dream-mapping dispute involving Noctic patient; testimony sealed; dangerous prophecy language corrected.","yellow"),
        T("Crisis nocturnal dispersal after mirror-haunting rumor; safe corridors opened; panic narratives suppressed.","red"),
        T("Serious Noctic fever episode during covered-mirror rite; patient removed safely; household witnesses debriefed.","red"),
        T("High-risk hidden-name panic in [[List of cities in Bassaridia Vaeringheim#Skøda|Skøda]]; Aprobelle and Sanctum Vitalis liaisons activated under seal.","red"),
    })

    addCultTasks("Conclave Illuminara", {
        T("Tarsican phase briefing for Noctic stewards; raw-leaf rites rescheduled away from high-anxiety night windows.","green"),
        T("Lunar calendar note issued for registered Noctic patients; dream disturbances and light-sensitivity triggers explained.","green"),
        T("Nocticine-Δ rumor correction after celestial alignment claims; hoarding and unsafe induction warnings posted.","yellow"),
        T("Moon-token and Noctic permit verification at night vigil; counterfeit ritual permissions seized.","yellow"),
        T("Controlled interpretation session after Noctic dream surge; public cycle-framing delivered to reduce panic.","yellow"),
        T("Emergency anti-panic bulletin after eclipse-linked Noctic outbreak claim; calm stations opened; clinic routes protected.","red"),
        T("High-risk nocturnal rite escort for registered Noctic patients; perimeter observers posted; false prophecy claims suppressed.","red"),
        T("Crisis interpretive response in Skødan mirror-vigil district; Tarsican language used to separate revelation from deception.","red"),
    })

    addCultTasks("Guild of Golden Shadows", {
        T("Quiet audit of [[Noctic-Rabrev]] market stalls; forged raw-leaf permissions logged; suspect brokers mapped.","green"),
        T("Noctic Fleet manifest cross-check; flower extract, tincture, and raw-leaf crates reconciled against Temple Bank seals.","green"),
        T("Undercover purchase of counterfeit Noctic induction permit; printer path traced; custody memo prepared.","yellow"),
        T("Raw-leaf diversion inquiry after Blood Orchard discrepancy; brokers interviewed; sealed attribution packet filed.","yellow"),
        T("Counterfeit nocticine tincture sweep; suspect vials seized; affected vendors routed to Temple Alabaster inspection.","yellow"),
        T("Night extraction of threatened Noctic witness; safe route screened; temporary housing arranged under seal.","red"),
        T("Major Noctic smuggling ring disruption: ledger seizure, broker detention support, and public market guidance coordinated.","red"),
        T("High-risk port-gate fraud surge involving raw Noctic leaf crates; inspection teams reinforced; evidence chain preserved.","red"),
    })

    addCultTasks("Temple Aprobelle", {
        T("[[Noctic Vampirism]] rumor-control briefing: discourage vigilante panic; explain registration, clinic access, and family support routes.","green"),
        T("Household anxiety visits after Noctic diagnosis; de-escalation coaching delivered; ostracism risks logged.","green"),
        T("Pattern-analysis intake for Noctic panic stories; dream claims, blood-hunger rumors, and raw-leaf reports separated.","yellow"),
        T("Noctic outbreak messaging cycle: official symptoms listed; false contagion claims corrected; clinic queues stabilized.","yellow"),
        T("Behavior audit after harassment of registered Noctic patients; corrective training issued; offenders warned.","yellow"),
        T("Silencing-cadre activated after Noctic panic flare; controlled messaging and care stations deployed before night crowds form.","red"),
        T("Emergency psychological stabilization after serious Noctic blood-hunger incident; retaliation bans and witness relocation arranged.","red"),
        T("High-risk mass scare after alleged Noctic attack; rumor nodes neutralized; supervised dispersal enforced; evidence chain sealed.","red"),
    })

    addCultTasks("Harmony Sanctum", {
        T("Family mediation after Noctic diagnosis; care duties, privacy expectations, and visitor rules written into household concord.","green"),
        T("Neighborhood explanation circle for registered Noctic household; stigma reduced; clinic and Temple Bank contacts posted.","green"),
        T("Market-lane calming after Noctic rumor; queue discipline restored; harassment complaints logged.","yellow"),
        T("Inter-family dispute over raw-leaf inheritance; compromise storage terms drafted; Temple Bank audit requested.","yellow"),
        T("Noctic clinic crowd-lane plan reviewed; patient privacy route and public waiting area separated.","yellow"),
        T("Emergency anti-reprisal pact after blood-hunger scare; escort corridors established; no-retaliation oaths collected.","red"),
        T("Mass grievance intake after Noctic outbreak panic; testimony queue metered; witness shielding arranged; outcomes logged.","red"),
        T("Crisis reconciliation hearing after violence against Noctic patient; restitution ledger initiated; family protection arranged.","red"),
    })

    addCultTasks("Azure Sentinel Sect", {
        T("Canal escort for licensed Noctic medical supplies; handoff signatures collected; chain-of-custody verified.","green"),
        T("Waterfront Noctic storage inspection after rain; flood exposure risks logged; damaged crates elevated.","green"),
        T("Storm-drain and wet-market sweep near Noctic vendors; runoff contamination warnings posted.","yellow"),
        T("Ferry-ramp crowd control during Noctic clinic transfer; privacy corridor and rescue lane maintained.","yellow"),
        T("Suspicious skiff check involving raw Noctic leaf bundles; manifests reviewed; contraband seized under seal.","yellow"),
        T("Emergency flood response at Noctic-Rabrev storehouse; restricted leaf material secured before dispersal through canals.","red"),
        T("Port lockdown support after Noctic smuggling violence; civilian zones cleared; clinic route protected.","red"),
        T("Mass casualty waterfront incident involving contaminated Noctic crates; triage staging and perimeter discipline enforced.","red"),
    })

    addCultTasks("Rex Catonis", {
        T("Noctic registration clinic: voluntary induction rules explained; lawful forms checked; appeal route posted.","green"),
        T("Public notice board update on raw [[Noctic-Rabrev]] restrictions; false decrees removed; clerk sign-off obtained.","green"),
        T("Hearing docket triage for unauthorized Noctic induction complaint; mediation attempted where lawful; evidence preserved.","yellow"),
        T("Raw-leaf permit compliance sweep; expired permissions suspended; corrective notices posted to shrine gates.","yellow"),
        T("Coerced induction allegation reviewed; victim protection options posted; suspect descriptions routed to Ironclad.","yellow"),
        T("Mass legal response after Noctic outbreak: unlawful vendors processed, custody ledgers seized, and public guidance issued.","red"),
        T("Coordinated violence response after Noctic panic; detention processing, court schedule triage, and after-action report filed.","red"),
        T("Emergency decree against unsafe raw-leaf distribution read publicly; clinic corridors protected during enforcement.","red"),
    })

    addCultTasks("Sanctum Delphica", {
        T("Noctic case archive update: diagnosis records, raw-leaf permissions, and family witness notes catalogued.","green"),
        T("Scribe training on Noctic custody language; distinguish raw leaf, flower extract, tincture, and nocticine concentrate.","green"),
        T("Doctrinal quarantine assistance after Noctic rumor; entry controls and approved signage posted.","yellow"),
        T("Forgery detection sweep for Noctic induction papers; suspect stamps catalogued; printer path traced.","yellow"),
        T("Witness packet assembled for raw-leaf desecration or coercive induction case; evidence collated and sealed.","yellow"),
        T("Emergency archive lockdown after Noctic registry breach; relocation plan activated; public narrative kept neutral.","red"),
        T("Mass panic after forged Noctic warning decree; authoritative retraction posted; printer network pursued; calm stations opened.","red"),
        T("High-risk transfer of Noctic medical ledgers; route denial markers deployed; decoy timing staged.","red"),
    })

    addCultTasks("Ordo Amicitia", {
        T("Milk and iron-food distribution for Noctic households; needs list updated; stigma-free delivery route assigned.","green"),
        T("Family support visits for congenital Noctic cases; caregiver relief scheduled; privacy rules posted.","green"),
        T("Aid line surge plan after Noctic diagnosis cluster; high-need triage and conflict scripts deployed.","yellow"),
        T("Fraudulent charity collectors using Noctic outbreak claims exposed; donations recovered; public warning posted.","yellow"),
        T("Shelter intake support for families displaced by Noctic panic; family reunification and trauma referrals recorded.","yellow"),
        T("Disaster relief activation after Noctic outbreak in wetland district; supply staging and rumor suppression enforced.","red"),
        T("Mass displacement response after raw-leaf scare; registration booth opened; care packages and witness shielding arranged.","red"),
        T("High-risk relief escort for registered Noctic patients leaving hostile neighborhood; safe housing arranged under seal.","red"),
    })

local function shouldAZSGoCovert(nextInt, sev, threat)
	-- Only under red posture and with a real threat record present
	if sev ~= "red" or not threat then return false end

	local u = urgencyScore(threat.urg)
	if u < 3 then return false end -- HIGH/CRITICAL only

	-- CRITICAL always qualifies; otherwise look for strong violence/sabotage signals
	local ev = string.lower(tostring(threat.event or ""))
	local signals =
		ev:match("sabot") or ev:match("arson") or ev:match("bomb") or ev:match("terror") or
		ev:match("assassin") or ev:match("hit") or ev:match("murder") or
		ev:match("insurgent") or ev:match("pirate") or ev:match("rogue")

	local qualifies = (u >= 4) or signals
	if not qualifies then return false end

	-- “Sometimes”: deterministic chance, higher for CRITICAL
	local chance = (u >= 4) and 25 or 15  -- percent
	return (nextInt() % 100) < chance
end

--------------------------------------------------------------------------------
-- 13) CITY PROFILES (bias order selection)
--------------------------------------------------------------------------------
local cityProfiles = {
	["Vaeringheim"]    = {weights={AUM=3,HSA=2,AZS=2,GGS=2,SVI=2,SDE=2,TAP=3}},
	["Somniumpolis"]   = {weights={RNB=3,SVI=2,GGS=2,TAP=3,AZS=1}},
	["Luminaria"]      = {weights={AUM=3,CON=2,HSA=2,TAP=2,SVI=1}},
	["Lunalis Sancta"] = {weights={SDE=3,CON=2,TAP=2,HSA=1}},
	["Delphica"]       = {weights={SDE=3,TAP=2,CON=1,SVI=1}},
	["Thermosalem"]    = {weights={SVI=2,TAP=2,AZS=2,HSA=1}},
	["Pyralis"]        = {weights={IGA=2,SVI=2,TAP=2,AZS=2,AUM=1}},
	["Keybir-Aviv"]    = {weights={AZS=3,TAP=2,GGS=2,HSA=1}},
	["Diamandis"]      = {weights={TAP=2,SVI=2,AUM=1,RNB=1,MIR=1}},
	["Tonar"]          = {weights={SDE=2,SVI=2,VDE=2,TAP=1,CICL=1}},
	["Bashkim"]        = {weights={VDE=3,SVI=2,TAP=1}},
	["Ourid"]          = {weights={VDE=3,SVI=2,TAP=1}},
	["Ardclach"]       = {weights={AZS=2,SVI=2,TAP=1,CON=1}},
}

local function getProfile(cityName)
	return cityProfiles[cityName] or {
		weights={AUM=1,HSA=1,IGA=1,CHS=1,GGS=1,AZS=1,RNB=1,EOF=1,UMB=1,VDE=1,CON=1,SVI=1,ALB=1,CICL=1,ACC=1,STY=1,SYL=1,MIR=1,CAT=1,SDE=1,AMI=1,ILL=1,TAP=1}
	}
end

--------------------------------------------------------------------------------
-- 14) ORDERS (missionary-capable cult list)
-- NOTE: These names must match GeneralPortOperations ritualCults list + Temple Aprobelle.
--------------------------------------------------------------------------------
local orders = {
	{key="AUM", name="Order of Aurora Mystica"},
	{key="HSA", name="Harmony Sanctum"},
	{key="IGA", name="Ignis Aeternum"},
	{key="CHS", name="Celestial Harmony Sect"},
	{key="GGS", name="Guild of Golden Shadows"},
	{key="AZS", name="Azure Sentinel Sect"},
	{key="RNB", name="Reverie Nebulous"},
	{key="EOF", name="Eon Fellowship"},
	{key="UMB", name="Order of the Umbral Oracle"},
	{key="VDE", name="Mystery of the Verdant Embrace"},
	{key="CON", name="Conclave Illuminara"},
	{key="SVI", name="Sanctum Vitalis"},
	{key="ALB", name="Temple Alabaster"},
	{key="CICL", name="Court of the Ironclad"},
	{key="ACC", name="Accord Concordia"},
	{key="STY", name="Mystery of the Stygian Veil"},
	{key="SYL", name="Sylvan Fellowship"},
	{key="MIR", name="Mystery of Red Mirth"},
	{key="CAT", name="Rex Catonis"},
	{key="SDE", name="Sanctum Delphica"},
	{key="AMI", name="Ordo Amicitia"},
	{key="ILL", name="Temple Illuminata"},
	{key="TAP", name="Temple Aprobelle"},
}

local orderByName = {}
for _, o in ipairs(orders) do orderByName[o.name] = o end

--------------------------------------------------------------------------------
-- 15) SEVERITY + ORDER/TASK CHOICE
--------------------------------------------------------------------------------
    --------------------------------------------------------------------------------
    -- 14.1) NOCTIC CITY / CULT WEIGHTING
    --
    -- Noctic Vampirism is more likely to appear where Noctic-Rabrev, Alperkin
    -- inheritance, dream rites, raw-leaf custody, or Skødan mirror-vigil customs
    -- are already locally important.
    --------------------------------------------------------------------------------

    local nocticCityRisk = {
        ["Somniumpolis"]    = 8,
        ["Odiferia"]        = 8,
        ["Erythros"]        = 7,
        ["Acheron"]         = 6,
        ["Norsolyra"]       = 6,
        ["Skøda"]           = 6,
        ["The Alpazkigz"]    = 6,
        ["Nexa"]            = 4,
        ["Pyralis"]         = 4,
        ["Vaeringheim"]     = 3,
        ["Jogi"]            = 3,
        ["Aurelia"]         = 3,
    }

    local nocticOrderBoost = {
        RNB = 4, -- Reverie Nebulous: dream entanglement, nightmares, trance
        SVI = 4, -- Sanctum Vitalis: clinic response, anemia, lesions, fever
        ALB = 3, -- Temple Alabaster: nocticine medicine and purity controls
        VDE = 4, -- Verdant Embrace: Noctic-Rabrev fields, wetlands, plant custody
        STY = 3, -- Stygian Veil: funerary rites, terminal transformation
        UMB = 3, -- Umbral Oracle: night rites, shadow, hidden revelation
        CON = 3, -- Conclave Illuminara: Tarsica, lunar timing, nocticines
        GGS = 3, -- Golden Shadows: smuggling, forged permits, counter-fraud
        TAP = 4, -- Temple Aprobelle: panic control, trauma, rumor suppression
        HSA = 2, -- Harmony Sanctum: family/community conflict stabilization
        SDE = 2, -- Sanctum Delphica: registries, documents, doctrine quarantine
        AMI = 2, -- Ordo Amicitia: relief for afflicted households
        AZS = 1, -- Azure Sentinel: canal/port custody and wetland movement
        CAT = 1, -- Rex Catonis: legal registration and enforcement
    }

    local nocticCitySpecificBoost = {
        ["Somniumpolis"] = {RNB=5, TAP=4, SVI=4, ALB=3, VDE=3},
        ["Odiferia"]    = {VDE=6, SVI=4, TAP=4, ALB=3, GGS=3},
        ["Erythros"]    = {CON=4, RNB=4, STY=3, TAP=3, SDE=2},
        ["Acheron"]     = {STY=6, SVI=3, ALB=3, UMB=3, TAP=3},
        ["Norsolyra"]   = {VDE=5, RNB=4, SVI=3, SYL=2, TAP=3},
        ["Skøda"]       = {UMB=6, CON=4, STY=4, SDE=3, TAP=3, GGS=2},
        ["The Alpazkigz"] = {VDE=4, STY=4, RNB=4, TAP=3, SVI=3},
        ["Jogi"]        = {GGS=3, MIR=2, TAP=3, SVI=2},
        ["Aurelia"]     = {CON=3, SDE=2, TAP=3, RNB=2},
        ["Vaeringheim"] = {GGS=3, TAP=3, SVI=2, ALB=2, CAT=2},
    }

    local function addNocticBoostsToWeights(weighted, seen, cityName)
        local risk = nocticCityRisk[cityName] or 0
        if risk <= 0 then return end

        local citySpecific = nocticCitySpecificBoost[cityName] or {}
        local riskBump = math.floor(risk / 2)

        for _, it in ipairs(weighted) do
            local base = nocticOrderBoost[it.key] or 0
            local localBoost = citySpecific[it.key] or 0
            if base > 0 or localBoost > 0 then
                it.w = it.w + base + localBoost + riskBump
            end
        end

        for key, base in pairs(nocticOrderBoost) do
            if not seen[key] then
                local localBoost = citySpecific[key] or 0
                if base > 0 or localBoost > 0 then
                    weighted[#weighted+1] = {key=key, w=base + localBoost + riskBump}
                    seen[key] = true
                end
            end
        end
    end
local function inferSeverity(cityTier, taskSev, threatUrg)
	local sev = tostring(taskSev or "green")
	if cityTier == "major" and sev == "green" then sev = "yellow" end
	if urgencyScore(threatUrg) >= 3 then
		sev = "red"
	elseif urgencyScore(threatUrg) == 2 and sev == "green" then
		sev = "yellow"
	end
	return sev
end

    local function pickOrder(nextInt, cityName, threat)
        local profile = getProfile(cityName)
        local weighted = {}
        local seen = {}

        for key, w in pairs(profile.weights or {}) do
            weighted[#weighted+1] = {key=key, w=tonumber(w) or 0}
            seen[key] = true
        end

        -- Noctic city bump: prefer the cults most likely to handle raw Noctic-Rabrev,
        -- Noctic Vampirism, dream disturbance, health evaluation, registration,
        -- smuggling, and family/community stabilization.
        addNocticBoostsToWeights(weighted, seen, cityName)

        -- Threat bump: prefer Aprobelle + safety/health + shadows.
        if threat and urgencyScore(threat.urg) >= 2 then
            for _, it in ipairs(weighted) do
                if it.key == "TAP" or it.key == "SVI" or it.key == "AZS" or it.key == "GGS" or it.key == "SDE" then
                    it.w = it.w + 2
                end
            end
        end

        local pickedKey = pickWeighted(nextInt, weighted).key

        for _, o in ipairs(orders) do
            if o.key == pickedKey then return o end
        end

        return orders[1]
    end

local function pickTask(nextInt, cultName, sev, usedIdx)
  local pool = tasksByCult[cultName] or tasksByCult["Harmony Sanctum"] or {}

  local weighted = {}
  for idx, t in ipairs(pool) do
    if not (usedIdx and usedIdx[idx]) then
      local w = 1
      if t.sev == sev then w = 4
      elseif sev == "red" and t.sev == "yellow" then w = 2
      elseif sev == "yellow" and t.sev == "green" then w = 2 end
      table.insert(weighted, {t=t, w=w, idx=idx})
    end
  end

  if #weighted == 0 then
    for idx, t in ipairs(pool) do
      local w = 1
      if t.sev == sev then w = 4
      elseif sev == "red" and t.sev == "yellow" then w = 2
      elseif sev == "yellow" and t.sev == "green" then w = 2 end
      table.insert(weighted, {t=t, w=w, idx=idx})
    end
  end

  if #weighted == 0 then
    return {text="Routine rites and civic support (no task pool configured).", sev="green"}, nil
  end

  local picked = pickWeighted(nextInt, weighted)
  return picked.t, picked.idx
end

--------------------------------------------------------------------------------
-- 16) TEMPLE BANK NOTES
--------------------------------------------------------------------------------
local bankNotes = {
	"Stipend disbursed after checklist verification; receipt countersigned by local steward.",
	"Voucher reconciliation complete; supplies logged and stored under dual-key protocol.",
	"Observer note: crowd discipline improved after posted guidance and steward coaching.",
	"Repair authorization issued; labor scheduled at off-peak hours.",
	"Custody ledger updated; medicines/artifacts sealed and moved to secure storage.",
	"Training memo filed; corrective instruction issued to volunteers for queue discipline.",
}

--------------------------------------------------------------------------------
-- 17) BUILD ONE CITY ROW
--------------------------------------------------------------------------------
local function buildCityRow(di, c, threatMap, includeThreat, showEcon, econSignals, ctx)
	local cityName = c.name
	local seed = hash31(string.format("mops:%d:%03d:%s", di.year, di.dayOfYear, cityName))
	local nextInt = lcg(seed)
	local th = includeThreat and threatMap and threatMap[cityName] or nil
        local o = pickOrder(nextInt, cityName, th)
        ctx.usedTasksByCult[o.name] = ctx.usedTasksByCult[o.name] or {}
        local used = ctx.usedTasksByCult[o.name]

        local threatUrg = th and th.urg or ""

        -- Preliminary severity gives pickTask a useful target before the exact
        -- task-driven severity is known.
        local prelimSev = "green"
        if c.tier == "major" then prelimSev = "yellow" end
        if urgencyScore(threatUrg) >= 3 then
            prelimSev = "red"
        elseif urgencyScore(threatUrg) == 2 and prelimSev == "green" then
            prelimSev = "yellow"
        end

        local baseTask, pickedIdx = pickTask(nextInt, o.name, prelimSev, used)
        if pickedIdx then used[pickedIdx] = true end

        local sev = inferSeverity(c.tier, baseTask.sev, threatUrg)

	-- WX overlay
	local opsBadge, wxData = opsCell(cityName, di.year, di.dayOfYear)
	sev = bumpSevWeather(sev, wxData)
	local taskText = baseTask.text .. weatherTaskOverlay(wxData)

	-- AZS special case: rare clandestine/assassin operations under severe threat
	if o.key == "AZS" and shouldAZSGoCovert(nextInt, sev, th) then
		local covert = pickFromList(nextInt, azsCovertOps, nil)
		if covert and covert.text then
			taskText = covert.text .. weatherTaskOverlay(wxData)
			sev = "red"
		end
	end

	-- unit
	local unitName = pickOrgUnit(nextInt, sev)
	local unitMeta = org[unitName]
	local unitIndex = (nextInt() % 12) + 1
	local unitCode = string.format("%s-%s%d", o.key, unitMeta.code, unitIndex)

	-- bank note
	local bank = pickFromList(nextInt, bankNotes, nil)

	-- econ
	local econ = ""
	if showEcon and econSignals and econSignals[cityName] then
		econ = econSignals[cityName].summary or ""
	end

	return {
		style = sevStyle(sev),
		date = di.text,
		city = string.format("%s %s", getCityFlagMarkup(cityName), cityLink(cityName)),
		region = c.region,
		ops = opsBadge,
		order = getCultFlagMarkup(o.name) .. cultLink(o.name),
		unit = string.format("%s (%d) [%s]", unitName, unitMeta.size, unitCode),
		task = taskText,
		bank = bank,
		threat = (includeThreat and th and th.event) and th.event or "",
		threatUrg = (includeThreat and th and th.urg) and th.urg or "",
		sev = sev,
		econ = econ,
	}
end

--------------------------------------------------------------------------------
-- 18) MAIN TABLE
--------------------------------------------------------------------------------
function p.makeTable(frame)
	local args = (frame and frame.args) or {}
	local regionFilter = tostring(args.region or "All")
	local showLegend = tostring(args.showlegend or "yes"):lower() ~= "no"
	local includeThreat = tostring(args.includeThreat or "no"):lower() == "yes"
	local showEcon = tostring(args.showEcon or "no"):lower() == "yes"
	local limit = tonumber(args.limit or "")
	local di = getDateInfo()

	-- Threat map (only if requested)
	local threatMap = {}
	if includeThreat then
		local ok, rel = pcall(require, "Module:ReligiousEvents")
		if ok and rel and type(rel.makeTable) == "function" then
			threatMap = parseReligiousEventsTable(rel.makeTable())
		end
	end

	-- Econ signals (expensive; only if requested)
	local econSignals = {}
	if showEcon then
		econSignals = getEconSignals()
	end

	local out = {}
	table.insert(out, "{| class='wikitable sortable'")
	local header = "! style='white-space:nowrap;' | Date !! City !! Region !! Ops Alert !! Mystery (Cult) !! Unit !! Tasking"
	if showEcon then header = header .. " !! Economic signal" end
	header = header .. " !! Temple Bank Notes"
	if includeThreat then header = header .. " !! Threat Watch" end
	header = header .. " !! Severity"
	table.insert(out, header)

	local count = 0
	for _, c in ipairs(cityOrder) do
		if regionPass(regionFilter, c.region) then
			local row = buildCityRow(di, c, threatMap, includeThreat, showEcon, econSignals, ctx)
			table.insert(out, "|-" .. row.style)
			local line = string.format("| %s || %s || %s || %s || %s || %s || %s",
				row.date, row.city, row.region, row.ops, row.order, row.unit, row.task
			)
			if showEcon then line = line .. " || " .. (row.econ ~= "" and row.econ or "n/a") end
			line = line .. " || " .. row.bank
			if includeThreat then
				local threatCell = (row.threat ~= "" and (row.threat .. (row.threatUrg ~= "" and (" ("..row.threatUrg..")") or ""))) or "No reports / n.a."
				line = line .. " || " .. threatCell
			end
			line = line .. " || " .. row.sev
			table.insert(out, line)

			count = count + 1
			if limit and count >= limit then break end
		end
	end

	table.insert(out, "|}")

	if showLegend then
		table.insert(out, "\n<div style='margin-top:0.5em; font-size:90%;'>")
		table.insert(out, "<b>Legend:</b> ")
		table.insert(out, "<span style='background:#d4edda;padding:2px 6px;border:1px solid #c3e6cb;'>Green</span> = Routine rites / civic support&nbsp; ")
		table.insert(out, "<span style='background:#fff3cd;padding:2px 6px;border:1px solid #ffeeba;'>Yellow</span> = Heightened oversight / rumor control / targeted intervention&nbsp; ")
		table.insert(out, "<span style='background:#f8d7da;padding:2px 6px;border:1px solid #f5c6cb;'>Red</span> = Crisis response / unrest / outbreak / high-risk operations")
		table.insert(out, "<br/>Ops Alert badge reflects forecast-driven operational risk and aligns with War League / Hatch posture.")
		table.insert(out, "<br/>For overseas deployments please see [[Bassaridian_involvement_in_Corum#Corumian_Missionary_Deployment_Reports|Corumian Missionary Deployment Reports]].")
		table.insert(out, "</div>")
	end

	if di.calendarEvent and di.calendarEvent ~= "" then
		table.insert(out, string.format("\n<div style='margin-top:0.5em; font-size:90%%;'><b>Calendar note:</b> %s</div>", di.calendarEvent))
	end

	return table.concat(out, "\n")
end

--------------------------------------------------------------------------------
-- 19) SINGLE CITY VIEW
--------------------------------------------------------------------------------
function p.makeCity(frame)
	local args = (frame and frame.args) or {}
	local city = tostring(args.city or "")
	if city == "" then return "''Error: city parameter required.''" end
	if not citySet[city] then return "''Error: unknown city (must match canonical name).''" end
	local includeThreat = tostring(args.includeThreat or "no"):lower() == "yes"
	local showEcon = tostring(args.showEcon or "no"):lower() == "yes"

	local di = getDateInfo()

	local threatMap = {}
	if includeThreat then
		local ok, rel = pcall(require, "Module:ReligiousEvents")
		if ok and rel and type(rel.makeTable) == "function" then
			threatMap = parseReligiousEventsTable(rel.makeTable())
		end
	end
	local econSignals = {}
	if showEcon then econSignals = getEconSignals() end

	local region, tier = "Core", "minor"
	for _, c in ipairs(cityOrder) do
		if c.name == city then region, tier = c.region, c.tier break end
	end

	local row = buildCityRow(di, {name=city, region=region, tier=tier}, threatMap, includeThreat, showEcon, econSignals)
	local out = {}
	table.insert(out, "{| class='wikitable'")
	local header = "! Date !! City !! Region !! Ops Alert !! Mystery (Cult) !! Unit !! Tasking"
	if showEcon then header = header .. " !! Economic signal" end
	header = header .. " !! Temple Bank Notes"
	if includeThreat then header = header .. " !! Threat Watch" end
	header = header .. " !! Severity"
	table.insert(out, header)
	table.insert(out, "|-" .. row.style)

	local line = string.format("| %s || %s || %s || %s || %s || %s || %s",
		row.date, row.city, row.region, row.ops, row.order, row.unit, row.task
	)
	if showEcon then line = line .. " || " .. (row.econ ~= "" and row.econ or "n/a") end
	line = line .. " || " .. row.bank
	if includeThreat then
		local threatCell = (row.threat ~= "" and (row.threat .. (row.threatUrg ~= "" and (" ("..row.threatUrg..")") or ""))) or "No reports / n.a."
		line = line .. " || " .. threatCell
	end
	line = line .. " || " .. row.sev
	table.insert(out, line)
	table.insert(out, "|}")
	return table.concat(out, "\n")
end

--------------------------------------------------------------------------------
-- 20) ORDER-ONLY VIEW
--------------------------------------------------------------------------------
function p.makeOrder(frame)
	local args = (frame and frame.args) or {}
	local wanted = tostring(args.order or "")
	if wanted == "" then
		return "''Error: order parameter required (use exact order name).''"
	end
	local wantedOrder = orderByName[wanted]
	if not wantedOrder then
		return "''Error: unknown order name (must match module order names).''"
	end
	local includeThreat = tostring(args.includeThreat or "no"):lower() == "yes"
	local showEcon = tostring(args.showEcon or "no"):lower() == "yes"

	local di = getDateInfo()

	local threatMap = {}
	if includeThreat then
		local ok, rel = pcall(require, "Module:ReligiousEvents")
		if ok and rel and type(rel.makeTable) == "function" then
			threatMap = parseReligiousEventsTable(rel.makeTable())
		end
	end
	local econSignals = {}
	if showEcon then econSignals = getEconSignals() end

	local out = {}
	table.insert(out, "{| class='wikitable sortable'")
	local header = "! Date !! City !! Region !! Ops Alert !! Unit !! Tasking"
	if showEcon then header = header .. " !! Economic signal" end
	header = header .. " !! Temple Bank Notes"
	if includeThreat then header = header .. " !! Threat Watch" end
	header = header .. " !! Severity"
	table.insert(out, header)

	for _, c in ipairs(cityOrder) do
		local row = buildCityRow(di, c, threatMap, includeThreat, showEcon, econSignals)
		-- Compare by cultLink target (stable) rather than raw text
		if row.order:find(cultLink(wantedOrder.name), 1, true) or row.order:find(wantedOrder.name, 1, true) then
			table.insert(out, "|-" .. row.style)
			local line = string.format("| %s || %s || %s || %s || %s || %s",
				row.date, row.city, row.region, row.ops, row.unit, row.task
			)
			if showEcon then
				line = line .. " || " .. (row.econ ~= "" and row.econ or "n/a")
			end
			line = line .. " || " .. row.bank
			if includeThreat then
				local threatCell = (row.threat ~= "" and (row.threat .. (row.threatUrg ~= "" and (" ("..row.threatUrg..")") or ""))) or "No reports / n.a."
				line = line .. " || " .. threatCell
			end
			line = line .. " || " .. row.sev
			table.insert(out, line)
		end
	end

	table.insert(out, "|}")
	return table.concat(out, "\n")
end

return p