@@ -122,13 +122,17 @@ const StatePanel: React.FC<{
122122 title : string ;
123123 fields : Record < string , unknown > ;
124124 changes ?: Map < string , ChangeInfo > ;
125- } > = ( { title, fields, changes } ) => {
125+ statusIndicator ?: React . ReactNode ;
126+ } > = ( { title, fields, changes, statusIndicator } ) => {
126127 const entries = Object . entries ( fields ) ;
127128
128129 return (
129130 < div className = "cex-state-panel" >
130131 < div className = "cex-state-header" >
131- { title }
132+ < span > { title } </ span >
133+ { statusIndicator && (
134+ < span className = "cex-state-status" > { statusIndicator } </ span >
135+ ) }
132136 </ div >
133137 < div className = "cex-state-body" >
134138 { entries . length === 0 ? (
@@ -148,12 +152,13 @@ const StatePanel: React.FC<{
148152/** Structured counterexample view with side-by-side pre/post states */
149153const StructuredCexView : React . FC < {
150154 data : StructuredJson ;
155+ property : string ;
151156 headerRightContent ?: React . ReactNode ;
152- } > = ( { data, headerRightContent } ) => {
157+ } > = ( { data, property , headerRightContent } ) => {
153158 const { preState, postState, label, instantiation } = data ;
154159
155160 // State for toolbar features
156- const [ showRemovals , setShowRemovals ] = React . useState ( true ) ;
161+ const [ showRemovals , setShowRemovals ] = React . useState ( false ) ;
157162 const [ hiddenFields , setHiddenFields ] = React . useState < Set < string > > ( new Set ( ) ) ;
158163 const [ showFilterPanel , setShowFilterPanel ] = React . useState ( false ) ;
159164 const [ isWideEnough , setIsWideEnough ] = React . useState ( true ) ;
@@ -166,7 +171,7 @@ const StructuredCexView: React.FC<{
166171
167172 const observer = new ResizeObserver ( ( entries ) => {
168173 for ( const entry of entries ) {
169- // Hide transition row when width < 600px (approximately when panels stack)
174+ // Stack panels vertically when width < 600px
170175 setIsWideEnough ( entry . contentRect . width >= 600 ) ;
171176 }
172177 } ) ;
@@ -306,34 +311,33 @@ const StructuredCexView: React.FC<{
306311 </ div >
307312 ) }
308313
309- { /* Induction counterexample transition visualization (hidden when narrow ) */ }
314+ { /* Centered action chip above panels ( when side-by-side ) */ }
310315 { isWideEnough && (
311- < div className = "cex-transition-row" >
312- < div className = "cex-transition-column" >
313- < div className = "cex-transition-state cex-transition-pre" >
314- < span className = "cex-transition-icon cex-icon-valid" > ✓</ span >
315- < span className = "cex-transition-label" > Satisfies invariant</ span >
316- </ div >
317- < div className = "cex-connector-line" />
318- </ div >
319- < div className = "cex-transition-center" >
320- < span className = "cex-action-chip" > { formatActionLabel ( label ) } </ span >
321- </ div >
322- < div className = "cex-transition-column" >
323- < div className = "cex-connector-line" />
324- < div className = "cex-transition-state cex-transition-post" >
325- < span className = "cex-transition-icon cex-icon-invalid" > ✗</ span >
326- < span className = "cex-transition-label" > Violates invariant</ span >
327- </ div >
328- </ div >
316+ < div className = "cex-action-row" >
317+ < span className = "cex-action-chip" > { formatActionLabel ( label ) } </ span >
329318 </ div >
330319 ) }
331320
332- { /* Side-by-side state panels */ }
333- < div className = "cex-states-container" >
334- < StatePanel title = "Pre-State" fields = { filteredPreState } />
321+ { /* Side-by-side or stacked state panels */ }
322+ < div className = { `cex-states-container ${ ! isWideEnough ? 'cex-states-stacked' : '' } ` } >
323+ < StatePanel
324+ title = "Pre-State"
325+ fields = { filteredPreState }
326+ statusIndicator = { < span className = "cex-status-valid" > ✓ Satisfies all invariants </ span > }
327+ />
328+ { /* Narrow view: centered action chip between stacked panels */ }
329+ { ! isWideEnough && filteredPostState && (
330+ < div className = "cex-narrow-action" >
331+ < span className = "cex-action-chip" > { formatActionLabel ( label ) } </ span >
332+ </ div >
333+ ) }
335334 { filteredPostState && (
336- < StatePanel title = "Post-State" fields = { filteredPostState } changes = { filteredChanges } />
335+ < StatePanel
336+ title = "Post-State"
337+ fields = { filteredPostState }
338+ changes = { filteredChanges }
339+ statusIndicator = { < span className = "cex-status-invalid" > ✗ Violates < span className = "cex-property-name" > { property } </ span > </ span > }
340+ />
337341 ) }
338342 </ div >
339343
@@ -571,6 +575,7 @@ const PropertyRow: React.FC<PropertyRowProps> = ({ vc, alternativeVC }) => {
571575 { activeCounterexample . structuredJson && ! showRawHtml ? (
572576 < StructuredCexView
573577 data = { activeCounterexample . structuredJson }
578+ property = { vc . metadata . property }
574579 headerRightContent = {
575580 < >
576581 < button
@@ -1208,92 +1213,27 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
12081213 align-items: center;
12091214 gap: 4px;
12101215 padding: 3px 10px;
1211- background: var(--vscode-badge-background, rgba(0, 122, 204, 0.15));
1216+ background: var(--vscode-activityBarBadge-background);
1217+ color: var(--vscode-activityBarBadge-foreground);
12121218 border-radius: 12px;
12131219 font-size: 12px;
12141220 }
12151221
12161222 .cex-instantiation-key {
1217- color: var(--vscode-descriptionForeground );
1223+ color: var(--vscode-activityBarBadge-foreground );
12181224 font-weight: 500;
12191225 }
12201226
12211227 .cex-instantiation-eq {
1222- color: var(--vscode-descriptionForeground );
1228+ color: var(--vscode-activityBarBadge-foreground );
12231229 opacity: 0.6;
12241230 }
12251231
12261232 .cex-instantiation-val {
1227- color: var(--vscode-foreground);
1233+ color: var(--vscode-activityBarBadge- foreground);
12281234 font-weight: 500;
12291235 }
12301236
1231- .cex-transition-row {
1232- display: flex;
1233- align-items: center;
1234- gap: 16px;
1235- margin-bottom: 12px;
1236- }
1237-
1238- .cex-transition-column {
1239- flex: 1;
1240- min-width: 280px;
1241- display: flex;
1242- align-items: center;
1243- justify-content: center;
1244- }
1245-
1246- .cex-connector-line {
1247- flex: 1;
1248- height: 2px;
1249- background: var(--vscode-panel-border);
1250- opacity: 0.4;
1251- }
1252-
1253- .cex-transition-center {
1254- flex-shrink: 0;
1255- display: flex;
1256- align-items: center;
1257- justify-content: center;
1258- }
1259-
1260- .cex-transition-state {
1261- display: inline-flex;
1262- align-items: center;
1263- gap: 6px;
1264- padding: 8px 16px;
1265- border-radius: 6px;
1266- font-size: 12px;
1267- font-weight: 500;
1268- }
1269-
1270- .cex-transition-pre {
1271- background: var(--vscode-diffEditor-insertedTextBackground, rgba(0, 180, 0, 0.15));
1272- border: 1px solid var(--vscode-diffEditor-insertedLineBackground, rgba(0, 180, 0, 0.3));
1273- }
1274-
1275- .cex-transition-post {
1276- background: var(--vscode-diffEditor-removedTextBackground, rgba(255, 80, 80, 0.15));
1277- border: 1px solid var(--vscode-diffEditor-removedLineBackground, rgba(255, 80, 80, 0.3));
1278- }
1279-
1280- .cex-transition-icon {
1281- font-size: 14px;
1282- font-weight: 700;
1283- }
1284-
1285- .cex-icon-valid {
1286- color: var(--vscode-testing-iconPassed, #4caf50);
1287- }
1288-
1289- .cex-icon-invalid {
1290- color: var(--vscode-testing-iconFailed, #f44336);
1291- }
1292-
1293- .cex-transition-label {
1294- color: var(--vscode-foreground);
1295- }
1296-
12971237 .cex-action-chip {
12981238 display: inline-block;
12991239 font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
@@ -1312,6 +1252,26 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
13121252 flex-wrap: wrap;
13131253 }
13141254
1255+ .cex-states-container.cex-states-stacked {
1256+ flex-direction: column;
1257+ }
1258+
1259+ .cex-narrow-action {
1260+ display: flex;
1261+ justify-content: center;
1262+ align-items: center;
1263+ padding: 8px 0;
1264+ width: 100%;
1265+ }
1266+
1267+ .cex-action-row {
1268+ display: flex;
1269+ justify-content: center;
1270+ align-items: center;
1271+ padding: 12px 0;
1272+ margin-bottom: 12px;
1273+ }
1274+
13151275 .cex-state-panel {
13161276 flex: 1;
13171277 min-width: 280px;
@@ -1323,6 +1283,9 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
13231283 }
13241284
13251285 .cex-state-header {
1286+ display: flex;
1287+ justify-content: space-between;
1288+ align-items: center;
13261289 font-weight: 600;
13271290 font-size: 12px;
13281291 padding: 8px 12px;
@@ -1333,6 +1296,26 @@ const VerificationResultsView: React.FC<VerificationResultsProps> = ({ results }
13331296 letter-spacing: 0.5px;
13341297 }
13351298
1299+ .cex-state-status {
1300+ font-size: 10px;
1301+ font-weight: 500;
1302+ text-transform: none;
1303+ letter-spacing: normal;
1304+ }
1305+
1306+ .cex-status-valid {
1307+ color: var(--vscode-testing-iconPassed, #4caf50);
1308+ }
1309+
1310+ .cex-status-invalid {
1311+ color: var(--vscode-testing-iconFailed, #f44336);
1312+ }
1313+
1314+ .cex-property-name {
1315+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
1316+ font-weight: 600;
1317+ }
1318+
13361319 .cex-state-body {
13371320 padding: 8px;
13381321 }
0 commit comments