diff --git a/crates/ghostlight-dungeon/src/assessor.rs b/crates/ghostlight-dungeon/src/assessor.rs index 061c7b4..4802b78 100644 --- a/crates/ghostlight-dungeon/src/assessor.rs +++ b/crates/ghostlight-dungeon/src/assessor.rs @@ -69,6 +69,7 @@ impl ActionAssessor { }) }) .collect(); + let information_facts = available_information_facts(campaign, actor); let allowed_references = allowed_references(campaign, actor); let agency_guidance = action_agency_guidance(&campaign.player_actor_id, &intent.actor_id); let mut schema = serde_json::to_value(schema_for!(AssessmentProposal))?; @@ -82,7 +83,7 @@ impl ActionAssessor { "maximum":10 }); let base_prompt = format!( - "OUTPUT JSON SCHEMA (follow exactly):\n{}\n\nAssess an attempted effect, not whether words can be spoken. Impossible actions are inadmissible and receive bargains, not a roll. Choose DC only from 5,10,15,20,25,30. Every modifier reference must be copied exactly from ALLOWED REFERENCES. Modifier total is capped at +/-10. Never grant capability, custody, access, knowledge, or spatial reach absent from state. State concrete success, mixed, and failure consequences and a bounded effect ceiling. Outcome deltas may only name actor IDs copied exactly from PRESENT ACTORS, change their conditions or relationships, move only the acting actor along an existing route, advance existing clocks, or change existing institution posture. When an outcome directly reveals information to the acting actor, actor_knowledge_additions must contain the specific observed finding as a player-readable natural-language declarative statement, never a fact ID, key, slug, or label. Strong and ordinary success share one visible stake, so give them identical knowledge additions. The runtime binds each exact finding into the player-visible stake; do not spend prose repeating it solely for formatting. Findings become provisional branch facts on commit, so do not invent remote events, hidden actors, unsupported proper nouns, or conclusions beyond the effect ceiling. Keep a delta empty only when the outcome truly has no canonical state change.\nAGENCY BOUNDARY:\n{}\nPLAYER ACTOR ID:\n{}\nINTENT:\n{}\nACTOR:\n{}\nLOCATION:\n{}\nPRESENT ACTORS:\n{}\nVISIBLE INSTITUTIONS:\n{}\nALLOWED REFERENCES:\n{}", + "OUTPUT JSON SCHEMA (follow exactly):\n{}\n\nAssess an attempted effect, not whether words can be spoken. Impossible actions are inadmissible and receive bargains, not a roll. Choose DC only from 5,10,15,20,25,30. Every modifier reference must be copied exactly from ALLOWED REFERENCES. Modifier total is capped at +/-10. Never grant capability, custody, access, knowledge, or spatial reach absent from state. State concrete success, mixed, and failure consequences and a bounded effect ceiling. Outcome deltas may only name actor IDs copied exactly from PRESENT ACTORS, change their conditions or relationships, move only the acting actor along an existing route, advance existing clocks, or change existing institution posture. Informational outcomes may reveal only an exact statement copied from AVAILABLE INFORMATION FACTS; they never create a new fact. A location-discoverable fact may be added only to the acting actor. A fact already known by the acting actor may instead be communicated to another present actor. actor_knowledge_additions contains the player-readable statement, never a fact ID, key, slug, or label. Strong and ordinary success share one visible stake, so give them identical knowledge additions. The runtime binds each exact finding into the player-visible stake; do not spend prose repeating it solely for formatting. If no supplied fact supports the intended discovery or disclosure, leave knowledge deltas empty and make the limitation explicit in the stakes or mark the attempt inadmissible. Never invent remote events, hidden actors, unsupported proper nouns, or conclusions beyond the effect ceiling. Keep a delta empty only when the outcome truly has no canonical state change.\nAGENCY BOUNDARY:\n{}\nPLAYER ACTOR ID:\n{}\nINTENT:\n{}\nACTOR:\n{}\nLOCATION:\n{}\nPRESENT ACTORS:\n{}\nVISIBLE INSTITUTIONS:\n{}\nAVAILABLE INFORMATION FACTS:\n{}\nALLOWED REFERENCES:\n{}", serde_json::to_string(&schema)?, agency_guidance, campaign.player_actor_id, @@ -91,6 +92,7 @@ impl ActionAssessor { serde_json::to_string(location)?, serde_json::to_string(&present_actors)?, serde_json::to_string(&visible_institutions)?, + serde_json::to_string(&information_facts)?, serde_json::to_string(&allowed_references)? ); let snapshot_binding = format!("campaign:{}:revision:{}", campaign.id, campaign.revision); @@ -139,7 +141,7 @@ impl ActionAssessor { .and_then(|value| serde_json::to_string(value).ok()) .unwrap_or_else(|| "unavailable".into()); correction = format!( - "\n\nLOCAL VALIDATOR REJECTED THE PREVIOUS ASSESSMENT: {error}\nPREVIOUS ASSESSMENT:\n{rejected}\nReturn a corrected complete assessment against the same snapshot. Copy every modifier reference from ALLOWED REFERENCES exactly; omit a modifier rather than paraphrasing or inventing its reference. Copy every actor and destination ID exactly from the supplied state. Bind specific directly observed findings only to the acting actor; strong and ordinary success must use identical knowledge additions. Otherwise leave the typed delta empty." + "\n\nLOCAL VALIDATOR REJECTED THE PREVIOUS ASSESSMENT: {error}\nPREVIOUS ASSESSMENT:\n{rejected}\nReturn a corrected complete assessment against the same snapshot. Copy every modifier reference from ALLOWED REFERENCES exactly; omit a modifier rather than paraphrasing or inventing its reference. Copy every actor and destination ID exactly from the supplied state. Every knowledge addition must copy one exact statement from AVAILABLE INFORMATION FACTS and obey its access mode; strong and ordinary success must use identical knowledge additions. Otherwise leave the typed delta empty." ); } Err(error) => { @@ -235,14 +237,43 @@ fn allowed_references(campaign: &Campaign, actor: &crate::domain::ActorState) -> for id in campaign.institutions.keys() { refs.insert(format!("institution:{id}")); } - for id in campaign.facts.keys() { - refs.insert(format!("fact:{id}")); + for fact in available_information_facts(campaign, actor) { + if let Some(id) = fact.get("id").and_then(serde_json::Value::as_str) { + refs.insert(format!("fact:{id}")); + } } for id in &campaign.branch_origin.evidence_receipt_ids { refs.insert(id.clone()); } refs } + +fn available_information_facts( + campaign: &Campaign, + actor: &crate::domain::ActorState, +) -> Vec { + campaign + .facts + .values() + .filter_map(|fact| { + let access = if actor.knowledge.contains(&fact.statement) { + "known_by_actor" + } else if fact + .discoverable_at_location_ids + .contains(&actor.location_id) + { + "discoverable_here" + } else { + return None; + }; + Some(serde_json::json!({ + "id": fact.id, + "statement": fact.statement, + "access": access, + })) + }) + .collect() +} fn validate_proposal(p: &AssessmentProposal, allowed: &BTreeSet) -> Result<()> { if ![5, 10, 15, 20, 25, 30].contains(&p.dc) { return Err(anyhow!("assessor chose invalid DC")); @@ -310,19 +341,38 @@ pub(crate) fn validate_effect( } } for (actor_id, additions) in &effect.actor_knowledge_additions { - if actor_id != &acting_actor.id - || additions.is_empty() + let target = campaign + .actors + .get(actor_id) + .ok_or_else(|| anyhow!("outcome knowledge target vanished"))?; + let invalid_finding = additions.iter().find(|finding| { + let Some(fact) = campaign + .facts + .values() + .find(|fact| fact.statement == finding.as_str()) + else { + return true; + }; + let accessible = if actor_id == &acting_actor.id { + fact.discoverable_at_location_ids + .contains(&acting_actor.location_id) + } else { + acting_actor.knowledge.contains(*finding) + }; + !accessible || target.knowledge.contains(*finding) + }); + if additions.is_empty() || additions.len() > 4 || additions.iter().any(|finding| { finding.trim().is_empty() || finding.chars().count() > 500 || looks_like_identifier(finding) - || acting_actor.knowledge.contains(finding) || !stake.contains(finding) }) + || invalid_finding.is_some() { return Err(anyhow!( - "outcome knowledge must be a new bounded natural-language finding, directly observed by the acting actor and visible verbatim in its stake" + "outcome knowledge must copy an existing accessible WorldFact statement: a location-discoverable fact may go only to the acting actor, while another present actor may receive only a fact already known by the acting actor; every finding must be new to its recipient and visible verbatim in its stake" )); } } diff --git a/crates/ghostlight-dungeon/src/compiler.rs b/crates/ghostlight-dungeon/src/compiler.rs index 498183d..5dfa01e 100644 --- a/crates/ghostlight-dungeon/src/compiler.rs +++ b/crates/ghostlight-dungeon/src/compiler.rs @@ -303,7 +303,7 @@ impl WorldCompiler { scoped_evidence ); let base_prompt = format!( - "{shared_prefix}Compile a bounded playable region with stable topology, local actors, populations, clocks, and only those remote institutions that have a direct causal relationship to this requested start. SCOPED EVIDENCE contains direct_seed witnesses only. Setting-background and excluded witnesses remain visible in the approval coverage but are deliberately absent here: they cannot donate cast, incidents, clocks, location state, goals, or institutional posture to this branch. When direct evidence cannot ground a requested local detail, keep the local cast sparse, mark reversible texture provisional_local, and list the material gap instead of borrowing a nearby story. Do not eagerly invent remote settlements, routes, or people. Emit only supported canon facts. A canon_baseline fact must cite one or more exact receipt_id values printed in SCOPED EVIDENCE whose witnesses directly support the whole statement. Never label an invented proper noun canon. The player location and every actor location must exist. Every route destination must exist, travel time must be positive, clocks need positive thresholds, and the player id must be unique. Actor relationship map keys must copy exact actor or institution IDs declared in this candidate, never display names, roles, groups, or location IDs. Represent populations that can act collectively (villages, crews, crowds, departments, corporations) as gestalt Personas. Seed a small roster of plausible durable member identities for people the player may encounter; member deltas contain only departures from their gestalt baseline and begin dematerialized. Do not duplicate a gestalt member in actors. Keep named plot-critical people as ordinary actors. Every gestalt home location and member gestalt reference must exist. Do not emit agency profiles or relations; those are compiled from the exact validated subject roster in the next stage." + "{shared_prefix}Compile a bounded playable region with stable topology, local actors, populations, clocks, and only those remote institutions that have a direct causal relationship to this requested start. SCOPED EVIDENCE contains direct_seed witnesses only. Setting-background and excluded witnesses remain visible in the approval coverage but are deliberately absent here: they cannot donate cast, incidents, clocks, location state, goals, or institutional posture to this branch. When direct evidence cannot ground a requested local detail, keep the local cast sparse, mark reversible texture provisional_local, and list the material gap instead of borrowing a nearby story. Do not eagerly invent remote settlements, routes, or people. Emit only supported canon facts. A canon_baseline fact must cite one or more exact receipt_id values printed in SCOPED EVIDENCE whose witnesses directly support the whole statement. Never label an invented proper noun canon. Facts that an actor can uncover through an admitted local observation must exist before play and list the exact discoverable_at_location_ids where that observation is possible. Seed enough branch_local or provisional_local discoverable facts to make the requested opening pressure and immediate goal actionable; the later action assessor can reveal an existing fact but cannot invent one. Facts that are private history or not directly observable have an empty discovery-location set. The player location and every actor location must exist. Every route destination and fact discovery location must exist, travel time must be positive, clocks need positive thresholds, and the player id must be unique. Actor relationship map keys must copy exact actor or institution IDs declared in this candidate, never display names, roles, groups, or location IDs. Represent populations that can act collectively (villages, crews, crowds, departments, corporations) as gestalt Personas. Seed a small roster of plausible durable member identities for people the player may encounter; member deltas contain only departures from their gestalt baseline and begin dematerialized. Do not duplicate a gestalt member in actors. Keep named plot-critical people as ordinary actors. Every gestalt home location and member gestalt reference must exist. Do not emit agency profiles or relations; those are compiled from the exact validated subject roster in the next stage." ); let schema = serde_json::to_value(schema_for!(CompiledSeed))?; let sources = receipt_ids_for_coverage(&receipts, &evidence_coverage); @@ -637,7 +637,7 @@ impl WorldCompiler { .await?; let snapshot = format!("campaign:{}:revision:{}", campaign.id, campaign.revision); let base_prompt = format!( - "Compile only the requested bounded destination region. Every new location id must be new. At least one new location must route back to origin id {} with a positive travel time. Do not rewrite existing geography. CAMPAIGN LOCATIONS:\n{}\nREQUEST:\n{}\nEVIDENCE:\n{}", + "Compile only the requested bounded destination region. Every new location id must be new. At least one new location must route back to origin id {} with a positive travel time. Do not rewrite existing geography. Any locally observable clue must already exist as a fact and list exact discoverable_at_location_ids from the combined existing and new topology; later action assessment can reveal facts but cannot invent them. CAMPAIGN LOCATIONS:\n{}\nREQUEST:\n{}\nEVIDENCE:\n{}", origin_location_id, serde_json::to_string(&campaign.locations)?, destination_request, @@ -1398,6 +1398,35 @@ pub fn validate_region_expansion( if !attached { return Err(anyhow!("destination expansion is not attached to origin")); } + let existing_fact_ids = campaign.facts.keys().collect::>(); + let mut new_fact_ids = BTreeSet::new(); + let mut fact_statements = campaign + .facts + .values() + .map(|fact| fact.statement.clone()) + .collect::>(); + for fact in &expansion.facts { + if fact.id.trim().is_empty() + || existing_fact_ids.contains(&fact.id) + || !new_fact_ids.insert(fact.id.clone()) + || fact.statement.trim().is_empty() + || !fact_statements.insert(fact.statement.clone()) + { + return Err(anyhow!( + "destination expansion facts must have new IDs and non-empty unique statements" + )); + } + if fact + .discoverable_at_location_ids + .iter() + .any(|id| !known(id)) + { + return Err(anyhow!( + "destination expansion fact {} has an unknown discovery location", + fact.id + )); + } + } Ok(()) } @@ -1993,6 +2022,29 @@ pub fn validate_campaign_seed(c: &Campaign) -> Result<()> { } } } + let mut fact_statements = BTreeSet::new(); + for fact in c.facts.values() { + if fact.statement.trim().is_empty() || !fact_statements.insert(fact.statement.clone()) { + return Err(anyhow!( + "world facts must have non-empty unique statements; rejected fact {}", + fact.id + )); + } + let invalid_locations = fact + .discoverable_at_location_ids + .iter() + .filter(|id| !c.locations.contains_key(*id)) + .cloned() + .collect::>(); + if !invalid_locations.is_empty() { + return Err(anyhow!( + "fact {} is discoverable at unknown locations {:?}; valid location IDs={:?}", + fact.id, + invalid_locations, + c.locations.keys().collect::>() + )); + } + } for clock in c.clocks.values() { if clock.threshold == 0 || clock.progress > clock.threshold { return Err(anyhow!("clock {} is invalid", clock.id)); diff --git a/crates/ghostlight-dungeon/src/domain.rs b/crates/ghostlight-dungeon/src/domain.rs index 8ced0c8..a7a5ebb 100644 --- a/crates/ghostlight-dungeon/src/domain.rs +++ b/crates/ghostlight-dungeon/src/domain.rs @@ -538,6 +538,11 @@ pub struct WorldFact { pub statement: String, pub scope: FactScope, pub evidence_receipt_ids: Vec, + /// Locations whose immediate environment can expose this fact through an + /// admitted informational attempt. Empty means the fact is not directly + /// discoverable from occupancy alone. + #[serde(default)] + pub discoverable_at_location_ids: BTreeSet, } #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] diff --git a/crates/ghostlight-dungeon/src/kernel.rs b/crates/ghostlight-dungeon/src/kernel.rs index 2945617..3289fd0 100644 --- a/crates/ghostlight-dungeon/src/kernel.rs +++ b/crates/ghostlight-dungeon/src/kernel.rs @@ -888,18 +888,6 @@ fn apply_world_effect( .get_mut(actor_id) .ok_or_else(|| KernelError::Invalid("outcome actor vanished".into()))?; actor.knowledge.extend(additions.clone()); - for finding in additions { - let fact_id = format!( - "fact:outcome:{:x}", - Sha256::digest(format!("{}:{finding}", campaign.id).as_bytes()) - ); - campaign.facts.entry(fact_id.clone()).or_insert(WorldFact { - id: fact_id, - statement: finding.clone(), - scope: FactScope::BranchLocal, - evidence_receipt_ids: vec![], - }); - } } for (actor_id, relationships) in &effect.actor_relationship_updates { campaign @@ -2539,7 +2527,18 @@ mod tests { let dir = tempfile::tempdir().unwrap(); let store = CampaignStore::open(dir.path().join("campaign.cc")).unwrap(); let kernel = WorldKernel::start(store.clone()); - let seed = campaign(); + let mut seed = campaign(); + let player_location = seed.actors["player"].location_id.clone(); + seed.facts.insert( + "fact:door-brace-seated".into(), + WorldFact { + id: "fact:door-brace-seated".into(), + statement: "The door brace is seated against the frame.".into(), + scope: FactScope::BranchLocal, + evidence_receipt_ids: vec![], + discoverable_at_location_ids: BTreeSet::from([player_location]), + }, + ); let campaign_id = seed.id; kernel .command(WorldCommand::CreateCampaign { @@ -2578,6 +2577,7 @@ mod tests { "player".into(), BTreeSet::from(["The hidden latch is broken.".into()]), ); + hidden_finding.success_stake = "The hidden latch is broken.".into(); hidden_finding.digest = crate::assessor::assessment_digest(&hidden_finding).unwrap(); assert!( kernel @@ -2643,6 +2643,79 @@ mod tests { fact.statement == "The door brace is seated against the frame." && fact.scope == FactScope::BranchLocal })); + assert_eq!(persisted.facts.len(), 1); + } + + #[test] + fn information_effects_reveal_existing_accessible_facts_only() { + let statement = "The maintenance panel records a seven-minute interruption."; + let mut seed = campaign(); + seed.facts.insert( + "fact:panel-interruption".into(), + WorldFact { + id: "fact:panel-interruption".into(), + statement: statement.into(), + scope: FactScope::BranchLocal, + evidence_receipt_ids: vec![], + discoverable_at_location_ids: BTreeSet::from(["room".into()]), + }, + ); + let effect = WorldEffectDelta { + actor_knowledge_additions: BTreeMap::from([( + "player".into(), + BTreeSet::from([statement.into()]), + )]), + ..Default::default() + }; + assert!( + crate::assessor::validate_effect(&seed, &seed.actors["player"], &effect, statement,) + .is_ok() + ); + + let mut absent = seed.clone(); + absent.facts.clear(); + assert!( + crate::assessor::validate_effect( + &absent, + &absent.actors["player"], + &effect, + statement, + ) + .unwrap_err() + .to_string() + .contains("existing accessible WorldFact") + ); + + let mut wrong_place = seed.clone(); + wrong_place + .facts + .get_mut("fact:panel-interruption") + .unwrap() + .discoverable_at_location_ids = BTreeSet::from(["elsewhere".into()]); + assert!( + crate::assessor::validate_effect( + &wrong_place, + &wrong_place.actors["player"], + &effect, + statement, + ) + .is_err() + ); + + let mut speaker = seed.actors["player"].clone(); + speaker.id = "speaker".into(); + speaker.name = "Speaker".into(); + speaker.knowledge.insert(statement.into()); + seed.actors.insert(speaker.id.clone(), speaker.clone()); + seed.facts + .get_mut("fact:panel-interruption") + .unwrap() + .discoverable_at_location_ids + .clear(); + assert!( + crate::assessor::validate_effect(&seed, &speaker, &effect, statement).is_ok(), + "an actor may communicate an existing fact they know to another present actor" + ); } fn resolution_stage( diff --git a/crates/ghostlight-dungeon/src/main.rs b/crates/ghostlight-dungeon/src/main.rs index 0138ddc..1151c58 100644 --- a/crates/ghostlight-dungeon/src/main.rs +++ b/crates/ghostlight-dungeon/src/main.rs @@ -14,8 +14,8 @@ use ghostlight_dungeon::{ SuggestedOpenings, SuggestedRoles, WorldCompiler, }, domain::{ - ActionIntent, Campaign, GestaltFissionPreview, NarrationProjection, RegionExpansionPreview, - RejectedProposalReceipt, WorldCommand, WorldCompilePreview, + ActionIntent, Campaign, FactScope, GestaltFissionPreview, NarrationProjection, + RegionExpansionPreview, RejectedProposalReceipt, WorldCommand, WorldCompilePreview, }, gestalt::GestaltPresencePlanner, kernel::{CommandResult, KernelError}, @@ -1315,6 +1315,19 @@ fn world_compile_preview_projection(preview: &WorldCompilePreview) -> serde_json }) }) .collect::>(); + let branch_facts = campaign + .facts + .values() + .filter(|fact| fact.scope != FactScope::CanonBaseline) + .map(|fact| { + serde_json::json!({ + "id":fact.id, + "scope":fact.scope, + "statement":fact.statement, + "discoverable_at_location_ids":fact.discoverable_at_location_ids, + }) + }) + .collect::>(); serde_json::json!({ "schema":preview.schema, "title":preview.title, @@ -1335,6 +1348,7 @@ fn world_compile_preview_projection(preview: &WorldCompilePreview) -> serde_json "evidence_coverage":preview.evidence_coverage, "gaps":preview.gaps, "branch_assumptions":preview.branch_assumptions, + "branch_facts":branch_facts, "requires_approval":preview.requires_approval, }) } diff --git a/docs/architecture/ghostlight-dungeon-mvp.md b/docs/architecture/ghostlight-dungeon-mvp.md index fe2907c..996ff00 100644 --- a/docs/architecture/ghostlight-dungeon-mvp.md +++ b/docs/architecture/ghostlight-dungeon-mvp.md @@ -607,16 +607,45 @@ receive no roll. Natural 20 and 1 shift one band and cannot cross impossibility or the effect ceiling. Speech occurs as speech; persuasion, deception, and intimidation are separate intended effects. -Informational attempts must preview the exact finding that becomes knowledge. -On resolution, only the acting character may receive those bounded knowledge -additions; the same statement is committed as a provisional branch fact. A -vague promise such as “identify any faults” is not a valid informational -outcome, and an unstated hidden finding cannot appear after the roll. -The assessor normalizes each bounded typed finding into its visible stake before -validation and digesting. Exact visibility is therefore deterministic; a model -retry is reserved for semantic or authority failure, not punctuation mismatch. -The schema names these values as player-readable declarative statements, and a -fact ID, key, or slug cannot enter the character ledger as knowledge. +Informational attempts may reveal an existing `WorldFact`; they may not author +one. `WorldFact` owns branch truth and the location boundaries at which a fact +can be discovered. `ActorState.knowledge` owns only which exact statements that +actor has learned. The compiler or an approval-gated region expansion must +therefore establish a clue before a roll can expose it. + +The assessor receives only facts already known by the acting actor or marked +discoverable at that actor's current location. Every proposed knowledge +addition must exactly match one of those statements. A fact known by the acting +actor may be communicated to another present actor; a location-bound fact may +be discovered only by the acting actor. Player attempts and NPC initiative use +the same validator. The kernel atomically updates actor knowledge but never +creates a fact from model prose. + +This ownership makes the negative invariant structural: an invented protocol +number, hidden culprit, remote event, or clue cannot become true because an +assessor wrote it into a successful stake. Unsupported information causes one +same-snapshot correction and then aborts without mutation. A vague promise such +as “identify any faults” is not a valid informational outcome, and an unstated +hidden finding cannot appear after the roll. Player-readable stakes still carry +the exact declarative statement; fact IDs, keys, and slugs remain private typed +references. + +Authority map: + +- Owner: `WorldFact` owns truth and discovery locations; `ActorState` owns + learned access. +- Inputs: approved compiler or region-expansion facts, current occupancy, + actor knowledge, and the attempted effect. +- Output: an assessment whose information deltas are a subset of existing + accessible facts. +- Derived state: the visible stake and narration are projections of that exact + assessment and committed revision. +- Forbidden writers: Personas, Interpreters, assessors, narrators, and + `apply_world_effect` cannot create facts. +- Shared path: player `Attempt` and `ResolveNpcAction` call the same fact-access + validator and atomic commit primitive. +- Cut line: the former promotion of arbitrary knowledge prose into a new + branch-local `WorldFact` is deleted. ### Actor and world action loop diff --git a/web/dist/assets/index-DmZm_kJC.js b/web/dist/assets/index-CicytASo.js similarity index 89% rename from web/dist/assets/index-DmZm_kJC.js rename to web/dist/assets/index-CicytASo.js index a7b9a23..6b35f48 100644 --- a/web/dist/assets/index-DmZm_kJC.js +++ b/web/dist/assets/index-CicytASo.js @@ -1,4 +1,4 @@ -(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))i(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const c of s.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&i(c)}).observe(document,{childList:!0,subtree:!0});function n(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function i(o){if(o.ep)return;o.ep=!0;const s=n(o);fetch(o.href,s)}})();const j=new WeakMap,Ie=20;function ft(e,t,n,i,o,s,c,l){const f=gt(e.canvas);if(!f)return!1;const a=f.gl;if(!yt(f,s,c))return j.set(e.canvas,null),!1;const r=mt(t,n,i,o,l);a.bindFramebuffer(a.FRAMEBUFFER,f.framebuffer),a.viewport(0,0,s,c),a.disable(a.DEPTH_TEST),a.disable(a.CULL_FACE),a.enable(a.BLEND),a.blendFunc(a.ONE,a.ONE),a.clearColor(0,0,0,1),a.clear(a.COLOR_BUFFER_BIT),r.gravity.length>0&&(a.useProgram(f.splatProgram),a.uniform4f(a.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),a.uniform1f(a.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),a.bindBuffer(a.ARRAY_BUFFER,f.splatBuffer),a.bufferData(a.ARRAY_BUFFER,r.gravity,a.DYNAMIC_DRAW),Be(a,f.splatProgram),a.drawArrays(a.TRIANGLES,0,r.gravity.length/Ie)),a.bindFramebuffer(a.FRAMEBUFFER,f.tintFramebuffer),a.clearColor(0,0,0,0),a.clear(a.COLOR_BUFFER_BIT),r.tint.length>0&&(a.useProgram(f.splatProgram),a.uniform4f(a.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),a.uniform1f(a.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),a.bindBuffer(a.ARRAY_BUFFER,f.splatBuffer),a.bufferData(a.ARRAY_BUFFER,r.tint,a.DYNAMIC_DRAW),Be(a,f.splatProgram),a.drawArrays(a.TRIANGLES,0,r.tint.length/Ie)),a.disable(a.BLEND),a.bindFramebuffer(a.FRAMEBUFFER,null),a.viewport(0,0,s,c),a.useProgram(f.shadeProgram),a.activeTexture(a.TEXTURE0),a.bindTexture(a.TEXTURE_2D,f.fieldTexture),a.uniform1i(a.getUniformLocation(f.shadeProgram,"u_field"),0),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,f.tintTexture),a.uniform1i(a.getUniformLocation(f.shadeProgram,"u_tint"),1),a.uniform2f(a.getUniformLocation(f.shadeProgram,"u_resolution"),s,c),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_time"),I(n.simulationTimeSeconds,I(t.simulationTimeSeconds,0))),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineInterval"),I(t.lineInterval,I(t.scalarFieldLineInterval,I(t.depthRange,228.79605)/20))),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineOffset"),I(t.lineOffset,I(t.startDepth,2.310401))),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineWidth"),I(t.lineWidth,.3)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineFade"),I(t.lineFade,5)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_angleWidth"),I(t.angleWidth,.05)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_angleFade"),I(t.angleFade,1.15)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_dangerSteepness"),I(t.dangerSteepness,1.5)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_scale"),I(t.isolineScale,2.6924083)),ne(a,f.shadeProgram,"u_baseColor",te(t.scalarFieldBaseColor,[.002,.006,.012])),ne(a,f.shadeProgram,"u_fieldGlowColor",te(t.scalarFieldGlowColor,[.018,.05,.075])),ne(a,f.shadeProgram,"u_lineLowColor",te(t.scalarFieldLowLineColor,[0,.34,.52])),ne(a,f.shadeProgram,"u_lineHighColor",te(t.scalarFieldHighLineColor,[1.45,.3,.05])),ne(a,f.shadeProgram,"u_angleLowColor",te(t.scalarFieldLowAngleColor,[.06,.16,.24])),ne(a,f.shadeProgram,"u_angleHighColor",te(t.scalarFieldHighAngleColor,[1.1,.24,.04])),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_tintScale"),I(t.vectorFieldTintScale,.45)),a.bindBuffer(a.ARRAY_BUFFER,f.quadBuffer);const d=a.getAttribLocation(f.shadeProgram,"a_position");return a.enableVertexAttribArray(d),a.vertexAttribPointer(d,2,a.FLOAT,!1,0,0),a.drawArrays(a.TRIANGLES,0,6),e.drawImage(f.canvas,0,0,s,c),!0}function mt(e,t,n,i,o){const s=[],c=[];return pt(s,e,t,n),ht(c,e,o),{gravity:new Float32Array(s),tint:new Float32Array(c)}}function pt(e,t,n,i,o){const s=I(n.terrainRadius,I(t.terrainRadius,1200)),c=I(n.terrainDepth,I(t.terrainDepth,-8));c!==0&&ye(e,0,0,Math.max(1,s*2),Math.max(1,s*2),-c,0,0,1,Math.max(1e-4,I(n.terrainDepthExponent,I(t.terrainDepthExponent,1.2))),0,1,0,0);for(const l of i)ye(e,l.x,l.y,Math.max(1,l.radius),Math.max(1,l.radius),-l.depth,0,0,1,Math.max(1e-4,l.exponent),0,1,0,0),l.waveRadius>0&&l.waveDepth!==0&&ye(e,l.x,l.y,l.waveRadius,l.waveRadius,-l.waveDepth,0,0,1,8,4,I(n.terrainWaveFrequency,I(t.terrainWaveFrequency,.6)),l.waveSpeed,0)}function ht(e,t,n){const i=vt(n?.splats),o=Array.isArray(n?.layers)?n.layers:[],s=new Set,c=xt(t.vectorFieldLayer,t.tintFieldLayer,"fog.tint");o.forEach((C,ee)=>{const ue=bt(C?.layerKey,"");I(C?.channel,-1)===4&&ue===c&&s.add(ee)});const l=Math.max(0,wt(i.count,0));if(l<=0||s.size===0)return;const f=L(i.centerX),a=L(i.centerY),r=L(i.halfExtentX),d=L(i.halfExtentY),u=L(i.rotationCos),h=L(i.rotationSin),y=L(i.channel),v=L(i.falloff),x=L(i.valueR),T=L(i.valueG),A=L(i.valueB),D=L(i.valueA),J=L(i.sourceKind),O=L(i.frequencyX),Z=L(i.animationSpeed),Q=L(i.sourceFlags),G=L(i.layerIndex);for(let C=0;CNumber(i));if(n.length>=3&&n.slice(0,3).every(Number.isFinite))return[n[0],n[1],n[2]]}if(typeof e=="string"){const n=e.split(/[,\s]+/).map(i=>Number(i)).filter(Number.isFinite);if(n.length>=3)return[n[0],n[1],n[2]]}return t}function ne(e,t,n,i){e.uniform3f(e.getUniformLocation(t,n),i[0],i[1],i[2])}function L(e){return Array.isArray(e)?e.map(t=>I(t,0)):[]}function vt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function bt(e,t){return e==null?t:String(e)}function xt(...e){for(const t of e){if(typeof t=="string"&&t.trim())return t;if(typeof t=="number"&&Number.isFinite(t))return String(t)}return""}function wt(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}const St=`#version 300 es +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))i(o);new MutationObserver(o=>{for(const s of o)if(s.type==="childList")for(const c of s.addedNodes)c.tagName==="LINK"&&c.rel==="modulepreload"&&i(c)}).observe(document,{childList:!0,subtree:!0});function n(o){const s={};return o.integrity&&(s.integrity=o.integrity),o.referrerPolicy&&(s.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?s.credentials="include":o.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function i(o){if(o.ep)return;o.ep=!0;const s=n(o);fetch(o.href,s)}})();const K=new WeakMap,Ie=20;function ft(e,t,n,i,o,s,c,l){const f=gt(e.canvas);if(!f)return!1;const a=f.gl;if(!yt(f,s,c))return K.set(e.canvas,null),!1;const r=mt(t,n,i,o,l);a.bindFramebuffer(a.FRAMEBUFFER,f.framebuffer),a.viewport(0,0,s,c),a.disable(a.DEPTH_TEST),a.disable(a.CULL_FACE),a.enable(a.BLEND),a.blendFunc(a.ONE,a.ONE),a.clearColor(0,0,0,1),a.clear(a.COLOR_BUFFER_BIT),r.gravity.length>0&&(a.useProgram(f.splatProgram),a.uniform4f(a.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),a.uniform1f(a.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),a.bindBuffer(a.ARRAY_BUFFER,f.splatBuffer),a.bufferData(a.ARRAY_BUFFER,r.gravity,a.DYNAMIC_DRAW),Be(a,f.splatProgram),a.drawArrays(a.TRIANGLES,0,r.gravity.length/Ie)),a.bindFramebuffer(a.FRAMEBUFFER,f.tintFramebuffer),a.clearColor(0,0,0,0),a.clear(a.COLOR_BUFFER_BIT),r.tint.length>0&&(a.useProgram(f.splatProgram),a.uniform4f(a.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),a.uniform1f(a.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),a.bindBuffer(a.ARRAY_BUFFER,f.splatBuffer),a.bufferData(a.ARRAY_BUFFER,r.tint,a.DYNAMIC_DRAW),Be(a,f.splatProgram),a.drawArrays(a.TRIANGLES,0,r.tint.length/Ie)),a.disable(a.BLEND),a.bindFramebuffer(a.FRAMEBUFFER,null),a.viewport(0,0,s,c),a.useProgram(f.shadeProgram),a.activeTexture(a.TEXTURE0),a.bindTexture(a.TEXTURE_2D,f.fieldTexture),a.uniform1i(a.getUniformLocation(f.shadeProgram,"u_field"),0),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,f.tintTexture),a.uniform1i(a.getUniformLocation(f.shadeProgram,"u_tint"),1),a.uniform2f(a.getUniformLocation(f.shadeProgram,"u_resolution"),s,c),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_time"),I(n.simulationTimeSeconds,I(t.simulationTimeSeconds,0))),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineInterval"),I(t.lineInterval,I(t.scalarFieldLineInterval,I(t.depthRange,228.79605)/20))),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineOffset"),I(t.lineOffset,I(t.startDepth,2.310401))),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineWidth"),I(t.lineWidth,.3)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_lineFade"),I(t.lineFade,5)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_angleWidth"),I(t.angleWidth,.05)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_angleFade"),I(t.angleFade,1.15)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_dangerSteepness"),I(t.dangerSteepness,1.5)),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_scale"),I(t.isolineScale,2.6924083)),ne(a,f.shadeProgram,"u_baseColor",te(t.scalarFieldBaseColor,[.002,.006,.012])),ne(a,f.shadeProgram,"u_fieldGlowColor",te(t.scalarFieldGlowColor,[.018,.05,.075])),ne(a,f.shadeProgram,"u_lineLowColor",te(t.scalarFieldLowLineColor,[0,.34,.52])),ne(a,f.shadeProgram,"u_lineHighColor",te(t.scalarFieldHighLineColor,[1.45,.3,.05])),ne(a,f.shadeProgram,"u_angleLowColor",te(t.scalarFieldLowAngleColor,[.06,.16,.24])),ne(a,f.shadeProgram,"u_angleHighColor",te(t.scalarFieldHighAngleColor,[1.1,.24,.04])),a.uniform1f(a.getUniformLocation(f.shadeProgram,"u_tintScale"),I(t.vectorFieldTintScale,.45)),a.bindBuffer(a.ARRAY_BUFFER,f.quadBuffer);const d=a.getAttribLocation(f.shadeProgram,"a_position");return a.enableVertexAttribArray(d),a.vertexAttribPointer(d,2,a.FLOAT,!1,0,0),a.drawArrays(a.TRIANGLES,0,6),e.drawImage(f.canvas,0,0,s,c),!0}function mt(e,t,n,i,o){const s=[],c=[];return pt(s,e,t,n),ht(c,e,o),{gravity:new Float32Array(s),tint:new Float32Array(c)}}function pt(e,t,n,i,o){const s=I(n.terrainRadius,I(t.terrainRadius,1200)),c=I(n.terrainDepth,I(t.terrainDepth,-8));c!==0&&ye(e,0,0,Math.max(1,s*2),Math.max(1,s*2),-c,0,0,1,Math.max(1e-4,I(n.terrainDepthExponent,I(t.terrainDepthExponent,1.2))),0,1,0,0);for(const l of i)ye(e,l.x,l.y,Math.max(1,l.radius),Math.max(1,l.radius),-l.depth,0,0,1,Math.max(1e-4,l.exponent),0,1,0,0),l.waveRadius>0&&l.waveDepth!==0&&ye(e,l.x,l.y,l.waveRadius,l.waveRadius,-l.waveDepth,0,0,1,8,4,I(n.terrainWaveFrequency,I(t.terrainWaveFrequency,.6)),l.waveSpeed,0)}function ht(e,t,n){const i=vt(n?.splats),o=Array.isArray(n?.layers)?n.layers:[],s=new Set,c=xt(t.vectorFieldLayer,t.tintFieldLayer,"fog.tint");o.forEach((C,ee)=>{const ue=bt(C?.layerKey,"");I(C?.channel,-1)===4&&ue===c&&s.add(ee)});const l=Math.max(0,wt(i.count,0));if(l<=0||s.size===0)return;const f=L(i.centerX),a=L(i.centerY),r=L(i.halfExtentX),d=L(i.halfExtentY),u=L(i.rotationCos),h=L(i.rotationSin),y=L(i.channel),v=L(i.falloff),x=L(i.valueR),T=L(i.valueG),A=L(i.valueB),D=L(i.valueA),J=L(i.sourceKind),O=L(i.frequencyX),Z=L(i.animationSpeed),Q=L(i.sourceFlags),j=L(i.layerIndex);for(let C=0;CNumber(i));if(n.length>=3&&n.slice(0,3).every(Number.isFinite))return[n[0],n[1],n[2]]}if(typeof e=="string"){const n=e.split(/[,\s]+/).map(i=>Number(i)).filter(Number.isFinite);if(n.length>=3)return[n[0],n[1],n[2]]}return t}function ne(e,t,n,i){e.uniform3f(e.getUniformLocation(t,n),i[0],i[1],i[2])}function L(e){return Array.isArray(e)?e.map(t=>I(t,0)):[]}function vt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function bt(e,t){return e==null?t:String(e)}function xt(...e){for(const t of e){if(typeof t=="string"&&t.trim())return t;if(typeof t=="number"&&Number.isFinite(t))return String(t)}return""}function wt(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}const St=`#version 300 es in vec2 a_corner; in vec2 a_center; in vec2 a_half; @@ -131,7 +131,7 @@ void main() { color += clamp(lines, 0.0, 1.7); outColor = vec4(color, 1.0); -}`,He=new Set(["gamecult.fields.splats.v1","gamecult.fields.gravity.v1","gamecult.fields.objects.v1"]),It={pluginId:"fields.surface",capabilities:["field.surface2d","gravity.surface","field.scalar","field.vector","field.objects"],componentKinds:["field.surface2d","gravity.surface"],schemas:[...He],normalizeDocument:Ce,renderComponent:Ct};function Ct(e,t,n,i,o,s){const c=document.createElement("canvas");c.className="cultui-gravity-surface",e.id&&(c.id=e.id),c.setAttribute("role","img"),c.setAttribute("aria-label",Jt(t.label,"gravity surface")),c.style.display="block",c.style.width="100%",c.style.height="100%",c.style.pointerEvents="none",s.applyGeneratedLayout(c,n,i);let l=!1;const f={},a=()=>Rt(c,t,f,s.resolveAssetUrl),r=()=>{!c.isConnected||l||(l=!0,requestAnimationFrame(()=>{l=!1,c.isConnected&&a()}))};c.addEventListener("cultui:asset-loaded",r);let d=0,u;const h=()=>{d&&window.clearInterval(d),u?.disconnect(),c.removeEventListener("cultui:asset-loaded",r)},y=()=>{if(!c.isConnected){h();return}Tt(e,t,o,s.providerId,f).then(x=>{x&&c.isConnected&&r()}).catch(x=>{f.lastError=x instanceof Error?x.message:String(x)})};typeof ResizeObserver<"u"&&(u=new ResizeObserver(r),u.observe(c)),r();const v=Math.max(33,Math.min(1e3,Zt(t.stateRefreshMs,100)));return d=window.setInterval(y,v),queueMicrotask(y),window.setTimeout(r,300),window.setTimeout(r,1e3),c}async function Tt(e,t,n,i,o){if(o.loading)return!1;const s=[Ee(e,t,"renderSplats","renderSplatsDocumentId","renderSplatsSchemaId"),Ee(e,t,"gravity","gravityDocumentId","gravitySchemaId"),Ee(e,t,"objects","objectsDocumentId","objectsSchemaId")].filter(c=>!!c?.documentId);if(s.length===0)return!1;o.loading=!0;try{let c=!1;for(const l of s){const f=await n.documentResolver?.(l,e);let a=xe(Ce(f?.schemaId||l.schemaId,f?.document));if(Object.keys(a).length===0&&(a=xe(Ce(l.schemaId,await kt(l,i||n.provider?.providerId)))),Object.keys(a).length===0)continue;const r=l.slotId==="renderSplats"?"renderSplats":l.slotId==="gravity"?"gravity":"objects",d=ke(o[r]?.frameId,-1),u=ke(a.frameId,d);o[r]=a,c||=u!==d}return o.lastLoadedAt=Date.now(),c}finally{o.loading=!1}}async function kt(e,t){if(typeof fetch!="function"||typeof window>"u"||!t)return;const n=new URLSearchParams({documentId:e.documentId});e.schemaId&&n.set("schemaId",e.schemaId),e.slotId&&n.set("slotId",e.slotId);const i=await fetch(`/eir/document/${encodeURIComponent(t)}?${n.toString()}`,{cache:"no-store",headers:{Accept:"application/json"}});if(i.ok)return xe(await i.json()).document}function Ee(e,t,n,i,o){const s=(e.embeddedDocuments||[]).find(l=>String(l?.slotId||"")===n),c=k(t[i],s?.documentId);if(c)return{documentId:c,schemaId:k(t[o],s?.schemaId),presentationKind:k(s?.presentationKind)||"data",slotId:n}}function Ce(e,t){const n=Array.isArray(t)?t:void 0,i=n?n[0]:t?.schema,o=String(e||i||"");return!n||!He.has(o)?t:o==="gamecult.fields.splats.v1"?zt(n):o==="gamecult.fields.gravity.v1"?Ot(n):Gt(n)}function Rt(e,t,n,i){const o=e.getBoundingClientRect(),s=Math.max(1,Math.floor(o.width||e.clientWidth||1)),c=Math.max(1,Math.floor(o.height||e.clientHeight||1)),l=Math.max(1,Math.min(2,window.devicePixelRatio||1)),f=Math.max(1,Math.floor(s*l)),a=Math.max(1,Math.floor(c*l));(e.width!==f||e.height!==a)&&(e.width=f,e.height=a);const r=e.getContext("2d");if(!r)return;r.setTransform(l,0,0,l,0,0),r.clearRect(0,0,s,c);const d=Wt(qt(t),s,c),u=Ze(n?.gravity),h=Bt(n?.gravity)||$t(k(t.bodies,"")),y=Ut(n?.objects)||Dt(k(t.objects,""));ft(r,t,u,h,d,s,c,n?.renderSplats)||Ft(r,t,s,c,"field.surface2d requires WebGL2 float render targets"),Pt(r,h,t,d,s,c,i),Mt(r,y,t,d,s,c,i)}function Ft(e,t,n,i,o){e.save(),e.fillStyle=k(t.failureBackground,"rgba(0, 0, 0, 0.72)"),e.fillRect(0,0,n,i),e.font=k(t.failureFont,"700 13px Cascadia Mono, Consolas, monospace"),e.fillStyle=k(t.failureColor,"rgba(255, 184, 79, 0.95)"),e.fillText(o,16,28),e.restore()}function Pt(e,t,n,i,o,s,c){for(const l of t){const f=Je(i,l.x,l.y,o,s),a=Math.max(18,Math.min(190,l.radius/Math.max(1,i.maxX-i.minX)*o*.32)),r=c(l.icon),d=l.kind.toLowerCase().includes("sun")?Math.max(E(n.sunIconMinPx,34),a*E(n.sunIconScale,.72)):Math.max(E(n.bodyIconMinPx,24),a*E(n.bodyIconScale,.48)),u=l.iconSize>0?l.iconSize:d;r&&Lt(e,r,f.x,f.y,u,.92),l.key&&Ve(e,n,l.key.replace(/^local\./,""),f.x+a*.44,f.y-a*.48,k(n.bodyLabelColor,"rgba(226, 244, 255, 0.82)"))}}const be=new Map;function Lt(e,t,n,i,o,s){let c=be.get(t);c||(c=new Image,c.decoding="async",c.onload=()=>requestAnimationFrame(()=>{e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded"))}),c.src=t,be.set(t,c)),!(!c.complete||c.naturalWidth===0)&&(e.save(),e.globalAlpha=s,e.drawImage(c,n-o/2,i-o/2,o,o),e.restore())}function Mt(e,t,n,i,o,s,c){for(const l of t){const f=Je(i,l.x,l.y,o,s);if(f.x<-40||f.x>o+40||f.y<-40||f.y>s+40)continue;const a=l.kind.toLowerCase().includes("station")?E(n.stationIconSizePx,34):l.controlled?E(n.shipIconSizePx,22):E(n.remoteShipIconSizePx,18),r=Nt(n,l.faction,l.controlled,l.visibility),d=c(l.icon);e.save(),e.globalAlpha=Math.max(.25,Math.min(1,l.visibility)),e.translate(f.x,f.y);const u=Math.atan2(l.directionY,l.directionX)+Math.PI/2;if(l.kind.toLowerCase().includes("ship")&&e.rotate(u),d){const h=be.get(d);if(h)h.complete&&h.naturalWidth>0&&e.drawImage(h,-a/2,-a/2,a,a);else{const y=new Image;y.decoding="async",y.onload=()=>e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded")),y.src=d,be.set(d,y)}}e.restore(),Ve(e,n,l.label,f.x+a*.55,f.y-a*.45,r)}}function Ve(e,t,n,i,o,s){n&&(e.save(),e.font=k(t.objectLabelFont,"700 12px Ubuntu, system-ui, sans-serif"),e.textBaseline="middle",e.lineWidth=E(t.objectLabelStrokeWidth,3),e.strokeStyle=k(t.objectLabelStroke,"rgba(0, 0, 0, 0.72)"),e.fillStyle=s,e.strokeText(n,i,o),e.fillText(n,i,o),e.restore())}function Nt(e,t,n,i){const o=Math.max(.25,Math.min(1,i));if(n)return fe(k(e.objectControlledColor,"rgba(122, 240, 255, {alpha})"),o);const s=t.toLowerCase();return s.includes("raider")?fe(k(e.objectRaiderColor,"rgba(255, 143, 74, {alpha})"),o):s.includes("neutral")?fe(k(e.objectNeutralColor,"rgba(232, 232, 224, {alpha})"),o):fe(k(e.objectDefaultColor,"rgba(214, 244, 255, {alpha})"),o)}function fe(e,t){return e.replaceAll("{alpha}",String(t))}function $t(e){return e.split(";").map(t=>t.trim()).filter(Boolean).map(t=>{const n=t.split("|");return{key:n[0]??"",kind:n[1]??"",x:Number(n[2])||0,y:Number(n[3])||0,radius:Math.max(1,Number(n[4])||1),depth:Number(n[5])||0,exponent:Number(n[6])||1,waveRadius:Number(n[7])||0,waveDepth:Number(n[8])||0,waveSpeed:Number(n[9])||0,icon:n[10]??"",iconSize:Number(n[12])||0,tint:n[11]??""}})}function Dt(e){return e.split(";").map(t=>t.trim()).filter(Boolean).map(t=>{const n=t.split("|");return{key:n[0]??"",kind:n[1]??"",label:n[2]??"",x:Number(n[3])||0,y:Number(n[4])||0,directionX:Number(n[5])||0,directionY:Number(n[6])||1,faction:n[7]??"",controlled:n[8]==="1"||n[8]==="true",visibility:Number(n[9])||1,icon:n[10]??""}})}function Bt(e){const t=Array.isArray(e?.gravityInfluences)?e.gravityInfluences:[],n=Array.isArray(e?.bodies)?e.bodies:[];if(t.length===0&&n.length===0)return;const i=new Map;for(const o of n){const s=k(o.bodyKey,o.name,"");s&&i.set(s,o)}return(t.length>0?t:n).map(o=>{const s=k(o.bodyKey,o.name,"body"),c=i.get(s),l=k(o.kind,"Body");return{key:s,kind:l,x:E(o.x,0),y:E(o.y,0),radius:Math.max(1,E(o.radius,80)),depth:E(o.gravityDepth,0),exponent:E(o.gravityDepthExponent,1),waveRadius:E(o.waveRadius,0),waveDepth:E(o.waveDepth,0),waveSpeed:E(o.waveSpeed,0),icon:Te(o.iconAsset)||Te(c?.iconAsset),iconSize:E(c?.iconSize,E(o.iconSize,0)),tint:""}})}function Ut(e){const t=Array.isArray(e?.objects)?e.objects:[];if(t.length!==0)return t.map(n=>{const i=k(n.kind,"object");return{key:k(n.entityKey,String(n.entityIndex??""),"object"),kind:i,label:k(n.displayName,n.entityKey,"object"),x:E(n.x,0),y:E(n.y,0),directionX:E(n.directionX,1),directionY:E(n.directionY,0),faction:k(n.factionKey,""),controlled:Qt(n.controlled),visibility:E(n.visibility,1),icon:Te(n.iconAsset)}})}function Te(e){const t=Ze(e);return k(t.uri,"")}function qt(e){const t=Math.max(1,E(e.viewRadius,Math.max(1200,E(e.terrainRadius,1200))));return{minX:E(e.minX,-t),minY:E(e.minY,-t),maxX:E(e.maxX,t),maxY:E(e.maxY,t)}}function Wt(e,t,n){const i=Math.max(1e-4,e.maxX-e.minX),o=Math.max(1e-4,e.maxY-e.minY),s=Math.max(1e-4,t/Math.max(1,n)),c=i/o,l=(e.minX+e.maxX)*.5,f=(e.minY+e.maxY)*.5;if(s>c){const r=o*s;return{minX:l-r*.5,maxX:l+r*.5,minY:e.minY,maxY:e.maxY}}const a=i/s;return{minX:e.minX,maxX:e.maxX,minY:f-a*.5,maxY:f+a*.5}}function Je(e,t,n,i,o){return{x:(t-e.minX)/Math.max(1,e.maxX-e.minX)*i,y:(n-e.minY)/Math.max(1,e.maxY-e.minY)*o}}function zt(e){const t=N(e[9]);return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],viewport:Fe(e[7]),layers:N(e[8]).map(Kt),splats:{count:t[0]??0,centerX:t[1]||[],centerY:t[2]||[],halfExtentX:t[3]||[],halfExtentY:t[4]||[],rotationCos:t[5]||[],rotationSin:t[6]||[],channel:t[7]||[],falloff:t[8]||[],valueR:t[9]||[],valueG:t[10]||[],valueB:t[11]||[],valueA:t[12]||[],sourceKey:t[13]||[],layerIndex:t[14]||[],sourceKind:t[15]||[],frequencyX:t[16]||[],frequencyY:t[17]||[],phaseX:t[18]||[],phaseY:t[19]||[],animationSpeed:t[20]||[],sourceFlags:t[21]||[]}}}function Ot(e){return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],viewport:Fe(e[7]),gravityInfluences:N(e[8]).map(jt),bodies:N(e[9]).map(Xt),terrainRadius:e[10],terrainDepth:e[11],terrainDepthExponent:e[12],terrainWaveFrequency:e[13]}}function Gt(e){return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],currentEntityKey:e[7],viewport:Fe(e[8]),controlledEntityIndices:N(e[9]),objects:N(e[10]).map(Yt)}}function Fe(e){const t=N(e);return t.length?{minX:t[0],minY:t[1],maxX:t[2],maxY:t[3]}:e}function Kt(e){const t=N(e);return t.length?{layerKey:t[0],displayName:t[1],channel:t[2],blendMode:t[3],graphicsFormat:t[4],clearBeforeDraw:t[5],clearR:t[6],clearG:t[7],clearB:t[8],clearA:t[9]}:e}function jt(e){const t=N(e);return t.length?{bodyKey:t[0],orbitKey:t[1],kind:t[2],x:t[3],y:t[4],radius:t[5],gravityDepth:t[6],gravityDepthExponent:t[7],waveRadius:t[8],waveDepth:t[9],waveSpeed:t[10]}:e}function Xt(e){const t=N(e);return t.length?{bodyKey:t[0],orbitKey:t[1],name:t[2],kind:t[3],x:t[4],y:t[5],radius:t[6],isAsteroidBelt:t[7],body:t[8],iconAsset:Pe(t[9])}:e}function Yt(e){const t=N(e);return t.length?{entityIndex:t[0],entityKey:t[1],displayName:t[2],kind:t[3],factionKey:t[4],x:t[5],y:t[6],z:t[7],directionX:t[8],directionY:t[9],velocityX:t[10],velocityY:t[11],controlled:t[12],targetEntityIndex:t[13],isActive:t[14],visibility:t[15],status:Ht(t[16]),inventory:N(t[17]).map(Vt),iconAsset:Pe(t[18])}:e}function Ht(e){const t=N(e);return t.length?{hull:t[0],shield:t[1],heat:t[2]}:e||{}}function Vt(e){const t=N(e);return t.length?{source:t[0],itemKey:t[1],quantity:t[2],quality:t[3],durability:t[4],enabled:t[5],sourceIndex:t[6],x:t[7],y:t[8],iconAsset:Pe(t[9])}:e}function Pe(e){const t=N(e);return t.length?{assetKey:t[0],kind:t[1],uri:t[2],transport:t[3],contentHash:t[4],mimeType:t[5],metadata:t[6]||{}}:e||{}}function N(e){return Array.isArray(e)?e:[]}function xe(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function k(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function Jt(e,t){return typeof e=="string"&&e?e:t}function Zt(e,t){const n=Number(e);return Number.isFinite(n)&&n>0?Math.floor(n):t}function ke(e,t){const n=Number(e);return Number.isFinite(n)?n:t}const Ze=xe,E=ke;function Qt(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"&&["1","true","yes","on"].includes(e.trim().toLowerCase())}const en=[It],tn={"--bg":"#020909","--bg-top":"#020909","--bg-mid":"#020909","--bg-bottom":"#020909","--shell-top":"#010707","--shell-bottom":"#010707","--panel":"#071918","--panel-2":"#0a2423","--line":"rgba(103, 240, 228, 0.28)","--line-deep":"rgba(103, 240, 228, 0.18)","--text":"#e7f1f1","--text-bright":"#e7f1f1","--quiet":"#8ba5a3","--accent":"#ffb84f","--accent-strong":"#ffb84f","--corner-accent":"#ffb84f","--cyan":"#8efcff","--shadow":"rgba(0, 0, 0, 0.35)","--pixel-grid":"rgba(142, 252, 255, 0.04)","--border-width":"1px","--border-bottom-width":"1px","--corner-accent-size":"0","--font-body":'"M PLUS 1", "Ubuntu Sans", Ubuntu, "Noto Sans JP", system-ui, sans-serif',"--font-title":'"Montserrat", "Zen Kaku Gothic New", "M PLUS 1", "Ubuntu Sans", system-ui, sans-serif',"--font-mono":'"Ubuntu Sans Mono", "M PLUS 1 Code", "Cascadia Mono", Consolas, monospace'};let me,Qe=Le(void 0),ce,z={};const We=new WeakMap;function et(e,t,n={}){if(We.get(t)?.dispose(),ce=e,z=n,Qe=Le(e.surface?.styles),globalThis.__eveCurrentMesh=e.mesh,xn(e.surface?.styles,n.body??document.body),n.body&&(n.body.dataset.provider=e.providerId||n.provider?.providerId||""),n.statusElement&&(n.statusElement.textContent=`${e.title||e.surface?.title||"surface"}${n.source?` (${n.source})`:""}`),e.surface?.root){if(t.replaceChildren(P(e.surface.root,n)),n.stateBindingResolver){const i=new rn(e,t,n);We.set(t,i),i.start()}}else t.replaceChildren(H("No surface root"));return t}function nn(e,t,n){const i=t.targetProp.split(".").filter(Boolean);if(i.length===0)throw new Error("Eve state binding targetProp must not be empty.");e.props||={};let o=e.props;for(const s of i.slice(0,-1)){const c=o[s];(!c||typeof c!="object"||Array.isArray(c))&&(o[s]={}),o=o[s]}o[i[i.length-1]]=n}class rn{surface;host;options;disposed=!1;unsubscribers=[];constructor(t,n,i){this.surface=t,this.host=n,this.options=i}async start(){const t=this.options.stateBindingResolver,n=this.surface.surface?.root;if(!(!t||!n))for(const i of tt(n))for(const o of i.stateBindings||[]){if(this.disposed)return;const s=await t(o,i);if(!s||this.disposed)continue;const c=l=>{this.disposed||(nn(i,o,l),this.renderCanonicalProjection())};if(c(await s.latest()),this.disposed)return;this.unsubscribers.push(s.watch(c))}}dispose(){this.disposed=!0;for(const t of this.unsubscribers.splice(0))t()}renderCanonicalProjection(){const t=this.surface.surface?.root;t&&this.host.replaceChildren(P(t,this.options))}}function*tt(e){yield e;for(const t of e.children||[])yield*tt(t)}function P(e,t=z){const n=e.kind||"panel",i=w(e.props),o=w(e.layout),s=w(e.style),c=e.children||[],l=e.embeddedDocuments||[];if(n==="surface"||n==="cockpit"||n==="dashboard"){const r=m("section","cultui-surface-root eve-surface");S(r,e),typeof o.direction=="string"?r.dataset.direction=o.direction:typeof i.layout=="object"&&i.layout&&typeof i.layout.direction=="string"&&(r.dataset.direction=String(i.layout.direction)),n!=="surface"&&(r.dataset.surfaceKind=n),_(r,o,s);for(const d of c)r.append(P(d,t));return r}if(n==="column"||n==="row"||n==="form"||n==="rail"){const r=m("div",`cultui-partition eve-${n}`);S(r,e),r.dataset.direction=n==="row"||n==="rail"?"horizontal":"vertical",n==="rail"&&(r.dataset.overflow="x"),he(r,{...o,...i}),_(r,o,s);for(const d of c)r.append(P(d,t));return r}if(n==="grid"){const r=m("section","cultui-grid"),d=U(i.columns,0);d>0?r.style.gridTemplateColumns=`repeat(${d}, minmax(0, 1fr))`:typeof i.columns=="string"&&(r.style.gridTemplateColumns=i.columns);const u=U(i.rows,0);u>0&&(r.style.gridTemplateRows=`repeat(${u}, minmax(0, auto))`),_(r,o,s);for(const h of c)r.append(P(h,t));return r}if(n==="partition"){const r=m("section",`cultui-partition split-${g(i.split,"none")}`);S(r,e),he(r,i),_(r,o,s),r.style.minWidth="0",g(i.split,"none")==="x"&&!p(i.flexWrap,o.flexWrap,"")&&(r.style.flexWrap="wrap"),typeof i.role=="string"&&(r.dataset.role=i.role);for(const d of c)r.append(P(d,t));return r}if(n==="input.binding-map")return gn(e,i,t);if(n==="inventory.drag_session")return un(e,i,o,s);if(n==="inventory.grid")return fn(e,i,o,s,t);if(n==="inventory.item")return mn(e,i,o,s);const f=(t.pluginAdapters||en).find(r=>r.componentKinds.includes(n));if(f?.renderComponent)return f.renderComponent(e,i,o,s,t,{applyGeneratedLayout:_,providerId:ce?.providerId||t.provider?.providerId,resolveAssetUrl:re});if(n==="world.scene3d"||n==="world.scene2d")return an(e,i,o,s,t);if(n==="image.background"){const r=m("div","cultui-background"),d=re(p(i.src,i.assetUri,i.assetRef,""));return d&&(r.style.backgroundImage=`url("${d}")`),r.setAttribute("aria-label",g(i.label,"background")),r}if(n==="image.sprite"){const r=m("figure",`cultui-sprite ${g(i.slot,"center")}`);S(r,e);const d=re(p(i.src,i.assetUri,i.assetRef,""));if(d){const u=m("img");u.src=d,u.alt=g(i.alt,g(i.actor,g(i.label,""))),r.append(u)}return r}if(n==="avatar"){const r=m("figure","cultui-avatar-card");S(r,e);const d=re(p(i.src,i.assetUri,i.assetRef,""));if(d){const v=m("img");v.src=d,v.alt=g(i.alt,g(i.text,g(i.label,""))),r.append(v)}else r.append(m("div","cultui-avatar-fallback",Pn(p(i.text,i.label,i.actor,"?"))));const u=p(i.text,i.label,i.actor,"");u&&r.append(m("figcaption","cultui-avatar-name",u));const h=p(i.status,"");h&&r.append(m("div","cultui-avatar-status",h));const y=p(i.detail,"");return y&&r.append(m("div","cultui-avatar-detail",y)),r}if(n==="pane"||n==="panel"){const r=m("section","pane cultui-pane");S(r,e);const d=g(i.span,"");d&&(r.dataset.span=d);const u=g(i.density,"");u&&(r.dataset.density=u);const h=g(i.title,e.text||"");h&&r.append(m("h2","",h));for(const y of c)r.append(P(y,t));return r}if(n==="list"||n.endsWith(".roster")){const r=m("section","cultui-list");S(r,e),r.dataset.componentKind=n;const d=g(i.title,"");d&&r.append(m("h3","cultui-list-title",d));for(const[u,h]of Rn(i.items).entries())r.append(P({id:`${e.id||"list"}-item-${u}`,kind:"list.item",props:{...h}},t));for(const u of c)r.append(P(u,t));return r}if(n==="list.item"||n.endsWith(".item")){const r=nt(e),d=m("article","cultui-list-item");S(d,e),d.dataset.componentKind=n;const u=m("div","cultui-list-item-heading");if(u.append(m("strong","cultui-list-item-label",r.label)),r.status&&u.append(m("span","cultui-list-item-status",r.status)),d.append(u),r.detail&&d.append(m("div","cultui-list-item-detail",r.detail)),r.badges.length){const h=m("div","cultui-list-item-badges");for(const y of r.badges)h.append(m("span","cultui-list-item-badge",y));d.append(h)}for(const h of c)d.append(P(h,t));return d}if(n==="bar"){const r=m("div","cultui-meter");S(r,e);const d=g(i.label,""),u=g(i.value,"");if(d||u){const v=m("div","cultui-meter-head");v.append(m("span","",d)),v.append(m("strong","",u)),r.append(v)}const h=m("div","cultui-meter-track"),y=m("span","cultui-meter-fill");return y.style.width=`${Xe(i.percent)}%`,h.append(y),r.append(h),r}if(n==="card"){const r=Ke(i,e),d=r?m("button","card cultui-card cultui-card-button"):m("article","card cultui-card");S(d,e),_(d,o,s),d instanceof HTMLButtonElement&&(d.type="button");const u=g(i.title,e.text||"");u&&d.append(m("div","card-title",u));for(const h of c)d.append(P(h,t));return r&&je(d,e,r,i,t),d}if(n==="control.button"){const r=m("button","cultui-button eve-control-button",g(i.label,"Action"));return S(r,e),r.type="button",_(r,o,s),je(r,e,Ke(i,e),i,t),r}if(n==="control.popup"){const r=m("button","cultui-button eve-control-popup",g(i.label,"Open"));return S(r,e),r.type="button",_(r,o,s),r.addEventListener("click",d=>{yn(e,t,r,d.clientX,d.clientY)}),r}if(n==="text.dialogue"||n==="text"||n==="text.title"||n==="text.subtitle"||n==="label"){const r=m("div",An(n,i),g(i.value,g(i.text,e.text||"")));return S(r,e),he(r,i),_(r,o,s),r}if(n==="metric"){const r=m("dl","metric cultui-reactive-metric eve-metric");return S(r,e),_(r,o,s),r.append(m("dt","",g(i.label,"Metric"))),r.append(m("dd","metric-value",g(i.value,""))),r}if(n==="progress"){const r=m("div","cultui-meter eve-progress");S(r,e),_(r,o,s);const d=g(i.label,""),u=g(i.value,""),h=Number(i.min??0),y=Number(i.max??1),v=Number(i.value??0),x=Number.isFinite(v)&&Number.isFinite(h)&&Number.isFinite(y)&&y!==h?(v-h)/(y-h)*100:Xe(i.percent);if(d||u){const D=m("div","cultui-meter-head");D.append(m("span","",d)),D.append(m("strong","",u)),r.append(D)}const T=m("div","cultui-meter-track"),A=m("span","cultui-meter-fill");return A.style.width=`${Math.max(0,Math.min(100,x))}%`,T.append(A),r.append(T),r}if(n==="modal"){const r=m("section","cultui-modal-surface");S(r,e),_(r,o,s);const d=g(i.title,"");d&&r.append(m("h2","cultui-modal-surface-title",d));for(const u of c)r.append(P(u,t));return r}if(n==="options"){const r=m("section","cultui-options");S(r,e),_(r,o,s);const d=g(i.label,"");d&&r.append(m("h3","cultui-list-title",d));for(const u of c)r.append(P(u,t));return c.length===0&&r.append(H("waiting for options")),r}if(n==="image.preview"){const r=m("figure","cultui-image-preview");S(r,e);const d=m("div","cultui-image-frame"),u=re(p(i.src,i.assetUri,i.assetRef,""));if(u){const h=m("img");h.src=u,h.alt=g(i.label,""),h.style.imageRendering=g(i.imageRendering,"auto"),i.zoom!==void 0&&(h.style.transform=`scale(${i.zoom})`,h.style.transformOrigin=g(i.crop,"50% 50%")),d.append(h)}else d.append(m("span","",g(i.label,"image")));return r.append(d),i.label&&r.append(m("figcaption","",String(i.label))),r}if(n==="canvas.preview"||n==="canvas.editor"){const r=m("div",`cultui-canvas-placeholder ${n==="canvas.editor"?"editor":"preview"}`);return S(r,e),r.append(m("div","viz-label",g(i.label,"Canvas"))),r.append(m("div","cultui-canvas-grid",i.state==="empty"?"waiting for pixels":g(i.state,""))),r}if(n==="surface.slot"){const r=m("section","cultui-embedded-slot");S(r,e),_(r,o,s),r.dataset.slotId=g(i.slotId,g(l[0]?.slotId,"")),r.dataset.documentId=g(i.documentId,g(l[0]?.documentId,"")),r.dataset.schemaId=g(i.schemaId,g(l[0]?.schemaId,"")),r.dataset.presentationKind=g(i.presentationKind,g(l[0]?.presentationKind,""));const d=l.map(h=>w(h.surface)).find(h=>w(h.root).kind||h.root),u=i.modal===!0||r.dataset.presentationKind.includes("modal");if((d||r.dataset.documentId)&&u){const h=m("button","cultui-button cultui-modal-trigger",g(i.label,r.dataset.slotId||"Configure"));h.type="button",h.addEventListener("click",()=>ot(Re(e,t),t)),r.append(h)}else if(d||r.dataset.documentId){const h=m("div","cultui-embedded-slot-body");h.append(m("div","detail","materializing surface")),r.append(h),Re(e,t).then(y=>{h.replaceChildren(y?.root?P(y.root,t):H("Embedded surface unavailable"))}).catch(y=>{h.replaceChildren(H(`Embedded surface failed: ${y instanceof Error?y.message:String(y)}`))})}else r.append(m("div","detail",r.dataset.presentationKind||r.dataset.slotId||"embedded surface"));return r}if(n==="control.slider")return Sn(i,c,t);if(n==="control.toggle"){const r=m("label","toggle-row cultui-toggle");return S(r,e),r.append(m("span","field-control",i.value?"on":"off")),r.append(m("span","toggle-copy",g(i.label,"Toggle"))),r}if(n==="input.number"||n==="input.select"||n==="control.range"||n==="control.input.text"||n==="control.select"){const r=m("label","field cultui-field");return S(r,e),he(r,i),_(r,o,s),r.append(m("span","field-label",g(i.label,""))),r.append(m("span","field-control cultui-field-value",i.value===void 0?"":String(i.value))),r}if(n==="color.swatch"){const r=m("div","paint-swatch cultui-swatch");return S(r,e),r.style.background=g(i.value,g(i.color,"currentColor")),r.title=g(i.label,"Color"),r}const a=m("section","pane");S(a,e),a.append(m("h2","",n));for(const r of c)a.append(P(r,t));return a}function nt(e){const t=w(e.props);return{label:p(t.label,t.title,t.displayName,e.text,e.kind,"item"),status:p(t.status,t.state,""),detail:p(t.detail,t.phase,t.repoName,""),badges:Array.isArray(t.badges)?t.badges.map(n=>String(n).trim()).filter(Boolean):p(t.badges,"").split(",").map(n=>n.trim()).filter(Boolean)}}function _(e,t,n={}){const i=p(t.display,"");i&&(e.style.display=i);const o=p(t.direction,"");o&&(e.style.flexDirection=o==="horizontal"?"row":o==="vertical"?"column":o);const s=p(t.flexWrap,"");s&&(e.style.flexWrap=s);const c=p(t.gridTemplateColumns,"");c&&(e.style.gridTemplateColumns=c);const l=p(t.gridTemplateRows,"");l&&(e.style.gridTemplateRows=l);const f=p(t.gridTemplateAreas,"");f&&(e.style.gridTemplateAreas=f);const a=p(t.gridArea,"");a&&(e.style.gridArea=a);const r=p(t.placeItems,"");r&&(e.style.placeItems=r),M(e,"gap",p(t.gap,"")),M(e,"padding",p(t.padding,"")),M(e,"margin",p(t.margin,"")),M(e,"top",p(t.top,"")),M(e,"right",p(t.right,"")),M(e,"bottom",p(t.bottom,"")),M(e,"left",p(t.left,"")),M(e,"width",p(t.width,"")),M(e,"minWidth",p(t.minWidth,"")),M(e,"maxWidth",p(t.maxWidth,"")),M(e,"height",p(t.height,"")),M(e,"minHeight",p(t.minHeight,"")),M(e,"maxHeight",p(t.maxHeight,""));const d=p(t.alignItems,"");d&&(e.style.alignItems=d);const u=p(t.justifyContent,"");u&&(e.style.justifyContent=u);const h=p(t.alignSelf,"");h&&(e.style.alignSelf=h);const y=p(t.overflow,"");y&&(e.style.overflow=y);const v=p(t.overflowX,"");v&&(e.style.overflowX=v);const x=p(t.overflowY,"");x&&(e.style.overflowY=x);const T=p(t.position,"");T&&(e.style.position=T);const A=p(t.cursor,"");A&&(e.style.cursor=A);const D=p(n.background,"");D&&(e.style.background=ve(D));const J=p(n.color,"");J&&(e.style.color=ve(J)),M(e,"borderWidth",p(n.borderWidth,""));const O=p(n.borderColor,"");O&&(e.style.borderColor=ve(O));const Z=p(n.borderStyle,"");Z&&(e.style.borderStyle=Z),M(e,"borderRadius",p(n.borderRadius,""));const Q=p(n.boxShadow,"");Q&&(e.style.boxShadow=Q);const G=p(n.font,"");G&&(e.style.font=G),M(e,"fontSize",p(n.fontSize,""));const C=p(n.fontWeight,"");C&&(e.style.fontWeight=C);const ee=p(n.textTransform,"");ee&&(e.style.textTransform=ee);const ue=p(n.textAlign,"");ue&&(e.style.textAlign=ue);const _e=p(n.whiteSpace,"");_e&&(e.style.whiteSpace=_e);const Ne=p(n.overflow,"");Ne&&(e.style.overflow=Ne);const $e=p(n.textOverflow,"");$e&&(e.style.textOverflow=$e),M(e,"lineHeight",p(n.lineHeight,""))}function M(e,t,n){n&&(e.style[t]=R(n))}function F(e,t){const n={};for(const[i,o]of Object.entries(e))i.startsWith(t)&&(n[i.slice(t.length)]=o);return n}function on(e){const t=(e.children||[]).filter(u=>u.kind==="world.entity3d"),n=t.map(u=>dn(w(u.props).position,[0,0,0])),i=n.map(u=>u[0]),o=n.map(u=>u[2]),s=Math.min(...i,-1),c=Math.max(...i,1),l=Math.min(...o,-1),f=Math.max(...o,1),a=Math.max(1,c-s),r=Math.max(1,f-l),d=6;return t.map((u,h)=>{const y=w(u.props);return{entityId:p(y.entityId,u.id),faction:g(y.faction,"neutral"),kind:g(y.entityKind,"entity"),label:p(y.label,y.entityId,u.id,"Entity"),controlled:Me(y.controllable),xPercent:d+(n[h][0]-s)/a*(100-d*2),yPercent:d+(1-(n[h][2]-l)/r)*(100-d*2),source:u}})}function an(e,t,n,i,o){const s=m("section","cultui-world-scene");S(s,e),_(s,n,i),s.tabIndex=0,s.setAttribute("aria-label",g(t.label,"Interactive world"));const c=on(e),l=c.find(r=>r.controlled),f=m("div","cultui-world-heading");f.append(m("strong","",g(t.label,"World"))),f.append(m("span","",`${c.length} entities`)),s.append(f);const a=m("div","cultui-world-plane");for(const r of c){const d=m("button",`cultui-world-entity faction-${ze(r.faction)} kind-${ze(r.kind)}`);d.type="button",d.style.left=`${r.xPercent}%`,d.style.top=`${r.yPercent}%`,d.dataset.entityId=r.entityId,d.dataset.controlled=r.controlled?"true":"false",d.title=r.label,d.setAttribute("aria-label",`${r.label}, ${r.kind}, ${r.faction}`),d.append(m("span","cultui-world-entity-glyph",ln(r.kind))),d.append(m("span","cultui-world-entity-label",r.label));const u=w(r.source.props),h=p(u.targetCommand,t.targetCommand,u.focusCommand,t.focusCommand);h&&d.addEventListener("click",()=>Ae(h,{actorEntityId:l?.entityId||p(t.playerEntityId),entityId:r.entityId,targetEntityId:r.entityId,targetEntityKey:r.entityId},r.source,o)),a.append(d)}return s.append(a),s.addEventListener("keydown",r=>{const d=cn(r.key);if(d){r.preventDefault();const h=p(t.movementCommand,w(l?.source.props).moveCommand);h&&Ae(h,{actorEntityId:l?.entityId||p(t.playerEntityId),actorEntityKey:l?.entityId||p(t.playerEntityId),directionX:d[0],directionY:d[1],scalar:1},e,o);return}const u=r.key===" "?p(t.actionCommand,w(l?.source.props).actionCommand):r.key.toLowerCase()==="f"?p(t.focusCommand,w(l?.source.props).focusCommand):"";u&&(r.preventDefault(),Ae(u,{actionId:r.key===" "?"0":"focus",actorEntityId:l?.entityId||p(t.playerEntityId),actorEntityKey:l?.entityId||p(t.playerEntityId)},e,o))}),s}function Ae(e,t,n,i){i.commandSink?.(sn(e,t,i),n)}function sn(e,t,n=z){return de(e,{action:t},n)}function cn(e){switch(e.toLowerCase()){case"w":case"arrowup":return[0,1];case"s":case"arrowdown":return[0,-1];case"a":case"arrowleft":return[-1,0];case"d":case"arrowright":return[1,0];default:return}}function ln(e){return e.includes("station")?"S":e.includes("projectile")?".":e.includes("ship")?"^":"+"}function ze(e){return e.toLowerCase().replace(/[^a-z0-9_-]+/g,"-")}function X(e,t){const n=Number(e);return Number.isFinite(n)?n:t}function dn(e,t){if(Array.isArray(e)){const n=e.map(i=>Number(i));if(n.length>=3&&n.slice(0,3).every(Number.isFinite))return[n[0],n[1],n[2]]}if(typeof e=="string"){const n=e.split(/[,\s]+/).map(i=>Number(i)).filter(Number.isFinite);if(n.length>=3)return[n[0],n[1],n[2]]}return t}function un(e,t,n,i){const o=Me(t.active),s=m("section","cultui-inventory-drag");S(s,e),_(s,n,i),s.dataset.active=o?"true":"false";const c=m("div","cultui-inventory-section-label","Drag");if(_(c,F(n,"sectionLabel."),F(i,"sectionLabel.")),s.append(c),!o){const d=m("div","cultui-inventory-empty","None");return _(d,F(n,"empty."),F(i,"empty.")),s.append(d),s}const l=p(t.itemKey,t.item,"item"),f=m("div","cultui-inventory-drag-chip",l);_(f,F(n,"dragChip."),F(i,"dragChip.")),s.append(f);const a=[t.originOffsetX,t.originOffsetY].map(d=>Number(d)).map(d=>Number.isFinite(d)?d:0),r=m("div","cultui-inventory-meta",`origin ${a[0]}, ${a[1]}`);return _(r,F(n,"meta."),F(i,"meta.")),s.append(r),s}function fn(e,t,n,i,o){const s=m("section","cultui-inventory-grid");S(s,e),_(s,n,i);const c=U(p(t.columns,t.gridColumns,t.widthCells,""),0),l=c>0?c:6,f=U(t.rows,0),a=f>0?f:Math.max(3,Math.ceil(Math.max((e.children||[]).length,1)/l));s.style.setProperty("--inventory-columns",String(l)),s.style.setProperty("--inventory-rows",String(a)),s.dataset.cellSpriteMode=g(t.cellSpriteMode,"");const r=p(t.title,t.label,"Inventory"),d=m("div","cultui-inventory-section-label",r);_(d,F(n,"sectionLabel."),F(i,"sectionLabel.")),s.append(d);const u=m("div","cultui-inventory-board");u.style.display="grid",u.style.gridTemplateColumns=`repeat(${l}, ${R(p(t.cellSize,"72"))})`,u.style.gridTemplateRows=`repeat(${a}, ${R(p(t.cellSize,"72"))})`,u.style.gap=R(p(t.cellGap,"4")),u.style.overflow=p(t.boardOverflow,"auto"),u.style.padding=R(p(t.boardPadding,"4")),_(u,F(n,"board."),F(i,"board.")),u.addEventListener("dragover",v=>{pn(t)&&(v.preventDefault(),v.dataTransfer&&(v.dataTransfer.dropEffect="move"))}),u.addEventListener("drop",v=>{const x=v.dataTransfer?.getData("application/vnd.gamecult.eve.inventory-item+json")||"";if(!x)return;let T;try{T=JSON.parse(x)}catch{return}const A=u.getBoundingClientRect(),D=Math.max(1,X(t.cellSize,72)),J=Math.max(0,X(t.cellGap,4)),O=D+J,Z=Math.max(0,Math.min(l-1,Math.floor((v.clientX-A.left)/O))),Q=Math.max(0,Math.min(a-1,Math.floor((v.clientY-A.top)/O))),G=hn(T,t,Z,Q,o);G&&(v.preventDefault(),o.commandSink?.(G,e))});const h=new Set;for(const v of e.children||[]){const x=w(v.props),T=U(x.x,0),A=U(x.y,0);h.add(`${T}:${A}`),u.append(P(v,o))}const y=Math.min(l*a,256);for(let v=0;v{!s.draggable||!y.dataTransfer||(y.dataTransfer.effectAllowed="move",y.dataTransfer.setData("application/vnd.gamecult.eve.inventory-item+json",JSON.stringify(t)))});let f=U(t.shapeWidth,1),a=U(t.shapeHeight,1);const r=p(t.rotation,"").toLowerCase();["clockwise","counterclockwise","right","left","rotate90","rotate270"].includes(r)&&([f,a]=[a,f]),s.style.gridColumn=`${c+1} / span ${f}`,s.style.gridRow=`${l+1} / span ${a}`;const d=m("span","cultui-inventory-item-icon");_(d,F(n,"icon."),F(i,"icon.")),d.textContent=Fn(p(t.iconAssetUri,t.iconAssetKey,t.itemKey,t.label,"")),s.append(d);const u=p(t.label,t.itemKey,"");if(u){const y=m("span","cultui-inventory-item-label",u);_(y,F(n,"label."),F(i,"label.")),s.append(y)}const h=Number(t.quantity);if(Number.isFinite(h)&&h>1){const y=m("span","cultui-inventory-item-quantity",String(h));_(y,F(n,"quantity."),F(i,"quantity.")),s.append(y)}return s.title=[u,p(t.source,""),p(t.quality,"")?`quality ${t.quality}`:"",p(t.durability,"")?`durability ${t.durability}`:""].filter(Boolean).join(" | "),s}function pn(e){return Object.entries(e).some(([t,n])=>(t==="dropCommand"||t.startsWith("dropCommand."))&&typeof n=="string"&&n.length>0)}function hn(e,t,n,i,o=z){const s=p(e.sourceKind,e.source,""),c=p(t[`dropCommand.${s}`],t.dropCommand,"");if(!s||!c)return;const l=X(e.sourceIndex,-1),f=X(t.targetIndex,-1),a=p(t.targetKind,""),r={sourceKind:s,originEntityKey:p(e.sourceEntityKey,e.entityKey,""),originIndex:l,originCargoIndex:s==="cargo"?l:-1,itemKey:p(e.itemKey,""),quantity:Math.max(1,X(e.quantity,1)),sourceX:X(e.x,-2147483648),sourceY:X(e.y,-2147483648),destinationKind:a,destinationEntityKey:p(t.targetEntityKey,t.entityKey,""),destinationIndex:f,destinationCargoIndex:a==="cargo"?f:-1,destinationX:Math.trunc(n),destinationY:Math.trunc(i),hasDestinationPosition:!0};return de(c,{action:r},o)}function gn(e,t,n){const i=m("section","cultui-binding-map");S(i,e);const o=document.createElementNS("http://www.w3.org/2000/svg","svg");o.setAttribute("class","cultui-xbox-controller"),o.setAttribute("viewBox","0 0 780 420"),o.setAttribute("role","img"),o.setAttribute("aria-label",g(t.label,"Xbox controller remapping")),o.innerHTML=bn(),i.append(o);const s=m("div","cultui-binding-overlay");for(const c of e.children||[]){const l=w(c.props),f=g(l.target,c.id||""),a=m("button","cultui-binding-box");S(a,c),a.type="button",a.dataset.target=f,a.dataset.kind=g(l.bindingKind,"button"),a.style.left=R(l.x??"50%"),a.style.top=R(l.y??"50%"),a.append(m("span","cultui-binding-target",g(l.label,f))),a.append(m("span","cultui-binding-source",g(l.current,"unmapped"))),a.addEventListener("click",()=>{const d=rt(c);if(it(c)||d?.documentId)ot(Re(c,n),n);else{const u=g(l.commandId,"");u&&n.commandSink?.(de(u,l,n),c)}}),s.append(a);const r=document.createElementNS("http://www.w3.org/2000/svg","line");r.setAttribute("class","cultui-binding-line"),r.setAttribute("x1",g(l.anchorX,"390")),r.setAttribute("y1",g(l.anchorY,"210")),r.setAttribute("x2",String(Ge(l.x,780))),r.setAttribute("y2",String(Ge(l.y,420))),o.append(r)}return i.append(s),i}function it(e){for(const t of e.embeddedDocuments||[]){const n=w(t.surface);if(n.root)return n}}function rt(e){const t=(e.embeddedDocuments||[])[0],n=w(e.props),i=p(n.documentId,t?.documentId,"");if(i)return{documentId:i,presentationKind:p(n.presentationKind,t?.presentationKind,""),schemaId:p(n.schemaId,t?.schemaId,""),slotId:p(n.slotId,t?.slotId,"")}}async function Re(e,t){const n=it(e);if(n)return n;const i=rt(e);if(!i?.documentId||!t.documentResolver)return;const o=await t.documentResolver(i,e);if(o)return w(o.surface).root?o.surface:o}function ot(e,t){const n=m("div","cultui-modal-backdrop"),i=m("section","cultui-modal");i.setAttribute("role","dialog"),i.setAttribute("aria-modal","true");const o=m("header","cultui-modal-header");o.append(m("h2","","Configure Binding"));const s=m("button","cultui-modal-close","Close");s.type="button",s.addEventListener("click",()=>n.remove()),o.append(s);const c=m("div","cultui-modal-body");i.append(o,c),n.append(i),n.addEventListener("click",l=>{l.target===n&&n.remove()}),document.body.append(n),c.append(m("div","detail","materializing document")),Promise.resolve(e).then(l=>{o.querySelector("h2").textContent=l?.title||"Configure Binding",c.replaceChildren(l?.root?P(l.root,t):H("Embedded document unavailable"))}).catch(l=>{c.replaceChildren(H(`Embedded document failed: ${l instanceof Error?l.message:String(l)}`))})}function yn(e,t,n,i,o){const s=w(e.props),c=(e.children||[])[0],l=w(c?.props),f=p(l.anchor,s.anchor,"trigger"),a=p(l.placement,s.placement,"below-start"),r=Number(p(l.offsetX,s.offsetX,"0"))||0,d=Number(p(l.offsetY,s.offsetY,"4"))||0,u=m("div","cultui-modal-backdrop");u.style.background="transparent",u.style.placeItems="start";const h=m("section","cultui-modal");h.setAttribute("role","dialog"),h.setAttribute("aria-modal","true"),h.style.position="fixed",h.style.width="min(420px, calc(100vw - 24px))",h.style.maxHeight="min(620px, calc(100vh - 24px))";const y=m("header","cultui-modal-header");y.append(m("h2","",p(l.title,s.title,s.label,"Options")));const v=m("button","cultui-modal-close","Close");v.type="button",v.addEventListener("click",()=>u.remove()),y.append(v);const x=m("div","cultui-modal-body");if(c){const A=c.children||[];A.length>0?x.replaceChildren(...A.map(D=>P(D,t))):x.append(P(c,t))}else x.append(H("Popup has no content"));h.append(y,x),u.append(h),u.addEventListener("click",A=>{A.target===u&&u.remove()}),document.body.append(u);const T=vn(f,a,n,h,i,o,r,d);h.style.left=`${T.left}px`,h.style.top=`${T.top}px`}function vn(e,t,n,i,o,s,c,l){const f=n.getBoundingClientRect(),a=i.getBoundingClientRect(),r=a.width||420,d=a.height||320,u=e==="cursor"?{left:o,right:o,top:s,bottom:s}:f;if(t==="right-down"||t==="dropdown")return pe(u,r,d,c,l,"right","down");if(t==="left-down")return pe(u,r,d,c,l,"left","down");if(t==="right-up")return pe(u,r,d,c,l,"right","up");if(t==="left-up")return pe(u,r,d,c,l,"left","up");switch(t){case"above-start":return W(u.left+c,u.top-d-l,r,d);case"above-end":return W(u.right-r+c,u.top-d-l,r,d);case"below-end":return W(u.right-r+c,u.bottom+l,r,d);case"right-start":return W(u.right+c,u.top+l,r,d);case"left-start":return W(u.left-r-c,u.top+l,r,d);case"center":return W((window.innerWidth-r)/2+c,(window.innerHeight-d)/2+l,r,d);default:return W(u.left+c,u.bottom+l,r,d)}}function pe(e,t,n,i,o,s,c){const f=window.innerWidth-e.right-i-12,a=e.left-i-12,r=window.innerHeight-e.top-o-12,d=e.bottom-o-12,u=s==="right"?f>=t||f>=a:!(a>=t||a>=f),h=c==="down"?r>=n||r>=d:!(d>=n||d>=r),y=u?e.right+i:e.left-t-i,v=h?e.top+o:e.bottom-n-o;return W(y,v,t,n)}function W(e,t,n,i){return{left:Oe(e,12,window.innerWidth-n-12),top:Oe(t,12,window.innerHeight-i-12)}}function Oe(e,t,n){return nRt(c,t,f,s.resolveAssetUrl),r=()=>{!c.isConnected||l||(l=!0,requestAnimationFrame(()=>{l=!1,c.isConnected&&a()}))};c.addEventListener("cultui:asset-loaded",r);let d=0,u;const h=()=>{d&&window.clearInterval(d),u?.disconnect(),c.removeEventListener("cultui:asset-loaded",r)},y=()=>{if(!c.isConnected){h();return}Tt(e,t,o,s.providerId,f).then(x=>{x&&c.isConnected&&r()}).catch(x=>{f.lastError=x instanceof Error?x.message:String(x)})};typeof ResizeObserver<"u"&&(u=new ResizeObserver(r),u.observe(c)),r();const v=Math.max(33,Math.min(1e3,Zt(t.stateRefreshMs,100)));return d=window.setInterval(y,v),queueMicrotask(y),window.setTimeout(r,300),window.setTimeout(r,1e3),c}async function Tt(e,t,n,i,o){if(o.loading)return!1;const s=[Ee(e,t,"renderSplats","renderSplatsDocumentId","renderSplatsSchemaId"),Ee(e,t,"gravity","gravityDocumentId","gravitySchemaId"),Ee(e,t,"objects","objectsDocumentId","objectsSchemaId")].filter(c=>!!c?.documentId);if(s.length===0)return!1;o.loading=!0;try{let c=!1;for(const l of s){const f=await n.documentResolver?.(l,e);let a=xe(Ce(f?.schemaId||l.schemaId,f?.document));if(Object.keys(a).length===0&&(a=xe(Ce(l.schemaId,await kt(l,i||n.provider?.providerId)))),Object.keys(a).length===0)continue;const r=l.slotId==="renderSplats"?"renderSplats":l.slotId==="gravity"?"gravity":"objects",d=ke(o[r]?.frameId,-1),u=ke(a.frameId,d);o[r]=a,c||=u!==d}return o.lastLoadedAt=Date.now(),c}finally{o.loading=!1}}async function kt(e,t){if(typeof fetch!="function"||typeof window>"u"||!t)return;const n=new URLSearchParams({documentId:e.documentId});e.schemaId&&n.set("schemaId",e.schemaId),e.slotId&&n.set("slotId",e.slotId);const i=await fetch(`/eir/document/${encodeURIComponent(t)}?${n.toString()}`,{cache:"no-store",headers:{Accept:"application/json"}});if(i.ok)return xe(await i.json()).document}function Ee(e,t,n,i,o){const s=(e.embeddedDocuments||[]).find(l=>String(l?.slotId||"")===n),c=k(t[i],s?.documentId);if(c)return{documentId:c,schemaId:k(t[o],s?.schemaId),presentationKind:k(s?.presentationKind)||"data",slotId:n}}function Ce(e,t){const n=Array.isArray(t)?t:void 0,i=n?n[0]:t?.schema,o=String(e||i||"");return!n||!He.has(o)?t:o==="gamecult.fields.splats.v1"?zt(n):o==="gamecult.fields.gravity.v1"?Ot(n):jt(n)}function Rt(e,t,n,i){const o=e.getBoundingClientRect(),s=Math.max(1,Math.floor(o.width||e.clientWidth||1)),c=Math.max(1,Math.floor(o.height||e.clientHeight||1)),l=Math.max(1,Math.min(2,window.devicePixelRatio||1)),f=Math.max(1,Math.floor(s*l)),a=Math.max(1,Math.floor(c*l));(e.width!==f||e.height!==a)&&(e.width=f,e.height=a);const r=e.getContext("2d");if(!r)return;r.setTransform(l,0,0,l,0,0),r.clearRect(0,0,s,c);const d=Wt(qt(t),s,c),u=Ze(n?.gravity),h=Bt(n?.gravity)||$t(k(t.bodies,"")),y=Ut(n?.objects)||Dt(k(t.objects,""));ft(r,t,u,h,d,s,c,n?.renderSplats)||Ft(r,t,s,c,"field.surface2d requires WebGL2 float render targets"),Pt(r,h,t,d,s,c,i),Mt(r,y,t,d,s,c,i)}function Ft(e,t,n,i,o){e.save(),e.fillStyle=k(t.failureBackground,"rgba(0, 0, 0, 0.72)"),e.fillRect(0,0,n,i),e.font=k(t.failureFont,"700 13px Cascadia Mono, Consolas, monospace"),e.fillStyle=k(t.failureColor,"rgba(255, 184, 79, 0.95)"),e.fillText(o,16,28),e.restore()}function Pt(e,t,n,i,o,s,c){for(const l of t){const f=Je(i,l.x,l.y,o,s),a=Math.max(18,Math.min(190,l.radius/Math.max(1,i.maxX-i.minX)*o*.32)),r=c(l.icon),d=l.kind.toLowerCase().includes("sun")?Math.max(E(n.sunIconMinPx,34),a*E(n.sunIconScale,.72)):Math.max(E(n.bodyIconMinPx,24),a*E(n.bodyIconScale,.48)),u=l.iconSize>0?l.iconSize:d;r&&Lt(e,r,f.x,f.y,u,.92),l.key&&Ve(e,n,l.key.replace(/^local\./,""),f.x+a*.44,f.y-a*.48,k(n.bodyLabelColor,"rgba(226, 244, 255, 0.82)"))}}const be=new Map;function Lt(e,t,n,i,o,s){let c=be.get(t);c||(c=new Image,c.decoding="async",c.onload=()=>requestAnimationFrame(()=>{e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded"))}),c.src=t,be.set(t,c)),!(!c.complete||c.naturalWidth===0)&&(e.save(),e.globalAlpha=s,e.drawImage(c,n-o/2,i-o/2,o,o),e.restore())}function Mt(e,t,n,i,o,s,c){for(const l of t){const f=Je(i,l.x,l.y,o,s);if(f.x<-40||f.x>o+40||f.y<-40||f.y>s+40)continue;const a=l.kind.toLowerCase().includes("station")?E(n.stationIconSizePx,34):l.controlled?E(n.shipIconSizePx,22):E(n.remoteShipIconSizePx,18),r=Nt(n,l.faction,l.controlled,l.visibility),d=c(l.icon);e.save(),e.globalAlpha=Math.max(.25,Math.min(1,l.visibility)),e.translate(f.x,f.y);const u=Math.atan2(l.directionY,l.directionX)+Math.PI/2;if(l.kind.toLowerCase().includes("ship")&&e.rotate(u),d){const h=be.get(d);if(h)h.complete&&h.naturalWidth>0&&e.drawImage(h,-a/2,-a/2,a,a);else{const y=new Image;y.decoding="async",y.onload=()=>e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded")),y.src=d,be.set(d,y)}}e.restore(),Ve(e,n,l.label,f.x+a*.55,f.y-a*.45,r)}}function Ve(e,t,n,i,o,s){n&&(e.save(),e.font=k(t.objectLabelFont,"700 12px Ubuntu, system-ui, sans-serif"),e.textBaseline="middle",e.lineWidth=E(t.objectLabelStrokeWidth,3),e.strokeStyle=k(t.objectLabelStroke,"rgba(0, 0, 0, 0.72)"),e.fillStyle=s,e.strokeText(n,i,o),e.fillText(n,i,o),e.restore())}function Nt(e,t,n,i){const o=Math.max(.25,Math.min(1,i));if(n)return fe(k(e.objectControlledColor,"rgba(122, 240, 255, {alpha})"),o);const s=t.toLowerCase();return s.includes("raider")?fe(k(e.objectRaiderColor,"rgba(255, 143, 74, {alpha})"),o):s.includes("neutral")?fe(k(e.objectNeutralColor,"rgba(232, 232, 224, {alpha})"),o):fe(k(e.objectDefaultColor,"rgba(214, 244, 255, {alpha})"),o)}function fe(e,t){return e.replaceAll("{alpha}",String(t))}function $t(e){return e.split(";").map(t=>t.trim()).filter(Boolean).map(t=>{const n=t.split("|");return{key:n[0]??"",kind:n[1]??"",x:Number(n[2])||0,y:Number(n[3])||0,radius:Math.max(1,Number(n[4])||1),depth:Number(n[5])||0,exponent:Number(n[6])||1,waveRadius:Number(n[7])||0,waveDepth:Number(n[8])||0,waveSpeed:Number(n[9])||0,icon:n[10]??"",iconSize:Number(n[12])||0,tint:n[11]??""}})}function Dt(e){return e.split(";").map(t=>t.trim()).filter(Boolean).map(t=>{const n=t.split("|");return{key:n[0]??"",kind:n[1]??"",label:n[2]??"",x:Number(n[3])||0,y:Number(n[4])||0,directionX:Number(n[5])||0,directionY:Number(n[6])||1,faction:n[7]??"",controlled:n[8]==="1"||n[8]==="true",visibility:Number(n[9])||1,icon:n[10]??""}})}function Bt(e){const t=Array.isArray(e?.gravityInfluences)?e.gravityInfluences:[],n=Array.isArray(e?.bodies)?e.bodies:[];if(t.length===0&&n.length===0)return;const i=new Map;for(const o of n){const s=k(o.bodyKey,o.name,"");s&&i.set(s,o)}return(t.length>0?t:n).map(o=>{const s=k(o.bodyKey,o.name,"body"),c=i.get(s),l=k(o.kind,"Body");return{key:s,kind:l,x:E(o.x,0),y:E(o.y,0),radius:Math.max(1,E(o.radius,80)),depth:E(o.gravityDepth,0),exponent:E(o.gravityDepthExponent,1),waveRadius:E(o.waveRadius,0),waveDepth:E(o.waveDepth,0),waveSpeed:E(o.waveSpeed,0),icon:Te(o.iconAsset)||Te(c?.iconAsset),iconSize:E(c?.iconSize,E(o.iconSize,0)),tint:""}})}function Ut(e){const t=Array.isArray(e?.objects)?e.objects:[];if(t.length!==0)return t.map(n=>{const i=k(n.kind,"object");return{key:k(n.entityKey,String(n.entityIndex??""),"object"),kind:i,label:k(n.displayName,n.entityKey,"object"),x:E(n.x,0),y:E(n.y,0),directionX:E(n.directionX,1),directionY:E(n.directionY,0),faction:k(n.factionKey,""),controlled:Qt(n.controlled),visibility:E(n.visibility,1),icon:Te(n.iconAsset)}})}function Te(e){const t=Ze(e);return k(t.uri,"")}function qt(e){const t=Math.max(1,E(e.viewRadius,Math.max(1200,E(e.terrainRadius,1200))));return{minX:E(e.minX,-t),minY:E(e.minY,-t),maxX:E(e.maxX,t),maxY:E(e.maxY,t)}}function Wt(e,t,n){const i=Math.max(1e-4,e.maxX-e.minX),o=Math.max(1e-4,e.maxY-e.minY),s=Math.max(1e-4,t/Math.max(1,n)),c=i/o,l=(e.minX+e.maxX)*.5,f=(e.minY+e.maxY)*.5;if(s>c){const r=o*s;return{minX:l-r*.5,maxX:l+r*.5,minY:e.minY,maxY:e.maxY}}const a=i/s;return{minX:e.minX,maxX:e.maxX,minY:f-a*.5,maxY:f+a*.5}}function Je(e,t,n,i,o){return{x:(t-e.minX)/Math.max(1,e.maxX-e.minX)*i,y:(n-e.minY)/Math.max(1,e.maxY-e.minY)*o}}function zt(e){const t=N(e[9]);return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],viewport:Fe(e[7]),layers:N(e[8]).map(Gt),splats:{count:t[0]??0,centerX:t[1]||[],centerY:t[2]||[],halfExtentX:t[3]||[],halfExtentY:t[4]||[],rotationCos:t[5]||[],rotationSin:t[6]||[],channel:t[7]||[],falloff:t[8]||[],valueR:t[9]||[],valueG:t[10]||[],valueB:t[11]||[],valueA:t[12]||[],sourceKey:t[13]||[],layerIndex:t[14]||[],sourceKind:t[15]||[],frequencyX:t[16]||[],frequencyY:t[17]||[],phaseX:t[18]||[],phaseY:t[19]||[],animationSpeed:t[20]||[],sourceFlags:t[21]||[]}}}function Ot(e){return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],viewport:Fe(e[7]),gravityInfluences:N(e[8]).map(Kt),bodies:N(e[9]).map(Xt),terrainRadius:e[10],terrainDepth:e[11],terrainDepthExponent:e[12],terrainWaveFrequency:e[13]}}function jt(e){return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],currentEntityKey:e[7],viewport:Fe(e[8]),controlledEntityIndices:N(e[9]),objects:N(e[10]).map(Yt)}}function Fe(e){const t=N(e);return t.length?{minX:t[0],minY:t[1],maxX:t[2],maxY:t[3]}:e}function Gt(e){const t=N(e);return t.length?{layerKey:t[0],displayName:t[1],channel:t[2],blendMode:t[3],graphicsFormat:t[4],clearBeforeDraw:t[5],clearR:t[6],clearG:t[7],clearB:t[8],clearA:t[9]}:e}function Kt(e){const t=N(e);return t.length?{bodyKey:t[0],orbitKey:t[1],kind:t[2],x:t[3],y:t[4],radius:t[5],gravityDepth:t[6],gravityDepthExponent:t[7],waveRadius:t[8],waveDepth:t[9],waveSpeed:t[10]}:e}function Xt(e){const t=N(e);return t.length?{bodyKey:t[0],orbitKey:t[1],name:t[2],kind:t[3],x:t[4],y:t[5],radius:t[6],isAsteroidBelt:t[7],body:t[8],iconAsset:Pe(t[9])}:e}function Yt(e){const t=N(e);return t.length?{entityIndex:t[0],entityKey:t[1],displayName:t[2],kind:t[3],factionKey:t[4],x:t[5],y:t[6],z:t[7],directionX:t[8],directionY:t[9],velocityX:t[10],velocityY:t[11],controlled:t[12],targetEntityIndex:t[13],isActive:t[14],visibility:t[15],status:Ht(t[16]),inventory:N(t[17]).map(Vt),iconAsset:Pe(t[18])}:e}function Ht(e){const t=N(e);return t.length?{hull:t[0],shield:t[1],heat:t[2]}:e||{}}function Vt(e){const t=N(e);return t.length?{source:t[0],itemKey:t[1],quantity:t[2],quality:t[3],durability:t[4],enabled:t[5],sourceIndex:t[6],x:t[7],y:t[8],iconAsset:Pe(t[9])}:e}function Pe(e){const t=N(e);return t.length?{assetKey:t[0],kind:t[1],uri:t[2],transport:t[3],contentHash:t[4],mimeType:t[5],metadata:t[6]||{}}:e||{}}function N(e){return Array.isArray(e)?e:[]}function xe(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function k(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function Jt(e,t){return typeof e=="string"&&e?e:t}function Zt(e,t){const n=Number(e);return Number.isFinite(n)&&n>0?Math.floor(n):t}function ke(e,t){const n=Number(e);return Number.isFinite(n)?n:t}const Ze=xe,E=ke;function Qt(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"&&["1","true","yes","on"].includes(e.trim().toLowerCase())}const en=[It],tn={"--bg":"#020909","--bg-top":"#020909","--bg-mid":"#020909","--bg-bottom":"#020909","--shell-top":"#010707","--shell-bottom":"#010707","--panel":"#071918","--panel-2":"#0a2423","--line":"rgba(103, 240, 228, 0.28)","--line-deep":"rgba(103, 240, 228, 0.18)","--text":"#e7f1f1","--text-bright":"#e7f1f1","--quiet":"#8ba5a3","--accent":"#ffb84f","--accent-strong":"#ffb84f","--corner-accent":"#ffb84f","--cyan":"#8efcff","--shadow":"rgba(0, 0, 0, 0.35)","--pixel-grid":"rgba(142, 252, 255, 0.04)","--border-width":"1px","--border-bottom-width":"1px","--corner-accent-size":"0","--font-body":'"M PLUS 1", "Ubuntu Sans", Ubuntu, "Noto Sans JP", system-ui, sans-serif',"--font-title":'"Montserrat", "Zen Kaku Gothic New", "M PLUS 1", "Ubuntu Sans", system-ui, sans-serif',"--font-mono":'"Ubuntu Sans Mono", "M PLUS 1 Code", "Cascadia Mono", Consolas, monospace'};let me,Qe=Le(void 0),ce,z={};const We=new WeakMap;function et(e,t,n={}){if(We.get(t)?.dispose(),ce=e,z=n,Qe=Le(e.surface?.styles),globalThis.__eveCurrentMesh=e.mesh,xn(e.surface?.styles,n.body??document.body),n.body&&(n.body.dataset.provider=e.providerId||n.provider?.providerId||""),n.statusElement&&(n.statusElement.textContent=`${e.title||e.surface?.title||"surface"}${n.source?` (${n.source})`:""}`),e.surface?.root){if(t.replaceChildren(P(e.surface.root,n)),n.stateBindingResolver){const i=new rn(e,t,n);We.set(t,i),i.start()}}else t.replaceChildren(H("No surface root"));return t}function nn(e,t,n){const i=t.targetProp.split(".").filter(Boolean);if(i.length===0)throw new Error("Eve state binding targetProp must not be empty.");e.props||={};let o=e.props;for(const s of i.slice(0,-1)){const c=o[s];(!c||typeof c!="object"||Array.isArray(c))&&(o[s]={}),o=o[s]}o[i[i.length-1]]=n}class rn{surface;host;options;disposed=!1;unsubscribers=[];constructor(t,n,i){this.surface=t,this.host=n,this.options=i}async start(){const t=this.options.stateBindingResolver,n=this.surface.surface?.root;if(!(!t||!n))for(const i of tt(n))for(const o of i.stateBindings||[]){if(this.disposed)return;const s=await t(o,i);if(!s||this.disposed)continue;const c=l=>{this.disposed||(nn(i,o,l),this.renderCanonicalProjection())};if(c(await s.latest()),this.disposed)return;this.unsubscribers.push(s.watch(c))}}dispose(){this.disposed=!0;for(const t of this.unsubscribers.splice(0))t()}renderCanonicalProjection(){const t=this.surface.surface?.root;t&&this.host.replaceChildren(P(t,this.options))}}function*tt(e){yield e;for(const t of e.children||[])yield*tt(t)}function P(e,t=z){const n=e.kind||"panel",i=w(e.props),o=w(e.layout),s=w(e.style),c=e.children||[],l=e.embeddedDocuments||[];if(n==="surface"||n==="cockpit"||n==="dashboard"){const r=m("section","cultui-surface-root eve-surface");S(r,e),typeof o.direction=="string"?r.dataset.direction=o.direction:typeof i.layout=="object"&&i.layout&&typeof i.layout.direction=="string"&&(r.dataset.direction=String(i.layout.direction)),n!=="surface"&&(r.dataset.surfaceKind=n),_(r,o,s);for(const d of c)r.append(P(d,t));return r}if(n==="column"||n==="row"||n==="form"||n==="rail"){const r=m("div",`cultui-partition eve-${n}`);S(r,e),r.dataset.direction=n==="row"||n==="rail"?"horizontal":"vertical",n==="rail"&&(r.dataset.overflow="x"),he(r,{...o,...i}),_(r,o,s);for(const d of c)r.append(P(d,t));return r}if(n==="grid"){const r=m("section","cultui-grid"),d=U(i.columns,0);d>0?r.style.gridTemplateColumns=`repeat(${d}, minmax(0, 1fr))`:typeof i.columns=="string"&&(r.style.gridTemplateColumns=i.columns);const u=U(i.rows,0);u>0&&(r.style.gridTemplateRows=`repeat(${u}, minmax(0, auto))`),_(r,o,s);for(const h of c)r.append(P(h,t));return r}if(n==="partition"){const r=m("section",`cultui-partition split-${g(i.split,"none")}`);S(r,e),he(r,i),_(r,o,s),r.style.minWidth="0",g(i.split,"none")==="x"&&!p(i.flexWrap,o.flexWrap,"")&&(r.style.flexWrap="wrap"),typeof i.role=="string"&&(r.dataset.role=i.role);for(const d of c)r.append(P(d,t));return r}if(n==="input.binding-map")return gn(e,i,t);if(n==="inventory.drag_session")return un(e,i,o,s);if(n==="inventory.grid")return fn(e,i,o,s,t);if(n==="inventory.item")return mn(e,i,o,s);const f=(t.pluginAdapters||en).find(r=>r.componentKinds.includes(n));if(f?.renderComponent)return f.renderComponent(e,i,o,s,t,{applyGeneratedLayout:_,providerId:ce?.providerId||t.provider?.providerId,resolveAssetUrl:re});if(n==="world.scene3d"||n==="world.scene2d")return an(e,i,o,s,t);if(n==="image.background"){const r=m("div","cultui-background"),d=re(p(i.src,i.assetUri,i.assetRef,""));return d&&(r.style.backgroundImage=`url("${d}")`),r.setAttribute("aria-label",g(i.label,"background")),r}if(n==="image.sprite"){const r=m("figure",`cultui-sprite ${g(i.slot,"center")}`);S(r,e);const d=re(p(i.src,i.assetUri,i.assetRef,""));if(d){const u=m("img");u.src=d,u.alt=g(i.alt,g(i.actor,g(i.label,""))),r.append(u)}return r}if(n==="avatar"){const r=m("figure","cultui-avatar-card");S(r,e);const d=re(p(i.src,i.assetUri,i.assetRef,""));if(d){const v=m("img");v.src=d,v.alt=g(i.alt,g(i.text,g(i.label,""))),r.append(v)}else r.append(m("div","cultui-avatar-fallback",Pn(p(i.text,i.label,i.actor,"?"))));const u=p(i.text,i.label,i.actor,"");u&&r.append(m("figcaption","cultui-avatar-name",u));const h=p(i.status,"");h&&r.append(m("div","cultui-avatar-status",h));const y=p(i.detail,"");return y&&r.append(m("div","cultui-avatar-detail",y)),r}if(n==="pane"||n==="panel"){const r=m("section","pane cultui-pane");S(r,e);const d=g(i.span,"");d&&(r.dataset.span=d);const u=g(i.density,"");u&&(r.dataset.density=u);const h=g(i.title,e.text||"");h&&r.append(m("h2","",h));for(const y of c)r.append(P(y,t));return r}if(n==="list"||n.endsWith(".roster")){const r=m("section","cultui-list");S(r,e),r.dataset.componentKind=n;const d=g(i.title,"");d&&r.append(m("h3","cultui-list-title",d));for(const[u,h]of Rn(i.items).entries())r.append(P({id:`${e.id||"list"}-item-${u}`,kind:"list.item",props:{...h}},t));for(const u of c)r.append(P(u,t));return r}if(n==="list.item"||n.endsWith(".item")){const r=nt(e),d=m("article","cultui-list-item");S(d,e),d.dataset.componentKind=n;const u=m("div","cultui-list-item-heading");if(u.append(m("strong","cultui-list-item-label",r.label)),r.status&&u.append(m("span","cultui-list-item-status",r.status)),d.append(u),r.detail&&d.append(m("div","cultui-list-item-detail",r.detail)),r.badges.length){const h=m("div","cultui-list-item-badges");for(const y of r.badges)h.append(m("span","cultui-list-item-badge",y));d.append(h)}for(const h of c)d.append(P(h,t));return d}if(n==="bar"){const r=m("div","cultui-meter");S(r,e);const d=g(i.label,""),u=g(i.value,"");if(d||u){const v=m("div","cultui-meter-head");v.append(m("span","",d)),v.append(m("strong","",u)),r.append(v)}const h=m("div","cultui-meter-track"),y=m("span","cultui-meter-fill");return y.style.width=`${Xe(i.percent)}%`,h.append(y),r.append(h),r}if(n==="card"){const r=Ge(i,e),d=r?m("button","card cultui-card cultui-card-button"):m("article","card cultui-card");S(d,e),_(d,o,s),d instanceof HTMLButtonElement&&(d.type="button");const u=g(i.title,e.text||"");u&&d.append(m("div","card-title",u));for(const h of c)d.append(P(h,t));return r&&Ke(d,e,r,i,t),d}if(n==="control.button"){const r=m("button","cultui-button eve-control-button",g(i.label,"Action"));return S(r,e),r.type="button",_(r,o,s),Ke(r,e,Ge(i,e),i,t),r}if(n==="control.popup"){const r=m("button","cultui-button eve-control-popup",g(i.label,"Open"));return S(r,e),r.type="button",_(r,o,s),r.addEventListener("click",d=>{yn(e,t,r,d.clientX,d.clientY)}),r}if(n==="text.dialogue"||n==="text"||n==="text.title"||n==="text.subtitle"||n==="label"){const r=m("div",An(n,i),g(i.value,g(i.text,e.text||"")));return S(r,e),he(r,i),_(r,o,s),r}if(n==="metric"){const r=m("dl","metric cultui-reactive-metric eve-metric");return S(r,e),_(r,o,s),r.append(m("dt","",g(i.label,"Metric"))),r.append(m("dd","metric-value",g(i.value,""))),r}if(n==="progress"){const r=m("div","cultui-meter eve-progress");S(r,e),_(r,o,s);const d=g(i.label,""),u=g(i.value,""),h=Number(i.min??0),y=Number(i.max??1),v=Number(i.value??0),x=Number.isFinite(v)&&Number.isFinite(h)&&Number.isFinite(y)&&y!==h?(v-h)/(y-h)*100:Xe(i.percent);if(d||u){const D=m("div","cultui-meter-head");D.append(m("span","",d)),D.append(m("strong","",u)),r.append(D)}const T=m("div","cultui-meter-track"),A=m("span","cultui-meter-fill");return A.style.width=`${Math.max(0,Math.min(100,x))}%`,T.append(A),r.append(T),r}if(n==="modal"){const r=m("section","cultui-modal-surface");S(r,e),_(r,o,s);const d=g(i.title,"");d&&r.append(m("h2","cultui-modal-surface-title",d));for(const u of c)r.append(P(u,t));return r}if(n==="options"){const r=m("section","cultui-options");S(r,e),_(r,o,s);const d=g(i.label,"");d&&r.append(m("h3","cultui-list-title",d));for(const u of c)r.append(P(u,t));return c.length===0&&r.append(H("waiting for options")),r}if(n==="image.preview"){const r=m("figure","cultui-image-preview");S(r,e);const d=m("div","cultui-image-frame"),u=re(p(i.src,i.assetUri,i.assetRef,""));if(u){const h=m("img");h.src=u,h.alt=g(i.label,""),h.style.imageRendering=g(i.imageRendering,"auto"),i.zoom!==void 0&&(h.style.transform=`scale(${i.zoom})`,h.style.transformOrigin=g(i.crop,"50% 50%")),d.append(h)}else d.append(m("span","",g(i.label,"image")));return r.append(d),i.label&&r.append(m("figcaption","",String(i.label))),r}if(n==="canvas.preview"||n==="canvas.editor"){const r=m("div",`cultui-canvas-placeholder ${n==="canvas.editor"?"editor":"preview"}`);return S(r,e),r.append(m("div","viz-label",g(i.label,"Canvas"))),r.append(m("div","cultui-canvas-grid",i.state==="empty"?"waiting for pixels":g(i.state,""))),r}if(n==="surface.slot"){const r=m("section","cultui-embedded-slot");S(r,e),_(r,o,s),r.dataset.slotId=g(i.slotId,g(l[0]?.slotId,"")),r.dataset.documentId=g(i.documentId,g(l[0]?.documentId,"")),r.dataset.schemaId=g(i.schemaId,g(l[0]?.schemaId,"")),r.dataset.presentationKind=g(i.presentationKind,g(l[0]?.presentationKind,""));const d=l.map(h=>w(h.surface)).find(h=>w(h.root).kind||h.root),u=i.modal===!0||r.dataset.presentationKind.includes("modal");if((d||r.dataset.documentId)&&u){const h=m("button","cultui-button cultui-modal-trigger",g(i.label,r.dataset.slotId||"Configure"));h.type="button",h.addEventListener("click",()=>ot(Re(e,t),t)),r.append(h)}else if(d||r.dataset.documentId){const h=m("div","cultui-embedded-slot-body");h.append(m("div","detail","materializing surface")),r.append(h),Re(e,t).then(y=>{h.replaceChildren(y?.root?P(y.root,t):H("Embedded surface unavailable"))}).catch(y=>{h.replaceChildren(H(`Embedded surface failed: ${y instanceof Error?y.message:String(y)}`))})}else r.append(m("div","detail",r.dataset.presentationKind||r.dataset.slotId||"embedded surface"));return r}if(n==="control.slider")return Sn(i,c,t);if(n==="control.toggle"){const r=m("label","toggle-row cultui-toggle");return S(r,e),r.append(m("span","field-control",i.value?"on":"off")),r.append(m("span","toggle-copy",g(i.label,"Toggle"))),r}if(n==="input.number"||n==="input.select"||n==="control.range"||n==="control.input.text"||n==="control.select"){const r=m("label","field cultui-field");return S(r,e),he(r,i),_(r,o,s),r.append(m("span","field-label",g(i.label,""))),r.append(m("span","field-control cultui-field-value",i.value===void 0?"":String(i.value))),r}if(n==="color.swatch"){const r=m("div","paint-swatch cultui-swatch");return S(r,e),r.style.background=g(i.value,g(i.color,"currentColor")),r.title=g(i.label,"Color"),r}const a=m("section","pane");S(a,e),a.append(m("h2","",n));for(const r of c)a.append(P(r,t));return a}function nt(e){const t=w(e.props);return{label:p(t.label,t.title,t.displayName,e.text,e.kind,"item"),status:p(t.status,t.state,""),detail:p(t.detail,t.phase,t.repoName,""),badges:Array.isArray(t.badges)?t.badges.map(n=>String(n).trim()).filter(Boolean):p(t.badges,"").split(",").map(n=>n.trim()).filter(Boolean)}}function _(e,t,n={}){const i=p(t.display,"");i&&(e.style.display=i);const o=p(t.direction,"");o&&(e.style.flexDirection=o==="horizontal"?"row":o==="vertical"?"column":o);const s=p(t.flexWrap,"");s&&(e.style.flexWrap=s);const c=p(t.gridTemplateColumns,"");c&&(e.style.gridTemplateColumns=c);const l=p(t.gridTemplateRows,"");l&&(e.style.gridTemplateRows=l);const f=p(t.gridTemplateAreas,"");f&&(e.style.gridTemplateAreas=f);const a=p(t.gridArea,"");a&&(e.style.gridArea=a);const r=p(t.placeItems,"");r&&(e.style.placeItems=r),M(e,"gap",p(t.gap,"")),M(e,"padding",p(t.padding,"")),M(e,"margin",p(t.margin,"")),M(e,"top",p(t.top,"")),M(e,"right",p(t.right,"")),M(e,"bottom",p(t.bottom,"")),M(e,"left",p(t.left,"")),M(e,"width",p(t.width,"")),M(e,"minWidth",p(t.minWidth,"")),M(e,"maxWidth",p(t.maxWidth,"")),M(e,"height",p(t.height,"")),M(e,"minHeight",p(t.minHeight,"")),M(e,"maxHeight",p(t.maxHeight,""));const d=p(t.alignItems,"");d&&(e.style.alignItems=d);const u=p(t.justifyContent,"");u&&(e.style.justifyContent=u);const h=p(t.alignSelf,"");h&&(e.style.alignSelf=h);const y=p(t.overflow,"");y&&(e.style.overflow=y);const v=p(t.overflowX,"");v&&(e.style.overflowX=v);const x=p(t.overflowY,"");x&&(e.style.overflowY=x);const T=p(t.position,"");T&&(e.style.position=T);const A=p(t.cursor,"");A&&(e.style.cursor=A);const D=p(n.background,"");D&&(e.style.background=ve(D));const J=p(n.color,"");J&&(e.style.color=ve(J)),M(e,"borderWidth",p(n.borderWidth,""));const O=p(n.borderColor,"");O&&(e.style.borderColor=ve(O));const Z=p(n.borderStyle,"");Z&&(e.style.borderStyle=Z),M(e,"borderRadius",p(n.borderRadius,""));const Q=p(n.boxShadow,"");Q&&(e.style.boxShadow=Q);const j=p(n.font,"");j&&(e.style.font=j),M(e,"fontSize",p(n.fontSize,""));const C=p(n.fontWeight,"");C&&(e.style.fontWeight=C);const ee=p(n.textTransform,"");ee&&(e.style.textTransform=ee);const ue=p(n.textAlign,"");ue&&(e.style.textAlign=ue);const _e=p(n.whiteSpace,"");_e&&(e.style.whiteSpace=_e);const Ne=p(n.overflow,"");Ne&&(e.style.overflow=Ne);const $e=p(n.textOverflow,"");$e&&(e.style.textOverflow=$e),M(e,"lineHeight",p(n.lineHeight,""))}function M(e,t,n){n&&(e.style[t]=R(n))}function F(e,t){const n={};for(const[i,o]of Object.entries(e))i.startsWith(t)&&(n[i.slice(t.length)]=o);return n}function on(e){const t=(e.children||[]).filter(u=>u.kind==="world.entity3d"),n=t.map(u=>dn(w(u.props).position,[0,0,0])),i=n.map(u=>u[0]),o=n.map(u=>u[2]),s=Math.min(...i,-1),c=Math.max(...i,1),l=Math.min(...o,-1),f=Math.max(...o,1),a=Math.max(1,c-s),r=Math.max(1,f-l),d=6;return t.map((u,h)=>{const y=w(u.props);return{entityId:p(y.entityId,u.id),faction:g(y.faction,"neutral"),kind:g(y.entityKind,"entity"),label:p(y.label,y.entityId,u.id,"Entity"),controlled:Me(y.controllable),xPercent:d+(n[h][0]-s)/a*(100-d*2),yPercent:d+(1-(n[h][2]-l)/r)*(100-d*2),source:u}})}function an(e,t,n,i,o){const s=m("section","cultui-world-scene");S(s,e),_(s,n,i),s.tabIndex=0,s.setAttribute("aria-label",g(t.label,"Interactive world"));const c=on(e),l=c.find(r=>r.controlled),f=m("div","cultui-world-heading");f.append(m("strong","",g(t.label,"World"))),f.append(m("span","",`${c.length} entities`)),s.append(f);const a=m("div","cultui-world-plane");for(const r of c){const d=m("button",`cultui-world-entity faction-${ze(r.faction)} kind-${ze(r.kind)}`);d.type="button",d.style.left=`${r.xPercent}%`,d.style.top=`${r.yPercent}%`,d.dataset.entityId=r.entityId,d.dataset.controlled=r.controlled?"true":"false",d.title=r.label,d.setAttribute("aria-label",`${r.label}, ${r.kind}, ${r.faction}`),d.append(m("span","cultui-world-entity-glyph",ln(r.kind))),d.append(m("span","cultui-world-entity-label",r.label));const u=w(r.source.props),h=p(u.targetCommand,t.targetCommand,u.focusCommand,t.focusCommand);h&&d.addEventListener("click",()=>Ae(h,{actorEntityId:l?.entityId||p(t.playerEntityId),entityId:r.entityId,targetEntityId:r.entityId,targetEntityKey:r.entityId},r.source,o)),a.append(d)}return s.append(a),s.addEventListener("keydown",r=>{const d=cn(r.key);if(d){r.preventDefault();const h=p(t.movementCommand,w(l?.source.props).moveCommand);h&&Ae(h,{actorEntityId:l?.entityId||p(t.playerEntityId),actorEntityKey:l?.entityId||p(t.playerEntityId),directionX:d[0],directionY:d[1],scalar:1},e,o);return}const u=r.key===" "?p(t.actionCommand,w(l?.source.props).actionCommand):r.key.toLowerCase()==="f"?p(t.focusCommand,w(l?.source.props).focusCommand):"";u&&(r.preventDefault(),Ae(u,{actionId:r.key===" "?"0":"focus",actorEntityId:l?.entityId||p(t.playerEntityId),actorEntityKey:l?.entityId||p(t.playerEntityId)},e,o))}),s}function Ae(e,t,n,i){i.commandSink?.(sn(e,t,i),n)}function sn(e,t,n=z){return de(e,{action:t},n)}function cn(e){switch(e.toLowerCase()){case"w":case"arrowup":return[0,1];case"s":case"arrowdown":return[0,-1];case"a":case"arrowleft":return[-1,0];case"d":case"arrowright":return[1,0];default:return}}function ln(e){return e.includes("station")?"S":e.includes("projectile")?".":e.includes("ship")?"^":"+"}function ze(e){return e.toLowerCase().replace(/[^a-z0-9_-]+/g,"-")}function X(e,t){const n=Number(e);return Number.isFinite(n)?n:t}function dn(e,t){if(Array.isArray(e)){const n=e.map(i=>Number(i));if(n.length>=3&&n.slice(0,3).every(Number.isFinite))return[n[0],n[1],n[2]]}if(typeof e=="string"){const n=e.split(/[,\s]+/).map(i=>Number(i)).filter(Number.isFinite);if(n.length>=3)return[n[0],n[1],n[2]]}return t}function un(e,t,n,i){const o=Me(t.active),s=m("section","cultui-inventory-drag");S(s,e),_(s,n,i),s.dataset.active=o?"true":"false";const c=m("div","cultui-inventory-section-label","Drag");if(_(c,F(n,"sectionLabel."),F(i,"sectionLabel.")),s.append(c),!o){const d=m("div","cultui-inventory-empty","None");return _(d,F(n,"empty."),F(i,"empty.")),s.append(d),s}const l=p(t.itemKey,t.item,"item"),f=m("div","cultui-inventory-drag-chip",l);_(f,F(n,"dragChip."),F(i,"dragChip.")),s.append(f);const a=[t.originOffsetX,t.originOffsetY].map(d=>Number(d)).map(d=>Number.isFinite(d)?d:0),r=m("div","cultui-inventory-meta",`origin ${a[0]}, ${a[1]}`);return _(r,F(n,"meta."),F(i,"meta.")),s.append(r),s}function fn(e,t,n,i,o){const s=m("section","cultui-inventory-grid");S(s,e),_(s,n,i);const c=U(p(t.columns,t.gridColumns,t.widthCells,""),0),l=c>0?c:6,f=U(t.rows,0),a=f>0?f:Math.max(3,Math.ceil(Math.max((e.children||[]).length,1)/l));s.style.setProperty("--inventory-columns",String(l)),s.style.setProperty("--inventory-rows",String(a)),s.dataset.cellSpriteMode=g(t.cellSpriteMode,"");const r=p(t.title,t.label,"Inventory"),d=m("div","cultui-inventory-section-label",r);_(d,F(n,"sectionLabel."),F(i,"sectionLabel.")),s.append(d);const u=m("div","cultui-inventory-board");u.style.display="grid",u.style.gridTemplateColumns=`repeat(${l}, ${R(p(t.cellSize,"72"))})`,u.style.gridTemplateRows=`repeat(${a}, ${R(p(t.cellSize,"72"))})`,u.style.gap=R(p(t.cellGap,"4")),u.style.overflow=p(t.boardOverflow,"auto"),u.style.padding=R(p(t.boardPadding,"4")),_(u,F(n,"board."),F(i,"board.")),u.addEventListener("dragover",v=>{pn(t)&&(v.preventDefault(),v.dataTransfer&&(v.dataTransfer.dropEffect="move"))}),u.addEventListener("drop",v=>{const x=v.dataTransfer?.getData("application/vnd.gamecult.eve.inventory-item+json")||"";if(!x)return;let T;try{T=JSON.parse(x)}catch{return}const A=u.getBoundingClientRect(),D=Math.max(1,X(t.cellSize,72)),J=Math.max(0,X(t.cellGap,4)),O=D+J,Z=Math.max(0,Math.min(l-1,Math.floor((v.clientX-A.left)/O))),Q=Math.max(0,Math.min(a-1,Math.floor((v.clientY-A.top)/O))),j=hn(T,t,Z,Q,o);j&&(v.preventDefault(),o.commandSink?.(j,e))});const h=new Set;for(const v of e.children||[]){const x=w(v.props),T=U(x.x,0),A=U(x.y,0);h.add(`${T}:${A}`),u.append(P(v,o))}const y=Math.min(l*a,256);for(let v=0;v{!s.draggable||!y.dataTransfer||(y.dataTransfer.effectAllowed="move",y.dataTransfer.setData("application/vnd.gamecult.eve.inventory-item+json",JSON.stringify(t)))});let f=U(t.shapeWidth,1),a=U(t.shapeHeight,1);const r=p(t.rotation,"").toLowerCase();["clockwise","counterclockwise","right","left","rotate90","rotate270"].includes(r)&&([f,a]=[a,f]),s.style.gridColumn=`${c+1} / span ${f}`,s.style.gridRow=`${l+1} / span ${a}`;const d=m("span","cultui-inventory-item-icon");_(d,F(n,"icon."),F(i,"icon.")),d.textContent=Fn(p(t.iconAssetUri,t.iconAssetKey,t.itemKey,t.label,"")),s.append(d);const u=p(t.label,t.itemKey,"");if(u){const y=m("span","cultui-inventory-item-label",u);_(y,F(n,"label."),F(i,"label.")),s.append(y)}const h=Number(t.quantity);if(Number.isFinite(h)&&h>1){const y=m("span","cultui-inventory-item-quantity",String(h));_(y,F(n,"quantity."),F(i,"quantity.")),s.append(y)}return s.title=[u,p(t.source,""),p(t.quality,"")?`quality ${t.quality}`:"",p(t.durability,"")?`durability ${t.durability}`:""].filter(Boolean).join(" | "),s}function pn(e){return Object.entries(e).some(([t,n])=>(t==="dropCommand"||t.startsWith("dropCommand."))&&typeof n=="string"&&n.length>0)}function hn(e,t,n,i,o=z){const s=p(e.sourceKind,e.source,""),c=p(t[`dropCommand.${s}`],t.dropCommand,"");if(!s||!c)return;const l=X(e.sourceIndex,-1),f=X(t.targetIndex,-1),a=p(t.targetKind,""),r={sourceKind:s,originEntityKey:p(e.sourceEntityKey,e.entityKey,""),originIndex:l,originCargoIndex:s==="cargo"?l:-1,itemKey:p(e.itemKey,""),quantity:Math.max(1,X(e.quantity,1)),sourceX:X(e.x,-2147483648),sourceY:X(e.y,-2147483648),destinationKind:a,destinationEntityKey:p(t.targetEntityKey,t.entityKey,""),destinationIndex:f,destinationCargoIndex:a==="cargo"?f:-1,destinationX:Math.trunc(n),destinationY:Math.trunc(i),hasDestinationPosition:!0};return de(c,{action:r},o)}function gn(e,t,n){const i=m("section","cultui-binding-map");S(i,e);const o=document.createElementNS("http://www.w3.org/2000/svg","svg");o.setAttribute("class","cultui-xbox-controller"),o.setAttribute("viewBox","0 0 780 420"),o.setAttribute("role","img"),o.setAttribute("aria-label",g(t.label,"Xbox controller remapping")),o.innerHTML=bn(),i.append(o);const s=m("div","cultui-binding-overlay");for(const c of e.children||[]){const l=w(c.props),f=g(l.target,c.id||""),a=m("button","cultui-binding-box");S(a,c),a.type="button",a.dataset.target=f,a.dataset.kind=g(l.bindingKind,"button"),a.style.left=R(l.x??"50%"),a.style.top=R(l.y??"50%"),a.append(m("span","cultui-binding-target",g(l.label,f))),a.append(m("span","cultui-binding-source",g(l.current,"unmapped"))),a.addEventListener("click",()=>{const d=rt(c);if(it(c)||d?.documentId)ot(Re(c,n),n);else{const u=g(l.commandId,"");u&&n.commandSink?.(de(u,l,n),c)}}),s.append(a);const r=document.createElementNS("http://www.w3.org/2000/svg","line");r.setAttribute("class","cultui-binding-line"),r.setAttribute("x1",g(l.anchorX,"390")),r.setAttribute("y1",g(l.anchorY,"210")),r.setAttribute("x2",String(je(l.x,780))),r.setAttribute("y2",String(je(l.y,420))),o.append(r)}return i.append(s),i}function it(e){for(const t of e.embeddedDocuments||[]){const n=w(t.surface);if(n.root)return n}}function rt(e){const t=(e.embeddedDocuments||[])[0],n=w(e.props),i=p(n.documentId,t?.documentId,"");if(i)return{documentId:i,presentationKind:p(n.presentationKind,t?.presentationKind,""),schemaId:p(n.schemaId,t?.schemaId,""),slotId:p(n.slotId,t?.slotId,"")}}async function Re(e,t){const n=it(e);if(n)return n;const i=rt(e);if(!i?.documentId||!t.documentResolver)return;const o=await t.documentResolver(i,e);if(o)return w(o.surface).root?o.surface:o}function ot(e,t){const n=m("div","cultui-modal-backdrop"),i=m("section","cultui-modal");i.setAttribute("role","dialog"),i.setAttribute("aria-modal","true");const o=m("header","cultui-modal-header");o.append(m("h2","","Configure Binding"));const s=m("button","cultui-modal-close","Close");s.type="button",s.addEventListener("click",()=>n.remove()),o.append(s);const c=m("div","cultui-modal-body");i.append(o,c),n.append(i),n.addEventListener("click",l=>{l.target===n&&n.remove()}),document.body.append(n),c.append(m("div","detail","materializing document")),Promise.resolve(e).then(l=>{o.querySelector("h2").textContent=l?.title||"Configure Binding",c.replaceChildren(l?.root?P(l.root,t):H("Embedded document unavailable"))}).catch(l=>{c.replaceChildren(H(`Embedded document failed: ${l instanceof Error?l.message:String(l)}`))})}function yn(e,t,n,i,o){const s=w(e.props),c=(e.children||[])[0],l=w(c?.props),f=p(l.anchor,s.anchor,"trigger"),a=p(l.placement,s.placement,"below-start"),r=Number(p(l.offsetX,s.offsetX,"0"))||0,d=Number(p(l.offsetY,s.offsetY,"4"))||0,u=m("div","cultui-modal-backdrop");u.style.background="transparent",u.style.placeItems="start";const h=m("section","cultui-modal");h.setAttribute("role","dialog"),h.setAttribute("aria-modal","true"),h.style.position="fixed",h.style.width="min(420px, calc(100vw - 24px))",h.style.maxHeight="min(620px, calc(100vh - 24px))";const y=m("header","cultui-modal-header");y.append(m("h2","",p(l.title,s.title,s.label,"Options")));const v=m("button","cultui-modal-close","Close");v.type="button",v.addEventListener("click",()=>u.remove()),y.append(v);const x=m("div","cultui-modal-body");if(c){const A=c.children||[];A.length>0?x.replaceChildren(...A.map(D=>P(D,t))):x.append(P(c,t))}else x.append(H("Popup has no content"));h.append(y,x),u.append(h),u.addEventListener("click",A=>{A.target===u&&u.remove()}),document.body.append(u);const T=vn(f,a,n,h,i,o,r,d);h.style.left=`${T.left}px`,h.style.top=`${T.top}px`}function vn(e,t,n,i,o,s,c,l){const f=n.getBoundingClientRect(),a=i.getBoundingClientRect(),r=a.width||420,d=a.height||320,u=e==="cursor"?{left:o,right:o,top:s,bottom:s}:f;if(t==="right-down"||t==="dropdown")return pe(u,r,d,c,l,"right","down");if(t==="left-down")return pe(u,r,d,c,l,"left","down");if(t==="right-up")return pe(u,r,d,c,l,"right","up");if(t==="left-up")return pe(u,r,d,c,l,"left","up");switch(t){case"above-start":return W(u.left+c,u.top-d-l,r,d);case"above-end":return W(u.right-r+c,u.top-d-l,r,d);case"below-end":return W(u.right-r+c,u.bottom+l,r,d);case"right-start":return W(u.right+c,u.top+l,r,d);case"left-start":return W(u.left-r-c,u.top+l,r,d);case"center":return W((window.innerWidth-r)/2+c,(window.innerHeight-d)/2+l,r,d);default:return W(u.left+c,u.bottom+l,r,d)}}function pe(e,t,n,i,o,s,c){const f=window.innerWidth-e.right-i-12,a=e.left-i-12,r=window.innerHeight-e.top-o-12,d=e.bottom-o-12,u=s==="right"?f>=t||f>=a:!(a>=t||a>=f),h=c==="down"?r>=n||r>=d:!(d>=n||d>=r),y=u?e.right+i:e.left-t-i,v=h?e.top+o:e.bottom-n-o;return W(y,v,t,n)}function W(e,t,n,i){return{left:Oe(e,12,window.innerWidth-n-12),top:Oe(t,12,window.innerHeight-i-12)}}function Oe(e,t,n){return n @@ -150,4 +150,4 @@ void main() { YBXA - `}function xn(e,t=document.body){const n=Le(e),i=document.documentElement.style;En(n.assets.fontCss);for(const[a,r]of Object.entries(tn))i.setProperty(a,r);const o={colorBackground:"--bg",colorBackgroundTop:"--bg-top",colorBackgroundMid:"--bg-mid",colorBackgroundBottom:"--bg-bottom",colorShellSurfaceTop:"--shell-top",colorShellSurfaceBottom:"--shell-bottom",colorPanel:"--panel",colorPanelAlt:"--panel-2",colorPanelBorder:"--line",colorPanelBorderDeep:"--line-deep",colorText:"--text",colorTextBright:"--text-bright",colorMuted:"--quiet",colorAccent:"--accent",colorAccentStrong:"--accent-strong",colorCornerAccent:"--corner-accent",colorLink:"--cyan",colorShadow:"--shadow",colorPixelGrid:"--pixel-grid"};for(const[a,r]of Object.entries(o)){const d=n.tokens[a];d!==void 0&&i.setProperty(r,String(d))}const s=n.tokens.fontBody,c=n.tokens.fontDisplay,l=n.tokens.fontTitle,f=n.tokens.fontMono;s&&i.setProperty("--font-body",ge(String(s))),c&&i.setProperty("--font-title",ge(String(c))),l&&i.setProperty("--font-title",ge(String(l))),f&&i.setProperty("--font-mono",ge(String(f))),n.tokens.borderWidthPx&&i.setProperty("--border-width",`${n.tokens.borderWidthPx}px`),n.tokens.borderBottomWidthPx&&i.setProperty("--border-bottom-width",`${n.tokens.borderBottomWidthPx}px`),n.tokens.cornerAccentPx&&i.setProperty("--corner-accent-size",`${n.tokens.cornerAccentPx}px`),t.dataset.pixelArt=n.tokens.pixelArt||n.tokens.imageRendering==="pixelated"?"true":"false",t.dataset.scanlines=n.tokens.scanlineOverlay?"true":"false"}function de(e,t={},n=z){const i=w(t.action),o=n.provider?.providerId||ce?.providerId||"surface unknown",s=n.activeSurfaceId||ce?.surface?.id||n.provider?.surfaces?.[0]?.surfaceId||o,c=wn(n,s),l=p(c.commandBoundary,t.commandBoundary,i.commandBoundary,i.target),f=p(c.receiptSchema,t.receiptSchema,i.receiptSchema),a={type:"surface-command",schema:"gamecult.eve.command_invocation.v1",providerId:o,surfaceId:s,command:e||g(i.type,"invoke"),payload:{...i,transport:t.transport??null},issuedAt:new Date().toISOString(),clientId:n.clientId||"eve.browser"};return l&&(a.commandBoundary=l),f&&(a.receiptSchema=f),a}function wn(e,t){const n=[...e.provider?.surfaces||[],...e.provider?.localAdvertisement?.surfaces||[]];return n.find(i=>i.surfaceId===t&&i.worldInteraction)?.worldInteraction||n.find(i=>i.worldInteraction)?.worldInteraction||{}}function Ke(e,t){const n=w(e.action);return g(e.command,g(e.commandId,g(n.command,g(n.target,g(n.type,t?.commandId||"")))))}function H(e){const t=m("section","pane");return t.append(m("h2","","No Surface")),t.append(m("div","detail",e)),t}function je(e,t,n,i,o){e.dataset.commandId=n,e.tabIndex=e instanceof HTMLButtonElement?e.tabIndex:0;const s=()=>{const c=de(n,i,o);o.commandSink?.(c,t)};e.addEventListener("click",s),e.addEventListener("keydown",c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),s())})}function Sn(e,t,n){const i=_n(e,t),o=w(i.find(u=>u.kind==="control.box")?.props),s=i.filter(u=>u.kind==="control.part"),c=Number(e.min??0),l=Number(e.max??1),f=m("div","cultui-slider");f.dataset.skin=g(e.skin,"default"),f.dataset.bind=g(e.bind,""),In(f,o);const a=m("div","cultui-slider-visual"),r=m("input","cultui-slider-input");r.type="range",r.min=String(c),r.max=String(l),r.step=String(e.step??.01),r.setAttribute("aria-label",g(e.bind,"slider"));for(const u of s){const h=w(u.props),y=m("span",`cultui-slider-part ${g(h.name,"part")}`);Cn(y,h),a.append(y)}return s.some(u=>w(u.props).name==="track")||a.append(m("span","cultui-slider-part track")),s.some(u=>w(u.props).name==="fill")||a.append(m("span","cultui-slider-part fill")),s.some(u=>w(u.props).name==="thumb")||a.append(m("span","cultui-slider-part thumb")),f.append(a,r),(u=>{const h=Number(u??c),y=Math.max(c,Math.min(l,Number.isFinite(h)?h:c)),v=l===c?0:(y-c)/(l-c)*100;r.value=String(y),f.style.setProperty("--cultui-slider-value",`${v}%`),f.dataset.value=String(y)})(e.value??c),r.addEventListener("input",()=>{const u=de(g(e.command,"control.slider.input"),{...e,action:{...w(e.action),value:Number(r.value)},value:Number(r.value)},n);n.commandSink?.(u,{kind:"control.slider",props:e})}),f}function _n(e,t){const n=typeof e.skin=="string"?e.skin:"",o=[...n?Qe.controlSkins[n]?.children||[]:[],...t];return o.length?o:[{kind:"control.box",props:{height:18,overflow:"visible"}},{kind:"control.part",props:{name:"track",anchor:"center",size:["100%",6],radius:2,fill:"color.panelInset"}},{kind:"control.part",props:{name:"fill",anchor:["left","center"],size:["value%",6],radius:2,fill:"color.accent"}},{kind:"control.part",props:{name:"thumb",anchor:["value","center"],size:[12,12],bleed:3,radius:999,fill:"color.accent"}}]}function Le(e){if(Array.isArray(e)){const t={},n={};for(const i of e)i?.name&&(i.name==="font.web.google"&&typeof i.value=="string"?n.fontCss=i.value:t[i.name]=i.value);return{tokens:t,assets:n,controlSkins:{}}}return{tokens:w(e?.tokens),assets:w(e?.assets),controlSkins:w(e?.controlSkins)}}function re(e){if(!e)return"";const t=z.assetUrlResolver;return t?t(e,ce):/^(https?:|data:|blob:)/i.test(e)?e:z.assetBaseUrl&&e.startsWith("/")?`${z.assetBaseUrl.replace(/\/+$/,"")}${e}`:e}function En(e){const t=typeof e=="string"?e.trim():"";if(me?.dataset.href===t||(me?.remove(),me=void 0,!t))return;const n=document.createElement("link");n.rel="preconnect",n.href="https://fonts.gstatic.com",n.crossOrigin="anonymous",document.head.append(n);const i=document.createElement("link");i.rel="stylesheet",i.href=t,i.dataset.href=t,document.head.append(i),me=i}function An(e,t,n){const i=[];return(e==="text.title"||t.role==="title")&&i.push("cultui-title","eve-text-title"),e==="text.subtitle"&&i.push("eve-text-subtitle"),e==="label"&&i.push("cultui-label"),t.role==="mono"&&i.push("detail","mono"),i.length===0&&i.push("detail","eve-text"),i.join(" ")}function In(e,t){t.height!==void 0&&(e.style.minHeight=R(t.height)),t.width!==void 0&&(e.style.width=R(t.width)),typeof t.overflow=="string"&&(e.style.overflow=t.overflow)}function Cn(e,t){const n=Array.isArray(t.size)?t.size:[t.size,void 0];n[0]!==void 0&&n[0]!=="value%"&&(e.style.width=R(n[0])),n[1]!==void 0&&(e.style.height=R(n[1])),t.radius!==void 0&&(e.style.borderRadius=R(t.radius)),t.fill!==void 0&&(e.style.background=ve(String(t.fill))),t.bleed!==void 0&&e.style.setProperty("--part-bleed",R(t.bleed)),(Array.isArray(t.anchor)?t.anchor:[t.anchor]).includes("value")&&(e.dataset.anchorValue="true")}function he(e,t){t.gap!==void 0&&(e.style.gap=R(t.gap)),t.padding!==void 0&&(e.style.padding=R(t.padding)),t.size!==void 0&&(e.style.flex=Tn(t.size)),t.min!==void 0&&(e.style.minWidth=R(t.min)),t.max!==void 0&&(e.style.maxWidth=R(t.max)),t.align!==void 0&&(e.style.alignItems=t.align==="end"?"flex-end":String(t.align)),(t.clip==="true"||t.clip===!0)&&(e.style.overflow="hidden"),t.scroll==="y"&&(e.style.overflowY="auto"),t.scroll==="x"&&(e.style.overflowX="auto")}function Tn(e){return typeof e=="string"&&e.endsWith("fr")?`${Number(e.slice(0,-2))||1} 1 0`:e==="auto"||e==="content"?"0 0 auto":`0 0 ${R(e)}`}function R(e){return Array.isArray(e)?e.map(R).join(" "):typeof e=="number"?`${e}px`:typeof e=="string"&&/^-?\d+(\.\d+)?$/.test(e)?`${e}px`:String(e??"")}function ve(e){return{"color.accent":"var(--accent)","color.panelInset":"rgba(0, 0, 0, 0.34)","color.panel":"var(--panel)","color.text":"var(--text)"}[e]||e}function ge(e){return e.includes("Zen Kaku Gothic New")||e.includes("M PLUS 1")?e:e.includes("Montserrat")?`${e}, "Zen Kaku Gothic New", "M PLUS 1", "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif`:e.includes("Ubuntu")?`${e}, "M PLUS 1", "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif`:`${e}, "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif`}function S(e,t){t.id&&(e.id=t.id),t.id&&(e.dataset.eveNodeId=t.id),t.kind&&(e.dataset.eveKind=t.kind)}function w(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function kn(e){return Array.isArray(e)?e:[]}function Rn(e){return kn(e).map((t,n)=>nt({kind:"list.item",props:w(t)}))}function g(e,t){return e==null?t:String(e)}function p(...e){for(const t of e){if(typeof t=="string"&&t.trim())return t;if(typeof t=="number"&&Number.isFinite(t))return String(t)}return""}function Me(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"?["1","true","yes","on"].includes(e.trim().toLowerCase()):!1}function U(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}function Fn(e){const t=e.toLowerCase();return t.includes("sensor")?"S":t.includes("thermal")?"T":t.includes("fuel")?"F":t.includes("cargo")?"C":t.includes("weapon")?"W":e.trim().slice(0,1).toUpperCase()||"?"}function Pn(e){const t=e.trim().split(/\s+/).filter(Boolean);return t.length&&t.slice(0,2).map(n=>n[0]?.toUpperCase()||"").join("")||"?"}function Xe(e){const t=Number(e);return Number.isFinite(t)?Math.max(0,Math.min(100,t)):0}function m(e,t="",n=""){const i=document.createElement(e);return t&&(i.className=t),n&&(i.textContent=n),i}const we=document.querySelector("#surface"),$=document.querySelector("#status"),le=document.querySelector("#receipt"),at=document.querySelector("#compiler"),Se=document.querySelector("#composer"),ae=document.querySelector("#destination-form"),st=document.querySelector("#compiler-results"),ct=document.querySelector("#campaign-lab"),Ln=document.querySelector("#campaign-list");let V=0,se=0,lt=0,oe=[];function b(e,t,n){const i=document.createElement(e);return t!==void 0&&(i.textContent=t),n&&(i.className=n),i}function Y(e,t){const n=[b("h3",e)];for(const i of t.filter(Boolean))n.push(b("p",i));le.replaceChildren(...n),le.hidden=!1}function Mn(e){if(e?.kind==="assessed"){const t=e.assessment,n=[b("h3",t.admissible?"Action assessment":"That attempt is not possible")];if(t.admissible){n.push(b("p",`DC ${t.dc} · modifier ${t.modifier_total>=0?"+":""}${t.modifier_total}`));const i=b("ul");for(const o of t.modifiers??[])i.append(b("li",`${o.label}: ${o.value>=0?"+":""}${o.value}`));n.push(i),n.push(b("p",`Strong/success: ${t.success_stake}`)),n.push(b("p",`Mixed: ${t.mixed_stake}`)),n.push(b("p",`Failure: ${t.failure_stake}`)),n.push(b("p",`Effect ceiling: ${t.effect_ceiling}`,"quiet"))}else{n.push(b("p",t.missing_permission??"The attempt has no admissible path from current state."));for(const i of t.bargains??[])n.push(b("p",`Possible bargain: ${i}`))}le.replaceChildren(...n),le.hidden=!1;return}if(e?.kind==="committed"){const t=e.receipt?.roll;if(t){const n=String(t.outcome).replaceAll("_"," ");Y(n.charAt(0).toUpperCase()+n.slice(1),[`d20 ${t.d20} ${t.modifier_total>=0?"+":"−"} ${Math.abs(t.modifier_total)} = ${t.total} against DC ${t.dc}`])}else Y("World advanced",[`Revision ${e.revision}`]);return}if(e?.kind==="resolution_updated"){Y("World resolution updated",[`Resolution epoch ${e.receipt?.resolution_epoch??"advanced"}`]);return}Y("Command result",[e?.error??"The world returned no player-facing detail."])}function Nn(){const e="This laboratory requires an unused invite link.";$.textContent=e,at.hidden=!0,Se.hidden=!0,ae.hidden=!0,ct.hidden=!0,le.hidden=!0,we.hidden=!1;const t=b("article",void 0,"card");t.append(b("h2","Private campaign laboratory"),b("p",e),b("p","Open one of the two single-use tester invitations on this device. The resulting session stays separate from the other player's campaigns.","quiet")),we.replaceChildren(t)}async function q(){const e=await fetch("/api/surface");if(e.status===401){Nn();return}const t=await e.json(),n=t.surface_id==="ghostlight.compiler";if(at.hidden=!n,Se.hidden=n,ae.hidden=n,we.hidden=n,ct.hidden=n,n){$.textContent="No campaign exists. Retrieve the Vault and approve a world seed.";return}V=Number(t.world_revision??t.version??0),se=Number(t.resolution?.policy?.resolution_epoch??0),lt=Number(t.resolution?.policy?.provider_configuration_epoch??0),oe=t.resolution?.pins??[];const i=Number(t.resolution?.policy?.active_cell_budget??8),o=document.querySelector("#active-cell-budget");o.value=String(i),document.querySelector("#active-cell-budget-value").value=String(i),document.querySelector("#resolution-status").textContent=`${t.resolution?.effective_budget??i} effective cells · ${t.resolution?.mandatory_overage??0} temporary overage · epoch ${se}`;const s=Number(t.resolution?.policy?.provider_parallelism??8);document.querySelector("#provider-parallelism").value=String(s),document.querySelector("#provider-parallelism-value").value=String(s);const c=document.querySelector("#pin-list");c.replaceChildren(),oe.length===0&&c.append(b("p","No persistent pins."));for(const a of oe){const r=b("p");r.append(b("code",String(a.kind)),document.createTextNode(` ${[...a.subject_ids].join(", ")} — ${a.reason} `));const d=b("button","Remove");d.type="button",d.addEventListener("click",async()=>{await ie({type:"replace_resolution_pins",expected_revision:V,expected_resolution_epoch:se,pins:oe.filter(u=>u.id!==a.id)})}),r.append(d),c.append(r)}const l=document.querySelector("#fission-parent");l.replaceChildren(...(t.resolution?.fission_targets??[]).map(a=>{const r=b("option",`${a.name} · ${a.id}`);return r.value=a.id,r})),document.querySelector("#fission-form").hidden=l.options.length===0,et(t,we,{body:document.body,clientId:"ghostlight.browser",statusElement:$});const f=await fetch("/api/campaigns").then(a=>a.json());Ln.replaceChildren(...f.campaigns.map(a=>{const r=b("button",`${a.selected?"●":"○"} ${a.name} · revision ${a.revision}`);return r.type="button",r.disabled=!!a.selected,a.selected||r.addEventListener("click",async()=>{await B(`/api/campaigns/select/${a.id}`,{}),await q()}),r}))}async function B(e,t){$.textContent="Retrieving evidence and compiling…";const n=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)}),i=n.headers.get("content-type")?.includes("json")?await n.json():await n.text();if(!n.ok)throw $.textContent=typeof i=="string"?i:"Compilation failed",new Error($.textContent);return i}function Ye(e,t,n){const i=b("div",void 0,"cards");e.forEach((o,s)=>{const c=b("article",void 0,"card");c.append(b("h3",o.title??o.name),b("p",o.player_hook??o.premise)),o.era&&c.append(b("p",`${o.era} · ${o.place} · ${o.pressure}`));const l=b("button",t);l.type="button",l.addEventListener("click",()=>n(e[s])),c.append(l),i.append(c)}),st.replaceChildren(i)}document.querySelector("#suggest-form").addEventListener("submit",async e=>{e.preventDefault();const t=await B("/api/compiler/openings",{setting:document.querySelector("#setting").value,constraints:[]});Ye(t.openings,"Choose opening",async n=>{const i=await B("/api/compiler/roles",n);Ye(i.roles,"Choose role",async o=>dt(await B("/api/compiler/selected",{campaign_name:n.title,opening:n,role:o})))})});document.querySelector("#custom-form").addEventListener("submit",async e=>{e.preventDefault(),await dt(await B("/api/compiler/custom",Object.fromEntries(new FormData(e.currentTarget))))});async function dt(e){const t=e.preview,n=Array.isArray(t.evidence_coverage)?t.evidence_coverage:[],i=n.reduce((c,l)=>{const f=String(l?.lane??"excluded");return c[f]=(c[f]??0)+1,c},{}),o=b("article",void 0,"card");o.append(b("h3",t.title),b("p",t.opening??""),b("p",`${t.locations?.length??0} locations · ${(t.cast?.length??0)+1} actors · ${t.institutions?.length??0} institutions`),b("p",t.gaps.length?`Material gaps: ${t.gaps.join("; ")}`:"No declared material gaps.","warning"),b("p",`Branch assumptions: ${t.branch_assumptions.join("; ")||"none"}`),b("p",n.length?`Evidence use: ${i.direct_seed??0} direct · ${i.setting_background??0} background · ${i.excluded??0} excluded`:"Evidence use: no retrieved sources were admitted to this seed.","quiet"));const s=b("button","Approve and enter");s.type="button",s.addEventListener("click",async()=>{await B(`/api/compiler/approve/${e.preview_id}`,{}),await q()}),o.append(s),st.replaceChildren(o),$.textContent="Preview compiled. Nothing has entered world state yet."}async function ie(e){$.textContent="The world is considering the command…";const t=await fetch("/api/command",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)}),n=await t.json();return Mn(n),t.ok?(await q(),n):($.textContent=n.error??"The command was refused.",await q(),n)}function ut(e){if(e?.kind!=="assessed")return;const t=document.createElement("button");t.type="button",t.textContent=e.assessment.admissible?"Confirm server roll":"Revise attempt",t.addEventListener("click",async()=>{if(!e.assessment.admissible){document.querySelector("#attempt").focus();return}const n=await ie({type:"attempt",assessment_digest:e.assessment.digest});t.remove(),ut(n)}),Se.append(t)}Se.addEventListener("submit",async e=>{e.preventDefault();const t=document.querySelector("#attempt").value.trim();t&&ut(await ie({type:"assess",expected_revision:V,intent:{actor_id:"player",description:t,intended_effect:t}}))});document.querySelector("#wait").addEventListener("click",()=>{ie({type:"wait",expected_revision:V,minutes:60})});document.querySelector("#active-cell-budget").addEventListener("input",e=>{document.querySelector("#active-cell-budget-value").value=e.currentTarget.value});document.querySelector("#resolution-form").addEventListener("submit",async e=>{e.preventDefault(),await ie({type:"set_resolution_budget",expected_revision:V,expected_resolution_epoch:se,active_cell_budget:Number(document.querySelector("#active-cell-budget").value)})});document.querySelector("#provider-parallelism").addEventListener("input",e=>{document.querySelector("#provider-parallelism-value").value=e.currentTarget.value});document.querySelector("#provider-parallelism-form").addEventListener("submit",async e=>{e.preventDefault(),$.textContent="Applying the provider concurrency limit…";const t=await fetch("/api/operator/provider-parallelism",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({expected_provider_configuration_epoch:lt,provider_parallelism:Number(document.querySelector("#provider-parallelism").value)})}),n=await t.json();Y(t.ok?"Provider concurrency updated":"Provider concurrency refused",[t.ok?`Parallel requests: ${n.receipt?.provider_parallelism??n.provider_parallelism??"updated"}`:n.error??"The operator limit was refused."]),t.ok||($.textContent=n.error??"The operator limit was refused."),await q()});document.querySelector("#pin-form").addEventListener("submit",async e=>{e.preventDefault();const t=new FormData(e.currentTarget),n=String(t.get("subject_ids")??"").split(",").map(o=>o.trim()).filter(Boolean),i={schema:"ghostlight.resolution_pin.v1",id:`pin:${crypto.randomUUID()}`,kind:String(t.get("kind")),subject_ids:n,reason:String(t.get("reason")??"").trim(),created_world_revision:V};await ie({type:"replace_resolution_pins",expected_revision:V,expected_resolution_epoch:se,pins:[...oe,i]})});ae.addEventListener("submit",async e=>{e.preventDefault();const t=await B("/api/compiler/destination",Object.fromEntries(new FormData(ae))),n=t.preview;Y("Destination preview",[...(n.locations??[]).map(o=>o.name),...(n.gaps??[]).map(o=>`Material gap: ${o}`)]),$.textContent="Destination preview compiled; topology is unchanged until approval.";const i=b("button","Approve destination");i.type="button",i.addEventListener("click",async()=>{await B(`/api/compiler/destination/approve/${t.preview_id}`,{}),i.remove(),await q()}),ae.append(i)});document.querySelector("#fission-form").addEventListener("submit",async e=>{e.preventDefault();const t=new FormData(e.currentTarget),n=await B("/api/compiler/gestalt/fission",{parent_gestalt_id:t.get("parent_gestalt_id"),partition_axis:t.get("partition_axis"),requested_partition_values:String(t.get("requested_partition_values")??"").split(",").map(o=>o.trim()).filter(Boolean),reason:t.get("reason")});Y("Population fission preview",[...(n.preview?.children??[]).map(o=>`${o.name} · ${o.id}`),...(n.preview?.gaps??[]).map(o=>`Material gap: ${o}`)]),$.textContent="Fission preview compiled. Canonical leaves are unchanged until approval.";const i=document.createElement("button");i.type="button",i.textContent="Approve population fission",i.addEventListener("click",async()=>{await B(`/api/compiler/gestalt/fission/approve/${n.preview_id}`,{}),i.remove(),await q()}),e.currentTarget.append(i)});document.querySelector("#fork-form").addEventListener("submit",async e=>{e.preventDefault(),await B("/api/campaigns/fork",Object.fromEntries(new FormData(e.currentTarget))),await q()});document.querySelector("#reset-form").addEventListener("submit",async e=>{e.preventDefault(),await B("/api/campaigns/reset",Object.fromEntries(new FormData(e.currentTarget))),await q()});document.querySelector("#load-operator").addEventListener("click",async()=>{const t=await(await fetch("/api/operator")).json();et(t,document.querySelector("#operator-output"),{body:document.body,clientId:"ghostlight.operator",statusElement:$})});q(); + `}function xn(e,t=document.body){const n=Le(e),i=document.documentElement.style;En(n.assets.fontCss);for(const[a,r]of Object.entries(tn))i.setProperty(a,r);const o={colorBackground:"--bg",colorBackgroundTop:"--bg-top",colorBackgroundMid:"--bg-mid",colorBackgroundBottom:"--bg-bottom",colorShellSurfaceTop:"--shell-top",colorShellSurfaceBottom:"--shell-bottom",colorPanel:"--panel",colorPanelAlt:"--panel-2",colorPanelBorder:"--line",colorPanelBorderDeep:"--line-deep",colorText:"--text",colorTextBright:"--text-bright",colorMuted:"--quiet",colorAccent:"--accent",colorAccentStrong:"--accent-strong",colorCornerAccent:"--corner-accent",colorLink:"--cyan",colorShadow:"--shadow",colorPixelGrid:"--pixel-grid"};for(const[a,r]of Object.entries(o)){const d=n.tokens[a];d!==void 0&&i.setProperty(r,String(d))}const s=n.tokens.fontBody,c=n.tokens.fontDisplay,l=n.tokens.fontTitle,f=n.tokens.fontMono;s&&i.setProperty("--font-body",ge(String(s))),c&&i.setProperty("--font-title",ge(String(c))),l&&i.setProperty("--font-title",ge(String(l))),f&&i.setProperty("--font-mono",ge(String(f))),n.tokens.borderWidthPx&&i.setProperty("--border-width",`${n.tokens.borderWidthPx}px`),n.tokens.borderBottomWidthPx&&i.setProperty("--border-bottom-width",`${n.tokens.borderBottomWidthPx}px`),n.tokens.cornerAccentPx&&i.setProperty("--corner-accent-size",`${n.tokens.cornerAccentPx}px`),t.dataset.pixelArt=n.tokens.pixelArt||n.tokens.imageRendering==="pixelated"?"true":"false",t.dataset.scanlines=n.tokens.scanlineOverlay?"true":"false"}function de(e,t={},n=z){const i=w(t.action),o=n.provider?.providerId||ce?.providerId||"surface unknown",s=n.activeSurfaceId||ce?.surface?.id||n.provider?.surfaces?.[0]?.surfaceId||o,c=wn(n,s),l=p(c.commandBoundary,t.commandBoundary,i.commandBoundary,i.target),f=p(c.receiptSchema,t.receiptSchema,i.receiptSchema),a={type:"surface-command",schema:"gamecult.eve.command_invocation.v1",providerId:o,surfaceId:s,command:e||g(i.type,"invoke"),payload:{...i,transport:t.transport??null},issuedAt:new Date().toISOString(),clientId:n.clientId||"eve.browser"};return l&&(a.commandBoundary=l),f&&(a.receiptSchema=f),a}function wn(e,t){const n=[...e.provider?.surfaces||[],...e.provider?.localAdvertisement?.surfaces||[]];return n.find(i=>i.surfaceId===t&&i.worldInteraction)?.worldInteraction||n.find(i=>i.worldInteraction)?.worldInteraction||{}}function Ge(e,t){const n=w(e.action);return g(e.command,g(e.commandId,g(n.command,g(n.target,g(n.type,t?.commandId||"")))))}function H(e){const t=m("section","pane");return t.append(m("h2","","No Surface")),t.append(m("div","detail",e)),t}function Ke(e,t,n,i,o){e.dataset.commandId=n,e.tabIndex=e instanceof HTMLButtonElement?e.tabIndex:0;const s=()=>{const c=de(n,i,o);o.commandSink?.(c,t)};e.addEventListener("click",s),e.addEventListener("keydown",c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),s())})}function Sn(e,t,n){const i=_n(e,t),o=w(i.find(u=>u.kind==="control.box")?.props),s=i.filter(u=>u.kind==="control.part"),c=Number(e.min??0),l=Number(e.max??1),f=m("div","cultui-slider");f.dataset.skin=g(e.skin,"default"),f.dataset.bind=g(e.bind,""),In(f,o);const a=m("div","cultui-slider-visual"),r=m("input","cultui-slider-input");r.type="range",r.min=String(c),r.max=String(l),r.step=String(e.step??.01),r.setAttribute("aria-label",g(e.bind,"slider"));for(const u of s){const h=w(u.props),y=m("span",`cultui-slider-part ${g(h.name,"part")}`);Cn(y,h),a.append(y)}return s.some(u=>w(u.props).name==="track")||a.append(m("span","cultui-slider-part track")),s.some(u=>w(u.props).name==="fill")||a.append(m("span","cultui-slider-part fill")),s.some(u=>w(u.props).name==="thumb")||a.append(m("span","cultui-slider-part thumb")),f.append(a,r),(u=>{const h=Number(u??c),y=Math.max(c,Math.min(l,Number.isFinite(h)?h:c)),v=l===c?0:(y-c)/(l-c)*100;r.value=String(y),f.style.setProperty("--cultui-slider-value",`${v}%`),f.dataset.value=String(y)})(e.value??c),r.addEventListener("input",()=>{const u=de(g(e.command,"control.slider.input"),{...e,action:{...w(e.action),value:Number(r.value)},value:Number(r.value)},n);n.commandSink?.(u,{kind:"control.slider",props:e})}),f}function _n(e,t){const n=typeof e.skin=="string"?e.skin:"",o=[...n?Qe.controlSkins[n]?.children||[]:[],...t];return o.length?o:[{kind:"control.box",props:{height:18,overflow:"visible"}},{kind:"control.part",props:{name:"track",anchor:"center",size:["100%",6],radius:2,fill:"color.panelInset"}},{kind:"control.part",props:{name:"fill",anchor:["left","center"],size:["value%",6],radius:2,fill:"color.accent"}},{kind:"control.part",props:{name:"thumb",anchor:["value","center"],size:[12,12],bleed:3,radius:999,fill:"color.accent"}}]}function Le(e){if(Array.isArray(e)){const t={},n={};for(const i of e)i?.name&&(i.name==="font.web.google"&&typeof i.value=="string"?n.fontCss=i.value:t[i.name]=i.value);return{tokens:t,assets:n,controlSkins:{}}}return{tokens:w(e?.tokens),assets:w(e?.assets),controlSkins:w(e?.controlSkins)}}function re(e){if(!e)return"";const t=z.assetUrlResolver;return t?t(e,ce):/^(https?:|data:|blob:)/i.test(e)?e:z.assetBaseUrl&&e.startsWith("/")?`${z.assetBaseUrl.replace(/\/+$/,"")}${e}`:e}function En(e){const t=typeof e=="string"?e.trim():"";if(me?.dataset.href===t||(me?.remove(),me=void 0,!t))return;const n=document.createElement("link");n.rel="preconnect",n.href="https://fonts.gstatic.com",n.crossOrigin="anonymous",document.head.append(n);const i=document.createElement("link");i.rel="stylesheet",i.href=t,i.dataset.href=t,document.head.append(i),me=i}function An(e,t,n){const i=[];return(e==="text.title"||t.role==="title")&&i.push("cultui-title","eve-text-title"),e==="text.subtitle"&&i.push("eve-text-subtitle"),e==="label"&&i.push("cultui-label"),t.role==="mono"&&i.push("detail","mono"),i.length===0&&i.push("detail","eve-text"),i.join(" ")}function In(e,t){t.height!==void 0&&(e.style.minHeight=R(t.height)),t.width!==void 0&&(e.style.width=R(t.width)),typeof t.overflow=="string"&&(e.style.overflow=t.overflow)}function Cn(e,t){const n=Array.isArray(t.size)?t.size:[t.size,void 0];n[0]!==void 0&&n[0]!=="value%"&&(e.style.width=R(n[0])),n[1]!==void 0&&(e.style.height=R(n[1])),t.radius!==void 0&&(e.style.borderRadius=R(t.radius)),t.fill!==void 0&&(e.style.background=ve(String(t.fill))),t.bleed!==void 0&&e.style.setProperty("--part-bleed",R(t.bleed)),(Array.isArray(t.anchor)?t.anchor:[t.anchor]).includes("value")&&(e.dataset.anchorValue="true")}function he(e,t){t.gap!==void 0&&(e.style.gap=R(t.gap)),t.padding!==void 0&&(e.style.padding=R(t.padding)),t.size!==void 0&&(e.style.flex=Tn(t.size)),t.min!==void 0&&(e.style.minWidth=R(t.min)),t.max!==void 0&&(e.style.maxWidth=R(t.max)),t.align!==void 0&&(e.style.alignItems=t.align==="end"?"flex-end":String(t.align)),(t.clip==="true"||t.clip===!0)&&(e.style.overflow="hidden"),t.scroll==="y"&&(e.style.overflowY="auto"),t.scroll==="x"&&(e.style.overflowX="auto")}function Tn(e){return typeof e=="string"&&e.endsWith("fr")?`${Number(e.slice(0,-2))||1} 1 0`:e==="auto"||e==="content"?"0 0 auto":`0 0 ${R(e)}`}function R(e){return Array.isArray(e)?e.map(R).join(" "):typeof e=="number"?`${e}px`:typeof e=="string"&&/^-?\d+(\.\d+)?$/.test(e)?`${e}px`:String(e??"")}function ve(e){return{"color.accent":"var(--accent)","color.panelInset":"rgba(0, 0, 0, 0.34)","color.panel":"var(--panel)","color.text":"var(--text)"}[e]||e}function ge(e){return e.includes("Zen Kaku Gothic New")||e.includes("M PLUS 1")?e:e.includes("Montserrat")?`${e}, "Zen Kaku Gothic New", "M PLUS 1", "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif`:e.includes("Ubuntu")?`${e}, "M PLUS 1", "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif`:`${e}, "Noto Sans JP", "Hiragino Sans", "Yu Gothic", sans-serif`}function S(e,t){t.id&&(e.id=t.id),t.id&&(e.dataset.eveNodeId=t.id),t.kind&&(e.dataset.eveKind=t.kind)}function w(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function kn(e){return Array.isArray(e)?e:[]}function Rn(e){return kn(e).map((t,n)=>nt({kind:"list.item",props:w(t)}))}function g(e,t){return e==null?t:String(e)}function p(...e){for(const t of e){if(typeof t=="string"&&t.trim())return t;if(typeof t=="number"&&Number.isFinite(t))return String(t)}return""}function Me(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"?["1","true","yes","on"].includes(e.trim().toLowerCase()):!1}function U(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}function Fn(e){const t=e.toLowerCase();return t.includes("sensor")?"S":t.includes("thermal")?"T":t.includes("fuel")?"F":t.includes("cargo")?"C":t.includes("weapon")?"W":e.trim().slice(0,1).toUpperCase()||"?"}function Pn(e){const t=e.trim().split(/\s+/).filter(Boolean);return t.length&&t.slice(0,2).map(n=>n[0]?.toUpperCase()||"").join("")||"?"}function Xe(e){const t=Number(e);return Number.isFinite(t)?Math.max(0,Math.min(100,t)):0}function m(e,t="",n=""){const i=document.createElement(e);return t&&(i.className=t),n&&(i.textContent=n),i}const we=document.querySelector("#surface"),$=document.querySelector("#status"),le=document.querySelector("#receipt"),at=document.querySelector("#compiler"),Se=document.querySelector("#composer"),ae=document.querySelector("#destination-form"),st=document.querySelector("#compiler-results"),ct=document.querySelector("#campaign-lab"),Ln=document.querySelector("#campaign-list");let V=0,se=0,lt=0,oe=[];function b(e,t,n){const i=document.createElement(e);return t!==void 0&&(i.textContent=t),n&&(i.className=n),i}function Y(e,t){const n=[b("h3",e)];for(const i of t.filter(Boolean))n.push(b("p",i));le.replaceChildren(...n),le.hidden=!1}function Mn(e){if(e?.kind==="assessed"){const t=e.assessment,n=[b("h3",t.admissible?"Action assessment":"That attempt is not possible")];if(t.admissible){n.push(b("p",`DC ${t.dc} · modifier ${t.modifier_total>=0?"+":""}${t.modifier_total}`));const i=b("ul");for(const o of t.modifiers??[])i.append(b("li",`${o.label}: ${o.value>=0?"+":""}${o.value}`));n.push(i),n.push(b("p",`Strong/success: ${t.success_stake}`)),n.push(b("p",`Mixed: ${t.mixed_stake}`)),n.push(b("p",`Failure: ${t.failure_stake}`)),n.push(b("p",`Effect ceiling: ${t.effect_ceiling}`,"quiet"))}else{n.push(b("p",t.missing_permission??"The attempt has no admissible path from current state."));for(const i of t.bargains??[])n.push(b("p",`Possible bargain: ${i}`))}le.replaceChildren(...n),le.hidden=!1;return}if(e?.kind==="committed"){const t=e.receipt?.roll;if(t){const n=String(t.outcome).replaceAll("_"," ");Y(n.charAt(0).toUpperCase()+n.slice(1),[`d20 ${t.d20} ${t.modifier_total>=0?"+":"−"} ${Math.abs(t.modifier_total)} = ${t.total} against DC ${t.dc}`])}else Y("World advanced",[`Revision ${e.revision}`]);return}if(e?.kind==="resolution_updated"){Y("World resolution updated",[`Resolution epoch ${e.receipt?.resolution_epoch??"advanced"}`]);return}Y("Command result",[e?.error??"The world returned no player-facing detail."])}function Nn(){const e="This laboratory requires an unused invite link.";$.textContent=e,at.hidden=!0,Se.hidden=!0,ae.hidden=!0,ct.hidden=!0,le.hidden=!0,we.hidden=!1;const t=b("article",void 0,"card");t.append(b("h2","Private campaign laboratory"),b("p",e),b("p","Open one of the two single-use tester invitations on this device. The resulting session stays separate from the other player's campaigns.","quiet")),we.replaceChildren(t)}async function q(){const e=await fetch("/api/surface");if(e.status===401){Nn();return}const t=await e.json(),n=t.surface_id==="ghostlight.compiler";if(at.hidden=!n,Se.hidden=n,ae.hidden=n,we.hidden=n,ct.hidden=n,n){$.textContent="No campaign exists. Retrieve the Vault and approve a world seed.";return}V=Number(t.world_revision??t.version??0),se=Number(t.resolution?.policy?.resolution_epoch??0),lt=Number(t.resolution?.policy?.provider_configuration_epoch??0),oe=t.resolution?.pins??[];const i=Number(t.resolution?.policy?.active_cell_budget??8),o=document.querySelector("#active-cell-budget");o.value=String(i),document.querySelector("#active-cell-budget-value").value=String(i),document.querySelector("#resolution-status").textContent=`${t.resolution?.effective_budget??i} effective cells · ${t.resolution?.mandatory_overage??0} temporary overage · epoch ${se}`;const s=Number(t.resolution?.policy?.provider_parallelism??8);document.querySelector("#provider-parallelism").value=String(s),document.querySelector("#provider-parallelism-value").value=String(s);const c=document.querySelector("#pin-list");c.replaceChildren(),oe.length===0&&c.append(b("p","No persistent pins."));for(const a of oe){const r=b("p");r.append(b("code",String(a.kind)),document.createTextNode(` ${[...a.subject_ids].join(", ")} — ${a.reason} `));const d=b("button","Remove");d.type="button",d.addEventListener("click",async()=>{await ie({type:"replace_resolution_pins",expected_revision:V,expected_resolution_epoch:se,pins:oe.filter(u=>u.id!==a.id)})}),r.append(d),c.append(r)}const l=document.querySelector("#fission-parent");l.replaceChildren(...(t.resolution?.fission_targets??[]).map(a=>{const r=b("option",`${a.name} · ${a.id}`);return r.value=a.id,r})),document.querySelector("#fission-form").hidden=l.options.length===0,et(t,we,{body:document.body,clientId:"ghostlight.browser",statusElement:$});const f=await fetch("/api/campaigns").then(a=>a.json());Ln.replaceChildren(...f.campaigns.map(a=>{const r=b("button",`${a.selected?"●":"○"} ${a.name} · revision ${a.revision}`);return r.type="button",r.disabled=!!a.selected,a.selected||r.addEventListener("click",async()=>{await B(`/api/campaigns/select/${a.id}`,{}),await q()}),r}))}async function B(e,t){$.textContent="Retrieving evidence and compiling…";const n=await fetch(e,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)}),i=n.headers.get("content-type")?.includes("json")?await n.json():await n.text();if(!n.ok)throw $.textContent=typeof i=="string"?i:"Compilation failed",new Error($.textContent);return i}function Ye(e,t,n){const i=b("div",void 0,"cards");e.forEach((o,s)=>{const c=b("article",void 0,"card");c.append(b("h3",o.title??o.name),b("p",o.player_hook??o.premise)),o.era&&c.append(b("p",`${o.era} · ${o.place} · ${o.pressure}`));const l=b("button",t);l.type="button",l.addEventListener("click",()=>n(e[s])),c.append(l),i.append(c)}),st.replaceChildren(i)}document.querySelector("#suggest-form").addEventListener("submit",async e=>{e.preventDefault();const t=await B("/api/compiler/openings",{setting:document.querySelector("#setting").value,constraints:[]});Ye(t.openings,"Choose opening",async n=>{const i=await B("/api/compiler/roles",n);Ye(i.roles,"Choose role",async o=>dt(await B("/api/compiler/selected",{campaign_name:n.title,opening:n,role:o})))})});document.querySelector("#custom-form").addEventListener("submit",async e=>{e.preventDefault(),await dt(await B("/api/compiler/custom",Object.fromEntries(new FormData(e.currentTarget))))});async function dt(e){const t=e.preview,n=Array.isArray(t.evidence_coverage)?t.evidence_coverage:[],i=n.reduce((f,a)=>{const r=String(a?.lane??"excluded");return f[r]=(f[r]??0)+1,f},{}),o=b("article",void 0,"card");o.append(b("h3",t.title),b("p",t.opening??""),b("p",`${t.locations?.length??0} locations · ${(t.cast?.length??0)+1} actors · ${t.institutions?.length??0} institutions`),b("p",t.gaps.length?`Material gaps: ${t.gaps.join("; ")}`:"No declared material gaps.","warning"),b("p",`Branch assumptions: ${t.branch_assumptions.join("; ")||"none"}`),b("p",n.length?`Evidence use: ${i.direct_seed??0} direct · ${i.setting_background??0} background · ${i.excluded??0} excluded`:"Evidence use: no retrieved sources were admitted to this seed.","quiet"));const s=Array.isArray(t.branch_facts)?t.branch_facts:[],c=b("details");if(c.append(b("summary",`Branch-local world facts (${s.length}) · contains operator spoilers`)),s.length){const f=b("ul");for(const a of s){const r=Array.isArray(a.discoverable_at_location_ids)&&a.discoverable_at_location_ids.length?` · discoverable at ${a.discoverable_at_location_ids.join(", ")}`:" · not directly discoverable";f.append(b("li",`${a.statement}${r}`))}c.append(f)}else c.append(b("p","No branch-local facts are proposed."));o.append(c);const l=b("button","Approve and enter");l.type="button",l.addEventListener("click",async()=>{await B(`/api/compiler/approve/${e.preview_id}`,{}),await q()}),o.append(l),st.replaceChildren(o),$.textContent="Preview compiled. Nothing has entered world state yet."}async function ie(e){$.textContent="The world is considering the command…";const t=await fetch("/api/command",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)}),n=await t.json();return Mn(n),t.ok?(await q(),n):($.textContent=n.error??"The command was refused.",await q(),n)}function ut(e){if(e?.kind!=="assessed")return;const t=document.createElement("button");t.type="button",t.textContent=e.assessment.admissible?"Confirm server roll":"Revise attempt",t.addEventListener("click",async()=>{if(!e.assessment.admissible){document.querySelector("#attempt").focus();return}const n=await ie({type:"attempt",assessment_digest:e.assessment.digest});t.remove(),ut(n)}),Se.append(t)}Se.addEventListener("submit",async e=>{e.preventDefault();const t=document.querySelector("#attempt").value.trim();t&&ut(await ie({type:"assess",expected_revision:V,intent:{actor_id:"player",description:t,intended_effect:t}}))});document.querySelector("#wait").addEventListener("click",()=>{ie({type:"wait",expected_revision:V,minutes:60})});document.querySelector("#active-cell-budget").addEventListener("input",e=>{document.querySelector("#active-cell-budget-value").value=e.currentTarget.value});document.querySelector("#resolution-form").addEventListener("submit",async e=>{e.preventDefault(),await ie({type:"set_resolution_budget",expected_revision:V,expected_resolution_epoch:se,active_cell_budget:Number(document.querySelector("#active-cell-budget").value)})});document.querySelector("#provider-parallelism").addEventListener("input",e=>{document.querySelector("#provider-parallelism-value").value=e.currentTarget.value});document.querySelector("#provider-parallelism-form").addEventListener("submit",async e=>{e.preventDefault(),$.textContent="Applying the provider concurrency limit…";const t=await fetch("/api/operator/provider-parallelism",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({expected_provider_configuration_epoch:lt,provider_parallelism:Number(document.querySelector("#provider-parallelism").value)})}),n=await t.json();Y(t.ok?"Provider concurrency updated":"Provider concurrency refused",[t.ok?`Parallel requests: ${n.receipt?.provider_parallelism??n.provider_parallelism??"updated"}`:n.error??"The operator limit was refused."]),t.ok||($.textContent=n.error??"The operator limit was refused."),await q()});document.querySelector("#pin-form").addEventListener("submit",async e=>{e.preventDefault();const t=new FormData(e.currentTarget),n=String(t.get("subject_ids")??"").split(",").map(o=>o.trim()).filter(Boolean),i={schema:"ghostlight.resolution_pin.v1",id:`pin:${crypto.randomUUID()}`,kind:String(t.get("kind")),subject_ids:n,reason:String(t.get("reason")??"").trim(),created_world_revision:V};await ie({type:"replace_resolution_pins",expected_revision:V,expected_resolution_epoch:se,pins:[...oe,i]})});ae.addEventListener("submit",async e=>{e.preventDefault();const t=await B("/api/compiler/destination",Object.fromEntries(new FormData(ae))),n=t.preview;Y("Destination preview",[...(n.locations??[]).map(o=>o.name),...(n.gaps??[]).map(o=>`Material gap: ${o}`)]),$.textContent="Destination preview compiled; topology is unchanged until approval.";const i=b("button","Approve destination");i.type="button",i.addEventListener("click",async()=>{await B(`/api/compiler/destination/approve/${t.preview_id}`,{}),i.remove(),await q()}),ae.append(i)});document.querySelector("#fission-form").addEventListener("submit",async e=>{e.preventDefault();const t=new FormData(e.currentTarget),n=await B("/api/compiler/gestalt/fission",{parent_gestalt_id:t.get("parent_gestalt_id"),partition_axis:t.get("partition_axis"),requested_partition_values:String(t.get("requested_partition_values")??"").split(",").map(o=>o.trim()).filter(Boolean),reason:t.get("reason")});Y("Population fission preview",[...(n.preview?.children??[]).map(o=>`${o.name} · ${o.id}`),...(n.preview?.gaps??[]).map(o=>`Material gap: ${o}`)]),$.textContent="Fission preview compiled. Canonical leaves are unchanged until approval.";const i=document.createElement("button");i.type="button",i.textContent="Approve population fission",i.addEventListener("click",async()=>{await B(`/api/compiler/gestalt/fission/approve/${n.preview_id}`,{}),i.remove(),await q()}),e.currentTarget.append(i)});document.querySelector("#fork-form").addEventListener("submit",async e=>{e.preventDefault(),await B("/api/campaigns/fork",Object.fromEntries(new FormData(e.currentTarget))),await q()});document.querySelector("#reset-form").addEventListener("submit",async e=>{e.preventDefault(),await B("/api/campaigns/reset",Object.fromEntries(new FormData(e.currentTarget))),await q()});document.querySelector("#load-operator").addEventListener("click",async()=>{const t=await(await fetch("/api/operator")).json();et(t,document.querySelector("#operator-output"),{body:document.body,clientId:"ghostlight.operator",statusElement:$})});q(); diff --git a/web/dist/index.html b/web/dist/index.html index fd2281a..8e7ff50 100644 --- a/web/dist/index.html +++ b/web/dist/index.html @@ -1,5 +1,5 @@ -GhostlightDungeon +GhostlightDungeon

STARFIRE / PRIVATE VERSE

GhostlightDungeon

Reading the world…

diff --git a/web/src/main.ts b/web/src/main.ts index 6521537..99f1554 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -198,6 +198,22 @@ async function showPreview(result: any) { ? `Evidence use: ${evidenceCounts.direct_seed ?? 0} direct · ${evidenceCounts.setting_background ?? 0} background · ${evidenceCounts.excluded ?? 0} excluded` : "Evidence use: no retrieved sources were admitted to this seed.", "quiet"), ); + const branchFacts = Array.isArray(preview.branch_facts) ? preview.branch_facts : []; + const factDisclosure = node("details"); + factDisclosure.append(node("summary", `Branch-local world facts (${branchFacts.length}) · contains operator spoilers`)); + if (branchFacts.length) { + const list = node("ul"); + for (const fact of branchFacts) { + const locations = Array.isArray(fact.discoverable_at_location_ids) && fact.discoverable_at_location_ids.length + ? ` · discoverable at ${fact.discoverable_at_location_ids.join(", ")}` + : " · not directly discoverable"; + list.append(node("li", `${fact.statement}${locations}`)); + } + factDisclosure.append(list); + } else { + factDisclosure.append(node("p", "No branch-local facts are proposed.")); + } + card.append(factDisclosure); const approve = node("button", "Approve and enter"); approve.type = "button"; approve.addEventListener("click", async () => { await compilerPost(`/api/compiler/approve/${result.preview_id}`, {}); await refresh(); });