@@ -768,6 +768,70 @@ function candidateDecisionGuardrail(action: CandidateDecision["action"]) {
768768 } ;
769769}
770770
771+ function CompactCandidatePreview ( {
772+ candidates,
773+ onViewFullReview,
774+ } : {
775+ candidates : Candidate [ ] ;
776+ onViewFullReview : ( ) => void ;
777+ } ) {
778+ return (
779+ < div
780+ id = "candidate-evidence-preview"
781+ className = "mb-5 rounded-2xl border border-blue-200 bg-blue-50/60 p-4"
782+ >
783+ < div className = "mb-3 flex flex-col gap-2 lg:flex-row lg:items-end lg:justify-between" >
784+ < div >
785+ < div className = "text-xs font-bold uppercase tracking-[0.18em] text-blue-700" >
786+ Candidate evidence
787+ </ div >
788+ < div className = "mt-1 text-sm font-semibold text-blue-900" >
789+ Candidate hypotheses are available for this break.
790+ </ div >
791+ </ div >
792+ < div className = "text-xs font-bold text-blue-700" >
793+ { candidates . length } candidate source(s)
794+ </ div >
795+ </ div >
796+
797+ < div className = "grid gap-3 lg:grid-cols-2" >
798+ { candidates . slice ( 0 , 2 ) . map ( ( candidate ) => (
799+ < div
800+ key = { `compact-${ candidate . source } ` }
801+ className = "rounded-xl border border-blue-100 bg-white p-3"
802+ >
803+ < div className = "flex items-center justify-between gap-3" >
804+ < span className = "rounded-full bg-blue-50 px-2.5 py-1 text-xs font-bold text-blue-700 ring-1 ring-blue-200" >
805+ { candidate . source }
806+ </ span >
807+ < span className = "text-xs font-bold text-slate-500" >
808+ Confidence { candidate . confidence }
809+ </ span >
810+ </ div >
811+ < p className = "mt-3 text-xs leading-5 text-slate-600" >
812+ { candidate . rationale }
813+ </ p >
814+ </ div >
815+ ) ) }
816+ </ div >
817+
818+ < div className = "mt-3 flex flex-col gap-2 rounded-xl border border-blue-100 bg-white p-3 text-xs leading-5 text-slate-600" >
819+ < div >
820+ Candidate evidence is shown here as a preview. Use the full candidate review section
821+ to stage Review, Accept, or Reject actions.
822+ </ div >
823+ < button
824+ type = "button"
825+ onClick = { onViewFullReview }
826+ className = "w-fit rounded-full bg-blue-700 px-3 py-1.5 text-xs font-bold text-white"
827+ >
828+ Open full candidate review
829+ </ button >
830+ </ div >
831+ </ div >
832+ ) ;
833+ }
834+
771835function CandidateCard ( {
772836 candidate,
773837 selectedDecision,
@@ -1341,6 +1405,12 @@ export default function BreakResolutionWorkbench() {
13411405 ?. scrollIntoView ( { behavior : "smooth" , block : "start" } ) ;
13421406 }
13431407
1408+ function scrollToFullCandidateReview ( ) {
1409+ document
1410+ . getElementById ( "related-candidate-evidence" )
1411+ ?. scrollIntoView ( { behavior : "smooth" , block : "start" } ) ;
1412+ }
1413+
13441414 const displayedRecommendedAction =
13451415 selectedPacket ?. summary ?. recommendedAction ?? selectedBreak . recommendedAction ;
13461416 const displayedReason = selectedPacket ?. summary ?. reason ?? selectedBreak . reason ;
@@ -1537,51 +1607,10 @@ export default function BreakResolutionWorkbench() {
15371607 />
15381608
15391609 { relatedCandidates . length > 0 ? (
1540- < div
1541- id = "candidate-evidence-preview"
1542- className = "mb-5 rounded-2xl border border-blue-200 bg-blue-50/60 p-4"
1543- >
1544- < div className = "mb-3 flex flex-col gap-2 lg:flex-row lg:items-end lg:justify-between" >
1545- < div >
1546- < div className = "text-xs font-bold uppercase tracking-[0.18em] text-blue-700" >
1547- Candidate evidence
1548- </ div >
1549- < div className = "mt-1 text-sm font-semibold text-blue-900" >
1550- Review candidate hypotheses before staging a candidate decision.
1551- </ div >
1552- </ div >
1553- < div className = "text-xs font-bold text-blue-700" >
1554- { relatedCandidates . length } candidate source(s)
1555- </ div >
1556- </ div >
1557-
1558- < div className = "grid gap-3 lg:grid-cols-2" >
1559- { relatedCandidates . slice ( 0 , 2 ) . map ( ( candidate ) => (
1560- < CandidateCard
1561- key = { `preview-${ candidate . source } ` }
1562- candidate = { candidate }
1563- selectedDecision = {
1564- candidateDecision ?. source === candidate . source
1565- ? candidateDecision
1566- : null
1567- }
1568- onDecision = { ( action ) => {
1569- const nextCandidateDecision = {
1570- source : candidate . source ,
1571- action,
1572- confidence : candidate . confidence ,
1573- rationale : candidate . rationale ,
1574- } ;
1575-
1576- setCandidateDecision ( nextCandidateDecision ) ;
1577- setAnalystNote ( "" ) ;
1578- setDecision ( `${ action } ${ candidate . source } candidate` ) ;
1579- setDecisionTimestamp ( new Date ( ) . toISOString ( ) ) ;
1580- } }
1581- />
1582- ) ) }
1583- </ div >
1584- </ div >
1610+ < CompactCandidatePreview
1611+ candidates = { relatedCandidates }
1612+ onViewFullReview = { scrollToFullCandidateReview }
1613+ />
15851614 ) : null }
15861615
15871616 < EvidenceComparison fields = { evidenceFields } />
0 commit comments