// data.jsx — 일일 시장 보고서 mock data
// 실제 데이터 아님. 전문 트레이더용 대시보드 와이어프레임에 쓰는 샘플.

const TODAY = {
  dateKo: '2026년 4월 20일 (월)',
  dateEn: 'Mon, Apr 20 2026',
  closeTimeKo: '오후 3:30 KST 마감',
  closeTimeEn: 'Close 3:30pm KST',
};

// 오늘의 핵심 (중요도 1~5)
const HEADLINES = {
  ko: [
    { imp:5, text:'코스피, 외국인 6거래일 연속 순매수에 +1.4% 반등 — 2,712p.' },
    { imp:4, text:'원·달러 환율 1,348원까지 하락, 연준 금리 동결 기대 반영.' },
    { imp:3, text:'반도체·2차전지 강세 vs. 건설·정유 동반 약세, 업종 양극화.' },
  ],
  en: [
    { imp:5, text:'KOSPI +1.4% to 2,712 as foreigners net-buy for 6th straight session.' },
    { imp:4, text:'USD/KRW slides to 1,348 on Fed hold expectations.' },
    { imp:3, text:'Semis & batteries lead gains; construction, refiners lag — sector split widens.' },
  ],
};

// 더보기: 추가 뉴스 (시간 + 카테고리)
const MORE_NEWS = {
  ko: [
    { t:'15:42', cat:'TECH',   imp:4, text:'엔비디아, Blackwell B200 5월 초도물량 TSMC 출하 확인' },
    { t:'15:18', cat:'MACRO',  imp:4, text:'연준 윌리엄스 "금리인하, 데이터 더 확인해야"' },
    { t:'14:55', cat:'EARN',   imp:5, text:'넷플릭스 1Q 가입자 +933만, 컨센 두 배 초과' },
    { t:'14:31', cat:'POLICY', imp:3, text:'이복현 금감원장, 공매도 재개 5/1 시행 확정' },
    { t:'14:02', cat:'FLOW',   imp:3, text:'외국인 삼성전자 1,820억 순매수 · SK하이닉스 940억' },
    { t:'13:40', cat:'COMM',   imp:4, text:'구리 $10,250/t 돌파, 중국 스팟 프리미엄 확대' },
    { t:'13:12', cat:'CRYPTO', imp:3, text:'비트코인 $68.4K, ETF 순유입 11일 연속' },
    { t:'12:58', cat:'FX',     imp:4, text:'엔·달러 154.8엔, 개입 경계감 속 변동성 축소' },
    { t:'12:22', cat:'EARN',   imp:3, text:'테슬라 상하이 4월 판매 7.2만대, MoM +3%' },
    { t:'11:48', cat:'M&A',    imp:3, text:'시스코, Splunk 통합 가이던스 하반기 +3% 상향 검토' },
  ],
  en: [
    { t:'15:42', cat:'TECH',   imp:4, text:'NVIDIA: Blackwell B200 initial shipments confirmed from TSMC in May' },
    { t:'15:18', cat:'MACRO',  imp:4, text:'Fed\u2019s Williams: Rate cuts need further data confirmation' },
    { t:'14:55', cat:'EARN',   imp:5, text:'Netflix Q1 adds 9.33M subs — double consensus' },
    { t:'14:31', cat:'POLICY', imp:3, text:'KR FSS: Short-selling to resume on May 1' },
    { t:'14:02', cat:'FLOW',   imp:3, text:'Foreigners bought \u20a9182B of Samsung, \u20a994B of SK Hynix' },
    { t:'13:40', cat:'COMM',   imp:4, text:'Copper tops $10,250/t, China spot premium widens' },
    { t:'13:12', cat:'CRYPTO', imp:3, text:'BTC $68.4K; spot ETF net inflow for 11th session' },
    { t:'12:58', cat:'FX',     imp:4, text:'USD/JPY 154.8, vol contracts amid MoF intervention watch' },
    { t:'12:22', cat:'EARN',   imp:3, text:'Tesla China April deliveries 72k, +3% MoM' },
    { t:'11:48', cat:'M&A',    imp:3, text:'Cisco weighing H2 guidance +3% on Splunk synergies' },
  ],
};

// 지수 스냅샷 (sym, px, chg, pct, spark, unit: 'idx' | 'fx' | 'bbl' | 'crypto')
// 순서: KR → US → 아시아 → FX → 원자재 → 암호화폐
const INDICES = [
  { sym: 'KOSPI',    px: 2712.48, chg: +37.21, pct: +1.39, unit:'idx',   spark: [48,50,49,52,55,53,57,60,58,62,65,63,68,72,70,74,78,76,80,84,82,86] },
  { sym: 'KOSDAQ',   px:  876.32, chg: +11.84, pct: +1.37, unit:'idx',   spark: [40,42,41,44,43,46,48,47,50,53,51,55,58,56,60,63,61,65,68,66,70,72] },
  { sym: 'DOW',      px:39420.12, chg:+142.80, pct: +0.36, unit:'idx',   spark: [60,61,63,62,64,66,65,67,68,70,69,72,74,73,76,78,76,79,81,80,82,84] },
  { sym: 'NASDAQ',   px:16412.90, chg: +42.18, pct: +0.26, unit:'idx',   spark: [55,57,56,58,60,59,62,64,63,65,67,66,68,70,69,71,73,72,74,76,75,77] },
  { sym: 'S&P 500',  px: 5234.18, chg:  -6.42, pct: -0.12, unit:'idx',   spark: [70,72,71,68,66,69,67,65,68,70,72,71,69,67,66,68,70,69,67,65,68,66] },
  { sym: 'Nikkei',   px:38720.50, chg:+218.40, pct: +0.57, unit:'idx',   spark: [50,52,54,53,56,58,57,60,62,61,64,66,65,68,70,69,72,74,73,76,78,77] },
  { sym: 'Shanghai', px: 3148.22, chg: -12.80, pct: -0.40, unit:'idx',   spark: [72,70,71,68,66,67,65,64,62,63,61,59,60,58,56,57,55,54,52,53,51,50] },
  { sym: 'USD/KRW',  px: 1348.20, chg:  -4.80, pct: -0.35, unit:'fx',    spark: [80,79,77,78,76,74,75,73,71,72,70,68,69,67,65,66,64,62,63,60,58,56] },
  { sym: 'WTI',      px:   79.42, chg:  +0.58, pct: +0.74, unit:'bbl',   spark: [50,52,51,54,53,55,57,56,58,60,59,62,64,63,65,67,66,68,70,69,72,73] },
  { sym: 'Bitcoin',  px: 68420.1, chg:+412.30, pct: +0.61, unit:'crypto',spark: [50,53,56,55,58,62,60,64,67,65,69,72,70,74,77,75,79,82,80,84,87,85] },
];

// 지수별 다기간 과거가 (1D는 타임스탬프 포함, 나머지는 종가만 — 차트 x축용)
// 값들은 시뮬레이션. 최근값 = INDICES.px 와 정렬됨.
function _seedRand(seed){ let s=seed; return ()=>{ s=(s*9301+49297)%233280; return s/233280; }; }
function _genSeries(len, endVal, vol, seedHash) {
  const r = _seedRand(seedHash);
  const arr = new Array(len);
  arr[len-1] = endVal;
  for (let i=len-2; i>=0; i--) {
    const drift = (r()-0.5)*vol + (r()-0.48)*vol*0.3;
    arr[i] = +(arr[i+1] * (1 - drift)).toFixed(4);
  }
  return arr;
}
const HISTORY = {};
INDICES.forEach((it, idx) => {
  const baseVol = it.unit==='crypto' ? 0.018 : it.unit==='fx'||it.unit==='yield' ? 0.004 : 0.010;
  HISTORY[it.sym] = {
    '1D': _genSeries(78, it.px, baseVol*0.35, 11 + idx), // 5-min bars, 9:00~15:30
    '1W': _genSeries(60, it.px, baseVol*0.6,  23 + idx),
    '1M': _genSeries(80, it.px, baseVol,      47 + idx),
    '3M': _genSeries(90, it.px, baseVol*1.4,  89 + idx),
    '1Y': _genSeries(120, it.px, baseVol*2.2, 131 + idx),
  };
});

// 섹터 히트맵 — (섹터, 등락률%, 시총 weight 0-1)
const SECTORS = [
  { name: '반도체',   pct: +2.81, w: 0.92 },
  { name: '2차전지',  pct: +2.14, w: 0.78 },
  { name: '자동차',   pct: +1.42, w: 0.66 },
  { name: '조선',     pct: +1.18, w: 0.32 },
  { name: '방산',     pct: +0.94, w: 0.40 },
  { name: '인터넷',   pct: +0.61, w: 0.58 },
  { name: '금융',     pct: +0.42, w: 0.70 },
  { name: '유통',     pct: +0.18, w: 0.28 },
  { name: '통신',     pct: -0.04, w: 0.34 },
  { name: '제약·바이오',pct: -0.32,w: 0.54 },
  { name: '화학',     pct: -0.58, w: 0.46 },
  { name: '철강',     pct: -0.72, w: 0.30 },
  { name: '정유',     pct: -1.24, w: 0.36 },
  { name: '건설',     pct: -1.81, w: 0.24 },
];

// 상승 TOP
const GAINERS = [
  { sym: '005930', name: '삼성전자',       px: 78400, pct:+3.84, vol:'22.4M' },
  { sym: '373220', name: 'LG에너지솔루션', px:412500, pct:+3.12, vol: '0.8M' },
  { sym: '000660', name: 'SK하이닉스',      px:198200, pct:+2.96, vol: '6.1M' },
  { sym: '247540', name: '에코프로비엠',    px:182400, pct:+2.71, vol: '1.2M' },
  { sym: '042660', name: '한화오션',        px: 34280, pct:+2.44, vol: '3.4M' },
];

// 하락 TOP
const LOSERS = [
  { sym: '000720', name: '현대건설',       px: 32150, pct:-2.84, vol: '2.1M' },
  { sym: '010950', name: 'S-Oil',          px: 68200, pct:-2.41, vol: '0.9M' },
  { sym: '009540', name: 'HD한국조선해양',  px:134500, pct:-1.92, vol: '0.4M' },
  { sym: '051910', name: 'LG화학',         px:352000, pct:-1.68, vol: '0.6M' },
  { sym: '035420', name: 'NAVER',          px:184200, pct:-1.41, vol: '1.1M' },
];

// 타임라인 — 오늘의 이벤트
const TIMELINE = [
  { t:'09:00', tag:'OPEN',   titleKo:'코스피 개장 +0.6%',              titleEn:'KOSPI opens +0.6%' },
  { t:'09:32', tag:'FILING', titleKo:'삼성전자 1분기 잠정실적 가이던스 상회',titleEn:'Samsung Q1 prelim beats guidance' },
  { t:'10:15', tag:'MACRO',  titleKo:'한은, 2월 생산자물가 +0.3% 발표',  titleEn:'BOK: PPI +0.3% YoY in Feb' },
  { t:'11:42', tag:'FX',     titleKo:'원·달러 1,350원 하회, 2주 최저',    titleEn:'USD/KRW breaks 1,350 — 2-wk low' },
  { t:'13:20', tag:'NEWS',   titleKo:'미 SEC, 현물 이더 ETF 승인 임박 보도',titleEn:'WSJ: SEC nears spot ETH ETF nod' },
  { t:'14:05', tag:'FLOW',   titleKo:'외국인 순매수 9,420억 돌파',         titleEn:'Foreign net buy tops ₩942B' },
  { t:'15:30', tag:'CLOSE',  titleKo:'코스피 2,712.48 마감 +1.39%',       titleEn:'KOSPI closes 2,712.48 +1.39%' },
];

// 애널리스트 코멘터리
const COMMENTARY = {
  author: 'Jae-won Park, Head of Strategy',
  initials: 'JP',
  ko: '외국인 순매수가 6거래일 연속 이어지며 지수는 1월 고점 저항선(2,710p)을 돌파했다. 반도체 업종의 실적 서프라이즈가 수급을 이끈 반면, 건설·정유는 유가 반등 지연과 중동 프리미엄 축소로 약세 흐름을 유지. 단기적으로는 4/25 PCE 발표와 5/1 FOMC가 분수령이며, 그 전까지 대형주 중심의 제한적 추가 상승을 예상한다.',
  en: 'Foreign net-buying extended to a 6th session and the index cleared its January resistance at 2,710. Semis led on earnings, while construction and refiners lagged as the Middle East premium faded. We see limited upside led by large-caps into the 4/25 PCE print and 5/1 FOMC as pivotal catalysts.',
  conviction: 'Constructive',
  posture: '대형주 비중확대 · Duration 중립',
};

// 내일의 일정
const TOMORROW = [
  { t:'08:50 KST', evt:'일본 3월 무역수지',   imp:'M' },
  { t:'15:00 KST', evt:'중국 4월 LPR 금리',   imp:'H' },
  { t:'21:30 KST', evt:'미 신규 실업수당 청구',imp:'M' },
  { t:'23:00 KST', evt:'미 4월 필라델피아 연준', imp:'M' },
  { t:'--',        evt:'실적: TSLA, NFLX (장후)', imp:'H' },
];

// 섹터별 종목 (드릴다운)
const SECTOR_STOCKS = {
  '반도체': [
    { sym:'005930', name:'삼성전자',        px: 78400, pct:+3.84, vol:'22.4M', mcap:'468조' },
    { sym:'000660', name:'SK하이닉스',      px:198200, pct:+2.96, vol: '6.1M', mcap:'144조' },
    { sym:'042700', name:'한미반도체',      px:148200, pct:+2.18, vol: '1.8M', mcap: '14조' },
    { sym:'039030', name:'이오테크닉스',    px:228500, pct:+1.42, vol: '0.3M', mcap: '2.8조' },
    { sym:'240810', name:'원익IPS',         px: 42150, pct:+0.94, vol: '0.5M', mcap: '2.1조' },
  ],
  '2차전지': [
    { sym:'373220', name:'LG에너지솔루션',  px:412500, pct:+3.12, vol: '0.8M', mcap:'96조' },
    { sym:'247540', name:'에코프로비엠',    px:182400, pct:+2.71, vol: '1.2M', mcap:'17.8조' },
    { sym:'066970', name:'엘앤에프',        px:148000, pct:+2.33, vol: '0.9M', mcap: '5.2조' },
    { sym:'051910', name:'LG화학',          px:352000, pct:-1.68, vol: '0.6M', mcap:'24.8조' },
    { sym:'006400', name:'삼성SDI',         px:386500, pct:+1.12, vol: '0.4M', mcap:'26.6조' },
  ],
  '자동차': [
    { sym:'005380', name:'현대차',          px:248000, pct:+2.04, vol: '1.2M', mcap:'52조' },
    { sym:'000270', name:'기아',            px:112800, pct:+1.84, vol: '1.8M', mcap:'45조' },
    { sym:'012330', name:'현대모비스',      px:242500, pct:+1.12, vol: '0.4M', mcap:'22조' },
    { sym:'018880', name:'한온시스템',      px:  7420, pct:+0.68, vol: '2.1M', mcap: '4조' },
    { sym:'204320', name:'HL만도',          px: 42800, pct:+0.42, vol: '0.3M', mcap: '2조' },
  ],
  '조선':    [
    { sym:'042660', name:'한화오션',        px: 34280, pct:+2.44, vol: '3.4M', mcap: '10조' },
    { sym:'009540', name:'HD한국조선해양',  px:134500, pct:-1.92, vol: '0.4M', mcap: '9.5조' },
    { sym:'010620', name:'HD현대미포',      px:128200, pct:+1.24, vol: '0.5M', mcap: '5.1조' },
    { sym:'267250', name:'HD현대중공업',    px:164000, pct:+1.02, vol: '0.6M', mcap:'14.6조' },
  ],
  '방산': [
    { sym:'047810', name:'한국항공우주',    px: 58200, pct:+1.84, vol: '0.8M', mcap: '5.7조' },
    { sym:'012450', name:'한화에어로스페이스', px:264000, pct:+1.12, vol: '0.4M', mcap:'13.2조' },
    { sym:'064350', name:'현대로템',        px: 34150, pct:+0.42, vol: '0.7M', mcap: '3.7조' },
    { sym:'079550', name:'LIG넥스원',       px:184000, pct:+0.18, vol: '0.2M', mcap: '4조' },
  ],
  '인터넷': [
    { sym:'035420', name:'NAVER',           px:184200, pct:-1.41, vol: '1.1M', mcap:'30조' },
    { sym:'035720', name:'카카오',          px: 48250, pct:+1.82, vol: '3.2M', mcap:'21조' },
    { sym:'293490', name:'카카오게임즈',    px: 22400, pct:+1.04, vol: '0.8M', mcap: '1.8조' },
    { sym:'251270', name:'넷마블',          px: 52800, pct:+0.42, vol: '0.3M', mcap: '4.5조' },
  ],
  '금융': [
    { sym:'105560', name:'KB금융',          px: 72400, pct:+0.62, vol: '1.4M', mcap:'28.8조' },
    { sym:'055550', name:'신한지주',        px: 46850, pct:+0.48, vol: '1.6M', mcap:'23.8조' },
    { sym:'086790', name:'하나금융지주',    px: 58200, pct:+0.34, vol: '1.1M', mcap:'17.4조' },
    { sym:'316140', name:'우리금융지주',    px: 14820, pct:+0.28, vol: '2.4M', mcap:'11.1조' },
  ],
  '유통': [
    { sym:'004990', name:'롯데지주',        px: 24500, pct:+0.42, vol: '0.3M', mcap: '2.6조' },
    { sym:'023530', name:'롯데쇼핑',        px: 68200, pct:+0.12, vol: '0.2M', mcap: '1.9조' },
    { sym:'139480', name:'이마트',          px: 72400, pct:-0.24, vol: '0.4M', mcap: '2조' },
    { sym:'282330', name:'BGF리테일',       px:118000, pct:+0.06, vol: '0.1M', mcap: '2.1조' },
  ],
  '통신': [
    { sym:'017670', name:'SK텔레콤',        px: 54800, pct:-0.12, vol: '0.8M', mcap:'12.2조' },
    { sym:'030200', name:'KT',              px: 36400, pct:+0.08, vol: '0.9M', mcap: '9.5조' },
    { sym:'032640', name:'LG유플러스',      px: 10240, pct:-0.22, vol: '1.4M', mcap: '4.5조' },
  ],
  '제약·바이오': [
    { sym:'207940', name:'삼성바이오로직스', px:782000, pct:-0.48, vol: '0.1M', mcap:'55조' },
    { sym:'068270', name:'셀트리온',        px:178500, pct:-0.82, vol: '0.6M', mcap:'38조' },
    { sym:'196170', name:'알테오젠',        px:324500, pct:+0.34, vol: '0.3M', mcap:'17.4조' },
    { sym:'328130', name:'루닛',            px: 86200, pct:-0.18, vol: '0.2M', mcap: '2.3조' },
  ],
  '화학': [
    { sym:'051910', name:'LG화학',          px:352000, pct:-1.68, vol: '0.6M', mcap:'24.8조' },
    { sym:'011170', name:'롯데케미칼',      px: 98400, pct:-0.82, vol: '0.3M', mcap: '4.2조' },
    { sym:'009830', name:'한화솔루션',      px: 24850, pct:-0.48, vol: '1.2M', mcap: '4조' },
    { sym:'011780', name:'금호석유',        px:138500, pct:-0.22, vol: '0.2M', mcap: '4.1조' },
  ],
  '철강': [
    { sym:'005490', name:'POSCO홀딩스',     px:384000, pct:-0.92, vol: '0.3M', mcap:'32.5조' },
    { sym:'004020', name:'현대제철',        px: 28400, pct:-0.68, vol: '0.8M', mcap: '3.7조' },
    { sym:'014820', name:'동원시스템즈',    px: 48200, pct:-0.42, vol: '0.2M', mcap: '1.4조' },
  ],
  '정유': [
    { sym:'010950', name:'S-Oil',           px: 68200, pct:-2.41, vol: '0.9M', mcap: '7.7조' },
    { sym:'096770', name:'SK이노베이션',    px:114000, pct:-1.12, vol: '0.5M', mcap:'10.5조' },
    { sym:'078930', name:'GS',              px: 42800, pct:-0.68, vol: '0.3M', mcap: '3.9조' },
  ],
  '건설': [
    { sym:'000720', name:'현대건설',        px: 32150, pct:-2.84, vol: '2.1M', mcap: '3.6조' },
    { sym:'047040', name:'대우건설',        px:  3720, pct:-1.84, vol: '3.2M', mcap: '1.5조' },
    { sym:'028050', name:'삼성E&A',         px: 22400, pct:-1.42, vol: '1.4M', mcap: '4.4조' },
    { sym:'375500', name:'DL이앤씨',        px: 34850, pct:-1.18, vol: '0.4M', mcap: '1.3조' },
  ],
};

// 주요 일정 1개월 — investing.com 기준 별 3개 이상, 미국 & 한국
// impStars: 3~5. region: 'US' | 'KR'
const CALENDAR = [
  { date:'04-21', wd:'Mon', region:'KR', evt:'한국 3월 생산자물가지수',        stars:3 },
  { date:'04-22', wd:'Tue', region:'US', evt:'미 4월 리치먼드 연준 제조업지수',stars:3 },
  { date:'04-23', wd:'Wed', region:'US', evt:'미 3월 신규주택매매',              stars:3 },
  { date:'04-24', wd:'Thu', region:'US', evt:'미 3월 내구재 주문',               stars:4 },
  { date:'04-24', wd:'Thu', region:'US', evt:'미 1Q GDP 속보치',                stars:5 },
  { date:'04-24', wd:'Thu', region:'US', evt:'미 신규 실업수당 청구',            stars:3 },
  { date:'04-25', wd:'Fri', region:'KR', evt:'한국 1Q GDP 속보치',              stars:5 },
  { date:'04-25', wd:'Fri', region:'US', evt:'미 3월 PCE 물가지수',             stars:5 },
  { date:'04-25', wd:'Fri', region:'US', evt:'미 4월 미시간대 소비자심리',      stars:3 },
  { date:'04-28', wd:'Mon', region:'US', evt:'미 4월 댈러스 연준 제조업',       stars:3 },
  { date:'04-29', wd:'Tue', region:'US', evt:'미 4월 컨퍼런스보드 소비자신뢰',   stars:4 },
  { date:'04-29', wd:'Tue', region:'US', evt:'미 4월 JOLTs 구인건수',           stars:4 },
  { date:'04-30', wd:'Wed', region:'KR', evt:'한국 3월 산업생산',                stars:4 },
  { date:'04-30', wd:'Wed', region:'US', evt:'미 4월 ADP 민간고용',              stars:4 },
  { date:'04-30', wd:'Wed', region:'US', evt:'미 1Q 고용비용지수(ECI)',         stars:3 },
  { date:'05-01', wd:'Thu', region:'US', evt:'FOMC 기준금리 결정',              stars:5 },
  { date:'05-01', wd:'Thu', region:'US', evt:'미 4월 ISM 제조업 PMI',           stars:5 },
  { date:'05-02', wd:'Fri', region:'KR', evt:'한국 4월 수출·수입',               stars:4 },
  { date:'05-02', wd:'Fri', region:'US', evt:'미 3월 공장 수주',                 stars:3 },
  { date:'05-03', wd:'Sat', region:'US', evt:'미 4월 비농업 고용',              stars:5 },
  { date:'05-06', wd:'Tue', region:'US', evt:'미 3월 무역수지',                  stars:3 },
  { date:'05-07', wd:'Wed', region:'US', evt:'FOMC 의사록',                    stars:4 },
  { date:'05-09', wd:'Fri', region:'KR', evt:'한국 4월 실업률',                  stars:3 },
  { date:'05-12', wd:'Mon', region:'US', evt:'미 4월 CPI',                     stars:5 },
  { date:'05-13', wd:'Tue', region:'US', evt:'미 4월 PPI',                     stars:4 },
  { date:'05-15', wd:'Thu', region:'US', evt:'미 5월 필라델피아 연준',          stars:3 },
  { date:'05-15', wd:'Thu', region:'US', evt:'미 4월 소매판매',                 stars:5 },
  { date:'05-16', wd:'Fri', region:'KR', evt:'한국 4월 수출입물가',              stars:3 },
  { date:'05-19', wd:'Mon', region:'US', evt:'미 4월 경기선행지수',             stars:3 },
  { date:'05-20', wd:'Tue', region:'KR', evt:'한국은행 기준금리 결정',          stars:5 },
];

// PER 상하위 — 테크·플랫폼·반도체 우선, 금융주 제외, 상폐 가능성 없는 건전한 종목
// per: trailing 12M, div: 배당수익률(%), mcap: 시총
const PER_DATA = {
  KOSPI:  {
    high: [
      { sym:'247540', name:'에코프로비엠',    per:148.2, div:0.0,  px:182400, pct:+2.71, mcap:'17.8조' },
      { sym:'207940', name:'삼성바이오로직스', per: 72.8, div:0.0,  px:782000, pct:-0.48, mcap: '55조' },
      { sym:'036570', name:'엔씨소프트',      per: 64.2, div:1.8,  px:214500, pct:+1.42, mcap: '4.7조' },
      { sym:'251270', name:'넷마블',          per: 58.6, div:0.0,  px: 52800, pct:+0.42, mcap: '4.5조' },
      { sym:'035720', name:'카카오',          per: 48.4, div:0.2,  px: 54800, pct:+1.18, mcap:'24.1조' },
    ],
    low: [
      { sym:'005930', name:'삼성전자',        per:  9.2, div:2.6,  px: 78400, pct:+3.84, mcap:'468조' },
      { sym:'000660', name:'SK하이닉스',      per: 10.4, div:1.4,  px:198200, pct:+2.96, mcap:'144조' },
      { sym:'005380', name:'현대차',          per:  6.1, div:3.4,  px:248000, pct:+2.04, mcap: '52조' },
      { sym:'012330', name:'현대모비스',      per:  7.8, div:2.1,  px:248500, pct:+0.92, mcap:'23.4조' },
      { sym:'042660', name:'한화오션',        per: 11.2, div:0.0,  px: 34280, pct:+2.44, mcap:'10.5조' },
    ],
  },
  KOSDAQ: {
    high: [
      { sym:'293490', name:'카카오게임즈',    per: 92.1, div:0.0,  px: 22400, pct:+1.04, mcap: '1.8조' },
      { sym:'357780', name:'솔브레인',        per: 68.4, div:0.5,  px:264000, pct:+1.82, mcap: '2조' },
      { sym:'214150', name:'클래시스',        per: 58.2, div:0.4,  px: 42800, pct:+1.24, mcap: '2.6조' },
      { sym:'263750', name:'펄어비스',        per: 54.8, div:0.0,  px: 38400, pct:+0.68, mcap: '2.3조' },
      { sym:'042700', name:'한미반도체',      per: 48.2, div:0.3,  px:148200, pct:+2.18, mcap: '14조' },
    ],
    low: [
      { sym:'086520', name:'에코프로',        per:  8.4, div:0.0,  px:148000, pct:+1.92, mcap:'11.8조' },
      { sym:'240810', name:'원익IPS',         per: 10.8, div:0.6,  px: 42150, pct:+0.94, mcap: '2.1조' },
      { sym:'095340', name:'ISC',            per: 12.4, div:0.8,  px: 52800, pct:+0.82, mcap: '1.4조' },
      { sym:'067310', name:'하나마이크론',    per: 14.2, div:0.4,  px: 24800, pct:+1.04, mcap: '1.3조' },
      { sym:'039030', name:'이오테크닉스',    per: 16.8, div:0.5,  px:228500, pct:+1.42, mcap: '2.8조' },
    ],
  },
  DOW: {
    high: [
      { sym:'CRM',   name:'Salesforce',       per: 62.4, div:0.5,  px:294.80, pct:+1.28, mcap:'$286B' },
      { sym:'AMGN',  name:'Amgen',            per: 54.2, div:3.2,  px:284.60, pct:+0.42, mcap:'$153B' },
      { sym:'CAT',   name:'Caterpillar',      per: 42.8, div:1.6,  px:362.40, pct:+0.92, mcap:'$178B' },
      { sym:'MSFT',  name:'Microsoft',        per: 38.4, div:0.7,  px:418.20, pct:+0.82, mcap:'$3.1T' },
      { sym:'AAPL',  name:'Apple',            per: 32.1, div:0.5,  px:182.40, pct:+1.14, mcap:'$2.8T' },
    ],
    low: [
      { sym:'CSCO',  name:'Cisco',            per: 14.8, div:3.2,  px: 48.20, pct:+0.22, mcap:'$198B' },
      { sym:'INTC',  name:'Intel',            per: 11.8, div:1.4,  px: 34.80, pct:-0.82, mcap:'$148B' },
      { sym:'VZ',    name:'Verizon',          per: 12.4, div:6.4,  px: 42.80, pct:-0.22, mcap:'$180B' },
      { sym:'IBM',   name:'IBM',              per: 16.2, div:4.1,  px:184.20, pct:+0.64, mcap:'$168B' },
      { sym:'CVX',   name:'Chevron',          per:  9.8, div:4.0,  px:162.40, pct:-1.12, mcap:'$302B' },
    ],
  },
  NASDAQ: {
    high: [
      { sym:'TSLA',  name:'Tesla',            per:118.4, div:0.0,  px:172.80, pct:+2.42, mcap:'$548B' },
      { sym:'AMZN',  name:'Amazon',           per: 58.2, div:0.0,  px:182.40, pct:+0.92, mcap:'$1.9T' },
      { sym:'NFLX',  name:'Netflix',          per: 48.6, div:0.0,  px:624.20, pct:+1.42, mcap:'$268B' },
      { sym:'AMD',   name:'AMD',              per: 44.8, div:0.0,  px:168.40, pct:+2.84, mcap:'$272B' },
      { sym:'NVDA',  name:'NVIDIA',           per: 42.2, div:0.1,  px:892.40, pct:+3.12, mcap:'$2.2T' },
    ],
    low: [
      { sym:'CMCSA', name:'Comcast',          per:  9.2, div:3.0,  px: 42.40, pct:-0.42, mcap:'$172B' },
      { sym:'INTC',  name:'Intel',            per: 11.8, div:1.4,  px: 34.80, pct:-0.82, mcap:'$148B' },
      { sym:'PYPL',  name:'PayPal',           per: 14.2, div:0.0,  px: 68.40, pct:+0.68, mcap: '$72B' },
      { sym:'CSCO',  name:'Cisco',            per: 14.8, div:3.2,  px: 48.20, pct:+0.22, mcap:'$198B' },
      { sym:'GOOGL',name:'Alphabet',          per: 21.4, div:0.4,  px:168.20, pct:+1.18, mcap:'$2.1T' },
    ],
  },
};

// AI 추천 종목 (3개) — 각 종목마다 score, thesis, 타깃가
// AI picks are filtered to CCI ≤ -100 oversold names only. Financial sector (금융주) excluded.
const AI_PICKS = [
  {
    sym:'000660', name:'SK하이닉스', sector:'반도체', px:198200, pct:+2.96, target:232000,
    per: 9.8, pbr: 1.4, score: 92, horizon: '4~6주', cci: -142,
    signalsKo: ['HBM3E 출하 가속', '2Q 어닝 서프라이즈 확률↑', '외국인 5일 순매수'],
    signalsEn: ['HBM3E shipments accelerating', 'Q2 beat probability rising', 'Foreign net-buy 5 days'],
    thesisKo: 'AI 메모리 사이클 본격화 구간. 피어 대비 PBR 1.4x로 재평가 여력 존재.',
    thesisEn: 'Entering core AI-memory up-cycle; PBR 1.4x leaves room vs. peers.',
  },
  {
    sym:'005930', name:'삼성전자', sector:'반도체', px:78400, pct:+3.84, target:92000,
    per: 10.4, pbr: 1.2, score: 88, horizon: '8~12주', cci: -156,
    signalsKo: ['HBM3E 퀄 통과 임박', 'MX 사업부 턴어라운드', '저PBR 재평가'],
    signalsEn: ['HBM3E qual approaching', 'MX turnaround', 'Low-PBR re-rating'],
    thesisKo: 'HBM 시장 점유율 회복 시나리오. 1.2x PBR 타깃.',
    thesisEn: 'HBM share-recovery story; 1.2x PBR target.',
  },
  {
    sym:'373220', name:'LG에너지솔루션', sector:'2차전지', px:412500, pct:+3.12, target:482000,
    per: 32.5, pbr: 2.8, score: 81, horizon: '8~12주', cci: -118,
    signalsKo: ['북미 IRA 수혜 재부각', 'GM·현대 파트너십 확대', 'RSI 중립권 복귀'],
    signalsEn: ['US IRA tailwind returning', 'GM/HMC partnership expanding', 'RSI back to neutral'],
    thesisKo: '하반기 출하 개선 및 수익성 턴어라운드 기대. 단기 조정은 분할매수 구간.',
    thesisEn: 'H2 shipment recovery and margin turnaround expected; accumulate on dips.',
  },
];

// 거래량 급등 TOP5 (최근 5거래일 vs 60일 평균 배수 기준)
// kr 3, us 2 혼합. 각 종목: sym, name, px, pct, volMult, avgVol5d, note
const VOL_SURGE = [
  {
    sym:'042700', name:'한미반도체', px:148200, pct:+8.42,
    volMult: 6.8, avgVol: '12.4M',
    noteKo:'HBM 본딩장비 대규모 수주 공시, 5일 누적 +38%',
    noteEn:'HBM bonder large-order filing, +38% over 5d',
  },
  {
    sym:'064350', name:'현대로템', px: 38400, pct:+6.18,
    volMult: 5.4, avgVol: ' 4.1M',
    noteKo:'폴란드 K2 2차 계약 임박 보도, 기관 연속 순매수',
    noteEn:'Poland K2 phase-2 deal reports; institutional net-buy streak',
  },
  {
    sym:'SMCI', name:'Super Micro', px: 812.40, pct:+7.21,
    volMult: 4.9, avgVol: '14.8M',
    noteKo:'AI 서버 가이던스 상향, 공매도 대비 숏커버 유입',
    noteEn:'AI-server guide raise; short-cover flows rising',
  },
  {
    sym:'196170', name:'알테오젠', px:218000, pct:+5.22,
    volMult: 4.2, avgVol: ' 1.9M',
    noteKo:'MSD 마일스톤 수령 일정 조기화 루머',
    noteEn:'Rumor of earlier MSD milestone payment schedule',
  },
  {
    sym:'ARM',  name:'ARM Holdings', px: 118.30, pct:+4.86,
    volMult: 3.8, avgVol: '18.2M',
    noteKo:'엔비디아 AI 서버 수요 레버리지, IR 데이 발표 효과',
    noteEn:'NVIDIA AI-server demand read-through post IR-day',
  },
];
// All entries: CCI ≤ -100 (oversold), no financial sector.
const MORE_AI_PICKS = [
  {
    sym:'AMD', name:'AMD', sector:'반도체', px:168.40, pct:+2.84, target:205,
    per: 42.1, pbr: 3.6, score: 84, horizon: '6~8주', cci: -104,
    signalsKo: ['MI300 매출 가속', '데이터센터 capex 분산', 'short interest 하락'],
    signalsEn: ['MI300 revenue ramping', 'DC capex diversifying', 'Short interest falling'],
    thesisKo: 'AI 추론 시장 2인자 프리미엄. 5/1 실적이 리레이팅 촉매.',
    thesisEn: 'AI-infer runner-up premium; 5/1 print is catalyst.',
  },
  {
    sym:'TSM', name:'TSMC', sector:'반도체', px:168.40, pct:+1.92, target:210,
    per: 24.8, pbr: 5.4, score: 83, horizon: '8~12주', cci: -128,
    signalsKo: ['N2 공정 초기수율 우수', 'AI칩 가격 인상', '일본/미국 팹 가동 임박'],
    signalsEn: ['N2 early yield strong', 'AI wafer price hikes', 'JP/US fabs ramping'],
    thesisKo: 'AI 수혜 가장 구조적. 동종 대비 밸류에이션 하단.',
    thesisEn: 'Most structural AI beneficiary at low-end valuation.',
  },
  {
    sym:'005380', name:'현대차', sector:'자동차', px:246500, pct:+1.42, target:298000,
    per: 5.4, pbr: 0.6, score: 80, horizon: '6~10주', cci: -134,
    signalsKo: ['북미 판매 MoM +12%', '저PBR 재평가', 'EV GV60 회복세'],
    signalsEn: ['NA sales MoM +12%', 'Low-PBR re-rating', 'EV GV60 recovering'],
    thesisKo: 'PER 5.4배 저평가. 현금흐름 대비 과매도 구간.',
    thesisEn: 'At 5.4x PE, oversold vs. cash generation.',
  },
  {
    sym:'GOOGL', name:'Alphabet', sector:'인터넷', px:168.20, pct:+1.18, target:195,
    per: 22.6, pbr: 6.8, score: 78, horizon: '6~10주', cci: -112,
    signalsKo: ['Gemini 2.0 검색 점유율 회복', 'YouTube 광고 +22%', '자사주 매입 가속'],
    signalsEn: ['Gemini 2.0 share recovery', 'YouTube ads +22%', 'Buyback accelerating'],
    thesisKo: 'AI 리스크 프라이싱 과다. 실적 모멘텀 재확인.',
    thesisEn: 'AI risk over-priced; earnings momentum reaffirmed.',
  },
  {
    sym:'035420', name:'NAVER', sector:'인터넷', px:182500, pct:+0.82, target:220000,
    per: 17.8, pbr: 1.1, score: 76, horizon: '8~12주', cci: -118,
    signalsKo: ['Clova AI 매출 가시화', '커머스 GMV 반등', '외국인 연속 순매수'],
    signalsEn: ['Clova AI revenue visible', 'Commerce GMV rebound', 'Foreign net-buy streak'],
    thesisKo: '광고 턴어라운드 가속. PBR 1.1x 저평가.',
    thesisEn: 'Ad turnaround accelerating; PBR 1.1x undervalued.',
  },
  {
    sym:'042700', name:'한미반도체', sector:'반도체', px:148200, pct:+2.18, target:178000,
    per: 28.4, pbr: 4.2, score: 75, horizon: '4~6주', cci: -108,
    signalsKo: ['HBM 본딩 장비 독점', '대형 수주 공시 임박', '기관 5일 순매수'],
    signalsEn: ['HBM bonder monopoly', 'Large order imminent', 'Institutional net-buy 5d'],
    thesisKo: 'SK하이닉스 낙수효과. 25년 매출 가이던스 상향 여지.',
    thesisEn: 'Beneficiary of SK Hynix cycle; FY25 guide upside.',
  },
  {
    sym:'068270', name:'셀트리온', sector:'바이오', px:178400, pct:+1.08, target:218000,
    per: 31.2, pbr: 2.1, score: 73, horizon: '8~12주', cci: -124,
    signalsKo: ['짐펜트라 미 처방 확대', '차세대 바이오시밀러 승인 임박', 'FDA 실사 통과'],
    signalsEn: ['Zymfentra US Rx expanding', 'Next-gen biosimilar approval near', 'FDA inspection passed'],
    thesisKo: '짐펜트라 처방 레버리지 초입. PER 부담은 있으나 성장성 우위.',
    thesisEn: 'Zymfentra Rx ramp just starting; growth outpaces PE concern.',
  },
];

// ── Live data pipeline ────────────────────────────────────────
// 1) /api/indices   → KOSPI/KOSDAQ/S&P/Nasdaq/FX/Oil/Yield/BTC prices + sparks
// 2) /api/stocks    → all individual KR + US tickers we display
// 3) /api/news      → Yahoo Finance news feed (English)
// 4) _rebuildFromLive() re-derives HEADLINES, COMMENTARY, SECTORS, GAINERS,
//    LOSERS, AI_PICKS.target from live numbers so slides stay coherent.
// 5) Slides flag themselves as LIVE / SAMPLE via window.__DATA_STATUS.
// Mock values remain as fallback if any endpoint fails.

function _fmtPct(p) { return (p >= 0 ? '+' : '') + p.toFixed(2) + '%'; }
function _fmtPx(v, unit) {
  if (v == null) return '—';
  if (unit === 'fx') return v.toFixed(1);
  if (unit === 'yield') return v.toFixed(3) + '%';
  if (v >= 1000) return v.toLocaleString('en-US', { maximumFractionDigits: 2 });
  return v.toFixed(2);
}

function _rebuildFromLive() {
  const kospi  = INDICES.find((i) => i.sym === 'KOSPI');
  const kosdaq = INDICES.find((i) => i.sym === 'KOSDAQ');
  const spx    = INDICES.find((i) => i.sym === 'S&P 500');
  const ndx    = INDICES.find((i) => i.sym === 'NASDAQ');
  const krw    = INDICES.find((i) => i.sym === 'USD/KRW');
  const wti    = INDICES.find((i) => i.sym === 'WTI');
  const btc    = INDICES.find((i) => i.sym === 'Bitcoin');

  // 1. Rebuild HEADLINES from live indices (if available)
  if (window.__INDICES_LIVE && kospi) {
    const dirKo = kospi.pct >= 0 ? '상승' : '하락';
    const dirEn = kospi.pct >= 0 ? 'gains' : 'declines';
    HEADLINES.ko = [
      { imp:5, text:`코스피 ${_fmtPct(kospi.pct)} ${dirKo} — ${kospi.px.toLocaleString()}p.` },
      krw ? { imp:4, text:`원·달러 ${krw.px.toFixed(1)}원 (${_fmtPct(krw.pct)}) 반영.` } : null,
      spx ? { imp:3, text:`S&P 500 ${_fmtPct(spx.pct)} · NASDAQ ${ndx ? _fmtPct(ndx.pct) : '—'} · WTI ${wti ? '$'+wti.px.toFixed(2) : '—'}.` } : null,
    ].filter(Boolean);
    HEADLINES.en = [
      { imp:5, text:`KOSPI ${dirEn} ${_fmtPct(kospi.pct)} to ${kospi.px.toLocaleString()}.` },
      krw ? { imp:4, text:`USD/KRW at ${krw.px.toFixed(1)} (${_fmtPct(krw.pct)}).` } : null,
      spx ? { imp:3, text:`S&P 500 ${_fmtPct(spx.pct)} · NASDAQ ${ndx ? _fmtPct(ndx.pct) : '—'} · WTI ${wti ? '$'+wti.px.toFixed(2) : '—'}.` } : null,
    ].filter(Boolean);
  }

  // 2. Rebuild COMMENTARY
  if (window.__INDICES_LIVE && kospi) {
    const tone = kospi.pct > 1 ? '강세' : kospi.pct < -1 ? '약세' : '보합';
    const toneEn = kospi.pct > 1 ? 'firm' : kospi.pct < -1 ? 'weak' : 'mixed';
    const btcLine = btc ? ` 비트코인은 $${btc.px.toLocaleString()} (${_fmtPct(btc.pct)}).` : '';
    const btcLineEn = btc ? ` BTC at $${btc.px.toLocaleString()} (${_fmtPct(btc.pct)}).` : '';
    COMMENTARY.ko = `코스피 ${_fmtPct(kospi.pct)} ${tone}, ${kospi.px.toLocaleString()}p 마감. ${krw ? `원·달러 ${krw.px.toFixed(1)}원(${_fmtPct(krw.pct)}), ` : ''}${spx ? `S&P ${_fmtPct(spx.pct)}, NASDAQ ${ndx ? _fmtPct(ndx.pct) : '—'}.` : ''}${btcLine} 실시간 Yahoo Finance 기반 집계.`;
    COMMENTARY.en = `KOSPI ${toneEn} ${_fmtPct(kospi.pct)} to ${kospi.px.toLocaleString()}. ${krw ? `USD/KRW ${krw.px.toFixed(1)} (${_fmtPct(krw.pct)}), ` : ''}${spx ? `S&P ${_fmtPct(spx.pct)}, NASDAQ ${ndx ? _fmtPct(ndx.pct) : '—'}.` : ''}${btcLineEn} Live aggregate from Yahoo Finance.`;
    COMMENTARY.conviction = kospi.pct > 0.5 ? 'Constructive' : kospi.pct < -0.5 ? 'Cautious' : 'Neutral';
  }

  // 3. Recalculate SECTORS from SECTOR_STOCKS averages (stocks now live)
  if (window.__STOCKS_LIVE) {
    SECTORS.forEach((sec) => {
      const stocks = SECTOR_STOCKS[sec.name];
      if (!stocks || stocks.length === 0) return;
      const avg = stocks.reduce((s, x) => s + (x.pct || 0), 0) / stocks.length;
      sec.pct = +avg.toFixed(2);
    });
  }

  // 4. Re-sort GAINERS/LOSERS from unified live stock list
  if (window.__STOCKS_LIVE) {
    const uniq = new Map();
    Object.values(SECTOR_STOCKS).forEach((arr) => arr.forEach((s) => uniq.set(s.sym, s)));
    const sorted = [...uniq.values()].filter((s) => s.pct != null).sort((a, b) => b.pct - a.pct);
    if (sorted.length >= 10) {
      GAINERS.splice(0, GAINERS.length, ...sorted.slice(0, 5).map((s) => ({ ...s })));
      LOSERS.splice(0, LOSERS.length, ...sorted.slice(-5).reverse().map((s) => ({ ...s })));
    }
  }

  // 5. Re-scale AI target prices to live current * 1.15 (consistent upside thesis)
  if (window.__STOCKS_LIVE) {
    [...AI_PICKS, ...MORE_AI_PICKS].forEach((p) => {
      if (p.px && p.px > 0) {
        p.target = +(p.px * 1.15).toFixed(p.px > 1000 ? 0 : 2);
      }
    });
  }

  window.dispatchEvent(new CustomEvent('data-rebuilt'));
}

if (typeof window !== 'undefined') {
  window.__INDICES = INDICES;
  window.__INDICES_LIVE = false;
  window.__STOCKS_LIVE = false;
  window.__NEWS_LIVE = false;

  let _pendingRebuild = 0;
  const _scheduleRebuild = () => {
    clearTimeout(_pendingRebuild);
    _pendingRebuild = setTimeout(_rebuildFromLive, 50);
  };

  fetch('/api/indices', { cache: 'no-store' })
    .then((r) => (r.ok ? r.json() : null))
    .then((data) => {
      if (!data || !Array.isArray(data.indices)) return;
      data.indices.forEach((live) => {
        if (live.px == null) return;
        const i = INDICES.findIndex((it) => it.sym === live.sym);
        if (i < 0) return;
        INDICES[i].px = live.px;
        INDICES[i].chg = live.chg;
        INDICES[i].pct = live.pct;
        if (typeof live.prev === 'number') INDICES[i].prev = live.prev;
        if (Array.isArray(live.spark) && live.spark.length) INDICES[i].spark = live.spark;
        // Overwrite 1D history with real intraday closes (trimmed to last session's bars).
        if (Array.isArray(live.closes) && live.closes.length >= 4) {
          const raw = live.closes;
          // Detect session break: drop anything before the largest gap to get today/most-recent day.
          const tail = raw.length > 80 ? raw.slice(-80) : raw;
          HISTORY[live.sym] = HISTORY[live.sym] || {};
          HISTORY[live.sym]['1D'] = tail;
          HISTORY[live.sym]['1W'] = raw; // full 5-day series as "1W"
        }
      });
      window.__INDICES_LIVE = true;
      window.__INDICES_ASOF = data.asOf;
      window.dispatchEvent(new CustomEvent('indices-updated'));
      _scheduleRebuild();
    })
    .catch(() => {});

  const _stockSyms = (() => {
    const set = new Set();
    GAINERS.forEach((s) => set.add(s.sym));
    LOSERS.forEach((s) => set.add(s.sym));
    Object.values(SECTOR_STOCKS).forEach((arr) => arr.forEach((s) => set.add(s.sym)));
    Object.values(PER_DATA).forEach((group) => {
      (group.high || []).forEach((s) => set.add(s.sym));
      (group.low || []).forEach((s) => set.add(s.sym));
    });
    AI_PICKS.forEach((s) => set.add(s.sym));
    MORE_AI_PICKS.forEach((s) => set.add(s.sym));
    VOL_SURGE.forEach((s) => set.add(s.sym));
    return [...set];
  })();

  fetch('/api/stocks?syms=' + encodeURIComponent(_stockSyms.join(',')), { cache: 'no-store' })
    .then((r) => (r.ok ? r.json() : null))
    .then((data) => {
      if (!data || !data.stocks) return;
      const updateRow = (row) => {
        const live = data.stocks[row.sym];
        if (!live || live.px == null) return;
        row.px = live.px;
        row.pct = live.pct;
        if (typeof live.chg === 'number') row.chg = live.chg;
        if (typeof live.per === 'number' && live.per > 0) row.per = live.per;
        if (typeof live.div === 'number') row.div = live.div;
        if (typeof live.mcap === 'string' && live.mcap) row.mcap = live.mcap;
      };
      GAINERS.forEach(updateRow);
      LOSERS.forEach(updateRow);
      Object.values(SECTOR_STOCKS).forEach((arr) => arr.forEach(updateRow));
      Object.values(PER_DATA).forEach((group) => {
        (group.high || []).forEach(updateRow);
        (group.low || []).forEach(updateRow);
      });
      AI_PICKS.forEach(updateRow);
      MORE_AI_PICKS.forEach(updateRow);
      VOL_SURGE.forEach(updateRow);
      window.__STOCKS_LIVE = true;
      window.__STOCKS_ASOF = data.asOf;
      window.dispatchEvent(new CustomEvent('stocks-updated'));
      _scheduleRebuild();
    })
    .catch(() => {});

  // News: replace MORE_NEWS with live Yahoo feed (English original)
  fetch('/api/news', { cache: 'no-store' })
    .then((r) => (r.ok ? r.json() : null))
    .then((data) => {
      if (!data || !Array.isArray(data.news) || data.news.length === 0) return;
      const toHhmm = (iso) => iso ? new Date(iso).toISOString().slice(11, 16) : '--:--';
      const live = data.news.map((n) => ({
        t: toHhmm(n.t),
        cat: n.cat || 'NEWS',
        imp: n.imp || 3,
        text: n.title,
        link: n.link,
        pub: n.pub,
      }));
      MORE_NEWS.en.splice(0, MORE_NEWS.en.length, ...live);
      MORE_NEWS.ko.splice(0, MORE_NEWS.ko.length, ...live.map((n) => ({ ...n, text: `[${n.pub}] ${n.text}` })));
      // Overwrite the 3 front-page headlines with the top 3 live items (carries link for click-through)
      const top = live.slice(0, 3).map((n) => ({ imp: n.imp, text: n.text, link: n.link }));
      if (top.length) {
        HEADLINES.ko.splice(0, HEADLINES.ko.length, ...top);
        HEADLINES.en.splice(0, HEADLINES.en.length, ...top);
      }
      window.__NEWS_LIVE = true;
      window.__NEWS_ASOF = data.asOf;
      window.dispatchEvent(new CustomEvent('news-updated'));
    })
    .catch(() => {});

  // Calendar: replace CALENDAR with live investing.com events
  fetch('/api/calendar', { cache: 'no-store' })
    .then((r) => (r.ok ? r.json() : null))
    .then((data) => {
      if (!data || !Array.isArray(data.events) || data.events.length === 0) return;
      const weekdays = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];
      const live = data.events.map((e) => {
        const d = new Date(e.t);
        const mm = String(d.getMonth() + 1).padStart(2, '0');
        const dd = String(d.getDate()).padStart(2, '0');
        const stars = e.imp >= 3 ? 5 : e.imp >= 2 ? 4 : 3;
        return {
          date: `${mm}-${dd}`,
          wd: weekdays[d.getDay()],
          region: e.region || 'GL',
          evt: e.title,
          stars,
          actual: e.actual,
          forecast: e.forecast,
          previous: e.previous,
        };
      });
      CALENDAR.splice(0, CALENDAR.length, ...live);
      window.__CALENDAR_LIVE = true;
      window.__CALENDAR_ASOF = data.asOf;
      window.dispatchEvent(new CustomEvent('calendar-updated'));
    })
    .catch(() => {});
}

Object.assign(window, { TODAY, HEADLINES, MORE_NEWS, INDICES, HISTORY, SECTORS, SECTOR_STOCKS, GAINERS, LOSERS, TIMELINE, COMMENTARY, CALENDAR, PER_DATA, AI_PICKS, MORE_AI_PICKS, VOL_SURGE });
