diff --git a/dashboard/public/jarvis.html b/dashboard/public/jarvis.html
index 45b5b8e..9349549 100644
--- a/dashboard/public/jarvis.html
+++ b/dashboard/public/jarvis.html
@@ -226,7 +226,25 @@ html,body{height:100%;background:var(--bg);color:var(--text);font-family:var(--s
/* RESPONSIVE */
@media(max-width:1400px){.grid{grid-template-columns:240px 1fr 320px}.metrics-row{grid-template-columns:repeat(3,1fr)}.src-grid{grid-template-columns:repeat(3,1fr)}}
-@media(max-width:1100px){.grid{grid-template-columns:1fr}.lower .lp-ticker,.lower .lp-delta,.lower .lp-macro,.lower .lp-ideas{flex:1 1 100%;max-width:none}.metrics-row{grid-template-columns:repeat(2,1fr)}.src-grid{grid-template-columns:repeat(2,1fr)}}
+@media(max-width:1100px){
+ #main{padding:8px}
+ .topbar{padding:10px 12px}
+ .top-left,.top-center,.top-right{width:100%}
+ .top-center{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}
+ .top-right{gap:6px}
+ .region-btn,.meta-pill,.alert-badge{font-size:10px}
+ .grid{display:flex;flex-direction:column}
+ #centerCol{order:1}
+ #rightRail{order:2}
+ #leftRail{order:3}
+ .map-container{min-height:420px}
+ .map-hint{font-size:8px;right:8px}
+ .map-legend{left:8px;right:8px;bottom:8px;gap:4px}
+ .leg-item{font-size:8px}
+ .lower .lp-ticker,.lower .lp-osint,.lower .lp-delta,.lower .lp-macro,.lower .lp-ideas{flex:1 1 100%;max-width:none}
+ .metrics-row{grid-template-columns:repeat(2,1fr)}
+ .src-grid{grid-template-columns:repeat(2,1fr)}
+}
/* CONFLICT LAYER */
@keyframes pulse-conflict{0%,100%{opacity:0.5;stroke-width:1.5}50%{opacity:0.9;stroke-width:2.5}}
@@ -295,7 +313,7 @@ let D = null;
// === GLOBALS ===
let globe = null;
let flightsVisible = true;
-let isFlat = true;
+let isFlat = !isMobileLayout();
let flatSvg, flatProjection, flatPath, flatG, flatZoom, flatW, flatH;
const regionPOV = {
world: { lat: 20, lng: 20, altitude: 1.8 },
@@ -486,18 +504,27 @@ function initMap(){
});
// Resize handler
- window.addEventListener('resize', () => {
- const c = document.getElementById('mapContainer');
- globe.width(c.clientWidth).height(c.clientHeight || 560);
+ window.addEventListener('resize', () => syncResponsiveLayout());
+ window.addEventListener('orientationchange', () => setTimeout(() => syncResponsiveLayout(true), 150));
+ document.addEventListener('visibilitychange', () => {
+ if(!document.hidden) setTimeout(() => syncResponsiveLayout(true), 150);
});
+ window.addEventListener('pageshow', () => setTimeout(() => syncResponsiveLayout(true), 150));
// Plot globe markers (preloaded but hidden)
plotMarkers();
// Start in flat mode โ hide globe, show flat map
- document.getElementById('globeViz').style.display = 'none';
- document.getElementById('flatMapSvg').style.display = 'block';
- initFlatMap();
+ if(isFlat){
+ document.getElementById('globeViz').style.display = 'none';
+ document.getElementById('flatMapSvg').style.display = 'block';
+ initFlatMap();
+ } else {
+ document.getElementById('globeViz').style.display = 'block';
+ document.getElementById('flatMapSvg').style.display = 'none';
+ document.getElementById('projToggle').textContent = 'FLAT MODE';
+ document.getElementById('mapHint').textContent = 'DRAG TO ROTATE ยท SCROLL TO ZOOM';
+ }
// Legend
document.getElementById('mapLegend').innerHTML=
@@ -976,6 +1003,7 @@ function mkSparkSvg(values, isGood){
// === LOWER GRID ===
function renderLower(){
+ const mobile = isMobileLayout();
const spread=D.fred.find(f=>f.id==='T10Y2Y');
const ff=D.fred.find(f=>f.id==='DFF');
const ue=D.bls.find(b=>b.id==='LNS14000000');
@@ -1092,23 +1120,14 @@ function renderLower(){
}
const deltaHtml = hasDelta ? deltaRows.join('') : '
No changes since last sweep
';
- document.getElementById('lowerGrid').innerHTML=`
-
+ const tickerPanel = `
Live News Ticker
${feed.length} ITEMS
${tickerCards}${tickerCards}
-
-
-
Sweep Delta
${dirEmoji} ${ds.direction?ds.direction.toUpperCase():'BASELINE'}
- ${hasDelta?`
- Changes: ${ds.totalChanges}
- Critical: ${ds.criticalChanges||0}
- ${ds.signalBreakdown?`New: ${ds.signalBreakdown.new} ↑${ds.signalBreakdown.escalated} ↓${ds.signalBreakdown.deescalated}`:''}
-
`:''}
-
${deltaHtml}
-
-
+
`;
+ const osintPanel = mobile ? buildOsintPanel('lp-osint', 240) : '';
+ const macroPanel = `
Macro + Markets
${mkt.timestamp?'LIVE':'DELAYED'}
${hasMarkets?`
INDEXES
@@ -1129,33 +1148,32 @@ function renderLower(){
WTI 5-DAY
${sparkHtml}
-
-
+
`;
+ const ideasPanel = `
Leverageable Ideas
${D.ideasSource==='llm'?'AI ENHANCED':D.ideasSource==='disabled'?'LLM OFF':'PENDING'}
${ideasHtml}
FOR INFORMATIONAL PURPOSES ONLY. This is not financial advice, a recommendation to buy or sell any security, or a solicitation of any kind. All signal-based observations are derived from publicly available OSINT data and should not be relied upon for investment decisions. Consult a licensed financial advisor before making any investment. Past performance does not guarantee future results.
`;
+ const deltaPanel = `
+
Sweep Delta
${dirEmoji} ${ds.direction?ds.direction.toUpperCase():'BASELINE'}
+ ${hasDelta?`
+ Changes: ${ds.totalChanges}
+ Critical: ${ds.criticalChanges||0}
+ ${ds.signalBreakdown?`New: ${ds.signalBreakdown.new} ↑${ds.signalBreakdown.escalated} ↓${ds.signalBreakdown.deescalated}`:''}
+
`:''}
+
${deltaHtml}
+
`;
+
+ document.getElementById('lowerGrid').innerHTML=`${tickerPanel}${osintPanel}${macroPanel}${ideasPanel}${deltaPanel}`;
}
// === RIGHT RAIL ===
function renderRight(){
+ const mobile = isMobileLayout();
// CROSS-SOURCE SIGNALS โ moved from lower grid to right rail
const signals=D.tSignals.slice(0,6).map((s,i)=>`
`).join('');
// OSINT TICKER โ Telegram + WHO as flowing cards
- const allPosts=[...D.tg.urgent,...D.tg.topPosts].sort((a,b)=>new Date(b.date||0)-new Date(a.date||0));
- const whoItems=D.who.slice(0,4).map(w=>({channel:'WHO ALERT',text:w.title,date:w.date,isWho:true}));
- const osintItems=[...allPosts.slice(0,15),...whoItems];
- const osintCards=osintItems.map(p=>{
- const isU=p.urgentFlags&&p.urgentFlags.length>0;
- const views=p.views?p.views>=1000?`${(p.views/1000).toFixed(0)}K`:p.views:'';
- const age=p.date?getAge(p.date):'';
- const flags=(p.urgentFlags||[]).map(f=>`
${f}`).join('');
- const srcCls=p.isWho?'style="color:#69f0ae;border-color:rgba(105,240,174,0.4)"':'class="tk-src tg"';
- return `
${(p.channel||'OSINT').toUpperCase().substring(0,14)}${views?`
${views}`:''}
${age}${flags}
${cleanText((p.text||'').substring(0,160))}
`;
- }).join('');
- const osintDuration=Math.max(25,osintItems.length*3);
-
const signalMetrics=[
{l:'Incident Tempo',v:D.tg.urgent.length,p:70},
{l:'Air Theaters',v:D.air.length,p:60},
@@ -1166,17 +1184,12 @@ function renderRight(){
];
document.getElementById('rightRail').innerHTML=`
-
+
Cross-Source Signals
WORLDVIEW
${signals}
-
-
OSINT Stream
${D.tg.urgent.length} URGENT
-
-
${osintCards}${osintCards}
-
-
-
+ ${mobile ? '' : buildOsintPanel('right-osint', 260)}
+
Signal Core
HOT METRICS
${signalMetrics.map(s=>`
`).join('')}
`;
@@ -1210,8 +1223,8 @@ function runBoot(){
tl.call(()=>{
const div=document.createElement('div');div.innerHTML=line.text;div.style.opacity='0';
container.appendChild(div);gsap.to(div,{opacity:1,duration:0.2});
- },null,line.delay/1000+0.5);
- });
+ },[],line.delay/1000+0.5);
+ });
tl.to('#bootFinal',{opacity:1,duration:0.4},3.1);
tl.to('#boot',{opacity:0,duration:0.5,ease:'power2.in'},3.7);
tl.set('#boot',{display:'none'},4.2);
@@ -1232,6 +1245,70 @@ function runBoot(){
},4.0);
}
+function isMobileLayout(){ return window.innerWidth <= 1100; }
+
+function buildOsintPanel(panelClass='', maxHeight=260){
+ const allPosts=[...D.tg.urgent,...D.tg.topPosts].sort((a,b)=>new Date(b.date||0)-new Date(a.date||0));
+ const whoItems=D.who.slice(0,4).map(w=>({channel:'WHO ALERT',text:w.title,date:w.date,isWho:true}));
+ const osintItems=[...allPosts.slice(0,15),...whoItems];
+ const osintCards=osintItems.map(p=>{
+ const isU=p.urgentFlags&&p.urgentFlags.length>0;
+ const views=p.views?p.views>=1000?`${(p.views/1000).toFixed(0)}K`:p.views:'';
+ const age=p.date?getAge(p.date):'';
+ const flags=(p.urgentFlags||[]).map(f=>`
${f}`).join('');
+ const srcCls=p.isWho?'style="color:#69f0ae;border-color:rgba(105,240,174,0.4)"':'class="tk-src tg"';
+ return `
${(p.channel||'OSINT').toUpperCase().substring(0,14)}${views?`
${views}`:''}
${age}${flags}
${cleanText((p.text||'').substring(0,160))}
`;
+ }).join('');
+ const osintDuration=Math.max(25,osintItems.length*3);
+ return `
+
OSINT Stream
${D.tg.urgent.length} URGENT
+
+
${osintCards}${osintCards}
+
+
`;
+}
+
+function refreshMapViewport(forceGlobeReflow=false){
+ const container = document.getElementById('mapContainer');
+ if(!container) return;
+ const width = container.clientWidth;
+ const height = container.clientHeight || (isMobileLayout() ? 420 : 560);
+ if(globe){
+ globe.width(width).height(height);
+ if(forceGlobeReflow && !isFlat){
+ const globeEl = document.getElementById('globeViz');
+ globeEl.style.display = 'none';
+ requestAnimationFrame(() => {
+ globeEl.style.display = 'block';
+ globe.width(width).height(height);
+ });
+ }
+ }
+ if(flatSvg){
+ flatW = width;
+ flatH = height;
+ flatSvg.attr('viewBox',`0 0 ${flatW} ${flatH}`).attr('preserveAspectRatio','xMidYMid meet');
+ if(flatProjection && flatG){
+ flatProjection = d3.geoNaturalEarth1().fitSize([flatW-20,flatH-20],{type:'Sphere'}).translate([flatW/2,flatH/2]);
+ flatPath = d3.geoPath(flatProjection);
+ flatG.selectAll('*').remove();
+ drawFlatMap();
+ }
+ }
+}
+
+let lastResponsiveMobile = null;
+function syncResponsiveLayout(force=false){
+ const mobileNow = isMobileLayout();
+ if(force || lastResponsiveMobile === null || mobileNow !== lastResponsiveMobile){
+ lastResponsiveMobile = mobileNow;
+ renderLeftRail();
+ renderLower();
+ renderRight();
+ }
+ refreshMapViewport(force && !isFlat);
+}
+
// === REINIT (for live updates without boot sequence) ===
function reinit(){
renderTopbar();renderLeftRail();renderLower();renderRight();
@@ -1288,6 +1365,7 @@ function init(){
if(url) window.open(url,'_blank','noopener');
}
});
+ syncResponsiveLayout(true);
}
document.addEventListener('DOMContentLoaded', () => {