// Report state — hero, layer table, heatmap, suspicious passages. const { useState: useStateRpt, useMemo: useMemoRpt } = React; function HeroStrip({ verdict }){ const score = verdict.final_score; const tone = verdictTone(score); const verdictColor = tone.tone === 'red' ? 'var(--red)' : tone.tone === 'green' ? 'var(--green)' : 'var(--amber)'; return (
{verdict.verdict_icon}

{verdict.verdict}

{verdict.verdict_description}

confidence {verdict.confidence}
→ {verdict.recommended_action}
final score
{score.toFixed(3)}
weighted across 10 layers
); } function ConflictBanner({ conflicts }){ if (!conflicts || !conflicts.length) return null; return (
signals are conflicted · human review strongly recommended
{conflicts.map((c, i) => { const a = layerMeta(c.layers[0]).short, b = layerMeta(c.layers[1]).short; return (
{a} ↔ {b} · Δ {c.delta.toFixed(2)} · {c.note}
); })}
); } function DocumentPanel({ doc, analysisTime, onDownloadJson, onDownloadPdf, onReset }){ return (
▸ document
filename
{doc.filename}
type
{doc.file_type}
size
{commas(doc.file_size_bytes)} bytes
words
{commas(doc.word_count)}
analyzed in
{analysisTime.toFixed(1)}s
▸ engine
version
0.4.2
chunker
tiktoken-cl100k
models
3 (ensemble)
seed
0xa3f1
); } function LayerTable({ rows, onRowClick }){ const [sortKey, setSortKey] = useStateRpt('weight'); const [sortDir, setSortDir] = useStateRpt('desc'); const sorted = useMemoRpt(() => { const arr = [...rows]; arr.sort((a, b) => { let av, bv; if (sortKey === 'layer') { av = layerMeta(a.layer).short; bv = layerMeta(b.layer).short; } else if (sortKey === 'signal') { av = a.signal; bv = b.signal; } else { av = a[sortKey]; bv = b[sortKey]; } if (av < bv) return sortDir === 'asc' ? -1 : 1; if (av > bv) return sortDir === 'asc' ? 1 : -1; return 0; }); return arr; }, [rows, sortKey, sortDir]); const setSort = k => { if (sortKey === k) setSortDir(d => d === 'asc' ? 'desc' : 'asc'); else { setSortKey(k); setSortDir(k === 'layer' ? 'asc' : 'desc'); } }; const arrow = k => sortKey === k ? (sortDir === 'asc' ? ' ↑' : ' ↓') : ''; return (
▸ layer breakdown · 10 forensic signals
click row for full evidence
{sorted.map((row) => { const meta = layerMeta(row.layer); const color = signalColor(row.ai_probability); const probColor = color==='red' ? 'var(--red)' : color==='green' ? 'var(--green)' : 'var(--amber)'; return ( onRowClick(row.layer)} className="layer-row" style={{borderBottom:'1px solid var(--border)', cursor:'default'}} onMouseOver={(e)=>e.currentTarget.style.background='var(--surface-2)'} onMouseOut={(e)=>e.currentTarget.style.background='transparent'}> ); })}
setSort('layer')} style={thStyle('left',30)}>Layer{arrow('layer')} setSort('weight')} style={thStyle('right',70)}>Weight{arrow('weight')} setSort('ai_probability')} style={thStyle('right',150)}>AI prob{arrow('ai_probability')} setSort('signal')} style={thStyle('left',90)}>Signal{arrow('signal')} Evidence
{meta.short} {meta.name} {pct0(row.weight)}
{fmt3(row.ai_probability)}
{row.evidence}
{/* Weighted sum visualization */}
weighted aggregation
{sorted .slice() // don't reorder for the bar — by layer .sort((a,b)=>{ const oa = window.LAYER_META.findIndex(m=>m.key===a.layer); const ob = window.LAYER_META.findIndex(m=>m.key===b.layer); return oa - ob; }) .map(r => { const c = signalColor(r.ai_probability); const col = c==='red' ? 'var(--red)' : c==='green' ? 'var(--green)' : 'var(--amber)'; return (
); })}
← human signalper-layer width = weight · intensity = AI probabilityAI signal →
); } function thStyle(align, width){ return { textAlign: align, padding:'10px 12px', fontSize:10, color:'var(--text-dim)', fontWeight:500, letterSpacing:'0.1em', width: width || 'auto' }; } function tdStyle(align){ return { textAlign: align, padding:'12px 12px', verticalAlign:'middle' }; } function SentenceHeatmap({ heatmap }){ const [selected, setSelected] = useStateRpt(null); const [hover, setHover] = useStateRpt(null); const buckets = useMemoRpt(() => { const b = [0,0,0,0,0,0,0,0,0,0]; heatmap.forEach(s => { b[Math.min(9, Math.floor(s.ai_probability*10))]++; }); return b; }, [heatmap]); return (
▸ sentence heatmap · {heatmap.length} sentences
0.0 1.0
{/* histogram */}
distribution
00.51
summary
human-leaning {heatmap.filter(s=>s.ai_probability<=0.4).length} mixed {heatmap.filter(s=>s.ai_probability>0.4 && s.ai_probability<0.6).length} AI-leaning {heatmap.filter(s=>s.ai_probability>=0.6).length}
{/* heat row */}
{heatmap.map((s, i) => (
setHover(i)} onMouseLeave={() => setHover(h => h===i ? null : h)} onClick={() => setSelected(i)} style={{ background: HeatColor(s.ai_probability), border: selected===i ? '1px solid var(--text)' : '1px solid transparent' }} /> ))}
{hover != null && hover !== selected && (
#{heatmap[hover].index} {fmt3(heatmap[hover].ai_probability)} {heatmap[hover].sentence}
)} {selected != null && (
sentence #{heatmap[selected].index} p = {fmt3(heatmap[selected].ai_probability)}
{/* show sentence in context: prev + selected highlighted + next */} {selected > 0 && {heatmap[selected-1].sentence + ' '}} {heatmap[selected].sentence} {selected < heatmap.length-1 && {' ' + heatmap[selected+1].sentence}}
)}
); } function SuspiciousPassages({ passages }){ if (!passages || passages.length === 0){ return (
▸ top suspicious passages
◇ none — no passages crossed the suspicion threshold (p ≥ 0.6)
); } return (
▸ top suspicious passages · ranked
{passages.map(p => { const color = signalColor(p.ai_probability); const colorVar = color==='red' ? 'var(--red)' : color==='green' ? 'var(--green)' : 'var(--amber)'; return (
#{p.rank}
"{p.quote}"
p{fmt3(p.ai_probability)} flagged by{p.flagged_by.map(l => layerMeta(l).short).join(', ')} location{p.location}
); })}
); } // ── Per-layer drawer ────────────────────────────────────────────────────────── function LayerDrawer({ layerKey, payload, onClose }){ if (!layerKey) return null; const meta = layerMeta(layerKey); const data = payload.layers[layerKey]; const row = payload.verdict.layer_breakdown.find(r => r.layer === layerKey); const color = signalColor(row.ai_probability); const colorVar = color==='red' ? 'var(--red)' : color==='green' ? 'var(--green)' : 'var(--amber)'; return ( <>
{meta.short} · weight {pct0(meta.weight)}
{meta.name}
{fmt3(row.ai_probability)}
); } function LayerDetailBody({ layerKey, data, payload }){ switch (layerKey){ case 'l1_perplexity': return ; case 'l2_burstiness': return ; case 'l3_stylometrics': return ; case 'l4_semantic': return ; case 'l5_unicode': return ; case 'l6_metadata': return ; case 'l7_fonts': return ; case 'l8_ensemble': return ; case 'l9_hallucination': return ; case 'l10_revisions': return ; default: return
{JSON.stringify(data, null, 2)}
; } } function DetailSection({ title, children }){ return (
{title}
{children}
); } function KV({ rows }){ return (
{rows.map(([k,v]) => (
{k}
{v}
))}
); } function L1Detail({ data }){ return <>
dashed line = AI/human threshold (perplexity 30)
{data.low_perplexity_sentences.length > 0 && (
{data.low_perplexity_sentences.map((s, i) => (
sent #{s.index} perp = {s.perplexity.toFixed(1)}
{s.sentence}
))}
)} ; } function L2Detail({ data }){ return <>
{data.length_distribution.map((v,i)=>{ const max = Math.max(...data.length_distribution); return
; })}
02550+
; } function L3Detail({ data }){ const aiSig = ['ai_phrase_density','hedging_density','em_dash_density','passive_voice_ratio','nominalization_ratio']; return <> {data.top_ai_signals.length > 0 && (
{data.top_ai_signals.map((s, i) => (
{s}
))}
)}
{Object.entries(data.features).map(([k,v]) => { const isAi = aiSig.includes(k) && v > 1; return (
{k} {Number(v).toFixed(4)}
); })}
; } function L4Detail({ data }){ return <> {data.cosine_matrix_excerpt.map((row,i) => ( {row.map((v,j) => ( ))} ))}
{v.toFixed(2)}
cell intensity = cosine similarity. uniform off-diagonals → AI-typical even drift.
; } function L5Detail({ data }){ return <> {data.findings.length === 0 ? (
✓ clean — no suspicious code points detected
) : ( {data.findings.map((f,i) => ( ))}
Char Hex Name Count First positions
{f.char} {f.hex} {f.name} {f.count} {f.first_positions.join(', ')}
)}
; } function L6Detail({ data }){ return <> {data.creator || '—'}], ['producer', data.producer || '—'], ['author', data.author || (empty)], ['created', data.created], ['modified', data.modified], ['EOF markers', data.eof_markers], ['pages', data.page_count], ]}/> {data.signals.length > 0 && (
{data.signals.map((s, i) => (
{s}
))}
)} ; } function L7Detail({ data }){ return <>
{data.fonts.map((f, i) => (
{String(i+1).padStart(2,'0')} {f}
))}
; } function L8Detail({ data }){ const max = Math.max(...data.model_results.map(m => m.ai_probability), 1); return <>
{fmt3(data.ai_probability)}
weighted across 3 classifier models
{data.model_results.map(m => { const c = signalColor(m.ai_probability); const colorVar = c==='red' ? 'var(--red)' : c==='green' ? 'var(--green)' : 'var(--amber)'; return (
{m.model} {fmt3(m.ai_probability)}
weight {pct0(m.weight)} · {m.chunks_analyzed} chunks vertical tick marks weight position
); })}
; } function L9Detail({ data }){ const statusColor = { verified: 'var(--green)', unverifiable: 'var(--amber)', contradicted: 'var(--red)' }; return <>
{data.claims.map((c, i) => (
{c.text}
{c.status}
))}
; } function L10Detail({ data }){ return <>
Humans iterate. A document with hundreds of revisions across multiple sessions is unlikely to have been emitted in a single AI generation pass. Conversely, a 0-revision document with a single emit pass is consistent with raw model output.
; } window.HeroStrip = HeroStrip; window.ConflictBanner = ConflictBanner; window.DocumentPanel = DocumentPanel; window.LayerTable = LayerTable; window.SentenceHeatmap = SentenceHeatmap; window.SuspiciousPassages = SuspiciousPassages; window.LayerDrawer = LayerDrawer;