/* ============================================================
   responsive.css — breakpoint overrides
   Mobile-first refinements layered on the desktop defaults.
   ============================================================ */

/* ---------- Tablet (≤ 1024 px) ---------- */
@media (max-width: 1024px) {
  .scroller { grid-template-columns: 1fr; }
  .scroller__chart {
    position: sticky;
    inset-block-start: var(--space-3);
    block-size: 70dvh;
  }
  .scroller__text { gap: 60dvh; padding-block: 12dvh; }
  .site-footer .footer-grid { grid-template-columns: 1fr 1fr; }
}

/* ---------- Tablet portrait (≤ 768 px) ---------- */
@media (max-width: 768px) {
  .scroller__text { gap: 55dvh; padding-block: 8dvh; }
  .scroller__step {
    max-inline-size: 100%;
    padding: var(--space-4) var(--space-5);
  }
  .scroller__chart {
    block-size: 70dvh;
    padding: var(--space-4);
    border-radius: var(--radius-2);
  }
  .scroller__chart h3 { font-size: var(--fs-400); }
  .scroller__chart .chart-controls { font-size: var(--fs-100); }

  /* [A2-F6] The §A.5 panel-foot is one nowrap flex line (source LEFT, compare-chips +
     zoom/brush presets RIGHT). That row fits desktop + 768, but the presets (race
     controls ~496px) leak past the viewport on phone. Let the foot and its controls
     wrap so the preset cluster drops to its own line, and drop the ac-zoom auto-margin
     so it flows inline instead of being pinned right on a wrapped line. */
  .chapter--a2 .panel-foot { flex-wrap: wrap; }
  /* flex-basis:100% forces the controls onto their own full-width row below the source;
     without it the A2 `flex:0 0 auto` sizes the block to its content max (~479px on race:
     add-country 255 + zoom 224) so its internal flex-wrap never engages and it overflows. */
  .chapter--a2 .panel-foot .chart-controls { flex-wrap: wrap; justify-content: flex-start; flex: 1 1 100%; }
  .chapter--a2 .panel-foot .ac-zoom { margin-inline-start: 0; }

  /* Heatmap → bar morph: on small screens, sparklines + event ticks would crowd. */
  .chart-svg .spark { display: none; }
  
  .chart-svg .country-name { font-size: 11px; }

  .site-footer .footer-grid { grid-template-columns: 1fr; gap: var(--space-5); }
}

/* ---------- Phone (≤ 480 px) ---------- */
@media (max-width: 480px) {
  .brand { font-size: var(--fs-300); }   /* long title on a narrow screen */

  .container { padding-inline: var(--space-4); }

  .scroller { gap: var(--space-5); padding-inline: var(--space-4); }
  .scroller__text { gap: 65dvh; }
  /* [Sweep iter 3] Bump panel height so the map / 8-panel grid has enough
     vertical space on phone-sized viewports. 55dvh left only ~170px for the
     chart body once header + controls + source were stacked. */
  .scroller__chart {
    block-size: 72dvh;
    padding: var(--space-3);
  }
  /* The fixed .theme-toggle sits inset-inline-end from the VIEWPORT edge, while the panel
     sits inset from the viewport edge by a constant page margin — so at every width in this
     breakpoint the toggle intrudes the SAME ~61px from the panel's own right edge (measured:
     390px → toggle.left 313 vs panel.right 374; 375px → 298 vs 359 — both a 61px gap). The
     centered, full-width `.panel-head .chart-title` (h3) has no clearance for it (the legend
     got one in AMENDMENT-3 §3 via inset-block-start; the title, being horizontal/centered, is
     fixed here by narrowing its box so text-align:center naturally keeps clear on the right).
     Confirmed real, visible overlap on 7 of 11 chapters (longer titles) with a Range-based
     text-extent measurement — a plain getBoundingClientRect on the centered block reports the
     full box regardless of text length and is not a reliable overlap test. 72px clears the
     61px danger zone with an ~11px buffer at every phone width. */
  .chapter--a2 .panel-head .chart-title { padding-inline-end: 72px; }



  /* Choropleth kicker year stays large but extremes get more compact */
  .chart-svg .year-kicker { font-size: 44px; }
  .chart-svg .year-kicker-extreme { font-size: 10px; }

  /* [Comp-eval R2] Mobile typography pass for the remaining charts.
     Pattern matches the chart 1 + 2 mobile passes: kicker smaller, sub smaller,
     axis labels tighter, legend caps muted. */

  /* Chart 3b — Choropleth: the shared 44px mobile year kicker (y=56) collided with its
     "EU avg · x%" sub-line (y=76) on phone — shrink it so the two clear. */
  #chart-choropleth svg .year-kicker { font-size: 33px; }
  #chart-choropleth svg .year-kicker-sub { font-size: 11px; }

  /* Chart 5 — RateLevel: the ECB-2% label can't clear the rate line on the narrow phone top panel
     (text-vs-marks). Drop it — the dashed 2% line + step copy carry it; desktop keeps it (§C.1, clear).
     [P4.5] The end label is NO LONGER dropped here. It was, for a real reason ("runs off the narrow
     phone right margin" — measured: it started at x=344 in a 357px svg), but that cost phone readers
     the tie between the chapter's thesis number and the point on the curve it names. RateLevel.js now
     places it INSIDE the plot on phone, right-aligned under the end dot, so the reason is gone. It
     scales to 17px there: 22px is tuned to a 612px-wide desktop plot and reads oversized in 291px. */
  #chart-rateLevel svg .rl-ref-label { display: none; }
  #chart-rateLevel svg .rl-end-label { font-size: 17px; }

  /* Chart 3 — AnnotatedLine */
  #chart-annotatedLine + * .year-kicker,
  #chart-annotatedLine svg .year-kicker { font-size: 32px; }
  #chart-annotatedLine svg .year-kicker-sub { font-size: 10.5px; }
  /* [§B/§D.2 phone] The 390px plot can't hold these annotations off the line (text-vs-marks). Hide the
     secondary ones — the step dock carries the words and the peak number stays as the single callout;
     desktop keeps them all, collision-free per §B. */
  #chart-annotatedLine svg .anno-ref-label { display: none; }
  #chart-annotatedLine svg .anno-tail-label,
  #chart-annotatedLine svg .anno-tail-leader { display: none; }
  #chart-annotatedLine svg .stamp-sentence { display: none; }

  /* Chart 7 — Heatmap. Compact mode (JS, width < 560) swaps to 2-letter ISO
     row codes + short rotated headers so the 8×27 matrix stays legible on
     phone instead of crushing to ~6 px rows. */
  #chart-heatmap svg .year-kicker { font-size: 30px; }
  #chart-heatmap svg .hm-col-head { font-size: 9px; font-weight: 600; }
  #chart-heatmap svg .hm-row-label { font-size: 9.5px; font-family: var(--font-mono); letter-spacing: 0.02em; }
  #chart-heatmap svg .hm-scale-tick { font-size: 8px; }
  /* On phone the kicker-sub caption + unit label + the two leftmost rotated
     headers all collide in one ~40 px band. Drop the redundant sub-caption and
     unit text (the ramp + step copy already say "greens calm / reds bad") so the
     year kicker, ramp and headers each get clear air. */
  #chart-heatmap svg .year-kicker-sub { display: none; }
  #chart-heatmap svg .hm-scale-unit { display: none; }
  /* [FULL-SITE AUDIT · heatmap] 27 rows need real vertical room. The default
     72dvh panel + 4-line subtitle left the chart-body only ~189 px, which the
     viewBox (336×420) then shrank to fit — letterboxing the board to ~150 px
     wide with ~5 px rows. Give this chapter a taller panel and a tighter,
     clamped header so the flex body fills ~70 % of the panel (≈ 480 px → ISO
     rows ~15 px). The SVG size() now matches the box exactly, so no shrink. */
  .scroller__chart[data-chart-mount="heatmap"] { block-size: 88dvh; }
  
  .scroller__chart[data-chart-mount="heatmap"] .chart-source { font-size: 9.5px; }

  /* [D87] waffle stacks its OWN header+kicker+legend above a still-full 6-row bars block on
     phone (D86's stacked layout) -- more content than the base 56dvh panel has room for. Without
     this the JS floor-clamp masked a too-small clientHeight reading, then this chart's own
     size()'s old Math.max(360,h) floor made it WORSE by handing the SVG a taller box than the
     (correctly, ~310px) measured container actually had -- silently clipped by .chart-body's
     overflow:hidden, and the grid itself shrank to ~2px "dust" cells fighting the leftover ~39px.
     92dvh (vs heatmap's 88dvh) because this chapter stacks header+legend/kicker chrome on TOP of
     a full 6-row bars block, not just one dense grid. */
  .scroller__chart[data-chart-mount="waffle"] { block-size: 92dvh; }

  /* [R2·1e] Chart 2 — SmallMultiples: 8 panels must stay legible inside the
     ~56dvh sticky area that clears the bottom step-dock. The body is 1fr after
     the header + 2-line subtitle + source (~200px of chrome) — leaving the eight
     panels only ~34px each (busy, hard to read line shapes). We CANNOT grow the
     panel past ~56dvh without sliding the bottom rows under the fixed dock, so
     instead we claw vertical room back from the chrome: clamp the subtitle to one
     line and tighten the header/source. That lifts the flex body ≈ +80px so each
     panel gets ~45px — enough to read each curve's shape. Mirrors the heatmap
     pattern above (chart-scoped, no shared-layout change). */
  
  .scroller__chart[data-chart-mount="smallMultiples"] h3 { font-size: var(--fs-300); }
  .scroller__chart[data-chart-mount="smallMultiples"] .chart-source { font-size: 9px; }

  /* Chart 8 — DivergingBar: compact header (set in JS) + tighter labels on phone */
  #chart-divergingBar svg .db-name { font-size: 9px; }
  #chart-divergingBar svg .db-val { font-size: 9.5px; }
  #chart-divergingBar svg .db-head-c { font-size: 19px; }
  #chart-divergingBar svg .db-head-cl { font-size: 10px; }

  /* Chart 9 — Waffle is already square; kicker tightened */
  #chart-waffle svg .year-kicker { font-size: 44px; }

  /* Chart 12 — BoxPlot */
  #chart-boxplot svg .year-kicker { font-size: 32px; }
  #chart-boxplot svg .bp-annotation { font-size: 10px; }
  /* [R2·12] Shrink the kicker sub-line so the step captions fit the 390px band
     without clipping at the right edge (chart-scoped — boxplot only). */
  #chart-boxplot svg .year-kicker-sub { font-size: 11px; }
  /* [Morph-v2 · Task 9] Mobile overrides for the bar morph layer */
  .bars-textbox--top { max-inline-size: 90vw; }
  .bars-textbox__title { font-size: 18px; }
  
  /* Note + legend are hidden ≤1100px (see the morph de-crowd block below); on phone the
     title + the centred EU-27 tag under the zero line carry the deviation framing. Drop the
     verbose directional cues too — the tag alone is the reference on the narrowest screens. */
  .choro-bars-svg .bars-axis-dir { display: none; }
  .choro-bars-svg .bar-spark { display: none; }

  .theme-toggle { padding: 2px; }
  .theme-toggle button { inline-size: 24px; block-size: 24px; }

  .site-footer { padding-block: var(--space-7) var(--space-5); }
  .site-footer .legal { flex-direction: column; gap: var(--space-2); font-size: 0.7rem; }
}

/* ---------- Wide screens ---------- */
@media (min-width: 1400px) {
  .scroller { gap: var(--space-9); }
  .scroller__step { max-inline-size: 42ch; }
}

/* ============================================================
   [FULL-SITE AUDIT · G3 fix] Mobile sticky-graphic scrollytelling.
   PROBLEM: at <=1024px the single-column .scroller placed .scroller__chart
   (sticky) AFTER .scroller__text in source order, so on phones/tablets the
   chart only appeared at the very END of each chapter — the scroll-driven
   narrative (the whole point of the essay) was invisible on mobile for ALL
   12 charts. Verified in pixels: phone frames 00-06 showed only text cards.
   FIX: overlay chart + text in the SAME grid cell so the chart is sticky at
   the top of the viewport while the text steps scroll over its lower edge —
   the standard NYT / Pudding mobile pattern. Appended last so it authoritatively
   overrides the earlier <=1024 / <=768 / <=480 .scroller rules.
   ============================================================ */
@media (max-width: 1024px) {
  .scroller {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    gap: 0;
  }
  .scroller__chart,
  .scroller__text { grid-column: 1; grid-row: 1; }   /* stack in one cell */
  .scroller__chart {
    position: sticky;
    inset-block-start: var(--space-2);
    block-size: 60dvh;
    align-self: start;            /* pin to the top of the tall cell */
    z-index: 1;
    pointer-events: none;         /* base layer; re-enable interactive children below */
    padding-block: 0;
    border-radius: 0;
  }
  .scroller__chart > * { pointer-events: auto; }
  .scroller__text {
    z-index: 2;
    align-self: start;
    /* first step clears the sticky chart; later steps scroll over its lower edge */
    padding-block-start: 62dvh;
    /* [scroll-fix §3] was 18dvh — the last step (Services / heatmap peak box) never reached the
       offset:0.55 trigger before the sticky released. 44dvh gives it room to fire + dwell on mobile. */
    padding-block-end: 44dvh;
    pointer-events: none;         /* let taps fall through the gaps to the chart */
  }
  /* [R2 · 1b] Mobile step-docking. Steps stay in-flow as INVISIBLE scroll-spacers (scrollama reads
     their positions to advance the chart); ScrollController mirrors the ACTIVE step's content into
     a single fixed bottom DOCK below — so exactly one card shows, pinned beneath the sticky chart,
     never covering the chart's top (kicker / key marks). One element → no pile-up (round-1's bug). */
  .scroller__step { opacity: 0 !important; pointer-events: none; }
}
.mobile-step-dock { display: none; }
@media (max-width: 1024px) {
  .mobile-step-dock {
    display: block;
    position: fixed;
    left: var(--space-4); right: var(--space-4);
    inset-block-end: var(--space-4);
    z-index: var(--z-dock);
    max-block-size: 44dvh; overflow-y: auto;
    padding: var(--space-4) var(--space-5);
    background: var(--bg-elev);
    border: 1px solid var(--rule);
    border-radius: var(--radius-2);
    box-shadow: var(--shadow-dock);
    opacity: 0; transform: translateY(14px); pointer-events: none;
    transition: opacity var(--dur-3, 280ms) var(--ease-out), transform var(--dur-3, 280ms) var(--ease-out);
  }
  .mobile-step-dock.is-shown { opacity: 1; transform: none; pointer-events: auto; }
  .mobile-step-dock .step-eyebrow { display: block; font-size: var(--fs-100); letter-spacing: .18em; text-transform: uppercase; color: var(--accent-text); margin-block-end: var(--space-2); }
  /* [D114] Step headings reach the dock as h4, styled by the base h4 rules. Until D114 no step
     heading was an h3, so this rule matched nothing; it now only gives CH1 step 0's h3 the h4
     size, so every dock card renders alike. */
  .mobile-step-dock h3 { font-size: var(--fs-500); }
  .mobile-step-dock p { font-size: var(--fs-300); line-height: var(--lh-relaxed); color: var(--ink-soft); margin: 0; }
  .mobile-step-dock strong { color: var(--ink); }
}
@media (max-width: 480px) {
  .scroller__chart { block-size: 56dvh; }
  .scroller__text { padding-block-start: 58dvh; }
}

/* ============================================================
   [Amendment §A] Layout v2 on the single-column mobile overlay.
   The desktop rail lives in the left column, which mobile overlays ON the
   sticky chart — so the rail + persistent subtitle would float over the chart.
   Hide both here (amendment §A.4 says hide the rail on narrow screens; the mobile
   step-dock already carries persistent step context). The overlay clearance that
   used to sit on .scroller__text now rides on .scroller__steps (steps moved into
   .scroller__flow > .scroller__steps in v2). NOTE: hidden at ≤1024, not ≤860 as
   the amendment literal says, because THIS codebase's single-column overlay
   starts at 1024 — the rail must be gone wherever the two-column layout is (LOG F1).
   ============================================================ */
@media (max-width: 1024px) {
  .chapter--v2 .scroller__text { display: block; }
  .chapter--v2 .step-rail { display: none; }
  .chapter--v2 .chapter-subtitle { display: none; }
  .chapter--v2 .scroller__flow { padding-block: 0; }
  .chapter--v2 .scroller__steps {
    padding-block-start: 62dvh;
    padding-block-end: 44dvh;
    gap: 60dvh;
  }
  .chapter--v2 .scroller__chart .chart-body { margin-block: 8px 8px; }
  /* Choropleth: let the near-full-bleed map fill the short mobile panel (its desktop 16/22 margin
     shrinks the mobile map enough that the in-SVG year kicker + EU-avg legend collide). */
  .chapter--v2 .scroller__chart[data-chart-mount="choropleth"] .chart-body { margin-block: 2px 2px; }
}
@media (max-width: 480px) {
  .chapter--v2 .scroller__steps { padding-block-start: 58dvh; gap: 65dvh; }
  
}

/* ============================================================
   [R2-elevate · choropleth morph de-crowd] At intermediate widths (≤1100px,
   i.e. small laptops + tablets) the morph's secondary text — the top NOTE line
   and the top-right LEGEND — crowded the 27 dense bars + sparklines and overlapped
   them (pixel-confirmed laptop-06 / tablet-06). The title ("…above or below the
   EU-27 average…"), the centred EU-27 tag and the ←cooler/hotter→ axis cues already
   carry the deviation framing, so the note + legend are redundant here. Scoped to
   morph-only classes — no sibling chart uses them. Phone (≤480) already hides these
   via the earlier block; this fills the 481–1100 gap.
   ============================================================ */
@media (max-width: 1100px) {
  .bars-textbox__note { display: none; }
  
  /* The closing prose restates what the bars + title + axis tag already show; bottom-anchored
     over 27 dense bars it overlapped the lowest rows at these widths (tablet-06). Drop it ≤1100. */
  .bars-textbox--bottom { display: none; }
}
