1- import { useMemo } from 'react' ;
1+ import { useMemo , useState } from 'react' ;
22import type { GameState , ActorSideState } from '../../hooks/useGameState.js' ;
33import { humanizeOutcome } from './humanize-outcome.js' ;
44import styles from './TurnBanner.module.scss' ;
@@ -69,6 +69,15 @@ const MAX_INLINE_OUTCOMES = 6;
6969 * so the banner stays under a screen on large cohort runs.
7070 */
7171export function TurnBanner ( { state, currentTurn } : TurnBannerProps ) {
72+ // Cohort runs (3+ actors) render all per-actor outcome lines which
73+ // can eat 6+ rows of vertical space on the viz tab, squeezing the
74+ // cohort grid below to just its column headers with the bodies
75+ // clipped. Default the per-actor block to collapsed for cohort runs
76+ // so the headline stays visible without crowding the grid; pair runs
77+ // keep the expanded default since two lines never crowd the layout.
78+ const isCohortDefault = state . actorIds . length > 2 ;
79+ const [ collapsed , setCollapsed ] = useState ( isCohortDefault ) ;
80+
7281 const summaries = useMemo ( ( ) => {
7382 const out : Array < { actorId : string ; summary : LeaderTurnSummary | null } > = [ ] ;
7483 for ( const actorId of state . actorIds ) {
@@ -87,15 +96,28 @@ export function TurnBanner({ state, currentTurn }: TurnBannerProps) {
8796
8897 const visible = populated . slice ( 0 , MAX_INLINE_OUTCOMES ) ;
8998 const hidden = populated . length - visible . length ;
99+ const showLines = ! collapsed ;
100+ const canCollapse = populated . length > 0 ;
90101
91102 return (
92103 < div role = "status" aria-label = "Current turn narrative" className = { styles . banner } >
93104 < div className = { styles . headline } >
94105 < span className = { styles . turnLabel } > T{ currentTurn + 1 } { time ? ` \u00b7 ${ time } ` : '' } </ span >
95106 < span className = { styles . title } > { headline } </ span >
96107 { category && < span className = { styles . categoryPill } > { category } </ span > }
108+ { canCollapse && (
109+ < button
110+ type = "button"
111+ onClick = { ( ) => setCollapsed ( c => ! c ) }
112+ aria-expanded = { ! collapsed }
113+ aria-label = { collapsed ? 'Expand per-actor outcomes' : 'Collapse per-actor outcomes' }
114+ className = { styles . collapseBtn }
115+ >
116+ { collapsed ? `\u25be ${ populated . length } actors` : '\u25b4 hide' }
117+ </ button >
118+ ) }
97119 </ div >
98- { visible . map ( ( entry , idx ) => (
120+ { showLines && visible . map ( ( entry , idx ) => (
99121 < div
100122 key = { entry . actorId }
101123 // For 2-actor pair runs, keep the legacy `.lineA` / `.lineB`
@@ -110,7 +132,7 @@ export function TurnBanner({ state, currentTurn }: TurnBannerProps) {
110132 < span className = { styles . lineBody } > : { humanizeOutcome ( entry . summary ) } </ span >
111133 </ div >
112134 ) ) }
113- { hidden > 0 && (
135+ { showLines && hidden > 0 && (
114136 < div className = { styles . lineMore } >
115137 +{ hidden } more \u00b7 see cohort grid below for the rest
116138 </ div >
0 commit comments