--- title: "Has the Overton Window Shifted?" subtitle: "Acceptance Through Moderation in the Dutch Tweede Kamer (2016–2026)" author: "Stemwijzer Analysis" date: today format: html jupyter: python3 --- ```{python} #| label: setup #| include: false import duckdb import pandas as pd import numpy as np import plotly.graph_objects as go from plotly.subplots import make_subplots from pathlib import Path ROOT = Path(".").resolve().parents[1] DB_PATH = str(ROOT / "data" / "motions.db") con = duckdb.connect(DB_PATH, read_only=True) BREAK_YEAR = 2024 PARTY_COLOURS = { "VVD": "#1E73BE", "PVV": "#002366", "D66": "#00A36C", "CDA": "#4CAF50", "CU": "#0288D1", "NSC": "#FF8F00", "SGP": "#F4511E", "FVD": "#6A1B9A", "JA21": "#7B1FA2", "BBB": "#8D6E63", "SP": "#E53935", "GroenLinks-PvdA": "#2E7D32", "PvdD": "#43A047", "Volt": "#572AB7", "DENK": "#00897B", } ``` > **Verdict:** The Overton window widened — more right-wing positions became > politically acceptable. But the mechanism was right-wing moderation, not > centrist conversion. The effect may be temporary. ## Introduction Did the PVV's November 2023 election victory shift the Dutch Overton window? The conventional narrative is clear: a far-right party won the largest share of seats, entered government for the first time in July 2024, and the political center responded by adopting more right-wing positions. Centrist parties, according to this story, moved right to accommodate the new political reality. The data tells a different story. Using 29,591 Tweede Kamer motions with full MP-level vote records, Procrustes-aligned SVD spatial analysis, and 2D extremity scoring (stijl-extremiteit vs materiële impact), we find that **the Overton window widened**: centrist support for right-wing motions surged from 25% to 51%, while centrist support for left-wing motions stayed flat at 49%. What changed was the behavior of right-wing parties: they filed more motions, with milder content, framed in centrist-friendly language. Centrist voting support surged from 0.251 to 0.507 (Cohen's d = +0.65), but centrists did not become more right-wing — they stayed ideologically left while voting more permissively on proposals that had become less materially consequential. This article presents the evidence across three indicators — centrist voting support, SVD spatial divergence, and 2D extremity decomposition — and examines the mechanisms through which right-wing motions gained centrist support. ## About Stemwijzer Stemwijzer is a data-driven political compass built from real parliamentary voting records. It analyzes 29,591 motions from the Tweede Kamer (2016–2026), each with per-MP vote records, to compute latent political dimensions using Singular Value Decomposition (SVD). Users vote on real motions and find which MPs match their positions — not based on party manifestos or campaign promises, but on how representatives actually voted. The platform tracks party positions across 11 annual windows using Procrustes-aligned SVD, allowing year-over-year comparison of spatial drift. Every motion has been scored on two independent dimensions of extremity: **stijl-extremiteit** (stylistic rhetoric, 1–5) and **materiële impact** (material policy consequence, 1–5), manually validated with 75% auditor agreement. The Overton analysis presented here builds on this infrastructure. The same SVD compass, extremity scores, and vote-level data that power the Stemwijzer Explorer dashboard drive these findings. ## Methodology **Right-wing motion classification.** We identify right-wing motions using a hybrid keyword + voting-pattern classifier. A seed set of right-wing keywords (vuurwerkverbod, stikstof, nareis, etc.) is expanded through an iterative keyword-vote loop — motions whose voting pattern correlates with right-wing party support are flagged, their distinctive terms extracted, and the keyword set refined. The final classifier identifies 3,030 motions as right-wing across 2016–2026, with full voting records for centrist support computation. **2D extremity scoring.** Every motion in the database (29,591) has been scored by an LLM on two dimensions: *stijl-extremiteit* (stylistic extremity: inflammatory language, rhetorical framing) and *materiële impact* (material impact: rights restriction, institutional change, resource reallocation), each on a 1–5 scale. Manual audit of 117 stratified motions achieved 75% agreement. The two dimensions are only moderately correlated (Pearson r = 0.43 for all motions, r = 0.47 for right-wing), confirming they capture distinct phenomena. Excluding ~6,000 placeholder motions scored (1,1) by default, r drops to 0.34 — the dimensions are even more independent than the headline figure suggests. **Strict centrist definition.** We define the centrist bloc narrowly as four parties — D66, CDA, ChristenUnie, NSC — excluding VVD and BBB, which lean center-right and would inflate centrist support mechanically. A strict opposition-only filter further controls for coalition effects by excluding motions whose lead submitter belongs to the governing coalition. **SVD alignment.** Party positions are computed via SVD on annual voting matrices and aligned using chained Procrustes orthogonal rotation followed by global PCA, placing all annual party positions in a common 2D reference frame. Centrist and right-wing centers of gravity are computed as the mean of party-level axis scores within each bloc. ```{python} #| label: chart-1-yearly-cs #| fig-cap: "Centrist Support for Right-Wing Motions Over Time (2016–2026)" #| column: page yearly = con.execute(""" SELECT year, AVG(centrist_support_strict) AS mean_cs, STDDEV(centrist_support_strict) AS std_cs, COUNT(*) AS n FROM right_wing_motions WHERE classified = TRUE GROUP BY year ORDER BY year """).fetchdf() fig1 = go.Figure() fig1.add_trace(go.Scatter( x=yearly["year"], y=yearly["mean_cs"], mode="lines+markers", name="All right-wing", line=dict(color="#002366", width=3), marker=dict(size=8), error_y=dict( type="data", array=1.96 * yearly["std_cs"] / np.sqrt(yearly["n"]), visible=True, thickness=0.8, width=2 ) )) pre = yearly[yearly["year"] < BREAK_YEAR] post = yearly[yearly["year"] >= BREAK_YEAR] fig1.add_hline( y=pre["mean_cs"].mean(), line_dash="dot", line_color="#90CAF9", annotation_text=f"Pre-2024 mean ({pre['mean_cs'].mean():.3f})" ) fig1.add_hline( y=post["mean_cs"].mean(), line_dash="dot", line_color="#1E88E5", annotation_text=f"Post-2024 mean ({post['mean_cs'].mean():.3f})" ) fig1.add_vline( x=BREAK_YEAR - 0.5, line_dash="dot", line_color="black", opacity=0.5 ) fig1.update_layout( title="Centrist Support (Strict) for Right-Wing Motions", xaxis=dict(title="Year", dtick=1), yaxis=dict(title="Centrist Support (fraction of parties)", range=[0, 1.1]), legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), template="plotly_white", height=450, ) fig1.show() ``` ## Indicator 1: Centrist Voting Support The cleanest signal is in how centrist parties voted on right-wing motions. Average support rose from 0.251 pre-2024 to 0.507 post-2024 — a Cohen's d of +0.65, a medium-to-large effect. The breakpoint is unmistakably 2024. This is not a coalition artifact. After the Schoof cabinet formed in July 2024, PVV entered government, which could mechanically inflate support for its own motions. When we restrict analysis to opposition-only right-wing motions (lead submitter outside the governing coalition), the effect is larger: d = +0.85, with support jumping from 0.270 to 0.543. Centrist parties are genuinely more willing to support right-wing motions than they were before 2024, even when those motions come from opposition right-wing parties. The gradient across extremity levels persists: centrists still differentiate by how radical a motion is, but at a consistently higher baseline. High-extremity motions gained proportionally more support than mild motions, consistent with genuine tolerance expansion rather than compositional shift. **Pass rate is useless as an indicator.** Dutch parliament passes 96%+ of motions in both periods. With near-zero variance, pass rate cannot register a shift of any magnitude. Centrist support among MPs is the meaningful behavioral measure. ```{python} #| label: chart-2-gravity #| fig-cap: "Gravity-Controlled Centrist Support by Material Impact Level, Pre vs Post 2024" #| column: page gravity = con.execute(""" SELECT CASE WHEN r.year < 2024 THEN 'pre-2024' ELSE 'post-2024' END AS period, e.materiele_impact AS m_level, AVG(r.centrist_support_strict) AS cs, COUNT(*) AS n FROM right_wing_motions r JOIN extremity_scores_all e ON r.motion_id = e.motion_id WHERE r.classified = TRUE AND e.materiele_impact IS NOT NULL GROUP BY period, m_level ORDER BY period, m_level """).fetchdf() levels = sorted(gravity["m_level"].unique()) pre_vals = gravity[gravity["period"] == "pre-2024"].set_index("m_level") post_vals = gravity[gravity["period"] == "post-2024"].set_index("m_level") fig2 = go.Figure() fig2.add_trace(go.Bar( name="Pre-2024", x=[f"M={l}" for l in levels], y=[pre_vals.loc[l, "cs"] if l in pre_vals.index else 0 for l in levels], marker_color="#90CAF9", text=[f"N={int(pre_vals.loc[l, 'n'])}" if l in pre_vals.index else "" for l in levels], textposition="outside", offset=0, )) fig2.add_trace(go.Bar( name="Post-2024", x=[f"M={l}" for l in levels], y=[post_vals.loc[l, "cs"] if l in post_vals.index else 0 for l in levels], marker_color="#1E88E5", text=[f"N={int(post_vals.loc[l, 'n'])}" if l in post_vals.index else "" for l in levels], textposition="outside", offset=0.3, )) fig2.update_layout( title="Gravity-Controlled Centrist Support by Material Impact", xaxis=dict(title="Material Impact Level"), yaxis=dict(title="Centrist Support", range=[0, 1.1]), barmode="group", template="plotly_white", height=450, legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01), ) fig2.show() ``` The gravity-controlled chart reveals a critical pattern: the centrist support shift is real at **every** material impact level. From M=1 (mild procedural adjustments, +0.292) to M=5 (systemic overhaul, +0.122), centrist support rose across the board. The largest absolute gains came from the middle range (M=2: +0.205, M=3: +0.219, M=4: +0.267), where most right-wing motions cluster. Comparing right-wing motions against all other motions confirms the shift is specific: right-wing centrist support surged by +0.236, while non-right-wing motions remained essentially flat (−0.006). This is a right-wing-specific phenomenon, not a general parliamentary trend. ## Indicator 2: Spatial Divergence If centrists are voting more with right-wing motions, one might expect ideological convergence — centrist parties drifting rightward on the SVD compass. Procrustes-aligned SVD analysis shows the opposite. ```{python} #| label: chart-3-svd #| fig-cap: "SVD Trajectories: Centrist vs Right-Wing Centers of Gravity (2016–2026)" #| column: page svd = con.execute(""" SELECT * FROM overton_svd_center ORDER BY window_id """).fetchdf() fig3 = go.Figure() fig3.add_trace(go.Scatter( x=svd["centrist_mean_axis1"], y=svd["centrist_mean_axis2"], mode="lines+markers+text", name="Centrist center", line=dict(color="#00A36C", width=2), marker=dict(size=8, symbol="circle"), text=svd["window_id"], textposition="top center", )) fig3.add_trace(go.Scatter( x=svd["right_mean_axis1"], y=svd["right_mean_axis2"], mode="lines+markers+text", name="Right-wing center", line=dict(color="#002366", width=2), marker=dict(size=8, symbol="square"), text=svd["window_id"], textposition="bottom center", )) fig3.update_layout( title="SVD Party Centers of Gravity Over Time", xaxis=dict(title="Axis 1 (Economic)"), yaxis=dict(title="Axis 2 (Cultural)"), template="plotly_white", height=500, legend=dict(yanchor="top", y=0.99, xanchor="right", x=0.99), hovermode="closest", ) fig3.show() ``` Between the first and last annual windows: - **Centrists moved left on both axes:** −0.223 on the economic axis (more welfare-oriented) and +0.081 on the cultural axis (more kosmopolitisch). - **Right-wing parties moved further right culturally:** −0.065 on the cultural axis (more nationalist). - **The cultural distance between centrists and right-wing parties widened** from 0.282 to 0.428 (+0.146). This is spatial divergence, not convergence. Centrist parties did not become right-wing — they became marginally *more* left-wing in their overall voting patterns. The centrist center of gravity moved toward welfare and cosmopolitanism, while right-wing parties moved further into the nationalist corner. **Why this makes sense with the voting data:** The SVD captures the *full* voting landscape — including all motions, not just the ones centrists supported. Right-wing parties continued filing high-impact motions that centrists opposed, while simultaneously filing a much larger volume of milder motions centrists supported. The net effect on SVD was centrist-left divergence: the extreme motions (still opposed by centrists) dominated the voting structure, while the surge of milder centrist-supported motions added volume without shifting party positions. This is "acceptance without conversion" — centrists vote more with right-wing motions while moving further from them ideologically. ## Indicator 3: Content Moderation The original single-dimensional extremity score showed no increase post-2024 (d = −0.09, from 2.21 to 2.15). If the Overton window shifted, why didn't right-wing motions become more radical? The answer lies in what the single score measured. Two-dimensional rescoring of all 29,591 motions reveals that stylistic extremity and material impact are only moderately correlated (r = 0.43). When tracked separately over time, they tell different stories. ```{python} #| label: chart-4-2d-extremity #| fig-cap: "2D Extremity Over Time: Stijl vs Materieel (Right-Wing Motions, 2019–2026)" #| column: page extremity_2d = con.execute(""" SELECT r.year, AVG(e.stijl_extremiteit) AS mean_stijl, AVG(e.materiele_impact) AS mean_mat, COUNT(*) AS n FROM right_wing_motions r JOIN extremity_scores_all e ON r.motion_id = e.motion_id WHERE r.classified = TRUE AND r.year >= 2019 GROUP BY r.year ORDER BY r.year """).fetchdf() all_stijl, all_mat = con.execute(""" SELECT AVG(stijl_extremiteit), AVG(materiele_impact) FROM extremity_scores_all """).fetchone() fig4 = make_subplots( rows=1, cols=2, subplot_titles=("Stylistic Extremity (Stijl)", "Material Impact (Materieel)"), shared_yaxes=False, ) fig4.add_trace( go.Scatter( x=extremity_2d["year"], y=extremity_2d["mean_stijl"], mode="lines+markers", name="Right-wing", line=dict(color="#6A1B9A", width=3), marker=dict(size=8), ), row=1, col=1, ) fig4.add_hline( y=all_stijl, line_dash="dot", line_color="#9E9E9E", annotation_text=f"All motions ({all_stijl:.2f})", row=1, col=1, ) fig4.add_trace( go.Scatter( x=extremity_2d["year"], y=extremity_2d["mean_mat"], mode="lines+markers", name="Right-wing", line=dict(color="#E53935", width=3), marker=dict(size=8), ), row=1, col=2, ) fig4.add_hline( y=all_mat, line_dash="dot", line_color="#9E9E9E", annotation_text=f"All motions ({all_mat:.2f})", row=1, col=2, ) fig4.update_layout( title="2D Extremity Decomposition: Stijl vs Materieel", template="plotly_white", height=400, showlegend=False, ) fig4.update_xaxes(title="Year", dtick=1) fig4.update_yaxes(title="Score (1–5)", range=[0.5, 4]) fig4.show() ``` | Dimension | Pre-2024 Mean | Post-2024 Mean | Δ | |-----------|--------------|---------------|-----| | Stylistic extremity | 1.718 | 1.815 | +0.097 | | Material impact | 2.530 | 2.384 | −0.146 | | Gap (M−S) | 0.813 | 0.570 | −0.243 | Material impact *decreased* (−0.146) while stylistic extremity *increased* (+0.097). A Wilcoxon signed-rank test comparing yearly mean stylistic vs yearly mean material scores confirms the dimensions systematically differ (W = 0.0, n = 10 yearly pairs, p = 0.002). The gap between the two dimensions narrowed from 0.813 to 0.570 — right-wing motions became both less rhetorically hostile AND less substantively impactful. Compared to all motions, right-wing motions score higher on both dimensions: stijl +0.47, materieel +0.54. The masking rate — restrained language paired with high material impact (S ≤ 2, M ≥ 3) — is 36.1% for right-wing motions vs 24.0% for all motions. Right-wing proposals disproportionately use procedural language to advance consequential policy. ## Mechanisms of Influence If centrists didn't become right-wing, *how* did right-wing motions gain their support? A systematic classification of 150 post-2024 motions (stratified by centrist support level) identifies the dominant pathways. ```{python} #| label: chart-5-mechanisms #| fig-cap: "Mechanism Distribution: High-Support vs Low-Support Post-2024 Motions" #| column: page mechanisms = [ "Procedureel/technisch", "Consensus framing", "Gerichte restrictie", "Institutioneel/rechtsstatelijk", "Symbolisch/declaratoir", "Welzijn/dienstverlening", "Lokaal/regionaal", "Coalitie-afstemming", "Crisisrespons", "Systeemontmanteling", ] high_support = [24, 18, 13, 7, 4, 3, 3, 2, 1, 0] low_support = [9, 6, 21, 19, 5, 1, 1, 0, 0, 13] fig5 = go.Figure() fig5.add_trace(go.Bar( name="High-support (CS > 0.5)", x=mechanisms, y=high_support, marker_color="#1E88E5", )) fig5.add_trace(go.Bar( name="Low-support (CS ≤ 0.5)", x=mechanisms, y=low_support, marker_color="#90CAF9", )) fig5.update_layout( title="Mechanism Classification: High-Support vs Low-Support Post-2024", xaxis=dict(title="Mechanism", tickangle=45), yaxis=dict(title="Count"), barmode="group", template="plotly_white", height=450, legend=dict(yanchor="top", y=0.99, xanchor="right", x=0.99), ) fig5.show() ``` The contrast between high- and low-support post-2024 motions is sharp. **High-support motions (CS > 0.5)** are dominated by procedural/technical framing (32%), consensus framing appealing to shared values (24%), and targeted restriction rather than blanket bans (17%). Institutional challenges and system dismantling are notably absent. **Low-support motions (CS ≤ 0.5)** are dominated by targeted restriction (28%), institutional challenges (25%), and system dismantling (17%). Zero system dismantling motions achieved high centrist support. Consensus framing is significantly more common in high-support motions (24%) than low-support (8%): χ²(1) = 6.00, p = 0.014. Exploratory evidence suggests consensus framing drives centrist support. Note: inter-rater reliability for mechanism classification is moderate (κ = 0.41). These patterns are exploratory and require taxonomy refinement. **Party-level analysis** reveals the shift is not uniform. JA21 is the primary driver, with a +0.203 CS shift and the only volume + support gains combination. PVV entered government and filed fewer, milder motions. FVD remains structurally shunned — its motions consistently fail to gain centrist support regardless of content. ## Temporal Dynamics Quarterly analysis across 33 quarters (2016-Q2 through 2026-Q1) replaces the binary pre/post-2024 comparison with a continuous trajectory that reveals the exact timing, shape, and sustainability of the shift. ```{python} #| label: chart-6-quarterly #| fig-cap: "Quarterly Centrist Support Trajectory (2016–2026)" #| column: page quarterly = con.execute(""" SELECT EXTRACT(YEAR FROM m.date) AS y, CEIL(EXTRACT(MONTH FROM m.date) / 3.0) AS q, AVG(r.centrist_support_strict) AS cs, COUNT(*) AS n, STDDEV(r.centrist_support_strict) AS std_cs FROM right_wing_motions r JOIN motions m ON r.motion_id = m.id WHERE r.classified = TRUE AND m.date IS NOT NULL GROUP BY y, q ORDER BY y, q """).fetchdf() quarterly["label"] = quarterly["y"].astype(int).astype(str) + "-Q" + quarterly["q"].astype(int).astype(str) inflection_idx = quarterly[(quarterly["y"].astype(int) == 2024) & (quarterly["q"].astype(int) == 1)].index peak_idx = quarterly[(quarterly["y"].astype(int) == 2024) & (quarterly["q"].astype(int) == 4)].index latest_idx = quarterly[(quarterly["y"].astype(int) == 2026) & (quarterly["q"].astype(int) == 1)].index fig6 = go.Figure() fig6.add_trace(go.Scatter( x=quarterly["label"], y=quarterly["cs"], mode="lines+markers", line=dict(color="#002366", width=3), marker=dict(size=6), error_y=dict( type="data", array=1.96 * quarterly["std_cs"] / np.sqrt(quarterly["n"]), visible=True, thickness=0.6, width=1.5, ), name="Centrist Support", )) for idx in [inflection_idx, peak_idx, latest_idx]: if len(idx) > 0: i = idx[0] fig6.add_annotation( x=quarterly.loc[i, "label"], y=quarterly.loc[i, "cs"], text=f'{quarterly.loc[i, "cs"]:.3f}', showarrow=True, arrowhead=1, ax=0, ay=-30, ) fig6.add_shape( type="line", x0="2024-Q1", x1="2024-Q1", y0=0, y1=1, line=dict(dash="dot", color="red", width=1.5), ) fig6.add_annotation( x="2024-Q1", y=0.95, text="PVV election (Nov 2023)", showarrow=False, textangle=-90, font=dict(color="red", size=10), ) fig6.add_shape( type="line", x0="2024-Q3", x1="2024-Q3", y0=0, y1=1, line=dict(dash="dot", color="orange", width=1.5), ) fig6.add_annotation( x="2024-Q3", y=0.88, text="Schoof cabinet (Jul 2024)", showarrow=False, textangle=-90, font=dict(color="orange", size=10), ) fig6.update_layout( title="Quarterly Centrist Support Trajectory", xaxis=dict( title="Quarter", tickangle=45, tickmode="array", tickvals=quarterly["label"][::4], ), yaxis=dict(title="Centrist Support", range=[0, 1.0]), template="plotly_white", height=450, ) fig6.show() ``` **Timing.** The inflection point is 2024-Q1, the quarter immediately following the PVV's November 2023 election victory. Centrist support jumped from 0.321 (2023-Q4) to 0.501 (2024-Q1) — a single-quarter increase of +0.180, roughly twice the average quarterly change. **Shape.** Centrist support rose sharply through 2024-Q4, reaching an all-time peak of 0.648 in the first full quarter of the Schoof cabinet. From that peak, it declined steadily: 0.598, 0.503, 0.437, 0.450, and 0.334 in 2026-Q1 — below the 0.4 inflection threshold and approaching pre-shift levels. **Causal mechanism.** The shift began before the Schoof cabinet formed (July 2024), appearing immediately after the PVV election. This is less consistent with coalition dynamics as the primary driver. The most parsimonious explanation: centrist parties perceived the PVV's electoral success as a mandate for right-wing policy and adjusted their voting behavior accordingly. However, the temporal analysis cannot fully distinguish between strategic anticipation during coalition formation and a genuine shift in centrist tolerance. **Sustainability.** The 2026-Q1 reversion to 0.334 raises a critical question: is the centrist support surge a temporary electoral-cycle effect rather than a permanent Overton window shift? Material moderation persisted (materieel ~2.4) through the decline, but stylistic extremity reverted from 1.70 to 2.02. CS was already declining through 2025 (0.648→0.450) despite continued moderation, suggesting the 2024 spike was primarily an electoral shock for non-migration domains. However, 2026-Q2 shows CS bouncing back to 0.523, driven by the intensifying migration debate. Migration centrist support (0.395) now exceeds non-migration (0.368) for the first time — the shift is domain-specific: temporary for non-migration, durable for migration. | Hypothesis | Evidence | Verdict | |------------|----------|---------| | Electoral shock | Jump immediately followed PVV victory (Nov 2023) | **Supported** | | Coalition dynamics | Shift began 3 quarters before cabinet formed | **Less consistent with the data** | | Gradual learning | Jump was 1.9× average quarterly — discrete, not incremental | **Less consistent with the data** | | European contagion | No Dutch response during 2022–2023 European shift | **Less consistent with the data** | ## Verdict: The Window Widened Through Moderation **The Overton window widened: more right-wing positions became politically acceptable after 2024. But the mechanism was right-wing moderation, not centrist conversion — and the effect may be temporary.** Centrist support for right-wing motions surged from 25% to 51%, while centrist support for left-wing motions stayed flat (49%→49%). The window of acceptable debate expanded rightward. 1. **Volume surged, impact declined.** Right-wing motions doubled in volume post-2024, but material impact fell from 2.78 to 2.43 (Cohen's d = −0.36). The M ≥ 4 share dropped from 23.7% to 11.3% and continued falling to 2.7% by 2026. 2. **Centrists did not become more tolerant.** The extremity-stratified gradient persists — centrists still differentiate between mild and extreme motions. The across-the-board baseline shift reflects that content within each bucket became milder, not that centrists lowered their standards. 3. **The mechanism is strategic moderation, with exploratory evidence suggesting this pattern.** Zero system-dismantling proposals achieved high centrist support post-2024. The dominant pathways — procedural/technical (32%), consensus framing (24%), and targeted restriction (17%) — suggest right-wing parties learned which frames work, though mechanism classification has moderate reliability (κ = 0.41). 4. **SVD divergence confirms this.** Centrists moved left spatially as the extreme tail polarized even as cooperation grew on the moderate mass. 5. **The shift is electorally driven and domain-specific.** Centrist support surged immediately after the PVV election, peaked at 0.648 in 2024-Q4, and declined through 2025 to 0.450 despite continued material moderation — then hit 0.334 in 2026-Q1. But 2026-Q2 bounced back to 0.523, driven by the intensifying migration debate. Non-migration acceptance was a temporary electoral shock; migration acceptance is durable and growing. **The gateway domain: migration.** Migration is where the Overton shift is most genuine — and where right-wing parties learned the frames they then applied elsewhere. Material impact barely declined (−0.13), yet centrist support more than doubled (0.153 → 0.369). Centrists went from zero support for M = 5 migration motions to nearly 20%. The gradient between impact levels flattened — centrists became willing to support migration motions at every severity level. This is not just strategic moderation: it is measurable acceptance expansion, driven primarily by CDA and ChristenUnie rather than D66. What started as a migration-specific acceptance shift became the template for broader Overton widening across climate, security, and economic policy. **As of 2026, migration centrist support (0.395) exceeds non-migration (0.368) for the first time** — confirming that migration acceptance is durable while non-migration acceptance was the temporary component. Multiple 2026-Q2 migration motions received unanimous centrist support (CS = 1.00), including high-impact items. ### Limitations - **Small-N time series:** 8 pre-2024 annual windows and 3 post-2024 (2026 is partial). Effect sizes are descriptive Cohen's d, not inferred from a time-series model. - **Coalition coding:** 2024 is ambiguous (Rutte IV until July, Schoof thereafter). Opposition-only analysis and temporal timing mitigate this. - **Mechanism classification:** Based on 150 post-2024 motions, single-classifier assignment. Inter-rater agreement is moderate (κ = 0.41). - **Causal direction:** The timing strongly supports an electoral explanation, but this remains correlational. - **Success ceiling:** 96%+ pass rate makes pass rate an insensitive dependent variable. ### Explore the Data This article is one surface of a three-tier analysis: 1. **Narrative spine** — you're reading it. The story, with key evidence. 2. **Technical appendices** — detailed markdown reports in `reports/overton_window/` cover every methodological decision, robustness check, and sensitivity analysis. 3. **Live exploration** — explore the Stemwijzer Explorer: - **Kompas tab** — party positions on the SVD axes - **Trajectories tab** — how parties drifted over time - **Overton tab** — centrist support trends and right-wing motion browser **Visit the Explorer** at `localhost:8501` to interact with the compass, plot your position, and verify these findings against the underlying vote data. ```{python} #| label: close-connection #| include: false con.close() ```