From 381cbf22c23e6297a2d64aaf15dcc310beb0bf63 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 16 Aug 2026 21:03:18 +0200 Subject: [PATCH] Add operator inspection and live turn pressure --- crates/ghostlight-dungeon/src/domain.rs | 11 ++ crates/ghostlight-dungeon/src/main.rs | 113 ++++++++++++++++-- crates/ghostlight-dungeon/src/persistence.rs | 9 ++ docs/architecture/ghostlight-dungeon-mvp.md | 13 ++ notes/ghostlight-dungeon.md | 1 + state/map.yaml | 2 +- .../{index-CSZpdeJl.js => index-DDHZWg6R.js} | 6 +- web/dist/index.html | 4 +- web/index.html | 2 +- web/src/main.ts | 1 + 10 files changed, 146 insertions(+), 16 deletions(-) rename web/dist/assets/{index-CSZpdeJl.js => index-DDHZWg6R.js} (89%) diff --git a/crates/ghostlight-dungeon/src/domain.rs b/crates/ghostlight-dungeon/src/domain.rs index b2a3e10..0a3e868 100644 --- a/crates/ghostlight-dungeon/src/domain.rs +++ b/crates/ghostlight-dungeon/src/domain.rs @@ -265,6 +265,17 @@ pub struct CampaignLifecycleReceipt { pub created_at: DateTime, } +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] +pub struct RejectedProposalReceipt { + pub schema: String, + pub id: String, + pub campaign_id: Uuid, + pub revision: u64, + pub command_kind: String, + pub reason: String, + pub rejected_at: DateTime, +} + #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)] pub struct ActionIntent { pub actor_id: String, diff --git a/crates/ghostlight-dungeon/src/main.rs b/crates/ghostlight-dungeon/src/main.rs index 4cb1736..92a3360 100644 --- a/crates/ghostlight-dungeon/src/main.rs +++ b/crates/ghostlight-dungeon/src/main.rs @@ -11,8 +11,8 @@ use ghostlight_dungeon::{ assessor::ActionAssessor, compiler::{CustomStart, OpeningRequest, OpeningSuggestion, SelectedStart, WorldCompiler}, domain::{ - ActionIntent, Campaign, NarrationProjection, RegionExpansionPreview, WorldCommand, - WorldCompilePreview, + ActionIntent, Campaign, NarrationProjection, RegionExpansionPreview, + RejectedProposalReceipt, WorldCommand, WorldCompilePreview, }, gestalt::GestaltPresencePlanner, kernel::CommandResult, @@ -33,6 +33,7 @@ use std::{ net::SocketAddr, path::PathBuf, sync::Arc, + sync::atomic::{AtomicUsize, Ordering}, }; use tokio::sync::Mutex; use tower_http::services::ServeDir; @@ -49,6 +50,20 @@ struct AppState { model: Option>, compile_previews: Arc>>>, expansion_previews: Arc>>>, + live_turns: Arc, +} + +struct LiveTurnGuard(Arc); +impl LiveTurnGuard { + fn enter(counter: &Arc) -> Self { + counter.fetch_add(1, Ordering::SeqCst); + Self(counter.clone()) + } +} +impl Drop for LiveTurnGuard { + fn drop(&mut self) { + self.0.fetch_sub(1, Ordering::SeqCst); + } } #[derive(Clone)] @@ -180,6 +195,7 @@ async fn main() -> anyhow::Result<()> { model: shared_model, compile_previews: Arc::new(Mutex::new(BTreeMap::new())), expansion_previews: Arc::new(Mutex::new(BTreeMap::new())), + live_turns: Arc::new(AtomicUsize::new(0)), }; tokio::spawn(scheduler_loop(state.clone())); let release_web_root = std::env::current_exe()? @@ -211,6 +227,7 @@ async fn main() -> anyhow::Result<()> { .route("/api/campaigns/fork", post(fork_campaign)) .route("/api/campaigns/reset", post(reset_campaign)) .route("/api/campaigns/export", get(export_campaign)) + .route("/api/operator", get(operator_inspector)) .fallback_service(ServeDir::new(web_root).append_index_html_on_directories(true)) .with_state(state); let address: SocketAddr = std::env::var("GHOSTLIGHT_DUNGEON_BIND") @@ -299,6 +316,7 @@ async fn compile_openings( if !authorized(&headers, &state).await { return StatusCode::UNAUTHORIZED.into_response(); } + let _live = LiveTurnGuard::enter(&state.live_turns); let Some(compiler) = &state.compiler else { return ( StatusCode::SERVICE_UNAVAILABLE, @@ -321,6 +339,7 @@ async fn compile_custom( Some(value) => value, None => return StatusCode::UNAUTHORIZED.into_response(), }; + let _live = LiveTurnGuard::enter(&state.live_turns); if session_runtime(&state, &session) .await .ok() @@ -365,6 +384,7 @@ async fn compile_roles( if !authorized(&headers, &state).await { return StatusCode::UNAUTHORIZED.into_response(); } + let _live = LiveTurnGuard::enter(&state.live_turns); let Some(compiler) = &state.compiler else { return ( StatusCode::SERVICE_UNAVAILABLE, @@ -387,6 +407,7 @@ async fn compile_selected( Some(value) => value, None => return StatusCode::UNAUTHORIZED.into_response(), }; + let _live = LiveTurnGuard::enter(&state.live_turns); if session_runtime(&state, &session) .await .ok() @@ -443,6 +464,7 @@ async fn approve_preview( Some(value) => value, None => return StatusCode::UNAUTHORIZED.into_response(), }; + let _live = LiveTurnGuard::enter(&state.live_turns); let mut previews = state.compile_previews.lock().await; let Some(owned) = previews.get(&preview_id).cloned() else { return (StatusCode::NOT_FOUND, "preview missing or already consumed").into_response(); @@ -487,6 +509,7 @@ async fn compile_destination( Some(value) => value, None => return StatusCode::UNAUTHORIZED.into_response(), }; + let _live = LiveTurnGuard::enter(&state.live_turns); let runtime = match session_runtime(&state, &session).await { Ok(Some(value)) => value, Ok(None) => { @@ -677,6 +700,7 @@ async fn command( Some(value) => value, None => return StatusCode::UNAUTHORIZED.into_response(), }; + let _live = LiveTurnGuard::enter(&state.live_turns); let runtime = match session_runtime(&state, &session).await { Ok(Some(value)) => value, Ok(None) => { @@ -759,6 +783,15 @@ async fn command( &command, WorldCommand::Attempt { .. } | WorldCommand::Speak { .. } ); + let command_kind = serde_json::to_value(&command) + .ok() + .and_then(|value| { + value + .get("type") + .and_then(|value| value.as_str()) + .map(str::to_owned) + }) + .unwrap_or_else(|| "unknown".into()); match runtime.kernel.command(command).await { Ok(result) => { if should_react { @@ -918,13 +951,32 @@ async fn command( Json(result).into_response() } } - Err(error) => ( - StatusCode::CONFLICT, - Json(ErrorBody { - error: error.to_string(), - }), - ) - .into_response(), + Err(error) => { + if let Ok(campaign) = load_campaign(&runtime.store) { + let receipt = RejectedProposalReceipt { + schema: "ghostlight.rejected_proposal_receipt.v1".into(), + id: uuid::Uuid::new_v4().to_string(), + campaign_id: campaign.id, + revision: campaign.revision, + command_kind, + reason: error.to_string(), + rejected_at: chrono::Utc::now(), + }; + let _ = runtime.store.insert( + "rejected_proposal_receipt.v1", + "ghostlight.rejected_proposal_receipt.v1", + &receipt.id, + &receipt, + ); + } + ( + StatusCode::CONFLICT, + Json(ErrorBody { + error: error.to_string(), + }), + ) + .into_response() + } } } @@ -934,6 +986,9 @@ async fn scheduler_loop(state: AppState) { pulse.tick().await; loop { pulse.tick().await; + if state.live_turns.load(Ordering::SeqCst) > 0 { + continue; + } for id in state.registry.list().await { match state.registry.runtime(id).await { Ok(runtime) => { @@ -1139,6 +1194,45 @@ async fn export_campaign(headers: HeaderMap, State(state): State) -> R } } +async fn operator_inspector(headers: HeaderMap, State(state): State) -> Response { + let session = match authenticated_session(&headers, &state).await { + Some(value) => value, + None => return StatusCode::UNAUTHORIZED.into_response(), + }; + let runtime = match session_runtime(&state, &session).await { + Ok(Some(value)) => value, + Ok(None) => { + return (StatusCode::NOT_FOUND, "session has no selected campaign").into_response(); + } + Err(error) => { + return (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(); + } + }; + let campaign = match load_campaign(&runtime.store) { + Ok(value) => value, + Err(error) => { + return (StatusCode::INTERNAL_SERVER_ERROR, error.to_string()).into_response(); + } + }; + let evidence = runtime + .store + .load_all::("vault_evidence_receipt.v1") + .unwrap_or_default(); + let commits = runtime + .store + .load_all::("world_commit_receipt.v1") + .unwrap_or_default(); + let stages = runtime + .store + .load_all::("persona_stage_receipt.v1") + .unwrap_or_default(); + let rejected = runtime + .store + .load_all::("rejected_proposal_receipt.v1") + .unwrap_or_default(); + Json(serde_json::json!({"schema":"ghostlight.operator_inspector.v1","campaign":campaign,"evidence":evidence,"commit_receipts":commits,"model_stage_receipts":stages,"rejected_proposals":rejected,"scheduler":{"live_turn_pressure":state.live_turns.load(Ordering::SeqCst)}})).into_response() +} + async fn process_due_ticks(runtime: &CampaignRuntime) -> anyhow::Result<()> { loop { let campaign = match load_campaign(&runtime.store) { @@ -1379,6 +1473,7 @@ mod tests { model: None, compile_previews: Arc::new(Mutex::new(BTreeMap::new())), expansion_previews: Arc::new(Mutex::new(BTreeMap::new())), + live_turns: Arc::new(AtomicUsize::new(0)), }; let left_runtime = session_runtime(&state, "left").await.unwrap().unwrap(); let right_runtime = session_runtime(&state, "right").await.unwrap().unwrap(); diff --git a/crates/ghostlight-dungeon/src/persistence.rs b/crates/ghostlight-dungeon/src/persistence.rs index 86b00bd..25e4eac 100644 --- a/crates/ghostlight-dungeon/src/persistence.rs +++ b/crates/ghostlight-dungeon/src/persistence.rs @@ -30,6 +30,15 @@ impl CampaignStore { .collect()) } + pub fn load_all(&self, kind: &str) -> Result> { + self.inner + .pull_all()? + .into_iter() + .filter(|row| row.r#type == kind) + .map(|row| rmp_serde::from_slice(&row.payload).context("decode CultCache row")) + .collect() + } + pub fn load( &self, kind: &str, diff --git a/docs/architecture/ghostlight-dungeon-mvp.md b/docs/architecture/ghostlight-dungeon-mvp.md index 9aadbef..c864bb3 100644 --- a/docs/architecture/ghostlight-dungeon-mvp.md +++ b/docs/architecture/ghostlight-dungeon-mvp.md @@ -593,6 +593,19 @@ campaign management, fork/reset/export, and optional operator inspection. CultMesh state is the source of the UI projection. HTTP health is a probe over the same service-state document. +The authenticated operator inspector projects the selected campaign's full +typed state, topology, evidence receipts, commit receipts, model-stage receipts, +rejected-proposal receipts, and scheduler live-turn pressure. It contains no +provider reasoning content or secret material. Kernel command refusals append a +private receipt without changing campaign revision, allowing the laboratory to +inspect why impossible, stale, or malformed proposals were rejected. + +Live compiler and player command paths hold a process-local inference-pressure +lease. The five-minute scheduler observes that pressure and launches no new +campaign work while any live lease exists. Already-committed campaign state +does not require a repair pass when background launch is skipped; the next +scheduler pulse or return catch-up uses the same strategic-tick command. + ## Model boundary The provider-neutral model port records provider, model, request hash, source diff --git a/notes/ghostlight-dungeon.md b/notes/ghostlight-dungeon.md index 59127b4..28473c2 100644 --- a/notes/ghostlight-dungeon.md +++ b/notes/ghostlight-dungeon.md @@ -169,6 +169,7 @@ stake prose alone never impersonates world mutation. - `persona_stage_receipt.v1`, `actor_state_delta.v1`, `world_action_proposal.v1` - `narration_projection.v1` - `strategic_tick.v1`, `news_issue.v1`, `canon_candidate.v1` +- `rejected_proposal_receipt.v1`, `campaign_lifecycle_receipt.v1` - `gestalt_persona_state.v1`, `gestalt_member_delta.v1`, `gestalt_materialization_receipt.v1` - Existing `gamecult.eve.surface.v1` and `gamecult.eve.command.v1` diff --git a/state/map.yaml b/state/map.yaml index fdcab43..2425d2d 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -255,5 +255,5 @@ data_flow: current_status: summary: GhostlightDungeon is the active MVP program. The approval-gated compiler persists evidence, canon candidates, and bounded region expansion. Fiction-first player and NPC attempts use deterministic initiative, model assessment, server-side d20, and prevalidated typed outcome deltas. Present NPCs appraise events in parallel; gestalt populations materialize durable individuals and fold them into member deltas. Narration is a revision-bound noncanonical projection. A CampaignRegistry now isolates per-campaign stores/mailboxes, persists hashed session ownership and selection, routes scheduler and HTTP work through the selected runtime, and supports fork/reset/select/CultCache export. Live DeepSeek plus VoidBot compilation and an earlier authenticated HTTP restart smoke passed; the expanded multi-campaign runtime still needs live acceptance. - next_action: Add operator inspection and live-inference priority gating, then run two-session HTTP, model-failure, restart, scheduler, live gestalt, typed-outcome, performance, and deployment acceptance against the registry runtime. + next_action: Run two-session HTTP, model-failure, restart, scheduler, live gestalt, typed-outcome, performance, and deployment acceptance against the registry runtime; repair any failures before updating deployment provenance. gestalt_population: Gestalt Personas own shared population baselines; persistent member deltas own named individuality; WorldKernel materialization commands compose and demote active actors without deleting member identity. diff --git a/web/dist/assets/index-CSZpdeJl.js b/web/dist/assets/index-DDHZWg6R.js similarity index 89% rename from web/dist/assets/index-CSZpdeJl.js rename to web/dist/assets/index-DDHZWg6R.js index 6d645ab..420f26b 100644 --- a/web/dist/assets/index-CSZpdeJl.js +++ b/web/dist/assets/index-DDHZWg6R.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 a of o)if(a.type==="childList")for(const s of a.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&i(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const a={};return o.integrity&&(a.integrity=o.integrity),o.referrerPolicy&&(a.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?a.credentials="include":o.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(o){if(o.ep)return;o.ep=!0;const a=n(o);fetch(o.href,a)}})();const X=new WeakMap,be=20;function rt(e,t,n,i,o,a,s,l){const f=st(e.canvas);if(!f)return!1;const c=f.gl;if(!lt(f,a,s))return X.set(e.canvas,null),!1;const r=ot(t,n,i,o,l);c.bindFramebuffer(c.FRAMEBUFFER,f.framebuffer),c.viewport(0,0,a,s),c.disable(c.DEPTH_TEST),c.disable(c.CULL_FACE),c.enable(c.BLEND),c.blendFunc(c.ONE,c.ONE),c.clearColor(0,0,0,1),c.clear(c.COLOR_BUFFER_BIT),r.gravity.length>0&&(c.useProgram(f.splatProgram),c.uniform4f(c.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),c.uniform1f(c.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),c.bindBuffer(c.ARRAY_BUFFER,f.splatBuffer),c.bufferData(c.ARRAY_BUFFER,r.gravity,c.DYNAMIC_DRAW),Me(c,f.splatProgram),c.drawArrays(c.TRIANGLES,0,r.gravity.length/be)),c.bindFramebuffer(c.FRAMEBUFFER,f.tintFramebuffer),c.clearColor(0,0,0,0),c.clear(c.COLOR_BUFFER_BIT),r.tint.length>0&&(c.useProgram(f.splatProgram),c.uniform4f(c.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),c.uniform1f(c.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),c.bindBuffer(c.ARRAY_BUFFER,f.splatBuffer),c.bufferData(c.ARRAY_BUFFER,r.tint,c.DYNAMIC_DRAW),Me(c,f.splatProgram),c.drawArrays(c.TRIANGLES,0,r.tint.length/be)),c.disable(c.BLEND),c.bindFramebuffer(c.FRAMEBUFFER,null),c.viewport(0,0,a,s),c.useProgram(f.shadeProgram),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,f.fieldTexture),c.uniform1i(c.getUniformLocation(f.shadeProgram,"u_field"),0),c.activeTexture(c.TEXTURE1),c.bindTexture(c.TEXTURE_2D,f.tintTexture),c.uniform1i(c.getUniformLocation(f.shadeProgram,"u_tint"),1),c.uniform2f(c.getUniformLocation(f.shadeProgram,"u_resolution"),a,s),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_time"),I(n.simulationTimeSeconds,I(t.simulationTimeSeconds,0))),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineInterval"),I(t.lineInterval,I(t.scalarFieldLineInterval,I(t.depthRange,228.79605)/20))),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineOffset"),I(t.lineOffset,I(t.startDepth,2.310401))),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineWidth"),I(t.lineWidth,.3)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineFade"),I(t.lineFade,5)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_angleWidth"),I(t.angleWidth,.05)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_angleFade"),I(t.angleFade,1.15)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_dangerSteepness"),I(t.dangerSteepness,1.5)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_scale"),I(t.isolineScale,2.6924083)),Q(c,f.shadeProgram,"u_baseColor",Z(t.scalarFieldBaseColor,[.002,.006,.012])),Q(c,f.shadeProgram,"u_fieldGlowColor",Z(t.scalarFieldGlowColor,[.018,.05,.075])),Q(c,f.shadeProgram,"u_lineLowColor",Z(t.scalarFieldLowLineColor,[0,.34,.52])),Q(c,f.shadeProgram,"u_lineHighColor",Z(t.scalarFieldHighLineColor,[1.45,.3,.05])),Q(c,f.shadeProgram,"u_angleLowColor",Z(t.scalarFieldLowAngleColor,[.06,.16,.24])),Q(c,f.shadeProgram,"u_angleHighColor",Z(t.scalarFieldHighAngleColor,[1.1,.24,.04])),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_tintScale"),I(t.vectorFieldTintScale,.45)),c.bindBuffer(c.ARRAY_BUFFER,f.quadBuffer);const d=c.getAttribLocation(f.shadeProgram,"a_position");return c.enableVertexAttribArray(d),c.vertexAttribPointer(d,2,c.FLOAT,!1,0,0),c.drawArrays(c.TRIANGLES,0,6),e.drawImage(f.canvas,0,0,a,s),!0}function ot(e,t,n,i,o){const a=[],s=[];return at(a,e,t,n),ct(s,e,o),{gravity:new Float32Array(a),tint:new Float32Array(s)}}function at(e,t,n,i,o){const a=I(n.terrainRadius,I(t.terrainRadius,1200)),s=I(n.terrainDepth,I(t.terrainDepth,-8));s!==0&&le(e,0,0,Math.max(1,a*2),Math.max(1,a*2),-s,0,0,1,Math.max(1e-4,I(n.terrainDepthExponent,I(t.terrainDepthExponent,1.2))),0,1,0,0);for(const l of i)le(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&&le(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 ct(e,t,n){const i=dt(n?.splats),o=Array.isArray(n?.layers)?n.layers:[],a=new Set,s=ft(t.vectorFieldLayer,t.tintFieldLayer,"fog.tint");o.forEach((_,J)=>{const ie=ut(_?.layerKey,"");I(_?.channel,-1)===4&&ie===s&&a.add(J)});const l=Math.max(0,mt(i.count,0));if(l<=0||a.size===0)return;const f=L(i.centerX),c=L(i.centerY),r=L(i.halfExtentX),d=L(i.halfExtentY),u=L(i.rotationCos),h=L(i.rotationSin),y=L(i.channel),b=L(i.falloff),v=L(i.valueR),C=L(i.valueG),A=L(i.valueB),N=L(i.valueA),q=L(i.sourceKind),z=L(i.frequencyX),H=L(i.animationSpeed),V=L(i.sourceFlags),K=L(i.layerIndex);for(let _=0;_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 Q(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 dt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function ut(e,t){return e==null?t:String(e)}function ft(...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 mt(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}const pt=`#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 a of o)if(a.type==="childList")for(const s of a.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&i(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const a={};return o.integrity&&(a.integrity=o.integrity),o.referrerPolicy&&(a.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?a.credentials="include":o.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function i(o){if(o.ep)return;o.ep=!0;const a=n(o);fetch(o.href,a)}})();const j=new WeakMap,be=20;function rt(e,t,n,i,o,a,s,l){const f=st(e.canvas);if(!f)return!1;const c=f.gl;if(!lt(f,a,s))return j.set(e.canvas,null),!1;const r=ot(t,n,i,o,l);c.bindFramebuffer(c.FRAMEBUFFER,f.framebuffer),c.viewport(0,0,a,s),c.disable(c.DEPTH_TEST),c.disable(c.CULL_FACE),c.enable(c.BLEND),c.blendFunc(c.ONE,c.ONE),c.clearColor(0,0,0,1),c.clear(c.COLOR_BUFFER_BIT),r.gravity.length>0&&(c.useProgram(f.splatProgram),c.uniform4f(c.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),c.uniform1f(c.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),c.bindBuffer(c.ARRAY_BUFFER,f.splatBuffer),c.bufferData(c.ARRAY_BUFFER,r.gravity,c.DYNAMIC_DRAW),Me(c,f.splatProgram),c.drawArrays(c.TRIANGLES,0,r.gravity.length/be)),c.bindFramebuffer(c.FRAMEBUFFER,f.tintFramebuffer),c.clearColor(0,0,0,0),c.clear(c.COLOR_BUFFER_BIT),r.tint.length>0&&(c.useProgram(f.splatProgram),c.uniform4f(c.getUniformLocation(f.splatProgram,"u_viewport"),o.minX,o.minY,o.maxX,o.maxY),c.uniform1f(c.getUniformLocation(f.splatProgram,"u_time"),I(t.simulationTimeSeconds,0)),c.bindBuffer(c.ARRAY_BUFFER,f.splatBuffer),c.bufferData(c.ARRAY_BUFFER,r.tint,c.DYNAMIC_DRAW),Me(c,f.splatProgram),c.drawArrays(c.TRIANGLES,0,r.tint.length/be)),c.disable(c.BLEND),c.bindFramebuffer(c.FRAMEBUFFER,null),c.viewport(0,0,a,s),c.useProgram(f.shadeProgram),c.activeTexture(c.TEXTURE0),c.bindTexture(c.TEXTURE_2D,f.fieldTexture),c.uniform1i(c.getUniformLocation(f.shadeProgram,"u_field"),0),c.activeTexture(c.TEXTURE1),c.bindTexture(c.TEXTURE_2D,f.tintTexture),c.uniform1i(c.getUniformLocation(f.shadeProgram,"u_tint"),1),c.uniform2f(c.getUniformLocation(f.shadeProgram,"u_resolution"),a,s),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_time"),I(n.simulationTimeSeconds,I(t.simulationTimeSeconds,0))),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineInterval"),I(t.lineInterval,I(t.scalarFieldLineInterval,I(t.depthRange,228.79605)/20))),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineOffset"),I(t.lineOffset,I(t.startDepth,2.310401))),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineWidth"),I(t.lineWidth,.3)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_lineFade"),I(t.lineFade,5)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_angleWidth"),I(t.angleWidth,.05)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_angleFade"),I(t.angleFade,1.15)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_dangerSteepness"),I(t.dangerSteepness,1.5)),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_scale"),I(t.isolineScale,2.6924083)),Q(c,f.shadeProgram,"u_baseColor",Z(t.scalarFieldBaseColor,[.002,.006,.012])),Q(c,f.shadeProgram,"u_fieldGlowColor",Z(t.scalarFieldGlowColor,[.018,.05,.075])),Q(c,f.shadeProgram,"u_lineLowColor",Z(t.scalarFieldLowLineColor,[0,.34,.52])),Q(c,f.shadeProgram,"u_lineHighColor",Z(t.scalarFieldHighLineColor,[1.45,.3,.05])),Q(c,f.shadeProgram,"u_angleLowColor",Z(t.scalarFieldLowAngleColor,[.06,.16,.24])),Q(c,f.shadeProgram,"u_angleHighColor",Z(t.scalarFieldHighAngleColor,[1.1,.24,.04])),c.uniform1f(c.getUniformLocation(f.shadeProgram,"u_tintScale"),I(t.vectorFieldTintScale,.45)),c.bindBuffer(c.ARRAY_BUFFER,f.quadBuffer);const d=c.getAttribLocation(f.shadeProgram,"a_position");return c.enableVertexAttribArray(d),c.vertexAttribPointer(d,2,c.FLOAT,!1,0,0),c.drawArrays(c.TRIANGLES,0,6),e.drawImage(f.canvas,0,0,a,s),!0}function ot(e,t,n,i,o){const a=[],s=[];return at(a,e,t,n),ct(s,e,o),{gravity:new Float32Array(a),tint:new Float32Array(s)}}function at(e,t,n,i,o){const a=I(n.terrainRadius,I(t.terrainRadius,1200)),s=I(n.terrainDepth,I(t.terrainDepth,-8));s!==0&&le(e,0,0,Math.max(1,a*2),Math.max(1,a*2),-s,0,0,1,Math.max(1e-4,I(n.terrainDepthExponent,I(t.terrainDepthExponent,1.2))),0,1,0,0);for(const l of i)le(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&&le(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 ct(e,t,n){const i=dt(n?.splats),o=Array.isArray(n?.layers)?n.layers:[],a=new Set,s=ft(t.vectorFieldLayer,t.tintFieldLayer,"fog.tint");o.forEach((_,J)=>{const ie=ut(_?.layerKey,"");I(_?.channel,-1)===4&&ie===s&&a.add(J)});const l=Math.max(0,mt(i.count,0));if(l<=0||a.size===0)return;const f=L(i.centerX),c=L(i.centerY),r=L(i.halfExtentX),d=L(i.halfExtentY),u=L(i.rotationCos),h=L(i.rotationSin),y=L(i.channel),b=L(i.falloff),v=L(i.valueR),C=L(i.valueG),A=L(i.valueB),N=L(i.valueA),Y=L(i.sourceKind),z=L(i.frequencyX),H=L(i.animationSpeed),V=L(i.sourceFlags),K=L(i.layerIndex);for(let _=0;_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 Q(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 dt(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function ut(e,t){return e==null?t:String(e)}function ft(...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 mt(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}const pt=`#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); -}`,Ye=new Set(["gamecult.fields.splats.v1","gamecult.fields.gravity.v1","gamecult.fields.objects.v1"]),bt={pluginId:"fields.surface",capabilities:["field.surface2d","gravity.surface","field.scalar","field.vector","field.objects"],componentKinds:["field.surface2d","gravity.surface"],schemas:[...Ye],normalizeDocument:ve,renderComponent:vt};function vt(e,t,n,i,o,a){const s=document.createElement("canvas");s.className="cultui-gravity-surface",e.id&&(s.id=e.id),s.setAttribute("role","img"),s.setAttribute("aria-label",Kt(t.label,"gravity surface")),s.style.display="block",s.style.width="100%",s.style.height="100%",s.style.pointerEvents="none",a.applyGeneratedLayout(s,n,i);let l=!1;const f={},c=()=>St(s,t,f,a.resolveAssetUrl),r=()=>{!s.isConnected||l||(l=!0,requestAnimationFrame(()=>{l=!1,s.isConnected&&c()}))};s.addEventListener("cultui:asset-loaded",r);let d=0,u;const h=()=>{d&&window.clearInterval(d),u?.disconnect(),s.removeEventListener("cultui:asset-loaded",r)},y=()=>{if(!s.isConnected){h();return}xt(e,t,o,a.providerId,f).then(v=>{v&&s.isConnected&&r()}).catch(v=>{f.lastError=v instanceof Error?v.message:String(v)})};typeof ResizeObserver<"u"&&(u=new ResizeObserver(r),u.observe(s)),r();const b=Math.max(33,Math.min(1e3,Gt(t.stateRefreshMs,100)));return d=window.setInterval(y,b),queueMicrotask(y),window.setTimeout(r,300),window.setTimeout(r,1e3),s}async function xt(e,t,n,i,o){if(o.loading)return!1;const a=[ge(e,t,"renderSplats","renderSplatsDocumentId","renderSplatsSchemaId"),ge(e,t,"gravity","gravityDocumentId","gravitySchemaId"),ge(e,t,"objects","objectsDocumentId","objectsSchemaId")].filter(s=>!!s?.documentId);if(a.length===0)return!1;o.loading=!0;try{let s=!1;for(const l of a){const f=await n.documentResolver?.(l,e);let c=me(ve(f?.schemaId||l.schemaId,f?.document));if(Object.keys(c).length===0&&(c=me(ve(l.schemaId,await wt(l,i||n.provider?.providerId)))),Object.keys(c).length===0)continue;const r=l.slotId==="renderSplats"?"renderSplats":l.slotId==="gravity"?"gravity":"objects",d=we(o[r]?.frameId,-1),u=we(c.frameId,d);o[r]=c,s||=u!==d}return o.lastLoadedAt=Date.now(),s}finally{o.loading=!1}}async function wt(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 me(await i.json()).document}function ge(e,t,n,i,o){const a=(e.embeddedDocuments||[]).find(l=>String(l?.slotId||"")===n),s=T(t[i],a?.documentId);if(s)return{documentId:s,schemaId:T(t[o],a?.schemaId),presentationKind:T(a?.presentationKind)||"data",slotId:n}}function ve(e,t){const n=Array.isArray(t)?t:void 0,i=n?n[0]:t?.schema,o=String(e||i||"");return!n||!Ye.has(o)?t:o==="gamecult.fields.splats.v1"?Mt(n):o==="gamecult.fields.gravity.v1"?Nt(n):Bt(n)}function St(e,t,n,i){const o=e.getBoundingClientRect(),a=Math.max(1,Math.floor(o.width||e.clientWidth||1)),s=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(a*l)),c=Math.max(1,Math.floor(s*l));(e.width!==f||e.height!==c)&&(e.width=f,e.height=c);const r=e.getContext("2d");if(!r)return;r.setTransform(l,0,0,l,0,0),r.clearRect(0,0,a,s);const d=Pt(Lt(t),a,s),u=Ve(n?.gravity),h=Ft(n?.gravity)||Tt(T(t.bodies,"")),y=kt(n?.objects)||Rt(T(t.objects,""));rt(r,t,u,h,d,a,s,n?.renderSplats)||Et(r,t,a,s,"field.surface2d requires WebGL2 float render targets"),At(r,h,t,d,a,s,i),_t(r,y,t,d,a,s,i)}function Et(e,t,n,i,o){e.save(),e.fillStyle=T(t.failureBackground,"rgba(0, 0, 0, 0.72)"),e.fillRect(0,0,n,i),e.font=T(t.failureFont,"700 13px Cascadia Mono, Consolas, monospace"),e.fillStyle=T(t.failureColor,"rgba(255, 184, 79, 0.95)"),e.fillText(o,16,28),e.restore()}function At(e,t,n,i,o,a,s){for(const l of t){const f=He(i,l.x,l.y,o,a),c=Math.max(18,Math.min(190,l.radius/Math.max(1,i.maxX-i.minX)*o*.32)),r=s(l.icon),d=l.kind.toLowerCase().includes("sun")?Math.max(E(n.sunIconMinPx,34),c*E(n.sunIconScale,.72)):Math.max(E(n.bodyIconMinPx,24),c*E(n.bodyIconScale,.48)),u=l.iconSize>0?l.iconSize:d;r&&It(e,r,f.x,f.y,u,.92),l.key&&qe(e,n,l.key.replace(/^local\./,""),f.x+c*.44,f.y-c*.48,T(n.bodyLabelColor,"rgba(226, 244, 255, 0.82)"))}}const fe=new Map;function It(e,t,n,i,o,a){let s=fe.get(t);s||(s=new Image,s.decoding="async",s.onload=()=>requestAnimationFrame(()=>{e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded"))}),s.src=t,fe.set(t,s)),!(!s.complete||s.naturalWidth===0)&&(e.save(),e.globalAlpha=a,e.drawImage(s,n-o/2,i-o/2,o,o),e.restore())}function _t(e,t,n,i,o,a,s){for(const l of t){const f=He(i,l.x,l.y,o,a);if(f.x<-40||f.x>o+40||f.y<-40||f.y>a+40)continue;const c=l.kind.toLowerCase().includes("station")?E(n.stationIconSizePx,34):l.controlled?E(n.shipIconSizePx,22):E(n.remoteShipIconSizePx,18),r=Ct(n,l.faction,l.controlled,l.visibility),d=s(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=fe.get(d);if(h)h.complete&&h.naturalWidth>0&&e.drawImage(h,-c/2,-c/2,c,c);else{const y=new Image;y.decoding="async",y.onload=()=>e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded")),y.src=d,fe.set(d,y)}}e.restore(),qe(e,n,l.label,f.x+c*.55,f.y-c*.45,r)}}function qe(e,t,n,i,o,a){n&&(e.save(),e.font=T(t.objectLabelFont,"700 12px Ubuntu, system-ui, sans-serif"),e.textBaseline="middle",e.lineWidth=E(t.objectLabelStrokeWidth,3),e.strokeStyle=T(t.objectLabelStroke,"rgba(0, 0, 0, 0.72)"),e.fillStyle=a,e.strokeText(n,i,o),e.fillText(n,i,o),e.restore())}function Ct(e,t,n,i){const o=Math.max(.25,Math.min(1,i));if(n)return re(T(e.objectControlledColor,"rgba(122, 240, 255, {alpha})"),o);const a=t.toLowerCase();return a.includes("raider")?re(T(e.objectRaiderColor,"rgba(255, 143, 74, {alpha})"),o):a.includes("neutral")?re(T(e.objectNeutralColor,"rgba(232, 232, 224, {alpha})"),o):re(T(e.objectDefaultColor,"rgba(214, 244, 255, {alpha})"),o)}function re(e,t){return e.replaceAll("{alpha}",String(t))}function Tt(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 Rt(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 Ft(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 a=T(o.bodyKey,o.name,"");a&&i.set(a,o)}return(t.length>0?t:n).map(o=>{const a=T(o.bodyKey,o.name,"body"),s=i.get(a),l=T(o.kind,"Body");return{key:a,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:xe(o.iconAsset)||xe(s?.iconAsset),iconSize:E(s?.iconSize,E(o.iconSize,0)),tint:""}})}function kt(e){const t=Array.isArray(e?.objects)?e.objects:[];if(t.length!==0)return t.map(n=>{const i=T(n.kind,"object");return{key:T(n.entityKey,String(n.entityIndex??""),"object"),kind:i,label:T(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:T(n.factionKey,""),controlled:Xt(n.controlled),visibility:E(n.visibility,1),icon:xe(n.iconAsset)}})}function xe(e){const t=Ve(e);return T(t.uri,"")}function Lt(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 Pt(e,t,n){const i=Math.max(1e-4,e.maxX-e.minX),o=Math.max(1e-4,e.maxY-e.minY),a=Math.max(1e-4,t/Math.max(1,n)),s=i/o,l=(e.minX+e.maxX)*.5,f=(e.minY+e.maxY)*.5;if(a>s){const r=o*a;return{minX:l-r*.5,maxX:l+r*.5,minY:e.minY,maxY:e.maxY}}const c=i/a;return{minX:e.minX,maxX:e.maxX,minY:f-c*.5,maxY:f+c*.5}}function He(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 Mt(e){const t=M(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:_e(e[7]),layers:M(e[8]).map(Dt),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 Nt(e){return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],viewport:_e(e[7]),gravityInfluences:M(e[8]).map($t),bodies:M(e[9]).map(Ut),terrainRadius:e[10],terrainDepth:e[11],terrainDepthExponent:e[12],terrainWaveFrequency:e[13]}}function Bt(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:_e(e[8]),controlledEntityIndices:M(e[9]),objects:M(e[10]).map(Wt)}}function _e(e){const t=M(e);return t.length?{minX:t[0],minY:t[1],maxX:t[2],maxY:t[3]}:e}function Dt(e){const t=M(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 $t(e){const t=M(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 Ut(e){const t=M(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:Ce(t[9])}:e}function Wt(e){const t=M(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:Ot(t[16]),inventory:M(t[17]).map(zt),iconAsset:Ce(t[18])}:e}function Ot(e){const t=M(e);return t.length?{hull:t[0],shield:t[1],heat:t[2]}:e||{}}function zt(e){const t=M(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:Ce(t[9])}:e}function Ce(e){const t=M(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 M(e){return Array.isArray(e)?e:[]}function me(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function T(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function Kt(e,t){return typeof e=="string"&&e?e:t}function Gt(e,t){const n=Number(e);return Number.isFinite(n)&&n>0?Math.floor(n):t}function we(e,t){const n=Number(e);return Number.isFinite(n)?n:t}const Ve=me,E=we;function Xt(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"&&["1","true","yes","on"].includes(e.trim().toLowerCase())}const jt=[bt],Yt={"--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 oe,Je=Te(void 0),te,W={};const De=new WeakMap;function qt(e,t,n={}){if(De.get(t)?.dispose(),te=e,W=n,Je=Te(e.surface?.styles),globalThis.__eveCurrentMesh=e.mesh,mn(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(k(e.surface.root,n)),n.stateBindingResolver){const i=new Vt(e,t,n);De.set(t,i),i.start()}}else t.replaceChildren(Y("No surface root"));return t}function Ht(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 a of i.slice(0,-1)){const s=o[a];(!s||typeof s!="object"||Array.isArray(s))&&(o[a]={}),o=o[a]}o[i[i.length-1]]=n}class Vt{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 Ze(n))for(const o of i.stateBindings||[]){if(this.disposed)return;const a=await t(o,i);if(!a||this.disposed)continue;const s=l=>{this.disposed||(Ht(i,o,l),this.renderCanonicalProjection())};if(s(await a.latest()),this.disposed)return;this.unsubscribers.push(a.watch(s))}}dispose(){this.disposed=!0;for(const t of this.unsubscribers.splice(0))t()}renderCanonicalProjection(){const t=this.surface.surface?.root;t&&this.host.replaceChildren(k(t,this.options))}}function*Ze(e){yield e;for(const t of e.children||[])yield*Ze(t)}function k(e,t=W){const n=e.kind||"panel",i=x(e.props),o=x(e.layout),a=x(e.style),s=e.children||[],l=e.embeddedDocuments||[];if(n==="surface"||n==="cockpit"||n==="dashboard"){const r=m("section","cultui-surface-root eve-surface");w(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),S(r,o,a);for(const d of s)r.append(k(d,t));return r}if(n==="column"||n==="row"||n==="form"||n==="rail"){const r=m("div",`cultui-partition eve-${n}`);w(r,e),r.dataset.direction=n==="row"||n==="rail"?"horizontal":"vertical",n==="rail"&&(r.dataset.overflow="x"),ce(r,{...o,...i}),S(r,o,a);for(const d of s)r.append(k(d,t));return r}if(n==="grid"){const r=m("section","cultui-grid"),d=B(i.columns,0);d>0?r.style.gridTemplateColumns=`repeat(${d}, minmax(0, 1fr))`:typeof i.columns=="string"&&(r.style.gridTemplateColumns=i.columns);const u=B(i.rows,0);u>0&&(r.style.gridTemplateRows=`repeat(${u}, minmax(0, auto))`),S(r,o,a);for(const h of s)r.append(k(h,t));return r}if(n==="partition"){const r=m("section",`cultui-partition split-${g(i.split,"none")}`);w(r,e),ce(r,i),S(r,o,a),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 s)r.append(k(d,t));return r}if(n==="input.binding-map")return ln(e,i,t);if(n==="inventory.drag_session")return rn(e,i,o,a);if(n==="inventory.grid")return on(e,i,o,a,t);if(n==="inventory.item")return an(e,i,o,a);const f=(t.pluginAdapters||jt).find(r=>r.componentKinds.includes(n));if(f?.renderComponent)return f.renderComponent(e,i,o,a,t,{applyGeneratedLayout:S,providerId:te?.providerId||t.provider?.providerId,resolveAssetUrl:ee});if(n==="world.scene3d"||n==="world.scene2d")return Zt(e,i,o,a,t);if(n==="image.background"){const r=m("div","cultui-background"),d=ee(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")}`);w(r,e);const d=ee(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");w(r,e);const d=ee(p(i.src,i.assetUri,i.assetRef,""));if(d){const b=m("img");b.src=d,b.alt=g(i.alt,g(i.text,g(i.label,""))),r.append(b)}else r.append(m("div","cultui-avatar-fallback",In(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");w(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 s)r.append(k(y,t));return r}if(n==="list"||n.endsWith(".roster")){const r=m("section","cultui-list");w(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 En(i.items).entries())r.append(k({id:`${e.id||"list"}-item-${u}`,kind:"list.item",props:{...h}},t));for(const u of s)r.append(k(u,t));return r}if(n==="list.item"||n.endsWith(".item")){const r=Qe(e),d=m("article","cultui-list-item");w(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 s)d.append(k(h,t));return d}if(n==="bar"){const r=m("div","cultui-meter");w(r,e);const d=g(i.label,""),u=g(i.value,"");if(d||u){const b=m("div","cultui-meter-head");b.append(m("span","",d)),b.append(m("strong","",u)),r.append(b)}const h=m("div","cultui-meter-track"),y=m("span","cultui-meter-fill");return y.style.width=`${Ke(i.percent)}%`,h.append(y),r.append(h),r}if(n==="card"){const r=Oe(i,e),d=r?m("button","card cultui-card cultui-card-button"):m("article","card cultui-card");w(d,e),S(d,o,a),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 s)d.append(k(h,t));return r&&ze(d,e,r,i,t),d}if(n==="control.button"){const r=m("button","cultui-button eve-control-button",g(i.label,"Action"));return w(r,e),r.type="button",S(r,o,a),ze(r,e,Oe(i,e),i,t),r}if(n==="control.popup"){const r=m("button","cultui-button eve-control-popup",g(i.label,"Open"));return w(r,e),r.type="button",S(r,o,a),r.addEventListener("click",d=>{dn(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",bn(n,i),g(i.value,g(i.text,e.text||"")));return w(r,e),ce(r,i),S(r,o,a),r}if(n==="metric"){const r=m("dl","metric cultui-reactive-metric eve-metric");return w(r,e),S(r,o,a),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");w(r,e),S(r,o,a);const d=g(i.label,""),u=g(i.value,""),h=Number(i.min??0),y=Number(i.max??1),b=Number(i.value??0),v=Number.isFinite(b)&&Number.isFinite(h)&&Number.isFinite(y)&&y!==h?(b-h)/(y-h)*100:Ke(i.percent);if(d||u){const N=m("div","cultui-meter-head");N.append(m("span","",d)),N.append(m("strong","",u)),r.append(N)}const C=m("div","cultui-meter-track"),A=m("span","cultui-meter-fill");return A.style.width=`${Math.max(0,Math.min(100,v))}%`,C.append(A),r.append(C),r}if(n==="modal"){const r=m("section","cultui-modal-surface");w(r,e),S(r,o,a);const d=g(i.title,"");d&&r.append(m("h2","cultui-modal-surface-title",d));for(const u of s)r.append(k(u,t));return r}if(n==="options"){const r=m("section","cultui-options");w(r,e),S(r,o,a);const d=g(i.label,"");d&&r.append(m("h3","cultui-list-title",d));for(const u of s)r.append(k(u,t));return s.length===0&&r.append(Y("waiting for options")),r}if(n==="image.preview"){const r=m("figure","cultui-image-preview");w(r,e);const d=m("div","cultui-image-frame"),u=ee(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 w(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");w(r,e),S(r,o,a),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=>x(h.surface)).find(h=>x(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",()=>nt(Se(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),Se(e,t).then(y=>{h.replaceChildren(y?.root?k(y.root,t):Y("Embedded surface unavailable"))}).catch(y=>{h.replaceChildren(Y(`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 hn(i,s,t);if(n==="control.toggle"){const r=m("label","toggle-row cultui-toggle");return w(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 w(r,e),ce(r,i),S(r,o,a),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 w(r,e),r.style.background=g(i.value,g(i.color,"currentColor")),r.title=g(i.label,"Color"),r}const c=m("section","pane");w(c,e),c.append(m("h2","",n));for(const r of s)c.append(k(r,t));return c}function Qe(e){const t=x(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 S(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 a=p(t.flexWrap,"");a&&(e.style.flexWrap=a);const s=p(t.gridTemplateColumns,"");s&&(e.style.gridTemplateColumns=s);const l=p(t.gridTemplateRows,"");l&&(e.style.gridTemplateRows=l);const f=p(t.gridTemplateAreas,"");f&&(e.style.gridTemplateAreas=f);const c=p(t.gridArea,"");c&&(e.style.gridArea=c);const r=p(t.placeItems,"");r&&(e.style.placeItems=r),P(e,"gap",p(t.gap,"")),P(e,"padding",p(t.padding,"")),P(e,"margin",p(t.margin,"")),P(e,"top",p(t.top,"")),P(e,"right",p(t.right,"")),P(e,"bottom",p(t.bottom,"")),P(e,"left",p(t.left,"")),P(e,"width",p(t.width,"")),P(e,"minWidth",p(t.minWidth,"")),P(e,"maxWidth",p(t.maxWidth,"")),P(e,"height",p(t.height,"")),P(e,"minHeight",p(t.minHeight,"")),P(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 b=p(t.overflowX,"");b&&(e.style.overflowX=b);const v=p(t.overflowY,"");v&&(e.style.overflowY=v);const C=p(t.position,"");C&&(e.style.position=C);const A=p(t.cursor,"");A&&(e.style.cursor=A);const N=p(n.background,"");N&&(e.style.background=de(N));const q=p(n.color,"");q&&(e.style.color=de(q)),P(e,"borderWidth",p(n.borderWidth,""));const z=p(n.borderColor,"");z&&(e.style.borderColor=de(z));const H=p(n.borderStyle,"");H&&(e.style.borderStyle=H),P(e,"borderRadius",p(n.borderRadius,""));const V=p(n.boxShadow,"");V&&(e.style.boxShadow=V);const K=p(n.font,"");K&&(e.style.font=K),P(e,"fontSize",p(n.fontSize,""));const _=p(n.fontWeight,"");_&&(e.style.fontWeight=_);const J=p(n.textTransform,"");J&&(e.style.textTransform=J);const ie=p(n.textAlign,"");ie&&(e.style.textAlign=ie);const he=p(n.whiteSpace,"");he&&(e.style.whiteSpace=he);const ke=p(n.overflow,"");ke&&(e.style.overflow=ke);const Le=p(n.textOverflow,"");Le&&(e.style.textOverflow=Le),P(e,"lineHeight",p(n.lineHeight,""))}function P(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 Jt(e){const t=(e.children||[]).filter(u=>u.kind==="world.entity3d"),n=t.map(u=>nn(x(u.props).position,[0,0,0])),i=n.map(u=>u[0]),o=n.map(u=>u[2]),a=Math.min(...i,-1),s=Math.max(...i,1),l=Math.min(...o,-1),f=Math.max(...o,1),c=Math.max(1,s-a),r=Math.max(1,f-l),d=6;return t.map((u,h)=>{const y=x(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:Re(y.controllable),xPercent:d+(n[h][0]-a)/c*(100-d*2),yPercent:d+(1-(n[h][2]-l)/r)*(100-d*2),source:u}})}function Zt(e,t,n,i,o){const a=m("section","cultui-world-scene");w(a,e),S(a,n,i),a.tabIndex=0,a.setAttribute("aria-label",g(t.label,"Interactive world"));const s=Jt(e),l=s.find(r=>r.controlled),f=m("div","cultui-world-heading");f.append(m("strong","",g(t.label,"World"))),f.append(m("span","",`${s.length} entities`)),a.append(f);const c=m("div","cultui-world-plane");for(const r of s){const d=m("button",`cultui-world-entity faction-${$e(r.faction)} kind-${$e(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",tn(r.kind))),d.append(m("span","cultui-world-entity-label",r.label));const u=x(r.source.props),h=p(u.targetCommand,t.targetCommand,u.focusCommand,t.focusCommand);h&&d.addEventListener("click",()=>ye(h,{actorEntityId:l?.entityId||p(t.playerEntityId),entityId:r.entityId,targetEntityId:r.entityId,targetEntityKey:r.entityId},r.source,o)),c.append(d)}return a.append(c),a.addEventListener("keydown",r=>{const d=en(r.key);if(d){r.preventDefault();const h=p(t.movementCommand,x(l?.source.props).moveCommand);h&&ye(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,x(l?.source.props).actionCommand):r.key.toLowerCase()==="f"?p(t.focusCommand,x(l?.source.props).focusCommand):"";u&&(r.preventDefault(),ye(u,{actionId:r.key===" "?"0":"focus",actorEntityId:l?.entityId||p(t.playerEntityId),actorEntityKey:l?.entityId||p(t.playerEntityId)},e,o))}),a}function ye(e,t,n,i){i.commandSink?.(Qt(e,t,i),n)}function Qt(e,t,n=W){return ne(e,{action:t},n)}function en(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 tn(e){return e.includes("station")?"S":e.includes("projectile")?".":e.includes("ship")?"^":"+"}function $e(e){return e.toLowerCase().replace(/[^a-z0-9_-]+/g,"-")}function j(e,t){const n=Number(e);return Number.isFinite(n)?n:t}function nn(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 rn(e,t,n,i){const o=Re(t.active),a=m("section","cultui-inventory-drag");w(a,e),S(a,n,i),a.dataset.active=o?"true":"false";const s=m("div","cultui-inventory-section-label","Drag");if(S(s,F(n,"sectionLabel."),F(i,"sectionLabel.")),a.append(s),!o){const d=m("div","cultui-inventory-empty","None");return S(d,F(n,"empty."),F(i,"empty.")),a.append(d),a}const l=p(t.itemKey,t.item,"item"),f=m("div","cultui-inventory-drag-chip",l);S(f,F(n,"dragChip."),F(i,"dragChip.")),a.append(f);const c=[t.originOffsetX,t.originOffsetY].map(d=>Number(d)).map(d=>Number.isFinite(d)?d:0),r=m("div","cultui-inventory-meta",`origin ${c[0]}, ${c[1]}`);return S(r,F(n,"meta."),F(i,"meta.")),a.append(r),a}function on(e,t,n,i,o){const a=m("section","cultui-inventory-grid");w(a,e),S(a,n,i);const s=B(p(t.columns,t.gridColumns,t.widthCells,""),0),l=s>0?s:6,f=B(t.rows,0),c=f>0?f:Math.max(3,Math.ceil(Math.max((e.children||[]).length,1)/l));a.style.setProperty("--inventory-columns",String(l)),a.style.setProperty("--inventory-rows",String(c)),a.dataset.cellSpriteMode=g(t.cellSpriteMode,"");const r=p(t.title,t.label,"Inventory"),d=m("div","cultui-inventory-section-label",r);S(d,F(n,"sectionLabel."),F(i,"sectionLabel.")),a.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(${c}, ${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")),S(u,F(n,"board."),F(i,"board.")),u.addEventListener("dragover",b=>{cn(t)&&(b.preventDefault(),b.dataTransfer&&(b.dataTransfer.dropEffect="move"))}),u.addEventListener("drop",b=>{const v=b.dataTransfer?.getData("application/vnd.gamecult.eve.inventory-item+json")||"";if(!v)return;let C;try{C=JSON.parse(v)}catch{return}const A=u.getBoundingClientRect(),N=Math.max(1,j(t.cellSize,72)),q=Math.max(0,j(t.cellGap,4)),z=N+q,H=Math.max(0,Math.min(l-1,Math.floor((b.clientX-A.left)/z))),V=Math.max(0,Math.min(c-1,Math.floor((b.clientY-A.top)/z))),K=sn(C,t,H,V,o);K&&(b.preventDefault(),o.commandSink?.(K,e))});const h=new Set;for(const b of e.children||[]){const v=x(b.props),C=B(v.x,0),A=B(v.y,0);h.add(`${C}:${A}`),u.append(k(b,o))}const y=Math.min(l*c,256);for(let b=0;b{!a.draggable||!y.dataTransfer||(y.dataTransfer.effectAllowed="move",y.dataTransfer.setData("application/vnd.gamecult.eve.inventory-item+json",JSON.stringify(t)))});let f=B(t.shapeWidth,1),c=B(t.shapeHeight,1);const r=p(t.rotation,"").toLowerCase();["clockwise","counterclockwise","right","left","rotate90","rotate270"].includes(r)&&([f,c]=[c,f]),a.style.gridColumn=`${s+1} / span ${f}`,a.style.gridRow=`${l+1} / span ${c}`;const d=m("span","cultui-inventory-item-icon");S(d,F(n,"icon."),F(i,"icon.")),d.textContent=An(p(t.iconAssetUri,t.iconAssetKey,t.itemKey,t.label,"")),a.append(d);const u=p(t.label,t.itemKey,"");if(u){const y=m("span","cultui-inventory-item-label",u);S(y,F(n,"label."),F(i,"label.")),a.append(y)}const h=Number(t.quantity);if(Number.isFinite(h)&&h>1){const y=m("span","cultui-inventory-item-quantity",String(h));S(y,F(n,"quantity."),F(i,"quantity.")),a.append(y)}return a.title=[u,p(t.source,""),p(t.quality,"")?`quality ${t.quality}`:"",p(t.durability,"")?`durability ${t.durability}`:""].filter(Boolean).join(" | "),a}function cn(e){return Object.entries(e).some(([t,n])=>(t==="dropCommand"||t.startsWith("dropCommand."))&&typeof n=="string"&&n.length>0)}function sn(e,t,n,i,o=W){const a=p(e.sourceKind,e.source,""),s=p(t[`dropCommand.${a}`],t.dropCommand,"");if(!a||!s)return;const l=j(e.sourceIndex,-1),f=j(t.targetIndex,-1),c=p(t.targetKind,""),r={sourceKind:a,originEntityKey:p(e.sourceEntityKey,e.entityKey,""),originIndex:l,originCargoIndex:a==="cargo"?l:-1,itemKey:p(e.itemKey,""),quantity:Math.max(1,j(e.quantity,1)),sourceX:j(e.x,-2147483648),sourceY:j(e.y,-2147483648),destinationKind:c,destinationEntityKey:p(t.targetEntityKey,t.entityKey,""),destinationIndex:f,destinationCargoIndex:c==="cargo"?f:-1,destinationX:Math.trunc(n),destinationY:Math.trunc(i),hasDestinationPosition:!0};return ne(s,{action:r},o)}function ln(e,t,n){const i=m("section","cultui-binding-map");w(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=fn(),i.append(o);const a=m("div","cultui-binding-overlay");for(const s of e.children||[]){const l=x(s.props),f=g(l.target,s.id||""),c=m("button","cultui-binding-box");w(c,s),c.type="button",c.dataset.target=f,c.dataset.kind=g(l.bindingKind,"button"),c.style.left=R(l.x??"50%"),c.style.top=R(l.y??"50%"),c.append(m("span","cultui-binding-target",g(l.label,f))),c.append(m("span","cultui-binding-source",g(l.current,"unmapped"))),c.addEventListener("click",()=>{const d=tt(s);if(et(s)||d?.documentId)nt(Se(s,n),n);else{const u=g(l.commandId,"");u&&n.commandSink?.(ne(u,l,n),s)}}),a.append(c);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(We(l.x,780))),r.setAttribute("y2",String(We(l.y,420))),o.append(r)}return i.append(a),i}function et(e){for(const t of e.embeddedDocuments||[]){const n=x(t.surface);if(n.root)return n}}function tt(e){const t=(e.embeddedDocuments||[])[0],n=x(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 Se(e,t){const n=et(e);if(n)return n;const i=tt(e);if(!i?.documentId||!t.documentResolver)return;const o=await t.documentResolver(i,e);if(o)return x(o.surface).root?o.surface:o}function nt(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 a=m("button","cultui-modal-close","Close");a.type="button",a.addEventListener("click",()=>n.remove()),o.append(a);const s=m("div","cultui-modal-body");i.append(o,s),n.append(i),n.addEventListener("click",l=>{l.target===n&&n.remove()}),document.body.append(n),s.append(m("div","detail","materializing document")),Promise.resolve(e).then(l=>{o.querySelector("h2").textContent=l?.title||"Configure Binding",s.replaceChildren(l?.root?k(l.root,t):Y("Embedded document unavailable"))}).catch(l=>{s.replaceChildren(Y(`Embedded document failed: ${l instanceof Error?l.message:String(l)}`))})}function dn(e,t,n,i,o){const a=x(e.props),s=(e.children||[])[0],l=x(s?.props),f=p(l.anchor,a.anchor,"trigger"),c=p(l.placement,a.placement,"below-start"),r=Number(p(l.offsetX,a.offsetX,"0"))||0,d=Number(p(l.offsetY,a.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,a.title,a.label,"Options")));const b=m("button","cultui-modal-close","Close");b.type="button",b.addEventListener("click",()=>u.remove()),y.append(b);const v=m("div","cultui-modal-body");if(s){const A=s.children||[];A.length>0?v.replaceChildren(...A.map(N=>k(N,t))):v.append(k(s,t))}else v.append(Y("Popup has no content"));h.append(y,v),u.append(h),u.addEventListener("click",A=>{A.target===u&&u.remove()}),document.body.append(u);const C=un(f,c,n,h,i,o,r,d);h.style.left=`${C.left}px`,h.style.top=`${C.top}px`}function un(e,t,n,i,o,a,s,l){const f=n.getBoundingClientRect(),c=i.getBoundingClientRect(),r=c.width||420,d=c.height||320,u=e==="cursor"?{left:o,right:o,top:a,bottom:a}:f;if(t==="right-down"||t==="dropdown")return ae(u,r,d,s,l,"right","down");if(t==="left-down")return ae(u,r,d,s,l,"left","down");if(t==="right-up")return ae(u,r,d,s,l,"right","up");if(t==="left-up")return ae(u,r,d,s,l,"left","up");switch(t){case"above-start":return U(u.left+s,u.top-d-l,r,d);case"above-end":return U(u.right-r+s,u.top-d-l,r,d);case"below-end":return U(u.right-r+s,u.bottom+l,r,d);case"right-start":return U(u.right+s,u.top+l,r,d);case"left-start":return U(u.left-r-s,u.top+l,r,d);case"center":return U((window.innerWidth-r)/2+s,(window.innerHeight-d)/2+l,r,d);default:return U(u.left+s,u.bottom+l,r,d)}}function ae(e,t,n,i,o,a,s){const f=window.innerWidth-e.right-i-12,c=e.left-i-12,r=window.innerHeight-e.top-o-12,d=e.bottom-o-12,u=a==="right"?f>=t||f>=c:!(c>=t||c>=f),h=s==="down"?r>=n||r>=d:!(d>=n||d>=r),y=u?e.right+i:e.left-t-i,b=h?e.top+o:e.bottom-n-o;return U(y,b,t,n)}function U(e,t,n,i){return{left:Ue(e,12,window.innerWidth-n-12),top:Ue(t,12,window.innerHeight-i-12)}}function Ue(e,t,n){return nSt(s,t,f,a.resolveAssetUrl),r=()=>{!s.isConnected||l||(l=!0,requestAnimationFrame(()=>{l=!1,s.isConnected&&c()}))};s.addEventListener("cultui:asset-loaded",r);let d=0,u;const h=()=>{d&&window.clearInterval(d),u?.disconnect(),s.removeEventListener("cultui:asset-loaded",r)},y=()=>{if(!s.isConnected){h();return}xt(e,t,o,a.providerId,f).then(v=>{v&&s.isConnected&&r()}).catch(v=>{f.lastError=v instanceof Error?v.message:String(v)})};typeof ResizeObserver<"u"&&(u=new ResizeObserver(r),u.observe(s)),r();const b=Math.max(33,Math.min(1e3,Gt(t.stateRefreshMs,100)));return d=window.setInterval(y,b),queueMicrotask(y),window.setTimeout(r,300),window.setTimeout(r,1e3),s}async function xt(e,t,n,i,o){if(o.loading)return!1;const a=[ge(e,t,"renderSplats","renderSplatsDocumentId","renderSplatsSchemaId"),ge(e,t,"gravity","gravityDocumentId","gravitySchemaId"),ge(e,t,"objects","objectsDocumentId","objectsSchemaId")].filter(s=>!!s?.documentId);if(a.length===0)return!1;o.loading=!0;try{let s=!1;for(const l of a){const f=await n.documentResolver?.(l,e);let c=me(ve(f?.schemaId||l.schemaId,f?.document));if(Object.keys(c).length===0&&(c=me(ve(l.schemaId,await wt(l,i||n.provider?.providerId)))),Object.keys(c).length===0)continue;const r=l.slotId==="renderSplats"?"renderSplats":l.slotId==="gravity"?"gravity":"objects",d=we(o[r]?.frameId,-1),u=we(c.frameId,d);o[r]=c,s||=u!==d}return o.lastLoadedAt=Date.now(),s}finally{o.loading=!1}}async function wt(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 me(await i.json()).document}function ge(e,t,n,i,o){const a=(e.embeddedDocuments||[]).find(l=>String(l?.slotId||"")===n),s=T(t[i],a?.documentId);if(s)return{documentId:s,schemaId:T(t[o],a?.schemaId),presentationKind:T(a?.presentationKind)||"data",slotId:n}}function ve(e,t){const n=Array.isArray(t)?t:void 0,i=n?n[0]:t?.schema,o=String(e||i||"");return!n||!qe.has(o)?t:o==="gamecult.fields.splats.v1"?Mt(n):o==="gamecult.fields.gravity.v1"?Nt(n):Bt(n)}function St(e,t,n,i){const o=e.getBoundingClientRect(),a=Math.max(1,Math.floor(o.width||e.clientWidth||1)),s=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(a*l)),c=Math.max(1,Math.floor(s*l));(e.width!==f||e.height!==c)&&(e.width=f,e.height=c);const r=e.getContext("2d");if(!r)return;r.setTransform(l,0,0,l,0,0),r.clearRect(0,0,a,s);const d=Pt(Lt(t),a,s),u=Ve(n?.gravity),h=kt(n?.gravity)||Tt(T(t.bodies,"")),y=Ft(n?.objects)||Rt(T(t.objects,""));rt(r,t,u,h,d,a,s,n?.renderSplats)||Et(r,t,a,s,"field.surface2d requires WebGL2 float render targets"),At(r,h,t,d,a,s,i),_t(r,y,t,d,a,s,i)}function Et(e,t,n,i,o){e.save(),e.fillStyle=T(t.failureBackground,"rgba(0, 0, 0, 0.72)"),e.fillRect(0,0,n,i),e.font=T(t.failureFont,"700 13px Cascadia Mono, Consolas, monospace"),e.fillStyle=T(t.failureColor,"rgba(255, 184, 79, 0.95)"),e.fillText(o,16,28),e.restore()}function At(e,t,n,i,o,a,s){for(const l of t){const f=He(i,l.x,l.y,o,a),c=Math.max(18,Math.min(190,l.radius/Math.max(1,i.maxX-i.minX)*o*.32)),r=s(l.icon),d=l.kind.toLowerCase().includes("sun")?Math.max(E(n.sunIconMinPx,34),c*E(n.sunIconScale,.72)):Math.max(E(n.bodyIconMinPx,24),c*E(n.bodyIconScale,.48)),u=l.iconSize>0?l.iconSize:d;r&&It(e,r,f.x,f.y,u,.92),l.key&&Ye(e,n,l.key.replace(/^local\./,""),f.x+c*.44,f.y-c*.48,T(n.bodyLabelColor,"rgba(226, 244, 255, 0.82)"))}}const fe=new Map;function It(e,t,n,i,o,a){let s=fe.get(t);s||(s=new Image,s.decoding="async",s.onload=()=>requestAnimationFrame(()=>{e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded"))}),s.src=t,fe.set(t,s)),!(!s.complete||s.naturalWidth===0)&&(e.save(),e.globalAlpha=a,e.drawImage(s,n-o/2,i-o/2,o,o),e.restore())}function _t(e,t,n,i,o,a,s){for(const l of t){const f=He(i,l.x,l.y,o,a);if(f.x<-40||f.x>o+40||f.y<-40||f.y>a+40)continue;const c=l.kind.toLowerCase().includes("station")?E(n.stationIconSizePx,34):l.controlled?E(n.shipIconSizePx,22):E(n.remoteShipIconSizePx,18),r=Ct(n,l.faction,l.controlled,l.visibility),d=s(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=fe.get(d);if(h)h.complete&&h.naturalWidth>0&&e.drawImage(h,-c/2,-c/2,c,c);else{const y=new Image;y.decoding="async",y.onload=()=>e.canvas.dispatchEvent(new CustomEvent("cultui:asset-loaded")),y.src=d,fe.set(d,y)}}e.restore(),Ye(e,n,l.label,f.x+c*.55,f.y-c*.45,r)}}function Ye(e,t,n,i,o,a){n&&(e.save(),e.font=T(t.objectLabelFont,"700 12px Ubuntu, system-ui, sans-serif"),e.textBaseline="middle",e.lineWidth=E(t.objectLabelStrokeWidth,3),e.strokeStyle=T(t.objectLabelStroke,"rgba(0, 0, 0, 0.72)"),e.fillStyle=a,e.strokeText(n,i,o),e.fillText(n,i,o),e.restore())}function Ct(e,t,n,i){const o=Math.max(.25,Math.min(1,i));if(n)return re(T(e.objectControlledColor,"rgba(122, 240, 255, {alpha})"),o);const a=t.toLowerCase();return a.includes("raider")?re(T(e.objectRaiderColor,"rgba(255, 143, 74, {alpha})"),o):a.includes("neutral")?re(T(e.objectNeutralColor,"rgba(232, 232, 224, {alpha})"),o):re(T(e.objectDefaultColor,"rgba(214, 244, 255, {alpha})"),o)}function re(e,t){return e.replaceAll("{alpha}",String(t))}function Tt(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 Rt(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 kt(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 a=T(o.bodyKey,o.name,"");a&&i.set(a,o)}return(t.length>0?t:n).map(o=>{const a=T(o.bodyKey,o.name,"body"),s=i.get(a),l=T(o.kind,"Body");return{key:a,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:xe(o.iconAsset)||xe(s?.iconAsset),iconSize:E(s?.iconSize,E(o.iconSize,0)),tint:""}})}function Ft(e){const t=Array.isArray(e?.objects)?e.objects:[];if(t.length!==0)return t.map(n=>{const i=T(n.kind,"object");return{key:T(n.entityKey,String(n.entityIndex??""),"object"),kind:i,label:T(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:T(n.factionKey,""),controlled:jt(n.controlled),visibility:E(n.visibility,1),icon:xe(n.iconAsset)}})}function xe(e){const t=Ve(e);return T(t.uri,"")}function Lt(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 Pt(e,t,n){const i=Math.max(1e-4,e.maxX-e.minX),o=Math.max(1e-4,e.maxY-e.minY),a=Math.max(1e-4,t/Math.max(1,n)),s=i/o,l=(e.minX+e.maxX)*.5,f=(e.minY+e.maxY)*.5;if(a>s){const r=o*a;return{minX:l-r*.5,maxX:l+r*.5,minY:e.minY,maxY:e.maxY}}const c=i/a;return{minX:e.minX,maxX:e.maxX,minY:f-c*.5,maxY:f+c*.5}}function He(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 Mt(e){const t=M(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:_e(e[7]),layers:M(e[8]).map(Dt),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 Nt(e){return{schema:e[0],frameId:e[1],publishedAtUtc:e[2],simulationTimeSeconds:e[3],runId:e[4],zoneIndex:e[5],zoneName:e[6],viewport:_e(e[7]),gravityInfluences:M(e[8]).map($t),bodies:M(e[9]).map(Ut),terrainRadius:e[10],terrainDepth:e[11],terrainDepthExponent:e[12],terrainWaveFrequency:e[13]}}function Bt(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:_e(e[8]),controlledEntityIndices:M(e[9]),objects:M(e[10]).map(Ot)}}function _e(e){const t=M(e);return t.length?{minX:t[0],minY:t[1],maxX:t[2],maxY:t[3]}:e}function Dt(e){const t=M(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 $t(e){const t=M(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 Ut(e){const t=M(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:Ce(t[9])}:e}function Ot(e){const t=M(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:Wt(t[16]),inventory:M(t[17]).map(zt),iconAsset:Ce(t[18])}:e}function Wt(e){const t=M(e);return t.length?{hull:t[0],shield:t[1],heat:t[2]}:e||{}}function zt(e){const t=M(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:Ce(t[9])}:e}function Ce(e){const t=M(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 M(e){return Array.isArray(e)?e:[]}function me(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function T(...e){for(const t of e)if(typeof t=="string"&&t.trim())return t.trim();return""}function Kt(e,t){return typeof e=="string"&&e?e:t}function Gt(e,t){const n=Number(e);return Number.isFinite(n)&&n>0?Math.floor(n):t}function we(e,t){const n=Number(e);return Number.isFinite(n)?n:t}const Ve=me,E=we;function jt(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"&&["1","true","yes","on"].includes(e.trim().toLowerCase())}const Xt=[bt],qt={"--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 oe,Je=Te(void 0),te,O={};const De=new WeakMap;function Yt(e,t,n={}){if(De.get(t)?.dispose(),te=e,O=n,Je=Te(e.surface?.styles),globalThis.__eveCurrentMesh=e.mesh,mn(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(F(e.surface.root,n)),n.stateBindingResolver){const i=new Vt(e,t,n);De.set(t,i),i.start()}}else t.replaceChildren(q("No surface root"));return t}function Ht(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 a of i.slice(0,-1)){const s=o[a];(!s||typeof s!="object"||Array.isArray(s))&&(o[a]={}),o=o[a]}o[i[i.length-1]]=n}class Vt{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 Ze(n))for(const o of i.stateBindings||[]){if(this.disposed)return;const a=await t(o,i);if(!a||this.disposed)continue;const s=l=>{this.disposed||(Ht(i,o,l),this.renderCanonicalProjection())};if(s(await a.latest()),this.disposed)return;this.unsubscribers.push(a.watch(s))}}dispose(){this.disposed=!0;for(const t of this.unsubscribers.splice(0))t()}renderCanonicalProjection(){const t=this.surface.surface?.root;t&&this.host.replaceChildren(F(t,this.options))}}function*Ze(e){yield e;for(const t of e.children||[])yield*Ze(t)}function F(e,t=O){const n=e.kind||"panel",i=x(e.props),o=x(e.layout),a=x(e.style),s=e.children||[],l=e.embeddedDocuments||[];if(n==="surface"||n==="cockpit"||n==="dashboard"){const r=m("section","cultui-surface-root eve-surface");w(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),S(r,o,a);for(const d of s)r.append(F(d,t));return r}if(n==="column"||n==="row"||n==="form"||n==="rail"){const r=m("div",`cultui-partition eve-${n}`);w(r,e),r.dataset.direction=n==="row"||n==="rail"?"horizontal":"vertical",n==="rail"&&(r.dataset.overflow="x"),ce(r,{...o,...i}),S(r,o,a);for(const d of s)r.append(F(d,t));return r}if(n==="grid"){const r=m("section","cultui-grid"),d=B(i.columns,0);d>0?r.style.gridTemplateColumns=`repeat(${d}, minmax(0, 1fr))`:typeof i.columns=="string"&&(r.style.gridTemplateColumns=i.columns);const u=B(i.rows,0);u>0&&(r.style.gridTemplateRows=`repeat(${u}, minmax(0, auto))`),S(r,o,a);for(const h of s)r.append(F(h,t));return r}if(n==="partition"){const r=m("section",`cultui-partition split-${g(i.split,"none")}`);w(r,e),ce(r,i),S(r,o,a),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 s)r.append(F(d,t));return r}if(n==="input.binding-map")return ln(e,i,t);if(n==="inventory.drag_session")return rn(e,i,o,a);if(n==="inventory.grid")return on(e,i,o,a,t);if(n==="inventory.item")return an(e,i,o,a);const f=(t.pluginAdapters||Xt).find(r=>r.componentKinds.includes(n));if(f?.renderComponent)return f.renderComponent(e,i,o,a,t,{applyGeneratedLayout:S,providerId:te?.providerId||t.provider?.providerId,resolveAssetUrl:ee});if(n==="world.scene3d"||n==="world.scene2d")return Zt(e,i,o,a,t);if(n==="image.background"){const r=m("div","cultui-background"),d=ee(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")}`);w(r,e);const d=ee(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");w(r,e);const d=ee(p(i.src,i.assetUri,i.assetRef,""));if(d){const b=m("img");b.src=d,b.alt=g(i.alt,g(i.text,g(i.label,""))),r.append(b)}else r.append(m("div","cultui-avatar-fallback",In(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");w(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 s)r.append(F(y,t));return r}if(n==="list"||n.endsWith(".roster")){const r=m("section","cultui-list");w(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 En(i.items).entries())r.append(F({id:`${e.id||"list"}-item-${u}`,kind:"list.item",props:{...h}},t));for(const u of s)r.append(F(u,t));return r}if(n==="list.item"||n.endsWith(".item")){const r=Qe(e),d=m("article","cultui-list-item");w(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 s)d.append(F(h,t));return d}if(n==="bar"){const r=m("div","cultui-meter");w(r,e);const d=g(i.label,""),u=g(i.value,"");if(d||u){const b=m("div","cultui-meter-head");b.append(m("span","",d)),b.append(m("strong","",u)),r.append(b)}const h=m("div","cultui-meter-track"),y=m("span","cultui-meter-fill");return y.style.width=`${Ke(i.percent)}%`,h.append(y),r.append(h),r}if(n==="card"){const r=We(i,e),d=r?m("button","card cultui-card cultui-card-button"):m("article","card cultui-card");w(d,e),S(d,o,a),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 s)d.append(F(h,t));return r&&ze(d,e,r,i,t),d}if(n==="control.button"){const r=m("button","cultui-button eve-control-button",g(i.label,"Action"));return w(r,e),r.type="button",S(r,o,a),ze(r,e,We(i,e),i,t),r}if(n==="control.popup"){const r=m("button","cultui-button eve-control-popup",g(i.label,"Open"));return w(r,e),r.type="button",S(r,o,a),r.addEventListener("click",d=>{dn(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",bn(n,i),g(i.value,g(i.text,e.text||"")));return w(r,e),ce(r,i),S(r,o,a),r}if(n==="metric"){const r=m("dl","metric cultui-reactive-metric eve-metric");return w(r,e),S(r,o,a),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");w(r,e),S(r,o,a);const d=g(i.label,""),u=g(i.value,""),h=Number(i.min??0),y=Number(i.max??1),b=Number(i.value??0),v=Number.isFinite(b)&&Number.isFinite(h)&&Number.isFinite(y)&&y!==h?(b-h)/(y-h)*100:Ke(i.percent);if(d||u){const N=m("div","cultui-meter-head");N.append(m("span","",d)),N.append(m("strong","",u)),r.append(N)}const C=m("div","cultui-meter-track"),A=m("span","cultui-meter-fill");return A.style.width=`${Math.max(0,Math.min(100,v))}%`,C.append(A),r.append(C),r}if(n==="modal"){const r=m("section","cultui-modal-surface");w(r,e),S(r,o,a);const d=g(i.title,"");d&&r.append(m("h2","cultui-modal-surface-title",d));for(const u of s)r.append(F(u,t));return r}if(n==="options"){const r=m("section","cultui-options");w(r,e),S(r,o,a);const d=g(i.label,"");d&&r.append(m("h3","cultui-list-title",d));for(const u of s)r.append(F(u,t));return s.length===0&&r.append(q("waiting for options")),r}if(n==="image.preview"){const r=m("figure","cultui-image-preview");w(r,e);const d=m("div","cultui-image-frame"),u=ee(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 w(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");w(r,e),S(r,o,a),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=>x(h.surface)).find(h=>x(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",()=>nt(Se(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),Se(e,t).then(y=>{h.replaceChildren(y?.root?F(y.root,t):q("Embedded surface unavailable"))}).catch(y=>{h.replaceChildren(q(`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 hn(i,s,t);if(n==="control.toggle"){const r=m("label","toggle-row cultui-toggle");return w(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 w(r,e),ce(r,i),S(r,o,a),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 w(r,e),r.style.background=g(i.value,g(i.color,"currentColor")),r.title=g(i.label,"Color"),r}const c=m("section","pane");w(c,e),c.append(m("h2","",n));for(const r of s)c.append(F(r,t));return c}function Qe(e){const t=x(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 S(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 a=p(t.flexWrap,"");a&&(e.style.flexWrap=a);const s=p(t.gridTemplateColumns,"");s&&(e.style.gridTemplateColumns=s);const l=p(t.gridTemplateRows,"");l&&(e.style.gridTemplateRows=l);const f=p(t.gridTemplateAreas,"");f&&(e.style.gridTemplateAreas=f);const c=p(t.gridArea,"");c&&(e.style.gridArea=c);const r=p(t.placeItems,"");r&&(e.style.placeItems=r),P(e,"gap",p(t.gap,"")),P(e,"padding",p(t.padding,"")),P(e,"margin",p(t.margin,"")),P(e,"top",p(t.top,"")),P(e,"right",p(t.right,"")),P(e,"bottom",p(t.bottom,"")),P(e,"left",p(t.left,"")),P(e,"width",p(t.width,"")),P(e,"minWidth",p(t.minWidth,"")),P(e,"maxWidth",p(t.maxWidth,"")),P(e,"height",p(t.height,"")),P(e,"minHeight",p(t.minHeight,"")),P(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 b=p(t.overflowX,"");b&&(e.style.overflowX=b);const v=p(t.overflowY,"");v&&(e.style.overflowY=v);const C=p(t.position,"");C&&(e.style.position=C);const A=p(t.cursor,"");A&&(e.style.cursor=A);const N=p(n.background,"");N&&(e.style.background=de(N));const Y=p(n.color,"");Y&&(e.style.color=de(Y)),P(e,"borderWidth",p(n.borderWidth,""));const z=p(n.borderColor,"");z&&(e.style.borderColor=de(z));const H=p(n.borderStyle,"");H&&(e.style.borderStyle=H),P(e,"borderRadius",p(n.borderRadius,""));const V=p(n.boxShadow,"");V&&(e.style.boxShadow=V);const K=p(n.font,"");K&&(e.style.font=K),P(e,"fontSize",p(n.fontSize,""));const _=p(n.fontWeight,"");_&&(e.style.fontWeight=_);const J=p(n.textTransform,"");J&&(e.style.textTransform=J);const ie=p(n.textAlign,"");ie&&(e.style.textAlign=ie);const he=p(n.whiteSpace,"");he&&(e.style.whiteSpace=he);const Fe=p(n.overflow,"");Fe&&(e.style.overflow=Fe);const Le=p(n.textOverflow,"");Le&&(e.style.textOverflow=Le),P(e,"lineHeight",p(n.lineHeight,""))}function P(e,t,n){n&&(e.style[t]=R(n))}function k(e,t){const n={};for(const[i,o]of Object.entries(e))i.startsWith(t)&&(n[i.slice(t.length)]=o);return n}function Jt(e){const t=(e.children||[]).filter(u=>u.kind==="world.entity3d"),n=t.map(u=>nn(x(u.props).position,[0,0,0])),i=n.map(u=>u[0]),o=n.map(u=>u[2]),a=Math.min(...i,-1),s=Math.max(...i,1),l=Math.min(...o,-1),f=Math.max(...o,1),c=Math.max(1,s-a),r=Math.max(1,f-l),d=6;return t.map((u,h)=>{const y=x(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:Re(y.controllable),xPercent:d+(n[h][0]-a)/c*(100-d*2),yPercent:d+(1-(n[h][2]-l)/r)*(100-d*2),source:u}})}function Zt(e,t,n,i,o){const a=m("section","cultui-world-scene");w(a,e),S(a,n,i),a.tabIndex=0,a.setAttribute("aria-label",g(t.label,"Interactive world"));const s=Jt(e),l=s.find(r=>r.controlled),f=m("div","cultui-world-heading");f.append(m("strong","",g(t.label,"World"))),f.append(m("span","",`${s.length} entities`)),a.append(f);const c=m("div","cultui-world-plane");for(const r of s){const d=m("button",`cultui-world-entity faction-${$e(r.faction)} kind-${$e(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",tn(r.kind))),d.append(m("span","cultui-world-entity-label",r.label));const u=x(r.source.props),h=p(u.targetCommand,t.targetCommand,u.focusCommand,t.focusCommand);h&&d.addEventListener("click",()=>ye(h,{actorEntityId:l?.entityId||p(t.playerEntityId),entityId:r.entityId,targetEntityId:r.entityId,targetEntityKey:r.entityId},r.source,o)),c.append(d)}return a.append(c),a.addEventListener("keydown",r=>{const d=en(r.key);if(d){r.preventDefault();const h=p(t.movementCommand,x(l?.source.props).moveCommand);h&&ye(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,x(l?.source.props).actionCommand):r.key.toLowerCase()==="f"?p(t.focusCommand,x(l?.source.props).focusCommand):"";u&&(r.preventDefault(),ye(u,{actionId:r.key===" "?"0":"focus",actorEntityId:l?.entityId||p(t.playerEntityId),actorEntityKey:l?.entityId||p(t.playerEntityId)},e,o))}),a}function ye(e,t,n,i){i.commandSink?.(Qt(e,t,i),n)}function Qt(e,t,n=O){return ne(e,{action:t},n)}function en(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 tn(e){return e.includes("station")?"S":e.includes("projectile")?".":e.includes("ship")?"^":"+"}function $e(e){return e.toLowerCase().replace(/[^a-z0-9_-]+/g,"-")}function X(e,t){const n=Number(e);return Number.isFinite(n)?n:t}function nn(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 rn(e,t,n,i){const o=Re(t.active),a=m("section","cultui-inventory-drag");w(a,e),S(a,n,i),a.dataset.active=o?"true":"false";const s=m("div","cultui-inventory-section-label","Drag");if(S(s,k(n,"sectionLabel."),k(i,"sectionLabel.")),a.append(s),!o){const d=m("div","cultui-inventory-empty","None");return S(d,k(n,"empty."),k(i,"empty.")),a.append(d),a}const l=p(t.itemKey,t.item,"item"),f=m("div","cultui-inventory-drag-chip",l);S(f,k(n,"dragChip."),k(i,"dragChip.")),a.append(f);const c=[t.originOffsetX,t.originOffsetY].map(d=>Number(d)).map(d=>Number.isFinite(d)?d:0),r=m("div","cultui-inventory-meta",`origin ${c[0]}, ${c[1]}`);return S(r,k(n,"meta."),k(i,"meta.")),a.append(r),a}function on(e,t,n,i,o){const a=m("section","cultui-inventory-grid");w(a,e),S(a,n,i);const s=B(p(t.columns,t.gridColumns,t.widthCells,""),0),l=s>0?s:6,f=B(t.rows,0),c=f>0?f:Math.max(3,Math.ceil(Math.max((e.children||[]).length,1)/l));a.style.setProperty("--inventory-columns",String(l)),a.style.setProperty("--inventory-rows",String(c)),a.dataset.cellSpriteMode=g(t.cellSpriteMode,"");const r=p(t.title,t.label,"Inventory"),d=m("div","cultui-inventory-section-label",r);S(d,k(n,"sectionLabel."),k(i,"sectionLabel.")),a.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(${c}, ${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")),S(u,k(n,"board."),k(i,"board.")),u.addEventListener("dragover",b=>{cn(t)&&(b.preventDefault(),b.dataTransfer&&(b.dataTransfer.dropEffect="move"))}),u.addEventListener("drop",b=>{const v=b.dataTransfer?.getData("application/vnd.gamecult.eve.inventory-item+json")||"";if(!v)return;let C;try{C=JSON.parse(v)}catch{return}const A=u.getBoundingClientRect(),N=Math.max(1,X(t.cellSize,72)),Y=Math.max(0,X(t.cellGap,4)),z=N+Y,H=Math.max(0,Math.min(l-1,Math.floor((b.clientX-A.left)/z))),V=Math.max(0,Math.min(c-1,Math.floor((b.clientY-A.top)/z))),K=sn(C,t,H,V,o);K&&(b.preventDefault(),o.commandSink?.(K,e))});const h=new Set;for(const b of e.children||[]){const v=x(b.props),C=B(v.x,0),A=B(v.y,0);h.add(`${C}:${A}`),u.append(F(b,o))}const y=Math.min(l*c,256);for(let b=0;b{!a.draggable||!y.dataTransfer||(y.dataTransfer.effectAllowed="move",y.dataTransfer.setData("application/vnd.gamecult.eve.inventory-item+json",JSON.stringify(t)))});let f=B(t.shapeWidth,1),c=B(t.shapeHeight,1);const r=p(t.rotation,"").toLowerCase();["clockwise","counterclockwise","right","left","rotate90","rotate270"].includes(r)&&([f,c]=[c,f]),a.style.gridColumn=`${s+1} / span ${f}`,a.style.gridRow=`${l+1} / span ${c}`;const d=m("span","cultui-inventory-item-icon");S(d,k(n,"icon."),k(i,"icon.")),d.textContent=An(p(t.iconAssetUri,t.iconAssetKey,t.itemKey,t.label,"")),a.append(d);const u=p(t.label,t.itemKey,"");if(u){const y=m("span","cultui-inventory-item-label",u);S(y,k(n,"label."),k(i,"label.")),a.append(y)}const h=Number(t.quantity);if(Number.isFinite(h)&&h>1){const y=m("span","cultui-inventory-item-quantity",String(h));S(y,k(n,"quantity."),k(i,"quantity.")),a.append(y)}return a.title=[u,p(t.source,""),p(t.quality,"")?`quality ${t.quality}`:"",p(t.durability,"")?`durability ${t.durability}`:""].filter(Boolean).join(" | "),a}function cn(e){return Object.entries(e).some(([t,n])=>(t==="dropCommand"||t.startsWith("dropCommand."))&&typeof n=="string"&&n.length>0)}function sn(e,t,n,i,o=O){const a=p(e.sourceKind,e.source,""),s=p(t[`dropCommand.${a}`],t.dropCommand,"");if(!a||!s)return;const l=X(e.sourceIndex,-1),f=X(t.targetIndex,-1),c=p(t.targetKind,""),r={sourceKind:a,originEntityKey:p(e.sourceEntityKey,e.entityKey,""),originIndex:l,originCargoIndex:a==="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:c,destinationEntityKey:p(t.targetEntityKey,t.entityKey,""),destinationIndex:f,destinationCargoIndex:c==="cargo"?f:-1,destinationX:Math.trunc(n),destinationY:Math.trunc(i),hasDestinationPosition:!0};return ne(s,{action:r},o)}function ln(e,t,n){const i=m("section","cultui-binding-map");w(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=fn(),i.append(o);const a=m("div","cultui-binding-overlay");for(const s of e.children||[]){const l=x(s.props),f=g(l.target,s.id||""),c=m("button","cultui-binding-box");w(c,s),c.type="button",c.dataset.target=f,c.dataset.kind=g(l.bindingKind,"button"),c.style.left=R(l.x??"50%"),c.style.top=R(l.y??"50%"),c.append(m("span","cultui-binding-target",g(l.label,f))),c.append(m("span","cultui-binding-source",g(l.current,"unmapped"))),c.addEventListener("click",()=>{const d=tt(s);if(et(s)||d?.documentId)nt(Se(s,n),n);else{const u=g(l.commandId,"");u&&n.commandSink?.(ne(u,l,n),s)}}),a.append(c);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(Oe(l.x,780))),r.setAttribute("y2",String(Oe(l.y,420))),o.append(r)}return i.append(a),i}function et(e){for(const t of e.embeddedDocuments||[]){const n=x(t.surface);if(n.root)return n}}function tt(e){const t=(e.embeddedDocuments||[])[0],n=x(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 Se(e,t){const n=et(e);if(n)return n;const i=tt(e);if(!i?.documentId||!t.documentResolver)return;const o=await t.documentResolver(i,e);if(o)return x(o.surface).root?o.surface:o}function nt(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 a=m("button","cultui-modal-close","Close");a.type="button",a.addEventListener("click",()=>n.remove()),o.append(a);const s=m("div","cultui-modal-body");i.append(o,s),n.append(i),n.addEventListener("click",l=>{l.target===n&&n.remove()}),document.body.append(n),s.append(m("div","detail","materializing document")),Promise.resolve(e).then(l=>{o.querySelector("h2").textContent=l?.title||"Configure Binding",s.replaceChildren(l?.root?F(l.root,t):q("Embedded document unavailable"))}).catch(l=>{s.replaceChildren(q(`Embedded document failed: ${l instanceof Error?l.message:String(l)}`))})}function dn(e,t,n,i,o){const a=x(e.props),s=(e.children||[])[0],l=x(s?.props),f=p(l.anchor,a.anchor,"trigger"),c=p(l.placement,a.placement,"below-start"),r=Number(p(l.offsetX,a.offsetX,"0"))||0,d=Number(p(l.offsetY,a.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,a.title,a.label,"Options")));const b=m("button","cultui-modal-close","Close");b.type="button",b.addEventListener("click",()=>u.remove()),y.append(b);const v=m("div","cultui-modal-body");if(s){const A=s.children||[];A.length>0?v.replaceChildren(...A.map(N=>F(N,t))):v.append(F(s,t))}else v.append(q("Popup has no content"));h.append(y,v),u.append(h),u.addEventListener("click",A=>{A.target===u&&u.remove()}),document.body.append(u);const C=un(f,c,n,h,i,o,r,d);h.style.left=`${C.left}px`,h.style.top=`${C.top}px`}function un(e,t,n,i,o,a,s,l){const f=n.getBoundingClientRect(),c=i.getBoundingClientRect(),r=c.width||420,d=c.height||320,u=e==="cursor"?{left:o,right:o,top:a,bottom:a}:f;if(t==="right-down"||t==="dropdown")return ae(u,r,d,s,l,"right","down");if(t==="left-down")return ae(u,r,d,s,l,"left","down");if(t==="right-up")return ae(u,r,d,s,l,"right","up");if(t==="left-up")return ae(u,r,d,s,l,"left","up");switch(t){case"above-start":return U(u.left+s,u.top-d-l,r,d);case"above-end":return U(u.right-r+s,u.top-d-l,r,d);case"below-end":return U(u.right-r+s,u.bottom+l,r,d);case"right-start":return U(u.right+s,u.top+l,r,d);case"left-start":return U(u.left-r-s,u.top+l,r,d);case"center":return U((window.innerWidth-r)/2+s,(window.innerHeight-d)/2+l,r,d);default:return U(u.left+s,u.bottom+l,r,d)}}function ae(e,t,n,i,o,a,s){const f=window.innerWidth-e.right-i-12,c=e.left-i-12,r=window.innerHeight-e.top-o-12,d=e.bottom-o-12,u=a==="right"?f>=t||f>=c:!(c>=t||c>=f),h=s==="down"?r>=n||r>=d:!(d>=n||d>=r),y=u?e.right+i:e.left-t-i,b=h?e.top+o:e.bottom-n-o;return U(y,b,t,n)}function U(e,t,n,i){return{left:Ue(e,12,window.innerWidth-n-12),top:Ue(t,12,window.innerHeight-i-12)}}function Ue(e,t,n){return n @@ -150,4 +150,4 @@ void main() { YBXA - `}function mn(e,t=document.body){const n=Te(e),i=document.documentElement.style;yn(n.assets.fontCss);for(const[c,r]of Object.entries(Yt))i.setProperty(c,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[c,r]of Object.entries(o)){const d=n.tokens[c];d!==void 0&&i.setProperty(r,String(d))}const a=n.tokens.fontBody,s=n.tokens.fontDisplay,l=n.tokens.fontTitle,f=n.tokens.fontMono;a&&i.setProperty("--font-body",se(String(a))),s&&i.setProperty("--font-title",se(String(s))),l&&i.setProperty("--font-title",se(String(l))),f&&i.setProperty("--font-mono",se(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 ne(e,t={},n=W){const i=x(t.action),o=n.provider?.providerId||te?.providerId||"surface unknown",a=n.activeSurfaceId||te?.surface?.id||n.provider?.surfaces?.[0]?.surfaceId||o,s=pn(n,a),l=p(s.commandBoundary,t.commandBoundary,i.commandBoundary,i.target),f=p(s.receiptSchema,t.receiptSchema,i.receiptSchema),c={type:"surface-command",schema:"gamecult.eve.command_invocation.v1",providerId:o,surfaceId:a,command:e||g(i.type,"invoke"),payload:{...i,transport:t.transport??null},issuedAt:new Date().toISOString(),clientId:n.clientId||"eve.browser"};return l&&(c.commandBoundary=l),f&&(c.receiptSchema=f),c}function pn(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 Oe(e,t){const n=x(e.action);return g(e.command,g(e.commandId,g(n.command,g(n.target,g(n.type,t?.commandId||"")))))}function Y(e){const t=m("section","pane");return t.append(m("h2","","No Surface")),t.append(m("div","detail",e)),t}function ze(e,t,n,i,o){e.dataset.commandId=n,e.tabIndex=e instanceof HTMLButtonElement?e.tabIndex:0;const a=()=>{const s=ne(n,i,o);o.commandSink?.(s,t)};e.addEventListener("click",a),e.addEventListener("keydown",s=>{(s.key==="Enter"||s.key===" ")&&(s.preventDefault(),a())})}function hn(e,t,n){const i=gn(e,t),o=x(i.find(u=>u.kind==="control.box")?.props),a=i.filter(u=>u.kind==="control.part"),s=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,""),vn(f,o);const c=m("div","cultui-slider-visual"),r=m("input","cultui-slider-input");r.type="range",r.min=String(s),r.max=String(l),r.step=String(e.step??.01),r.setAttribute("aria-label",g(e.bind,"slider"));for(const u of a){const h=x(u.props),y=m("span",`cultui-slider-part ${g(h.name,"part")}`);xn(y,h),c.append(y)}return a.some(u=>x(u.props).name==="track")||c.append(m("span","cultui-slider-part track")),a.some(u=>x(u.props).name==="fill")||c.append(m("span","cultui-slider-part fill")),a.some(u=>x(u.props).name==="thumb")||c.append(m("span","cultui-slider-part thumb")),f.append(c,r),(u=>{const h=Number(u??s),y=Math.max(s,Math.min(l,Number.isFinite(h)?h:s)),b=l===s?0:(y-s)/(l-s)*100;r.value=String(y),f.style.setProperty("--cultui-slider-value",`${b}%`),f.dataset.value=String(y)})(e.value??s),r.addEventListener("input",()=>{const u=ne(g(e.command,"control.slider.input"),{...e,action:{...x(e.action),value:Number(r.value)},value:Number(r.value)},n);n.commandSink?.(u,{kind:"control.slider",props:e})}),f}function gn(e,t){const n=typeof e.skin=="string"?e.skin:"",o=[...n?Je.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 Te(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:x(e?.tokens),assets:x(e?.assets),controlSkins:x(e?.controlSkins)}}function ee(e){if(!e)return"";const t=W.assetUrlResolver;return t?t(e,te):/^(https?:|data:|blob:)/i.test(e)?e:W.assetBaseUrl&&e.startsWith("/")?`${W.assetBaseUrl.replace(/\/+$/,"")}${e}`:e}function yn(e){const t=typeof e=="string"?e.trim():"";if(oe?.dataset.href===t||(oe?.remove(),oe=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),oe=i}function bn(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 vn(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 xn(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=de(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 ce(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=wn(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 wn(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 de(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 se(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 w(e,t){t.id&&(e.id=t.id),t.id&&(e.dataset.eveNodeId=t.id),t.kind&&(e.dataset.eveKind=t.kind)}function x(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function Sn(e){return Array.isArray(e)?e:[]}function En(e){return Sn(e).map((t,n)=>Qe({kind:"list.item",props:x(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 Re(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"?["1","true","yes","on"].includes(e.trim().toLowerCase()):!1}function B(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}function An(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 In(e){const t=e.trim().split(/\s+/).filter(Boolean);return t.length&&t.slice(0,2).map(n=>n[0]?.toUpperCase()||"").join("")||"?"}function Ke(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 Ge=document.querySelector("#surface"),D=document.querySelector("#status"),pe=document.querySelector("#receipt"),_n=document.querySelector("#compiler"),Ee=document.querySelector("#composer"),ue=document.querySelector("#destination-form"),Ae=document.querySelector("#compiler-results"),Cn=document.querySelector("#campaign-lab"),Xe=document.querySelector("#campaign-list");let Fe=0;async function O(){const e=await fetch("/api/surface");if(e.status===401){D.textContent="This laboratory requires an unused invite link.";return}const t=await e.json(),n=t.surface_id==="ghostlight.compiler";if(_n.hidden=!n,Ee.hidden=n,ue.hidden=n,Ge.hidden=n,Cn.hidden=n,n){D.textContent="No campaign exists. Retrieve the Vault and approve a world seed.";return}Fe=Number(t.version??0),qt(t,Ge,{body:document.body,clientId:"ghostlight.browser",statusElement:D});const i=await fetch("/api/campaigns").then(o=>o.json());Xe.innerHTML=i.campaigns.map(o=>``).join(""),Xe.querySelectorAll("button:not(:disabled)").forEach(o=>o.addEventListener("click",async()=>{await $(`/api/campaigns/select/${o.dataset.campaignId}`,{}),await O()}))}async function $(e,t){D.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 D.textContent=typeof i=="string"?i:"Compilation failed",new Error(D.textContent);return i}function je(e,t,n){Ae.innerHTML=`
${e.map((i,o)=>`

${i.title??i.name}

${i.player_hook??i.premise}

${i.era?`${i.era} · ${i.place} · ${i.pressure}`:""}

`).join("")}
`,Ae.querySelectorAll("button").forEach(i=>i.addEventListener("click",()=>n(e[Number(i.dataset.index)])))}document.querySelector("#suggest-form").addEventListener("submit",async e=>{e.preventDefault();const t=await $("/api/compiler/openings",{setting:document.querySelector("#setting").value,constraints:[]});je(t.openings,"Choose opening",async n=>{const i=await $("/api/compiler/roles",n);je(i.roles,"Choose role",async o=>it(await $("/api/compiler/selected",{campaign_name:n.title,opening:n,role:o})))})});document.querySelector("#custom-form").addEventListener("submit",async e=>{e.preventDefault(),await it(await $("/api/compiler/custom",Object.fromEntries(new FormData(e.currentTarget))))});async function it(e){const t=e.preview;Ae.innerHTML=`

${t.title}

${t.campaign.transcript?.[0]?.text??""}

${Object.keys(t.campaign.locations).length} locations · ${Object.keys(t.campaign.actors).length} actors · ${Object.keys(t.campaign.institutions).length} institutions

${t.gaps.length?`Material gaps: ${t.gaps.join("; ")}`:"No declared material gaps."}

Branch assumptions: ${t.branch_assumptions.join("; ")||"none"}

`,document.querySelector("#approve-world").addEventListener("click",async()=>{await $(`/api/compiler/approve/${e.preview_id}`,{}),await O()}),D.textContent="Preview compiled. Nothing has entered world state yet."}async function Ie(e){D.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 pe.hidden=!1,pe.textContent=JSON.stringify(n,null,2),t.ok?(await O(),n):(D.textContent=n.error??"The command was refused.",await O(),n)}Ee.addEventListener("submit",async e=>{e.preventDefault();const t=document.querySelector("#attempt").value.trim();if(!t)return;const n=await Ie({type:"assess",expected_revision:Fe,intent:{actor_id:"player",description:t,intended_effect:t}});if(n?.kind==="assessed"){const i=document.createElement("button");i.textContent=n.assessment.admissible?"Confirm server roll":"Revise attempt",i.addEventListener("click",async()=>{n.assessment.admissible?(await Ie({type:"attempt",assessment_digest:n.assessment.digest}),i.remove()):document.querySelector("#attempt").focus()}),Ee.append(i)}});document.querySelector("#wait").addEventListener("click",()=>{Ie({type:"wait",expected_revision:Fe,minutes:60})});ue.addEventListener("submit",async e=>{e.preventDefault();const t=await $("/api/compiler/destination",Object.fromEntries(new FormData(ue))),n=t.preview;pe.hidden=!1,pe.textContent=JSON.stringify(n,null,2),D.textContent="Destination preview compiled; topology is unchanged until approval.";const i=document.createElement("button");i.textContent="Approve destination",i.addEventListener("click",async()=>{await $(`/api/compiler/destination/approve/${t.preview_id}`,{}),i.remove(),await O()}),ue.append(i)});document.querySelector("#fork-form").addEventListener("submit",async e=>{e.preventDefault(),await $("/api/campaigns/fork",Object.fromEntries(new FormData(e.currentTarget))),await O()});document.querySelector("#reset-form").addEventListener("submit",async e=>{e.preventDefault(),await $("/api/campaigns/reset",Object.fromEntries(new FormData(e.currentTarget))),await O()});O(); + `}function mn(e,t=document.body){const n=Te(e),i=document.documentElement.style;yn(n.assets.fontCss);for(const[c,r]of Object.entries(qt))i.setProperty(c,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[c,r]of Object.entries(o)){const d=n.tokens[c];d!==void 0&&i.setProperty(r,String(d))}const a=n.tokens.fontBody,s=n.tokens.fontDisplay,l=n.tokens.fontTitle,f=n.tokens.fontMono;a&&i.setProperty("--font-body",se(String(a))),s&&i.setProperty("--font-title",se(String(s))),l&&i.setProperty("--font-title",se(String(l))),f&&i.setProperty("--font-mono",se(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 ne(e,t={},n=O){const i=x(t.action),o=n.provider?.providerId||te?.providerId||"surface unknown",a=n.activeSurfaceId||te?.surface?.id||n.provider?.surfaces?.[0]?.surfaceId||o,s=pn(n,a),l=p(s.commandBoundary,t.commandBoundary,i.commandBoundary,i.target),f=p(s.receiptSchema,t.receiptSchema,i.receiptSchema),c={type:"surface-command",schema:"gamecult.eve.command_invocation.v1",providerId:o,surfaceId:a,command:e||g(i.type,"invoke"),payload:{...i,transport:t.transport??null},issuedAt:new Date().toISOString(),clientId:n.clientId||"eve.browser"};return l&&(c.commandBoundary=l),f&&(c.receiptSchema=f),c}function pn(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 We(e,t){const n=x(e.action);return g(e.command,g(e.commandId,g(n.command,g(n.target,g(n.type,t?.commandId||"")))))}function q(e){const t=m("section","pane");return t.append(m("h2","","No Surface")),t.append(m("div","detail",e)),t}function ze(e,t,n,i,o){e.dataset.commandId=n,e.tabIndex=e instanceof HTMLButtonElement?e.tabIndex:0;const a=()=>{const s=ne(n,i,o);o.commandSink?.(s,t)};e.addEventListener("click",a),e.addEventListener("keydown",s=>{(s.key==="Enter"||s.key===" ")&&(s.preventDefault(),a())})}function hn(e,t,n){const i=gn(e,t),o=x(i.find(u=>u.kind==="control.box")?.props),a=i.filter(u=>u.kind==="control.part"),s=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,""),vn(f,o);const c=m("div","cultui-slider-visual"),r=m("input","cultui-slider-input");r.type="range",r.min=String(s),r.max=String(l),r.step=String(e.step??.01),r.setAttribute("aria-label",g(e.bind,"slider"));for(const u of a){const h=x(u.props),y=m("span",`cultui-slider-part ${g(h.name,"part")}`);xn(y,h),c.append(y)}return a.some(u=>x(u.props).name==="track")||c.append(m("span","cultui-slider-part track")),a.some(u=>x(u.props).name==="fill")||c.append(m("span","cultui-slider-part fill")),a.some(u=>x(u.props).name==="thumb")||c.append(m("span","cultui-slider-part thumb")),f.append(c,r),(u=>{const h=Number(u??s),y=Math.max(s,Math.min(l,Number.isFinite(h)?h:s)),b=l===s?0:(y-s)/(l-s)*100;r.value=String(y),f.style.setProperty("--cultui-slider-value",`${b}%`),f.dataset.value=String(y)})(e.value??s),r.addEventListener("input",()=>{const u=ne(g(e.command,"control.slider.input"),{...e,action:{...x(e.action),value:Number(r.value)},value:Number(r.value)},n);n.commandSink?.(u,{kind:"control.slider",props:e})}),f}function gn(e,t){const n=typeof e.skin=="string"?e.skin:"",o=[...n?Je.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 Te(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:x(e?.tokens),assets:x(e?.assets),controlSkins:x(e?.controlSkins)}}function ee(e){if(!e)return"";const t=O.assetUrlResolver;return t?t(e,te):/^(https?:|data:|blob:)/i.test(e)?e:O.assetBaseUrl&&e.startsWith("/")?`${O.assetBaseUrl.replace(/\/+$/,"")}${e}`:e}function yn(e){const t=typeof e=="string"?e.trim():"";if(oe?.dataset.href===t||(oe?.remove(),oe=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),oe=i}function bn(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 vn(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 xn(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=de(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 ce(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=wn(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 wn(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 de(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 se(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 w(e,t){t.id&&(e.id=t.id),t.id&&(e.dataset.eveNodeId=t.id),t.kind&&(e.dataset.eveKind=t.kind)}function x(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function Sn(e){return Array.isArray(e)?e:[]}function En(e){return Sn(e).map((t,n)=>Qe({kind:"list.item",props:x(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 Re(e){return typeof e=="boolean"?e:typeof e=="number"?e!==0:typeof e=="string"?["1","true","yes","on"].includes(e.trim().toLowerCase()):!1}function B(e,t){const n=Number(e);return Number.isFinite(n)?Math.max(0,Math.floor(n)):t}function An(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 In(e){const t=e.trim().split(/\s+/).filter(Boolean);return t.length&&t.slice(0,2).map(n=>n[0]?.toUpperCase()||"").join("")||"?"}function Ke(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 Ge=document.querySelector("#surface"),D=document.querySelector("#status"),pe=document.querySelector("#receipt"),_n=document.querySelector("#compiler"),Ee=document.querySelector("#composer"),ue=document.querySelector("#destination-form"),Ae=document.querySelector("#compiler-results"),Cn=document.querySelector("#campaign-lab"),je=document.querySelector("#campaign-list");let ke=0;async function W(){const e=await fetch("/api/surface");if(e.status===401){D.textContent="This laboratory requires an unused invite link.";return}const t=await e.json(),n=t.surface_id==="ghostlight.compiler";if(_n.hidden=!n,Ee.hidden=n,ue.hidden=n,Ge.hidden=n,Cn.hidden=n,n){D.textContent="No campaign exists. Retrieve the Vault and approve a world seed.";return}ke=Number(t.version??0),Yt(t,Ge,{body:document.body,clientId:"ghostlight.browser",statusElement:D});const i=await fetch("/api/campaigns").then(o=>o.json());je.innerHTML=i.campaigns.map(o=>``).join(""),je.querySelectorAll("button:not(:disabled)").forEach(o=>o.addEventListener("click",async()=>{await $(`/api/campaigns/select/${o.dataset.campaignId}`,{}),await W()}))}async function $(e,t){D.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 D.textContent=typeof i=="string"?i:"Compilation failed",new Error(D.textContent);return i}function Xe(e,t,n){Ae.innerHTML=`
${e.map((i,o)=>`

${i.title??i.name}

${i.player_hook??i.premise}

${i.era?`${i.era} · ${i.place} · ${i.pressure}`:""}

`).join("")}
`,Ae.querySelectorAll("button").forEach(i=>i.addEventListener("click",()=>n(e[Number(i.dataset.index)])))}document.querySelector("#suggest-form").addEventListener("submit",async e=>{e.preventDefault();const t=await $("/api/compiler/openings",{setting:document.querySelector("#setting").value,constraints:[]});Xe(t.openings,"Choose opening",async n=>{const i=await $("/api/compiler/roles",n);Xe(i.roles,"Choose role",async o=>it(await $("/api/compiler/selected",{campaign_name:n.title,opening:n,role:o})))})});document.querySelector("#custom-form").addEventListener("submit",async e=>{e.preventDefault(),await it(await $("/api/compiler/custom",Object.fromEntries(new FormData(e.currentTarget))))});async function it(e){const t=e.preview;Ae.innerHTML=`

${t.title}

${t.campaign.transcript?.[0]?.text??""}

${Object.keys(t.campaign.locations).length} locations · ${Object.keys(t.campaign.actors).length} actors · ${Object.keys(t.campaign.institutions).length} institutions

${t.gaps.length?`Material gaps: ${t.gaps.join("; ")}`:"No declared material gaps."}

Branch assumptions: ${t.branch_assumptions.join("; ")||"none"}

`,document.querySelector("#approve-world").addEventListener("click",async()=>{await $(`/api/compiler/approve/${e.preview_id}`,{}),await W()}),D.textContent="Preview compiled. Nothing has entered world state yet."}async function Ie(e){D.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 pe.hidden=!1,pe.textContent=JSON.stringify(n,null,2),t.ok?(await W(),n):(D.textContent=n.error??"The command was refused.",await W(),n)}Ee.addEventListener("submit",async e=>{e.preventDefault();const t=document.querySelector("#attempt").value.trim();if(!t)return;const n=await Ie({type:"assess",expected_revision:ke,intent:{actor_id:"player",description:t,intended_effect:t}});if(n?.kind==="assessed"){const i=document.createElement("button");i.textContent=n.assessment.admissible?"Confirm server roll":"Revise attempt",i.addEventListener("click",async()=>{n.assessment.admissible?(await Ie({type:"attempt",assessment_digest:n.assessment.digest}),i.remove()):document.querySelector("#attempt").focus()}),Ee.append(i)}});document.querySelector("#wait").addEventListener("click",()=>{Ie({type:"wait",expected_revision:ke,minutes:60})});ue.addEventListener("submit",async e=>{e.preventDefault();const t=await $("/api/compiler/destination",Object.fromEntries(new FormData(ue))),n=t.preview;pe.hidden=!1,pe.textContent=JSON.stringify(n,null,2),D.textContent="Destination preview compiled; topology is unchanged until approval.";const i=document.createElement("button");i.textContent="Approve destination",i.addEventListener("click",async()=>{await $(`/api/compiler/destination/approve/${t.preview_id}`,{}),i.remove(),await W()}),ue.append(i)});document.querySelector("#fork-form").addEventListener("submit",async e=>{e.preventDefault(),await $("/api/campaigns/fork",Object.fromEntries(new FormData(e.currentTarget))),await W()});document.querySelector("#reset-form").addEventListener("submit",async e=>{e.preventDefault(),await $("/api/campaigns/reset",Object.fromEntries(new FormData(e.currentTarget))),await W()});document.querySelector("#load-operator").addEventListener("click",async()=>{const e=await fetch("/api/operator");document.querySelector("#operator-output").textContent=JSON.stringify(await e.json(),null,2)});W(); diff --git a/web/dist/index.html b/web/dist/index.html index 49d74f8..e72c237 100644 --- a/web/dist/index.html +++ b/web/dist/index.html @@ -1,5 +1,5 @@ -GhostlightDungeon +GhostlightDungeon

STARFIRE / PRIVATE VERSE

GhostlightDungeon

Reading the world…

@@ -9,5 +9,5 @@
- +
diff --git a/web/index.html b/web/index.html index f2ee136..82aaabb 100644 --- a/web/index.html +++ b/web/index.html @@ -7,5 +7,5 @@
- + diff --git a/web/src/main.ts b/web/src/main.ts index 878dadc..16a10cb 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -64,4 +64,5 @@ document.querySelector("#wait")!.addEventListener("click", () destinationForm.addEventListener("submit",async event=>{event.preventDefault();const result=await compilerPost("/api/compiler/destination",Object.fromEntries(new FormData(destinationForm)));const preview=result.preview;receipt.hidden=false;receipt.textContent=JSON.stringify(preview,null,2);status.textContent="Destination preview compiled; topology is unchanged until approval.";const button=document.createElement("button");button.textContent="Approve destination";button.addEventListener("click",async()=>{await compilerPost(`/api/compiler/destination/approve/${result.preview_id}`,{});button.remove();await refresh();});destinationForm.append(button);}); document.querySelector("#fork-form")!.addEventListener("submit",async event=>{event.preventDefault();await compilerPost("/api/campaigns/fork",Object.fromEntries(new FormData(event.currentTarget as HTMLFormElement)));await refresh();}); document.querySelector("#reset-form")!.addEventListener("submit",async event=>{event.preventDefault();await compilerPost("/api/campaigns/reset",Object.fromEntries(new FormData(event.currentTarget as HTMLFormElement)));await refresh();}); +document.querySelector("#load-operator")!.addEventListener("click",async()=>{const response=await fetch("/api/operator");document.querySelector("#operator-output")!.textContent=JSON.stringify(await response.json(),null,2);}); void refresh();