Skip to content

Commit f3f8471

Browse files
fix(story): tighten wrap-up and chart cues
1 parent f2ddc5b commit f3f8471

7 files changed

Lines changed: 107 additions & 71 deletions

File tree

index.html

Lines changed: 37 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ <h1>
3535
<section class="findings-panel" aria-labelledby="findings-title">
3636
<div class="section-kicker">
3737
<p class="eyebrow">Key findings</p>
38-
<h2 id="findings-title">Europe grew. Public equity gains concentrated in the US.</h2>
38+
<h2 id="findings-title">Europe kept growing, but listed-equity gains and index weight shifted toward the US.</h2>
3939
</div>
4040
<div class="finding-grid">
4141
<article class="finding-card">
@@ -111,15 +111,15 @@ <h2>The benchmark is not arbitrary.</h2>
111111
<p class="eyebrow">Act 3 &middot; Divergence hypothesis</p>
112112
<h2>The gap opens when we change the measure.</h2>
113113
<p>
114-
This leads us to the hypothesis that it isn't that Europe
115-
stopped producing output, it is that output growth diverged from
116-
broader market indicators. We apply a break-fit test to find
117-
divergence points in various metrics, and find that candidate
118-
break years cluster around the 2008 crisis window. The
119-
normalization view lets you explore these critical years and
120-
view the apparent divergence - much wider for ETF data and
121-
market cap, but much narrower for GDP, and especially after
122-
adjusting for PPP.
114+
This leads to a narrower hypothesis: Europe did not stop
115+
producing output, but market-linked indicators pulled away
116+
after the crisis. To check that, we fit the log US/Europe gap
117+
with the same piecewise trend at each candidate break year from
118+
2005 to 2015 and rank those fits by BIC. The best-ranked years
119+
cluster around the 2008 crisis window. The normalization view
120+
then lets you stress-test the split across base years and
121+
lenses: it is widest for ETF and market-cap proxies, narrower
122+
for GDP, and narrower still after PPP adjustment.
123123
</p>
124124
<div class="story-stat-row">
125125
<span><strong>2.51x</strong> US ETF</span>
@@ -181,45 +181,19 @@ <h2>The sectors driving divergence.</h2>
181181

182182
<article class="story-step story-step--explore" data-story-preset="wrap-up">
183183
<p class="eyebrow">Conclusion &middot; What falling behind means</p>
184-
<h2>Europe is not collapsing. Listed-market power moved elsewhere.</h2>
184+
<h2>Europe kept growing. Market-linked gains pulled away.</h2>
185185
<p>
186186
The final scatter keeps the comparison narrow: selected Europe
187-
versus the US. Output per person is not wildly different, but the
188-
market proxy is. Europe did not stop growing; the listed-market
189-
upside concentrated elsewhere.
187+
versus the US. Output per person remains in the same broad
188+
neighborhood, but market proxies do not. The claim is not that
189+
Europe stopped producing; it is that listed-equity gains and
190+
benchmark index weight accumulated much more strongly in the US.
190191
</p>
191192
<div class="story-stat-row">
192193
<span><strong>1.18x-1.26x</strong> Europe GDP/person</span>
193194
<span><strong>0.43x-1.15x</strong> Europe ETF</span>
194195
<span><strong>1.52x</strong> US ETF</span>
195196
</div>
196-
<div class="story-verdict-panel" aria-label="Conclusion verdict">
197-
<strong>Final read</strong>
198-
<p>
199-
The evidence does not support a simple European collapse
200-
story. It supports a more specific claim: Europe continued to
201-
grow, but was outpaced in capital markets, especially through
202-
listed equity concentration in the US and in technology-heavy
203-
sectors. The divergence is much sharper in market proxies than
204-
in real output, and the gap opens around the 2008 crisis
205-
window.
206-
<!-- Europe kept growing, but the
207-
market values shifted toward the US, especially through
208-
listed equity concentration and technology-heavy sectors. -->
209-
</p>
210-
<p>
211-
The limitation is equally important: these charts measure output
212-
and listed capital, not the full well-being of households.
213-
</p>
214-
<p>
215-
It leads to a final question: do market gains and indicators
216-
really represent lived well-being trends? The data
217-
demonstrates a divergence in perceived market values, but the
218-
divergence is much smaller in real output terms. This
219-
necessitates a deeper future focus on how and whether market
220-
trends translate to broader economic welfare.
221-
</p>
222-
</div>
223197
<button class="story-preset-button" type="button" data-story-action="wrap-up">
224198
Show final comparison
225199
</button>
@@ -394,28 +368,30 @@ <h3>MSCI ACWI sectors</h3>
394368
<section class="story-close-panel" aria-label="Conclusion and limitations">
395369
<div class="section-kicker">
396370
<p class="eyebrow">Wrap up</p>
397-
<h2>Europe is not simply falling behind. It is falling behind in a specific market story.</h2>
371+
<h2>Europe kept growing, but listed-equity gains and global index weight shifted toward the US.</h2>
372+
</div>
373+
<div class="story-verdict-panel story-verdict-panel--close" aria-label="Final read">
374+
<strong>Final read</strong>
398375
<p>
399-
The evidence supports a narrower thesis: Europe continued to grow,
400-
but the investable-market rewards, sector concentration, and global
401-
index weight shifted more strongly toward the United States. The
402-
final question is whether these indicators track broad well-being,
403-
or mostly the returns to listed capital.
376+
The evidence does not support a simple European collapse story.
377+
GDP and GDP per capita reject that reading. The sharper divergence
378+
appears in ETF, market-cap, and ACWI views, where listed-equity
379+
rewards and global benchmark weight shift much more strongly toward
380+
the United States.
381+
</p>
382+
<p>
383+
The break-year check compares the same piecewise fit of the log
384+
US/Europe gap across candidate years. Those rankings repeatedly land
385+
near the 2008 crisis window, which makes the crisis period a
386+
plausible turning point for the market story even though the
387+
PPP-adjusted output split is milder.
388+
</p>
389+
<p>
390+
The limitation is equally important: these charts measure output
391+
and listed capital, not the full well-being of households. The
392+
next question is how far market gains track lived economic welfare
393+
rather than asset concentration.
404394
</p>
405-
</div>
406-
<div class="story-close-grid">
407-
<article class="story-close-card">
408-
<h3>What the data can say</h3>
409-
<p>GDP and GDP per capita reject a simple stagnation story. ETF, market-cap, and ACWI views show the sharper divergence.</p>
410-
</article>
411-
<article class="story-close-card">
412-
<h3>What it cannot fully say</h3>
413-
<p>Market data does not measure public services, inequality, household balance sheets, or lived well-being directly.</p>
414-
</article>
415-
<article class="story-close-card">
416-
<h3>How to read the project</h3>
417-
<p>Treat the guided story as the argument and the controls as the audit trail: change the indicator, year, and geography to look for exceptions.</p>
418-
</article>
419395
</div>
420396
</section>
421397

src/main.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ function renderStoryEvidenceCallout(container, callout) {
519519

520520
content.append(title, body);
521521
container.append(label, content);
522+
setStoryEvidenceCalloutCollapsedWidth(container, label);
522523

523524
if (!callout.stats?.length) return;
524525
const statList = document.createElement("div");
@@ -559,6 +560,24 @@ function resetStoryEvidenceCallout(container) {
559560
container.replaceChildren();
560561
container.hidden = true;
561562
container.removeAttribute("tabindex");
563+
container.style.removeProperty("--story-callout-collapsed-width");
564+
}
565+
566+
/**
567+
* Sizes the collapsed callout to the rendered label width.
568+
*
569+
* @param {HTMLElement} container Callout container.
570+
* @param {HTMLElement} label Callout label element.
571+
*/
572+
function setStoryEvidenceCalloutCollapsedWidth(container, label) {
573+
const collapsedWidth = Math.min(
574+
Math.max(Math.ceil(label.scrollWidth + 34), 176),
575+
320,
576+
);
577+
container.style.setProperty(
578+
"--story-callout-collapsed-width",
579+
`${collapsedWidth}px`,
580+
);
562581
}
563582

564583
/**

src/post-2008-analysis.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,14 @@ export function renderBreakFinderAnalysis(rows, container) {
5656
const wrap = d3.select(container);
5757
wrap.selectAll("*").remove();
5858
wrap
59-
.append("p")
59+
.selectAll("p.story-methodology")
60+
.data([
61+
"For each metric, we fit the same piecewise-linear model to log(US / Europe) at every candidate break year from 2005 to 2015.",
62+
"We then rank those candidates by BIC and rescale the scores within each metric so 1 marks the lowest-BIC fit and 0 the weakest; 2008 is kept as the crisis reference year.",
63+
])
64+
.join("p")
6065
.attr("class", "story-methodology")
61-
.text("Candidate break years from 2005-2015. Height shows relative BIC score for a piecewise US/Europe gap model; 1 is the best candidate for that metric.");
66+
.text((text) => text);
6267

6368
selectedRows.forEach((row) => {
6469
const item = wrap.append("div").attr("class", "story-break");
@@ -76,7 +81,7 @@ export function renderBreakFinderAnalysis(rows, container) {
7681
item
7782
.append("span")
7883
.attr("class", "story-break__axis-note")
79-
.text("2005 -> 2015, highlighted bar = best fit; 2008 is marked where relevant.");
84+
.text("2005 -> 2015, tallest bar = lowest BIC for that metric; 2008 is marked as the crisis reference year.");
8085
});
8186
}
8287

src/regional-map.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function createIndicatorMap(container, data, onSelectCountry, onSelectReg
6565
const mapLayer = viewportLayer.append("g").attr("class", "indicator-map");
6666
const scatterLayer = svg.append("g").attr("class", "scatter-layer");
6767
const labelLayer = viewportLayer.append("g").attr("class", "map-labels");
68-
const legendLayer = svg.append("g").attr("class", "map-legend");
68+
const legendLayer = svg.append("g").attr("class", "map-legend").attr("pointer-events", "none");
6969
const tooltip = d3.select(container).append("div").attr("class", "map-tooltip").attr("hidden", true);
7070

7171
renderBaseMap(baseLayer, geoPath);
@@ -122,7 +122,14 @@ export function createIndicatorMap(container, data, onSelectCountry, onSelectReg
122122
scatterLayer
123123
.attr("opacity", options.viewMode === "scatter" ? 1 : 0)
124124
.attr("pointer-events", options.viewMode === "scatter" ? "auto" : "none");
125-
renderLegend(legendLayer, data, options.axis, options.valueMode, finiteValues);
125+
renderLegend(
126+
legendLayer,
127+
data,
128+
options.axis,
129+
options.valueMode,
130+
finiteValues,
131+
options.viewMode,
132+
);
126133
renderMap(mapLayer, values, geoPath, colorScale, options, data, onSelectCountry, onSelectRegion, tooltip, container);
127134
renderLabels(labelLayer, values, options, data);
128135
renderScatter(
@@ -702,17 +709,34 @@ function createMetricColorScale(values, valueMode) {
702709
* @param {string} axis Indicator name.
703710
* @param {"growth" | "absolute"} valueMode Value mode.
704711
* @param {number[]} values Visible numeric values.
712+
* @param {"map" | "scatter"} viewMode Active view mode.
705713
*/
706-
function renderLegend(layer, data, axis, valueMode, values) {
714+
function renderLegend(layer, data, axis, valueMode, values, viewMode) {
707715
const maxValue = d3.max(values) ?? 1;
708716
const minValue = d3.min(values) ?? 1;
709717
const stops =
710718
valueMode === "growth"
711719
? getCompoundedLegendStops(minValue, maxValue)
712720
: [0, maxValue / 2, maxValue];
713721
const colorScale = createMetricColorScale(values, valueMode);
722+
const legendX = viewMode === "scatter" ? SCATTER_PLOT_BOUNDS.left + 18 : 28;
723+
const legendY = viewMode === "scatter" ? SCATTER_PLOT_BOUNDS.top + 20 : 46;
724+
const legendWidth = Math.max(220, (stops.length - 1) * 78 + 82);
725+
726+
layer.attr("transform", `translate(${legendX},${legendY})`);
714727

715-
layer.attr("transform", `translate(${WIDTH - 250},${HEIGHT - 26})`);
728+
layer
729+
.selectAll("rect.legend-backdrop")
730+
.data([0])
731+
.join("rect")
732+
.attr("class", "legend-backdrop")
733+
.attr("x", -16)
734+
.attr("y", -34)
735+
.attr("width", legendWidth)
736+
.attr("height", 56)
737+
.attr("rx", 14)
738+
.attr("ry", 14)
739+
.lower();
716740

717741
layer
718742
.selectAll("text.legend-title")

src/story-presets.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@ export const STORY_PRESETS = {
117117
stageFocus: "stage-map",
118118
callout: {
119119
label: "Conclusion evidence",
120-
title: "Similar output neighborhood, different market outcome.",
121-
body: "The final scatter is scoped to Europe + US. Selected European GDP per person growth stays near the US, but every selected European ETF proxy sits below the US.",
120+
title: "Similar output range, different market outcome.",
121+
body: "The final scatter keeps Europe and the US on the same rich-market frame. Output per person stays relatively close, but every selected European ETF proxy remains below the US.",
122122
stats: ["Europe + US only", "GDP/person close", "ETF gap large"],
123123
},
124124
},

src/story.css

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@
475475
z-index: 3;
476476
display: grid;
477477
gap: 0;
478-
width: min(176px, calc(100% - 44px));
478+
width: min(var(--story-callout-collapsed-width, 176px), calc(100% - 44px));
479479
max-width: min(320px, calc(100% - 44px));
480480
max-height: 48px;
481481
overflow: hidden;
@@ -711,6 +711,12 @@
711711
box-shadow: var(--shadow-soft);
712712
}
713713

714+
.story-verdict-panel--close {
715+
max-width: none;
716+
margin-top: 0;
717+
padding: 22px;
718+
}
719+
714720
.story-close-grid {
715721
display: grid;
716722
grid-template-columns: repeat(3, minmax(0, 1fr));

src/style.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,12 @@ button:active {
17621762
letter-spacing: 0.02em;
17631763
}
17641764

1765+
.map-legend .legend-backdrop {
1766+
fill: rgba(7, 16, 29, 0.78);
1767+
stroke: rgba(255, 255, 255, 0.12);
1768+
stroke-width: 1;
1769+
}
1770+
17651771
.scatter-axis path,
17661772
.scatter-axis line {
17671773
stroke: rgba(255, 255, 255, 0.18);

0 commit comments

Comments
 (0)