/* --- src/screens-dashboard.jsx --- */
// Presentation-grade Dashboard — "관제센터" view
// Replaces DashboardScreen in screens-1.jsx
const { useState: useStateD, useEffect: useEffectD } = React;

function DashboardScreen({ go }){
  const [region, setRegion] = useStateD('전체');
  const [type, setType] = useStateD('전체');
  const [priorityFilter, setPriorityFilter] = useStateD('전체');
  const [now, setNow] = useStateD(new Date('2026-04-30T23:48:00'));
  const [day5Metrics, setDay5Metrics] = useStateD(RSData.DAY5_DEFAULT_METRICS);

  useEffectD(()=>{
    const id = setInterval(()=> setNow(new Date(Date.now())), 30000);
    return ()=> clearInterval(id);
  },[]);
  useEffectD(() => {
    let alive = true;
    RSData.loadDay5Metrics()
      .then((metrics) => { if (alive) setDay5Metrics(metrics); })
      .catch(() => { if (alive) setDay5Metrics({ ...RSData.DAY5_DEFAULT_METRICS, status:'error' }); });
    return () => { alive = false; };
  }, []);

  const t = now;
  const ts = `${t.getFullYear()}.${String(t.getMonth()+1).padStart(2,'0')}.${String(t.getDate()).padStart(2,'0')} ${String(t.getHours()).padStart(2,'0')}:${String(t.getMinutes()).padStart(2,'0')}:${String(t.getSeconds()).padStart(2,'0')}`;
  const m = day5Metrics;
  const liveTrend = RSData.TREND.map((item, idx, arr) => {
    const p = (idx + 1) / arr.length;
    return {
      ...item,
      total: Math.max(1, Math.round(m.sourceTotal * (0.64 + p * 0.36))),
      residual: Math.max(1, Math.round(m.totalAClassificationCandidates * (0.50 + p * 0.50))),
      shadow: Math.max(1, Math.round(m.highAnomalyCount * (0.45 + p * 0.55)))
    };
  });
  const kpiItems = [
    { tone:'amber', icon:'shield', label:'정비 검토 권고 자치법규', value:m.flaggedOrdinances, delta:`+${m.flaggedOrdinances}`, share:m.sampleSize ? Number((m.flaggedOrdinances / m.sampleSize * 100).toFixed(1)) : null, sub:'본문 점검에서 정비 신호 발견', kpiKey:'flagged-ordinances' },
    { tone:'amber', icon:'layers', label:'명시적 차이 신호', value:m.totalAClassificationCandidates, delta:`+${m.aRuleSignals}`, share:null, sub:'숫자·기간·권한자·폐지·시행일', kpiKey:'rule-signals' },
    { tone:'teal', icon:'check', label:'경과조치·정비 제외 자치법규', value:m.bClassificationOrdinances, delta:`+${m.bRuleSignals}`, share:m.sampleSize ? Number((m.bClassificationOrdinances / m.sampleSize * 100).toFixed(1)) : null, sub:'의도적 존치로 분리', kpiKey:'exempt-ordinances' },
    { tone:'steel', icon:'building', label:'건축법 영향 자치법규', value:m.uniqueOrdinances, delta:`${m.sourceTotal.toLocaleString()} 연계`, share:null, sub:'법제처 ELIS 실측', kpiKey:'linked-ordinances' },
    { tone:'steel', icon:'compare', label:'표준 표현에서 이탈 (보조 지표)', value:m.highAnomalyCount, delta:`${m.anomalyChunks} 청크`, share:m.anomalyOrdinances ? Number((m.highAnomalyCount / m.anomalyOrdinances * 100).toFixed(1)) : null, sub:'정렬용 참고만', kpiKey:'standard-deviation' },
    { tone:'teal', icon:'brain', label:'AI 검토 메모 생성', value:m.level4Reviews, delta:`+${m.level4Reviews}`, share:null, sub:'직접 비교 기반 자동 작성', kpiKey:'ai-review-memos' },
  ];
  const allPriorityItems = (m.reformPool && m.reformPool.length) ? m.reformPool : (m.topAnomalies || []);
  const priorityItems = priorityFilter === 'A'
    ? allPriorityItems.filter(r => r.grade === 'A' || r.source === 'direct-comparison' || r.source === 'policy-hunter')
    : priorityFilter === 'B'
      ? allPriorityItems.filter(r => r.grade === 'B' || (r.source !== 'direct-comparison' && r.source !== 'policy-hunter'))
      : allPriorityItems;
  const poolCounts = m.reformPoolCounts || { A: 0, APolicy: 0, ADirect: 0, B: 0, total: allPriorityItems.length };
  const openPriorityAnalysis = (item) => {
    try {
      const payload = {
        ordinanceId: item.ordinanceId,
        mst: item.mst,
        title: item.title,
        agency: item.agency,
        source: item.source || null,
        grade: item.grade || null
      };
      if (item.source === 'policy-hunter' && item.policyHunterItem) {
        payload.source = 'policyHunter';
        payload.policyHunterItem = item.policyHunterItem;
      } else if (item.source === 'policy-hunter') {
        payload.source = 'policyHunter';
        payload.localArticle = item.localArticle || null;
        payload.upperLawArticle = item.upperLawArticle || null;
        payload.upperValue = item.upperValue || null;
        payload.lowerValue = item.lowerValue || null;
        payload.policyHunterItem = {
          id: item.ordinanceId || item.mst,
          mst: item.mst,
          title: item.title,
          agency: item.agency,
          type: item.worstErrorType || '기간 불일치',
          localArticle: item.localArticle || null,
          upperLawArticle: item.upperLawArticle || null,
          upperValue: item.upperValue || null,
          lowerValue: item.lowerValue || null,
          aiReview: item.aiConfidence ? { source:'gemini', confidence:item.aiConfidence } : null
        };
      }
      sessionStorage.setItem('syncLaw.analysisOrdinance', JSON.stringify(payload));
    } catch(e) {}
    RSData.setCurrentCase('building');
    go('analysis');
  };

  return (
    <div id="screen-dashboard" data-screen-label="02 탐지 대시보드" style={{padding:'20px 28px 60px', maxWidth:1480}}>
      {/* Live data notice */}
      <div data-role="live-data-notice" style={{
        display:'inline-flex', alignItems:'center', gap:8, padding:'5px 12px',
        background:'#DBEEEA', border:'1px solid #A7D8CF', borderRadius:99,
        fontSize:11, color:'#155F53', fontWeight:600, marginBottom:12
      }}>
        <span style={{width:6, height:6, borderRadius:'50%', background:'#1F7A6B', boxShadow:'0 0 0 3px rgba(31,122,107,0.18)'}}/>
        법제처 API · 자치법규정보(ELIS) 실측 데이터 연결 · 최종 정비 판단은 담당 부서가 합니다
      </div>
      {/* ─────────── HERO BAND ─────────── */}
      <div style={{
        position:'relative',
        background:'linear-gradient(120deg, #0B2E5C 0%, #143A73 55%, #1E4D8C 100%)',
        borderRadius:14, padding:'26px 32px', color:'#fff', overflow:'hidden',
        marginBottom:16, boxShadow:'0 8px 24px rgba(11,46,92,0.18)'
      }}>
        {/* decorative grid */}
        <svg style={{position:'absolute', inset:0, width:'100%', height:'100%', opacity:0.16, pointerEvents:'none'}} viewBox="0 0 1400 220" preserveAspectRatio="none">
          <defs>
            <pattern id="dotGrid" x="0" y="0" width="22" height="22" patternUnits="userSpaceOnUse">
              <circle cx="1.2" cy="1.2" r="1.2" fill="#7DA9E6"/>
            </pattern>
          </defs>
          <rect width="100%" height="100%" fill="url(#dotGrid)"/>
          <circle cx="1180" cy="40"  r="160" stroke="#7DA9E6" strokeWidth="1" fill="none"/>
          <circle cx="1180" cy="40"  r="100" stroke="#7DA9E6" strokeWidth="1" fill="none"/>
          <circle cx="1180" cy="40"  r="50"  stroke="#5EE6B5" strokeWidth="1" fill="none"/>
        </svg>

        <div style={{position:'relative', display:'flex', alignItems:'flex-start', gap:32}}>
          <div style={{flex:1, minWidth:0}}>
            <div style={{
              display:'inline-flex', alignItems:'center', gap:10, padding:'5px 12px',
              background:'rgba(94,230,181,0.14)', borderRadius:99,
              fontSize:11, fontWeight:600, color:'#5EE6B5', marginBottom:14,
              border:'1px solid rgba(94,230,181,0.28)', whiteSpace:'nowrap'
            }}>
              <span style={{
                width:7, height:7, borderRadius:'50%', background:'#5EE6B5',
                boxShadow:'0 0 0 4px rgba(94,230,181,0.18)'
              }}/>
              범정부 규제 동기화 플랫폼 · LIVE
              <span className="mono" style={{opacity:.7, marginLeft:6}}>{ts}</span>
            </div>
            <div style={{fontSize:30, fontWeight:700, lineHeight:1.3, letterSpacing:'-0.02em', color:'#fff'}}>
              상위법 개정 효과의 <span style={{color:'#7DA9E6'}}>현장 도달 수준을</span><br/>
              <span style={{color:'#fff'}}>싱크Law율로 수치화합니다.</span>
            </div>
            <div style={{fontSize:13.5, opacity:.78, marginTop:12, maxWidth:680, lineHeight:1.7}}>
              상위법 → 행정규칙·고시 → 자치법규 → 민원서식·안내문 → 국민 제보까지
              규제의 동기화 수준을 점검하고, 정비 필요성 검토 리포트를 자동 생성합니다.
            </div>
          </div>

          {/* right pulse status */}
          <div style={{display:'flex', gap:10, position:'relative'}}>
            <SyncLawGauge value={m.syncLawRate}/>
            <PulseStat label="AI 검토 메모" value={m.level4Reviews} unit="건" highlight/>
          </div>
        </div>

        {/* Filter strip embedded in hero */}
        <div style={{
          position:'relative', marginTop:22, paddingTop:16,
          borderTop:'1px solid rgba(255,255,255,0.14)',
          display:'flex', alignItems:'center', gap:14, flexWrap:'wrap'
        }}>
          <div style={{display:'flex', alignItems:'center', gap:8, color:'rgba(255,255,255,0.65)', fontSize:11.5, fontWeight:600, letterSpacing:'0.04em'}}>
            <Icon name="filter" size={13}/> 필터
          </div>
          <DarkChips label="지역"     filterKey="region"   value={region} options={['전체','중앙','권역 A','권역 B','권역 D','권역 E','권역 C','권역 F','권역 G','권역 I','권역 J','권역 K','권역 L','권역 M','권역 N','권역 O','권역 P','권역 Q','권역 H']} onChange={setRegion}/>
          <DarkChips label="규제 유형" filterKey="risk-type" value={type}   options={['전체','하위규정','행정규칙','자치법규','민원서식','안내문','고시·공고','지침']} onChange={setType}/>
          <DarkChips label="기관 분류" filterKey="agency"   value="전체"   options={['전체','중앙행정기관','광역지자체','기초지자체','공공기관']} onChange={()=>{}}/>
          <div style={{flex:1}}/>
          <button data-action="export-report-csv" style={{...heroBtn(false), whiteSpace:'nowrap'}}><Icon name="download" size={13}/> 데이터 내보내기</button>
          <button data-action="generate-sync-law-report" style={{...heroBtn(true), whiteSpace:'nowrap'}} onClick={()=>go('insight')}><Icon name="spark" size={13}/> Sync Law 분석 리포트 생성</button>
        </div>
      </div>

      {/* ─────────── MAIN GRID: KPIs (left+center) | TOP10 (right) ─────────── */}
      <div style={{display:'grid', gridTemplateColumns:'1.85fr 1fr', gap:14, marginBottom:14}}>

        {/* LEFT: KPIs (7 cards) + alert ribbon */}
        <div style={{display:'grid', gap:14}}>

          {/* Hero KPI — 전체 탐지 건수 + sparkline (구 디자인 복원, 싱크Law율은 괄호 보조) */}
          <div data-sync-rate="average" style={{
            background:'#fff', border:'1px solid var(--line)', borderRadius:14,
            padding:'18px 20px', display:'grid', gridTemplateColumns:'1.4fr 1fr', gap:22,
            alignItems:'stretch', boxShadow:'var(--shadow-sm)'
          }}>
            {/* LEFT: count + sub-counts */}
            <div style={{display:'flex', flexDirection:'column', justifyContent:'space-between', minHeight:172}}>
              <div>
                <div style={{display:'flex', alignItems:'center', gap:8, marginBottom:6, flexWrap:'wrap'}}>
                  <span style={{width:8, height:8, borderRadius:2, background:'var(--navy)', flexShrink:0}}/>
                  <span style={{fontSize:12, fontWeight:600, color:'var(--ink-3)', letterSpacing:'0.02em', whiteSpace:'nowrap'}}>연계 조문 row</span>
                  <Badge tone="navy" size="sm">최근 12주</Badge>
                  {/* parenthetical sync-law badge */}
                  <span style={{fontSize:11, color:'var(--ink-4)', whiteSpace:'nowrap'}}>
                    (건축법 싱크Law율 <span className="mono" style={{color:'var(--ink-2)', fontWeight:700}}>{m.syncLawRate}%</span>
                    <span style={{margin:'0 4px', color:'var(--ink-4)'}}>·</span>
                    <span className="mono" style={{color:'var(--amber)', fontWeight:700}}>A {m.flaggedOrdinances}건</span>)
                  </span>
                </div>
                <div style={{display:'flex', alignItems:'baseline', gap:10}}>
                  <CountUp value={m.sourceTotal} style={{fontSize:40, fontWeight:700, color:'var(--ink)', letterSpacing:'-0.025em', lineHeight:1.05}}/>
                  <span style={{fontSize:14, color:'var(--ink-4)'}}>건</span>
                </div>
                <div style={{display:'flex', alignItems:'center', gap:10, marginTop:6, fontSize:12, flexWrap:'wrap'}}>
                  <span style={{
                    display:'inline-flex', alignItems:'center', gap:4,
                    color:'var(--teal)', fontWeight:700, padding:'2px 8px',
                    background:'var(--teal-soft)', borderRadius:99, whiteSpace:'nowrap'
                  }}>
                    <Icon name="arrow-up" size={11}/> +{m.totalAClassificationCandidates}
                  </span>
                  <span style={{color:'var(--ink-3)', whiteSpace:'nowrap'}}>AI가 본문까지 읽은 사례 <span className="mono" style={{color:'var(--ink-2)', fontWeight:600}}>{m.sampleSize}</span>건</span>
                </div>
              </div>
              {/* 3 institutional buckets */}
              <div style={{display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:10, paddingTop:12, borderTop:'1px dashed var(--line)'}}>
                {[
                  {l:'확인한 자치법규', v:m.uniqueOrdinances, tone:'#0B2E5C'},
                  {l:'본문 확인 사례',   v:m.sampleSize, tone:'#2E5FB0'},
                  {l:'AI 검토 메모', v: m.level4Reviews, tone:'#5B7C99'},
                ].map(s=>(
                  <div key={s.l} style={{minWidth:0}}>
                    <div style={{fontSize:10.5, color:'var(--ink-3)', whiteSpace:'nowrap', marginBottom:2}}>{s.l}</div>
                    <div style={{display:'flex', alignItems:'baseline', gap:3}}>
                      <span className="mono" style={{fontSize:17, fontWeight:700, color:s.tone, letterSpacing:'-0.01em'}}>{s.v.toLocaleString()}</span>
                      <span style={{fontSize:10, color:'var(--ink-4)'}}>건</span>
                    </div>
                  </div>
                ))}
              </div>
            </div>

            {/* RIGHT: trend chart fills the column */}
            <div style={{display:'flex', flexDirection:'column', minHeight:172}}>
              <div style={{display:'flex', justifyContent:'space-between', alignItems:'center', marginBottom:8}}>
                <span style={{fontSize:11, color:'var(--ink-3)', fontWeight:600}}>주별 누적 추이</span>
                <div style={{display:'flex', gap:10, fontSize:10.5, color:'var(--ink-3)'}}>
                  <LegendDot color="#2E5FB0" label="전체"/>
                  <LegendDot color="#C77A1B" label="잔존" dashed/>
                </div>
              </div>
              <div style={{flex:1, minHeight:0, position:'relative'}}>
                <AreaChart data={liveTrend} fill/>
              </div>
              <div style={{display:'flex', justifyContent:'space-between', fontSize:9.5, color:'var(--ink-4)', marginTop:6}}>
                {liveTrend.filter((_,i)=>i%3===0).map(t=> <span key={t.w}>{t.w}</span>)}
              </div>
            </div>
          </div>

          {/* 6 type KPIs */}
          <div style={{display:'grid', gridTemplateColumns:'repeat(3, 1fr)', gap:10}}>
            {kpiItems.map((item) => (
              <KPI key={item.kpiKey} {...item}/>
            ))}
          </div>

          {/* Recent upper-law alert ribbon */}
          <div style={{
            background:'#fff', border:'1px solid var(--line)', borderRadius:14, padding:'16px 18px',
            boxShadow:'var(--shadow-sm)'
          }}>
            <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:12}}>
              <div style={{display:'flex', alignItems:'center', gap:10}}>
                <span style={{
                  width:28, height:28, borderRadius:7, background:'#FBEFD9',
                  display:'flex', alignItems:'center', justifyContent:'center', color:'var(--amber)'
                }}><Icon name="bell" size={14}/></span>
                <div>
                  <div style={{fontSize:13.5, fontWeight:700, color:'var(--ink)'}}>최근 상위법 개정 감지</div>
                  <div style={{fontSize:11, color:'var(--ink-3)'}}>국가법령정보센터 5분 간격 수집 · 영향도 자동 계산</div>
                </div>
              </div>
              <Btn kind="ghost" size="sm" icon="arrow-right" style={{color:'var(--blue)'}} onClick={()=>go('upper')}>전체 알림</Btn>
            </div>
            <div style={{display:'grid', gridTemplateColumns:'repeat(5, 1fr)', gap:8}}>
              {RSData.RECENT_ALERTS.map((a,i)=>(
              <button key={i} data-action="select-sync-case" data-case-id={`UPPER-${i}`} data-law={a.law} onClick={()=>{RSData.setCurrentCaseByLaw(a.law); go('upper');}} style={{
                textAlign:'left', padding:'12px 12px', border:'1px solid var(--line)',
                borderRadius:9, background:'#FBFCFE', cursor:'pointer'
              }}
              onMouseEnter={e=>{e.currentTarget.style.borderColor='var(--blue)'; e.currentTarget.style.background='#fff';}}
              onMouseLeave={e=>{e.currentTarget.style.borderColor='var(--line)'; e.currentTarget.style.background='#FBFCFE';}}>
                <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:6}}>
                  <span className="mono" style={{fontSize:10, color:'var(--ink-4)'}}>{a.date}</span>
                  <span style={{
                    width:6, height:6, borderRadius:'50%',
                    background: a.severity==='high'?'#C77A1B': a.severity==='mid'?'#5B7C99':'#94A3B8'
                  }}/>
                </div>
                <div style={{fontSize:12.5, fontWeight:700, color:'var(--ink)', lineHeight:1.4, minHeight:34}}>{a.law}</div>
                <div style={{fontSize:10.5, color:'var(--ink-3)', marginTop:3, lineHeight:1.4}}>{a.change}</div>
                <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginTop:8, gap:6}}>
                  <div>
                    <span className="mono" style={{fontSize:13, fontWeight:700, color:'var(--navy)'}}>{a.impact}</span>
                    <span style={{fontSize:10, color:'var(--ink-3)'}}> 검토 필요</span>
                  </div>
                  <span style={{
                    fontSize:10, fontWeight:700, color:'#C77A1B',
                    background:'#FBEFD9', padding:'2px 6px', borderRadius:4
                  }}>싱크Law율 ↓</span>
                </div>
              </button>
              ))}
            </div>
          </div>
        </div>

        {/* RIGHT: TOP 10 priority */}
        <div style={{
          background:'#fff', border:'1px solid var(--line)', borderRadius:14, padding:0,
          boxShadow:'var(--shadow-sm)', display:'flex', flexDirection:'column'
        }}>
          <div style={{padding:'18px 20px 12px', borderBottom:'1px solid var(--line)'}}>
            <div style={{display:'flex', alignItems:'center', justifyContent:'space-between'}}>
              <div>
                <div style={{display:'flex', alignItems:'center', gap:8, marginBottom:4, flexWrap:'wrap'}}>
                  <span style={{
                    fontSize:10, fontWeight:700, letterSpacing:'0.1em',
                    color:'var(--amber)', background:'var(--amber-soft)',
                    padding:'2px 8px', borderRadius:4
                  }}>정비 검토 후보</span>
                  <span style={{fontSize:10.5, color:'#991B1B', fontWeight:700, background:'#FEE2E2', padding:'2px 7px', borderRadius:4, border:'1px solid #FCA5A5'}}>A {poolCounts.A}건</span>
                  <span style={{fontSize:10.5, color:'#5B7C99', fontWeight:600, background:'#EEF2F7', padding:'2px 7px', borderRadius:4}}>B {poolCounts.B}건</span>
                </div>
                <div style={{fontSize:16, fontWeight:700, color:'var(--ink)'}}>정비 검토 후보 통합 목록</div>
                <div style={{fontSize:11.5, color:'var(--ink-3)', marginTop:3, lineHeight:1.55}}>
                  정책 탐색·직접 비교·검토 신호 세 출처를 등급별로 정렬합니다. A는 직접 상위근거가 확인된 후보, B는 검토 신호만 잡힌 후보입니다.
                </div>
              </div>
              <div style={{display:'flex', gap:4}}>
                <Chip active={priorityFilter==='전체'} onClick={()=>setPriorityFilter('전체')}>전체 {allPriorityItems.length}</Chip>
                <Chip active={priorityFilter==='A'} onClick={()=>setPriorityFilter('A')}>A 등급 {poolCounts.A}</Chip>
                <Chip active={priorityFilter==='B'} onClick={()=>setPriorityFilter('B')}>B 등급 {poolCounts.B}</Chip>
              </div>
            </div>
          </div>
          <div style={{flex:1, overflowY:'auto'}}>
            {priorityItems.map((r,i)=>{
              const isPolicy = r.source === 'policy-hunter';
              const isDirect = r.source === 'direct-comparison' || r.directComparisonAvailable;
              const isIndicator = r.source === 'indicator-only' || (!isPolicy && !isDirect);
              const isAGrade = isPolicy || isDirect;
              const gradeColor = isPolicy ? '#155F53' : isDirect ? '#991B1B' : '#5B7C99';
              const gradeBg = isPolicy ? '#DBEEEA' : isDirect ? '#FEE2E2' : '#EEF2F7';
              const gradeLabel = isAGrade ? 'A · AI 탐색 + 직접 검증' : 'B · 검토 신호';
              const rankColor = isPolicy ? 'linear-gradient(135deg, #1F7A6B, #2EA08D)' : isDirect ? 'linear-gradient(135deg, #DC2626, #B91C1C)' : '#EEF2F7';
              const rankFg = (isPolicy || isDirect) ? '#fff' : 'var(--ink-3)';
              const hasLineCompare = (isPolicy || isDirect) && r.upperValue && r.lowerValue;
              // A 등급(실측 발굴) 카드는 외곽이 은은하게 빛나는 효과 + 좌측 보더 강조
              const cardBg = isAGrade ? (isDirect ? 'linear-gradient(90deg, #FEF7F7 0%, #fff 22%)' : 'linear-gradient(90deg, #F0FBF8 0%, #fff 22%)') : 'transparent';
              const cardBorderLeft = isDirect ? '4px solid #DC2626' : isPolicy ? '4px solid #1F7A6B' : '4px solid transparent';
              const cardShadow = isAGrade ? (isDirect ? 'inset 0 0 0 1px #FCA5A555, 0 0 8px rgba(220,38,38,0.06)' : 'inset 0 0 0 1px #A7D8CF55, 0 0 8px rgba(31,122,107,0.06)') : 'none';
              return (
              <button key={`${r.rank}-${r.mst || r.title}`} data-action="select-day5-anomaly" data-case-id={`DAY5-${r.rank}`} data-agency={r.agency} data-grade={r.grade || ''} data-source={r.source || ''} data-sync-rate={Math.max(40, 100 - r.score + 10)} onClick={()=>openPriorityAnalysis(r)} style={{
                display:'grid', gridTemplateColumns:'34px 1fr auto',
                width:'100%', textAlign:'left', padding:'14px 16px', gap:12,
                border:'none', borderLeft: cardBorderLeft, borderBottom: i<priorityItems.length-1?'1px solid var(--line)':'none',
                background: cardBg, boxShadow: cardShadow, cursor:'pointer', alignItems:'center'
              }}
              onMouseEnter={e=>{ e.currentTarget.style.filter='brightness(0.985)'; }}
              onMouseLeave={e=>{ e.currentTarget.style.filter='none'; }}>
                <div style={{
                  width:30, height:30, borderRadius:8,
                  background: rankColor,
                  color: rankFg,
                  display:'flex', alignItems:'center', justifyContent:'center',
                  fontSize:12, fontWeight:700, fontFamily:'JetBrains Mono'
                }}>{String(r.rank).padStart(2,'0')}</div>
                <div style={{minWidth:0}}>
                  <div style={{display:'flex', alignItems:'center', gap:6, marginBottom:4, flexWrap:'wrap'}}>
                    <span style={{fontSize:10, fontWeight:800, color:gradeColor, background:gradeBg, padding:'2px 7px', borderRadius:4, border:'1px solid '+gradeColor+'44'}}>{gradeLabel}</span>
                    {isAGrade && (
                      <span style={{fontSize:9.5, fontWeight:800, color:'#fff', background:'linear-gradient(135deg,#7DA9E6,#5B7C99)', padding:'2px 7px', borderRadius:4, letterSpacing:'0.04em', boxShadow:'0 0 6px rgba(125,169,230,0.45)'}}>● AI 실측 발굴</span>
                    )}
                    <span style={{fontSize:11, fontWeight:600, color:'var(--ink-2)'}}>{r.agency}</span>
                    <span style={{width:3, height:3, borderRadius:'50%', background:'var(--ink-4)'}}/>
                    <span style={{fontSize:10.5, color:'var(--ink-3)'}}>{r.worstErrorType || r.type}</span>
                  </div>
                  <div style={{fontSize:12.5, fontWeight:700, color:'var(--ink)', lineHeight:1.4, whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}} title={r.title}>{r.title}</div>
                  {hasLineCompare && (
                    <div style={{display:'flex', alignItems:'center', gap:6, marginTop:6, fontSize:10.5, flexWrap:'wrap'}}>
                      <span style={{fontSize:10, color:'var(--ink-4)', fontWeight:700}}>상위법</span>
                      <span style={{color:'#fff', background:'#1E40AF', padding:'2px 7px', borderRadius:3, fontWeight:800}}>{String(r.upperValue).length > 22 ? String(r.upperValue).slice(0, 22) + '…' : r.upperValue}</span>
                      <span style={{color:'var(--ink-4)'}}>vs</span>
                      <span style={{fontSize:10, color:'var(--ink-4)', fontWeight:700}}>조례</span>
                      <span style={{color:'#fff', background:'#DC2626', padding:'2px 7px', borderRadius:3, fontWeight:800}}>{String(r.lowerValue).length > 22 ? String(r.lowerValue).slice(0, 22) + '…' : r.lowerValue}</span>
                    </div>
                  )}
                  {!hasLineCompare && (
                    <div style={{display:'flex', alignItems:'center', gap:8, marginTop:5}}>
                      <div style={{flex:1, height:4, background:'#EEF2F7', borderRadius:99, overflow:'hidden'}}>
                        <div style={{
                          width:`${r.score}%`, height:'100%',
                          background: isDirect?'#DC2626':r.score>=90?'#C77A1B':r.score>=80?'#D4A24A':'#5B7C99'
                        }}/>
                      </div>
                      <span className="mono" style={{fontSize:11, fontWeight:700, color:'var(--ink-2)', minWidth:24, textAlign:'right'}}>{r.score}</span>
                    </div>
                  )}
                  <div style={{fontSize:10.5, color:'var(--ink-4)', marginTop:5, fontWeight:600}}>
                    {r.upperLawArticle ? `상위근거: ${r.upperLawArticle}${r.localArticle ? ` · 조례 ${r.localArticle}` : ''}` : isDirect ? '직접 상위근거 확인 완료' : `표준 표현 거리 ${Number(r.worstDistance || 0).toFixed(3)} · 참고 보조 지표`}
                  </div>
                </div>
                <Icon name="arrow-right" size={13} color="var(--ink-4)"/>
              </button>
              );
            })}
          </div>
          <div style={{padding:'10px 16px', borderTop:'1px solid var(--line)', background:'#F8FAFC', borderRadius:'0 0 14px 14px'}}>
            <div style={{display:'flex', alignItems:'center', justifyContent:'space-between'}}>
              <span style={{fontSize:11, color:'var(--ink-3)'}}>가중치: 권리 0.30 · 금전 0.20 · 시행일 0.15 · 민원 0.15 · 기관 0.10 · 취약계층 0.10</span>
              <Btn kind="ghost" size="sm" icon="arrow-right" style={{color:'var(--blue)'}} onClick={()=>go('insight')}>전체 순위</Btn>
            </div>
          </div>
        </div>
      </div>

      {/* ─────────── DATA FLOW ─────────── */}
      <div style={{
        background:'#fff', border:'1px solid var(--line)', borderRadius:14,
        padding:'22px 26px', boxShadow:'var(--shadow-sm)'
      }}>
        <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:18}}>
          <div>
            <div style={{
              fontSize:10, fontWeight:700, color:'var(--blue)', letterSpacing:'0.1em',
              marginBottom:6
            }}>DATA PIPELINE · 실시간 추적</div>
            <div style={{fontSize:18, fontWeight:700, color:'var(--ink)', letterSpacing:'-0.01em'}}>법령 개정 효과의 현장 도달 경로</div>
            <div style={{fontSize:12.5, color:'var(--ink-3)', marginTop:4}}>각 단계의 정비 도달율과 미정비 의심 건수를 실시간 표시</div>
          </div>
          <div style={{display:'flex', gap:14, alignItems:'center', fontSize:11, color:'var(--ink-3)'}}>
            <LegendDot color="#1F7A6B" label="정비 완료"/>
            <LegendDot color="#C77A1B" label="미정비 의심"/>
            <LegendDot color="#94A3B8" label="검토 대기"/>
          </div>
        </div>

        <DataFlow metrics={m}/>
      </div>
    </div>
  );
}

// ─────────── SUB COMPONENTS ───────────

// SyncLaw circular gauge
function SyncLawGauge({ value }){
  const R = 36, C = 2*Math.PI*R;
  const dash = C * (value/100);
  return (
    <div data-sync-rate="overall" style={{
      padding:'12px 16px', borderRadius:10,
      background:'rgba(94,230,181,0.10)',
      border:'1px solid rgba(94,230,181,0.30)',
      minWidth:160, display:'flex', alignItems:'center', gap:12
    }}>
      <svg width="82" height="82" viewBox="0 0 82 82">
        <circle cx="41" cy="41" r={R} fill="none" stroke="rgba(255,255,255,0.14)" strokeWidth="6"/>
        <circle cx="41" cy="41" r={R} fill="none" stroke="#5EE6B5" strokeWidth="6" strokeLinecap="round"
          strokeDasharray={`${dash} ${C}`} transform="rotate(-90 41 41)"/>
        <text x="41" y="40" textAnchor="middle" fill="#fff" fontSize="18" fontWeight="700" fontFamily="JetBrains Mono" letterSpacing="-0.5">{value}</text>
        <text x="41" y="54" textAnchor="middle" fill="#5EE6B5" fontSize="9">%</text>
      </svg>
      <div>
        <div style={{fontSize:10.5, color:'rgba(255,255,255,0.65)', fontWeight:500, letterSpacing:'0.04em'}}>전체 싱크Law율</div>
        <div style={{fontSize:11, color:'#fff', fontWeight:700, marginTop:4, lineHeight:1.4}}>일부 싱크<br/>불일치 감지</div>
      </div>
    </div>
  );
}

function PulseStat({ label, value, unit, highlight }){
  return (
    <div style={{
      padding:'14px 18px', borderRadius:10,
      background: highlight ? 'rgba(94,230,181,0.10)' : 'rgba(255,255,255,0.06)',
      border: '1px solid ' + (highlight ? 'rgba(94,230,181,0.30)' : 'rgba(255,255,255,0.12)'),
      minWidth:120
    }}>
      <div style={{fontSize:10.5, color:'rgba(255,255,255,0.65)', fontWeight:500, letterSpacing:'0.04em'}}>{label}</div>
      <div style={{display:'flex', alignItems:'baseline', gap:4, marginTop:6}}>
        <span className="mono" style={{
          fontSize:22, fontWeight:700, color: highlight?'#5EE6B5':'#fff', letterSpacing:'-0.02em'
        }}>{value}</span>
        <span style={{fontSize:10.5, color:'rgba(255,255,255,0.55)'}}>{unit}</span>
      </div>
    </div>
  );
}

function DarkChips({ label, value, options, onChange, filterKey }){
  const [open, setOpen] = useStateD(false);
  const [pos, setPos] = useStateD(null);
  const wrapRef = React.useRef(null);
  const menuRef = React.useRef(null);

  const updatePosition = React.useCallback(()=>{
    if(!wrapRef.current) return;
    const r = wrapRef.current.getBoundingClientRect();
    setPos({ left:r.left, top:r.bottom + 6, width:Math.max(190, r.width) });
  },[]);

  React.useEffect(()=>{
    if(!open) return;
    updatePosition();
    const onWindow = ()=> updatePosition();
    const onDoc = (ev)=>{
      if(wrapRef.current && wrapRef.current.contains(ev.target)) return;
      if(menuRef.current && menuRef.current.contains(ev.target)) return;
      setOpen(false);
    };
    window.addEventListener('resize', onWindow);
    window.addEventListener('scroll', onWindow, true);
    document.addEventListener('pointerdown', onDoc);
    return ()=>{
      window.removeEventListener('resize', onWindow);
      window.removeEventListener('scroll', onWindow, true);
      document.removeEventListener('pointerdown', onDoc);
    };
  }, [open, updatePosition]);

  const menu = open && pos ? ReactDOM.createPortal(
    <div ref={menuRef} style={{
      position:'fixed', top:pos.top, left:pos.left, zIndex:99999,
      background:'#fff', border:'1px solid var(--line)', borderRadius:10,
      boxShadow:'0 18px 42px rgba(15,23,42,0.24)', minWidth:pos.width,
      maxHeight:'min(360px, calc(100vh - 120px))', overflowY:'auto',
      padding:'4px 0'
    }}>
      {options.map(o=>(
        <button key={o} onClick={()=>{onChange(o); setOpen(false);}} style={{
          display:'block', width:'100%', textAlign:'left', padding:'9px 12px',
          background: o===value?'var(--blue-soft)':'transparent',
          border:'none', fontSize:12, color: o===value?'var(--navy)':'var(--ink-2)',
          fontWeight: o===value?700:500
        }}>{o}</button>
      ))}
    </div>,
    document.body
  ) : null;

  return (
    <div ref={wrapRef} data-filter={filterKey} style={{position:'relative', overflow:'visible'}}>
      <button onClick={(e)=>{ e.stopPropagation(); updatePosition(); setOpen(o=>!o); }} style={{
        display:'inline-flex', alignItems:'center', gap:8, padding:'6px 12px',
        background:'rgba(255,255,255,0.08)', border:'1px solid rgba(255,255,255,0.16)',
        borderRadius:6, color:'#fff', fontSize:12, whiteSpace:'nowrap'
      }}>
        <span style={{opacity:.65}}>{label}</span>
        <span style={{fontWeight:600}}>{value}</span>
        <Icon name="arrow-down" size={11}/>
      </button>
      {menu}
    </div>
  );
}

const heroBtn = (primary)=>({
  display:'inline-flex', alignItems:'center', gap:6,
  padding:'8px 14px', borderRadius:7, fontSize:12, fontWeight:600,
  background: primary ? '#fff' : 'rgba(255,255,255,0.08)',
  color: primary ? 'var(--navy)' : '#fff',
  border: '1px solid ' + (primary ? '#fff' : 'rgba(255,255,255,0.18)'),
  fontFamily:'inherit'
});

// Animated count-up
function CountUp({ value, style }){
  const [v, setV] = useStateD(0);
  useEffectD(()=>{
    const start = performance.now();
    const dur = 900;
    let raf;
    const tick = (now)=>{
      const p = Math.min(1, (now-start)/dur);
      const e = 1 - Math.pow(1-p, 3);
      setV(Math.round(value*e));
      if(p<1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return ()=> cancelAnimationFrame(raf);
  }, [value]);
  return <span className="mono" style={style}>{v.toLocaleString()}</span>;
}

function KPI({ tone, icon, label, value, delta, share, sub, kpiKey }){
  const tones = {
    amber: { strip:'#C77A1B', dot:'#C77A1B', soft:'#FBEFD9' },
    steel: { strip:'#5B7C99', dot:'#5B7C99', soft:'#EEF2F7' },
    teal:  { strip:'#1F7A6B', dot:'#1F7A6B', soft:'#DBEEEA' },
    navy:  { strip:'#0B2E5C', dot:'#0B2E5C', soft:'#E6EEFB' },
  };
  const t = tones[tone] || tones.steel;
  return (
    <div data-kpi={kpiKey} style={{
      background:'#fff', border:'1px solid var(--line)', borderRadius:11,
      padding:'14px 14px 12px', position:'relative', overflow:'hidden'
    }}>
      <div style={{position:'absolute', left:0, top:0, bottom:0, width:3, background:t.strip}}/>
      <div style={{display:'flex', alignItems:'center', justifyContent:'space-between', marginBottom:6}}>
        <div style={{display:'flex', alignItems:'center', gap:6}}>
          <span style={{
            width:22, height:22, borderRadius:5, background:t.soft,
            display:'flex', alignItems:'center', justifyContent:'center', color:t.dot
          }}><Icon name={icon} size={12}/></span>
          <span style={{fontSize:11.5, color:'var(--ink-3)', fontWeight:600}}>{label}</span>
        </div>
        {share!==null && share!==undefined && (
          <span className="mono" style={{fontSize:10, color:'var(--ink-4)'}}>{share}%</span>
        )}
      </div>
      <div style={{display:'flex', alignItems:'baseline', gap:6, marginTop:4}}>
        <CountUp value={value} style={{fontSize:24, fontWeight:700, color:'var(--ink)', letterSpacing:'-0.02em'}}/>
        <span style={{fontSize:10.5, color:'var(--ink-4)'}}>건</span>
      </div>
      <div style={{display:'flex', alignItems:'center', gap:6, marginTop:4}}>
        <Icon name="arrow-up" size={10} color="var(--teal)"/>
        <span className="mono" style={{fontSize:10.5, color:'var(--teal)', fontWeight:700}}>{delta}</span>
        <span style={{fontSize:10.5, color:'var(--ink-4)'}}>{sub || '전주 대비'}</span>
      </div>
    </div>
  );
}

// ───────── Data Flow visualization ─────────
function DataFlow({ metrics }){
  const m = metrics || RSData.DAY5_DEFAULT_METRICS;
  const stages = [
    { id:'law',   t:'상위법 기준점',     icon:'pulse',     count:'3', done:3, pending:0, miss:0, note:'건축법·시행령·시행규칙 MST' },
    { id:'link',  t:'연계 조문 row',     icon:'building',  count:m.sourceTotal.toLocaleString(), done:m.sourceTotal, pending:0, miss:0, note:`고유 조례 ${m.uniqueOrdinances.toLocaleString()}건` },
    { id:'sample',t:'본문 확인 사례',     icon:'layers',    count:m.sampleSize.toLocaleString(), done:m.bodyFetched, pending:Math.max(0, m.sampleSize - m.bodyFetched), miss:m.flaggedOrdinances, note:'18건 본문 확인' },
    { id:'rule',  t:'규칙으로 1차 점검',  icon:'shield',    count:m.totalRuleSignals.toLocaleString(), done:m.bRuleSignals, pending:m.aRuleSignals, miss:m.totalAClassificationCandidates, note:`정비 후보 ${m.totalAClassificationCandidates} · 제외 ${m.bRuleSignals}` },
    { id:'embed', t:'표준 사례와 비교',   icon:'compare',   count:m.anomalyChunks.toLocaleString(), done:m.anomalyOrdinances, pending:m.highAnomalyCount, miss:m.highAnomalyCount, note:'참고용 유사도' },
    { id:'review',t:'AI 검토 메모',       icon:'brain',     count:m.level4Reviews.toLocaleString(), done:m.level4Reviews, pending:0, miss:m.flaggedOrdinances, note:'담당자 확인용 3문장' },
  ];
  // canvas size
  const W = 1380, H = 280;
  const colW = W / stages.length;
  return (
    <div style={{position:'relative'}}>
      <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={H} style={{display:'block'}}>
        <defs>
          <linearGradient id="flowG" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="#0B2E5C"/>
            <stop offset="50%" stopColor="#2E5FB0"/>
            <stop offset="100%" stopColor="#1F7A6B"/>
          </linearGradient>
          <linearGradient id="flowFade" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor="#7DA9E6" stopOpacity="0.5"/>
            <stop offset="100%" stopColor="#7DA9E6" stopOpacity="0"/>
          </linearGradient>
        </defs>

        {/* base flow band */}
        <path d={`M 60 140 L ${W-60} 140`} stroke="url(#flowG)" strokeWidth="3" strokeLinecap="round" opacity="0.85"/>
        {/* moving dashes */}
        <path d={`M 60 140 L ${W-60} 140`} stroke="#7DA9E6" strokeWidth="2" strokeDasharray="6 14" strokeLinecap="round" opacity="0.6">
          <animate attributeName="stroke-dashoffset" from="0" to="-40" dur="1.6s" repeatCount="indefinite"/>
        </path>

        {/* stage nodes */}
        {stages.map((s,i)=>{
          const cx = colW/2 + i*colW;
          const total = s.done + s.pending + s.miss;
          const rDone = total ? s.done/total : 0;
          const rPend = total ? s.pending/total : 0;
          // donut around node
          const R = 38, C = 2*Math.PI*R;
          const dDone = C * rDone;
          const dPend = C * rPend;
          const dMiss = C - dDone - dPend;
          return (
            <g key={s.id}>
              {/* outer ring base */}
              <circle cx={cx} cy={140} r={R} fill="#fff" stroke="#EEF2F7" strokeWidth="6"/>
              {/* miss segment */}
              <circle cx={cx} cy={140} r={R} fill="none" stroke="#C77A1B" strokeWidth="6"
                strokeDasharray={`${dMiss} ${C}`} transform={`rotate(-90 ${cx} 140)`}/>
              {/* pending */}
              <circle cx={cx} cy={140} r={R} fill="none" stroke="#94A3B8" strokeWidth="6"
                strokeDasharray={`${dPend} ${C}`} strokeDashoffset={-dMiss} transform={`rotate(-90 ${cx} 140)`}/>
              {/* done */}
              <circle cx={cx} cy={140} r={R} fill="none" stroke="#1F7A6B" strokeWidth="6"
                strokeDasharray={`${dDone} ${C}`} strokeDashoffset={-(dMiss+dPend)} transform={`rotate(-90 ${cx} 140)`}/>

              {/* center dot */}
              <circle cx={cx} cy={140} r={28} fill="#0B2E5C"/>
              <circle cx={cx} cy={140} r={28} fill="url(#flowFade)" opacity="0.4"/>

              {/* count center */}
              <text x={cx} y={138} textAnchor="middle" fill="#fff" fontSize="14" fontWeight="700" fontFamily="JetBrains Mono" letterSpacing="-0.5">{s.count}</text>
              <text x={cx} y={152} textAnchor="middle" fill="#7DA9E6" fontSize="9">건</text>

              {/* step number tag */}
              <g transform={`translate(${cx-20}, ${140-58})`}>
                <rect width="40" height="18" rx="4" fill="#143A73"/>
                <text x="20" y="13" textAnchor="middle" fill="#7DA9E6" fontSize="10" fontWeight="700" fontFamily="JetBrains Mono">STEP {String(i+1).padStart(2,'0')}</text>
              </g>

              {/* title */}
              <text x={cx} y={216} textAnchor="middle" fill="#0F172A" fontSize="13.5" fontWeight="700">{s.t}</text>
              <text x={cx} y={232} textAnchor="middle" fill="#64748B" fontSize="10.5">{s.note}</text>

              {/* completion percentage */}
              <text x={cx} y={258} textAnchor="middle" fill="#1F7A6B" fontSize="11" fontWeight="700" fontFamily="JetBrains Mono">
                처리율 {Math.round(rDone*100)}%
              </text>
            </g>
          );
        })}

        {/* arrows between stages */}
        {stages.slice(0,-1).map((_,i)=>{
          const x1 = colW/2 + i*colW + 42;
          const x2 = colW/2 + (i+1)*colW - 42;
          return (
            <g key={i}>
              <path d={`M ${x1} 140 L ${x2} 140`} stroke="#CBD5E1" strokeWidth="1.4" fill="none"/>
              <path d={`M ${x2-6} 136 L ${x2} 140 L ${x2-6} 144`} stroke="#5B7C99" strokeWidth="1.4" fill="none"/>
            </g>
          );
        })}
      </svg>

      {/* breakdown chips below */}
      <div style={{
        display:'grid', gridTemplateColumns:`repeat(${stages.length}, 1fr)`,
        marginTop:8, gap:6
      }}>
        {stages.map(s=>{
          const total = s.done + s.pending + s.miss || 1;
          return (
            <div key={s.id} style={{
              padding:'10px 12px', background:'#F8FAFC', borderRadius:8,
              border:'1px solid var(--line)'
            }}>
              <div style={{display:'flex', height:5, borderRadius:99, overflow:'hidden', background:'#EEF2F7', marginBottom:8}}>
                <div style={{width:`${s.done/total*100}%`,    background:'#1F7A6B'}}/>
                <div style={{width:`${s.pending/total*100}%`, background:'#94A3B8'}}/>
                <div style={{width:`${s.miss/total*100}%`,    background:'#C77A1B'}}/>
              </div>
              <div style={{display:'flex', justifyContent:'space-between', fontSize:10, color:'var(--ink-3)'}}>
                <span><span className="mono" style={{color:'var(--teal)', fontWeight:700}}>{s.done.toLocaleString()}</span> 완료</span>
                <span><span className="mono" style={{color:'var(--amber)', fontWeight:700}}>{s.miss.toLocaleString()}</span> 미정비</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

Object.assign(window, { DashboardScreen });
