// 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 (
▸ layer breakdown · 10 forensic signals
click row for full evidence
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
{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'}>
{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 signal per-layer width = weight · intensity = AI probability AI 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
{/* histogram */}
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)}
setSelected(null)} style={{background:'transparent', border:0, color:'var(--text-dim)', cursor:'default', fontSize:11}}>× close
{/* 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)}
× close
>
);
}
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 (
);
}
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
;
})}
0 25 50+
>;
}
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
) : (
Char
Hex
Name
Count
First positions
{data.findings.map((f,i) => (
{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) => (
))}
>;
}
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;