/* Section layout. Mobile-first: the Figma file only provides the 1440 desktop
   artboard, so every small-screen rule below is a proposal to validate with design. */

.container, .impact__inner, .impact__outro, .chapter > .block, .priorities, .closing, .report-cta__inner {
  width: min(100% - (2 * var(--gutter)), var(--container));
  margin-inline: auto;
}

/* ---------- Header ---------- */
/* The band itself is the UNDP Design System's Country Site Header, loaded from
   assets/vendor/undp-ds before this file. What follows is only what the system
   leaves to the page that uses it — its base stylesheet, which the report does
   not load, would otherwise have set these — plus the download link. */
.country-header .header { color: var(--undpds-color-text-default); }
.country-header a { text-decoration: none; }
:where(.country-header) ul { margin: 0; }
.country-header button { font-family: inherit; }

/* The download of the system's Download Card without the card around it: the
   card's label (bold capitals, 14px, 16px from 48em) and its animated icon,
   whose arrow drops into the tray when the link is pointed at or focused. */
.download-link {
  display: flex; align-items: center;
  font-size: var(--undpds-font-size-14); font-weight: 700; line-height: 1.4;
  letter-spacing: 0.03em; text-transform: uppercase;
  color: var(--undpds-color-text-default); text-decoration: none; white-space: nowrap;
}
@media (min-width: 48em) { .download-link { font-size: var(--undpds-font-size-16); } }
.download-link .download-animated { margin-inline-start: var(--undpds-spacing-04); }
.download-link:is(:hover, :focus-visible) .download-animated::after { transform: rotate(-45deg) translate(7px, -7px); }
.download-link:is(:hover, :focus-visible) .download-animated::before { transform: translateY(-10px); }

/* In the band it behaves as the system's header button does: gone below 64em,
   where the burger menu carries it, and spaced like the controls beside it. */
.country-header .header .download-link--header { display: none; margin-inline: var(--undpds-spacing-03); }
@media (min-width: 64em) {
  .country-header .header .download-link--header { display: flex; }
  /* A burger menu left open while the window widens would hang under a band
     that no longer has a burger to close it. */
  .country-header .mobile-nav.show { display: none; }
}

/* Below 64em the band is logo, title and burger. The system sizes the title's
   cell to its text and lets nothing shrink, so a title longer than its
   Storybook "Site Title" pushes the burger onto a second row. Here the title
   takes what is left and breaks between words when it must — at 320px it
   reads "Annual Report / 2025", as the 2024 report's own header does. */
@media (max-width: 63.9375em) {
  .country-header .header .top-left:not(.large-9) { flex: 1 1 0; min-width: 0; }
  .country-header .header .site-title { flex-shrink: 1; min-width: 0; width: auto; }
  /* The menu hangs from the band, not from the grid row inside its padding:
     edge to edge, starting where the band ends. */
  .country-header .header .align-content-middle { position: static; }
}

/* The burger menu holds two entries, not the long list of sections the
   system's top padding is measured for. */
.country-header .mobile-nav .mobile-links { padding-block-start: var(--undpds-spacing-09); }
.country-header .mobile-nav .mobile-nav-options .download-link { color: var(--undpds-color-text-default); }

/* The band's language switcher, repeated in the burger menu. The system hides
   every switcher in the band below 64em, this one included, and dresses the
   menu's lists and links for its section menu — a rule and 36px under each
   list and item, a flex row and a bottom margin on each link. The dropdown
   takes the link's margin; its list and items keep their own. The band's rule
   also pushes the switcher to the end of its row: here it lines up with the
   download under it.
   In the band the open list lies over the page; in the menu it would lie over
   the download, so it opens in the flow instead and moves the download down,
   at the same 3px under the button and 16px in. */
.country-header .header .mobile-nav .dropdown-language {
  display: flex; flex-direction: column; align-items: flex-start;
  width: fit-content; justify-self: start;
  margin-inline: 0; margin-block-end: 1.58125rem;
}
.country-header .mobile-nav .mobile-links .dropdown-language ul {
  position: static; border-block-end: 0; margin: 0; margin-inline-start: var(--undpds-spacing-05);
}
.country-header .mobile-nav .mobile-links .dropdown-language.active ul { margin-block-start: 3px; }
.country-header .mobile-nav .mobile-links .dropdown-language ul li { padding-block-end: 0; }
.country-header .mobile-nav .mobile-nav-options .dropdown-language ul li a {
  display: block; margin-block-end: 0; color: var(--undpds-color-text-default);
}

/* ---------- Hero ---------- */
/* The file's hero is frame 142:2870, 1440 x 1457: two prints in the upper half,
   the display headline across the middle at 154.524px, the intro paragraph at
   1039 and the scroll arrow at 1333. The frame is taller than a laptop screen
   on purpose — the paragraph is something the reader arrives at, not something
   they land on — so nothing below is fitted to the window. The map is NOT here:
   in the design it sits behind the impact band that follows. */
.hero {
  /* One design pixel of that frame. It stops growing at 1440: past that width
     the window gets more backdrop, not a larger composition. */
  --u: min(0.06944vw, 1px);
  --hero-h: calc(1457 * var(--u));
  /* The headline's size, hoisted out of the h1 so the layout can measure it.
     `--hero-chars` and `--hero-lines` come from the template: the length of the
     longest line as it will actually be set, and how many lines there are. */
  --hero-fs: min(
    var(--fs-display),
    (100vw - 2 * var(--gutter)) / (var(--hero-chars, 10) * 0.8)
  );
  --title-h: calc(var(--hero-lines, 4) * 0.851 * var(--hero-fs));
  /* The file starts the headline 383px down its 1457px frame. That is where it
     starts here too, unless the window is too short to hold the whole headline
     under the header — then it starts as far down as it can and still finish
     inside the first screen. A headline cut across its last line is the one
     thing an opening cannot do, and it is what a 1440x900 laptop would get at
     the file's own offset. */
  --hero-top: clamp(
    calc(40 * var(--u)),
    calc(100svh - var(--header-h) - var(--title-h) - 6svh),
    calc(383 * var(--u))
  );
  position: relative; isolation: isolate; overflow: clip;
  /* The frame's own height, and only that. Stretching the hero to a window
     taller than 1457 would put the empty gradient back under the arrow, which
     is the space the file does not have and the reader should not see. On a
     very tall screen the band that follows simply starts to show, which is what
     a document does. */
  min-height: var(--hero-h);
  display: grid; align-content: start; justify-items: center;
  padding: var(--hero-top) var(--gutter) calc(83 * var(--u));
  color: var(--color-white);
  /* The backdrop URLs come from the template (--hero-bg, --hero-bg-webp) so
     they carry the content hash like every other image: swapping the file
     changes the URL and no cache keeps the old one. */
  background: #2a0f4a var(--hero-bg) center / cover no-repeat;
}
@supports (background-image: image-set(url('x.webp') type('image/webp'))) {
  .hero { background-image: image-set(var(--hero-bg-webp) type('image/webp'),
                                      var(--hero-bg) type('image/jpeg')); }
}
.hero__title {
  font-family: var(--font-display); font-weight: 700;
  /* Two limits on the size, whichever bites first, both set on the section.
     `--fs-display` is the file's own. The second is the one that matters on a
     phone: Söhne Breit sets at about 0.755em per character, so a ten-character
     line needs 7.55 times its own font size in width — more than a 360px screen
     has at the design's size. Measuring against `--hero-chars` rather than a
     fixed breakpoint means a longer French headline shrinks to fit instead of
     running off the edge. */
  font-size: var(--hero-fs);
  /* 107.248px of leading plus 24.285px between lines on a 154.524px face. */
  line-height: 0.851;
  text-transform: uppercase; text-align: center;
  margin: 0; max-width: 16ch; text-wrap: balance;
}
.hero__title-line { display: block; }
.hero__title-line > span { display: block; }
/* 1030 of the frame's 1440, set at 32px — the file's measure and the file's
   size. Held to 46rem it read as a caption under a headline instead of the
   second voice of the opening. */
.hero__intro {
  inline-size: min(100%, calc(1030 * var(--u)));
  margin-top: calc(var(--fs-display) * 0.98); text-align: center;
  font-size: max(1rem, calc(32 * var(--u))); line-height: 1.2;
}
.hero__intro p + p { margin-top: calc(21.5 * var(--u)); }
.hero__intro strong { font-weight: 800; }

/* The prints keep the frame's own geometry: `--u` is one of its pixels, the
   scene is the 1440 x 1457 frame centred in the hero and anchored to its
   bottom edge — the same edge the copy hangs from — and each print sits at the
   offset the file gives it. The right-hand print runs off the right edge of the
   page in the file, and does here. */
.hero__photos {
  position: absolute; z-index: -1; pointer-events: none;
  inline-size: calc(1440 * var(--u)); block-size: var(--hero-h);
  inset-block-start: 0; inset-inline-start: 50%;
  margin-inline-start: calc(-720 * var(--u));
}
.hero__photo {
  position: absolute; margin: 0;
  inline-size: calc(var(--fw, 560) * var(--u));
  background: var(--color-white); padding: max(3px, calc(8.327 * var(--u)));
  box-shadow: 0 18px 44px rgb(0 0 0 / 0.32);
  rotate: var(--rot, 0deg);
}
.hero__photo .polaroid__frame { display: block; overflow: hidden; overflow: clip; }
.hero__photo img { display: block; width: 100%; height: auto; }
/* Literal Figma offsets, taken from each print's rotated bounding box on the
   frame and resolved back to the unrotated box CSS lays out — `--px` / `--py` —
   with each print's distance from the midpoint between the two, `--dx` / `--dy`,
   carried alongside so the pair can be drawn closer together.

   `--spread` is that distance as a fraction of the file's own. The file hangs
   the prints 336px apart down a 1457px frame; a laptop shows a little over half
   that frame at once, so the two never meet in one screen and the composition
   arrives in pieces. At 0.45 they keep their angles, their sizes and their
   place either side of the headline, and the whole scene lands inside the first
   screen — on a laptop and, scaled by `--u`, on a phone. Horizontally they stay
   where the file puts them: that is what holds the print against the right edge
   of the page and the other against the left. */
.hero { --spread-x: 1; --spread-y: 0.38; }
.hero__photo {
  inset-inline-start: calc((var(--px) + var(--dx) * (1 - var(--spread-x))) * var(--u));
  inset-block-start:  calc((var(--py) + var(--dy) * (1 - var(--spread-y))) * var(--u));
}
.hero__photo--1 { --px: 800.1; --py: 85.75;  --dx: -433.9; --dy: 167.95; }
.hero__photo--2 { --px: -8.96; --py: 485.94; --dx: 433.9;  --dy: -167.95; }

/* The header's one scroll effect: the two prints ride the wheel at different
   speeds, so the pair opens as the reader moves while the headline stays where
   it was typeset. The larger print on the right is the near one and runs at
   roughly twice the far one on the left — that difference is what the eye reads
   as depth; a single speed would read as the page simply scrolling.

   `--travel` is each print's half-travel as a share of its own height, read by
   parallax.js, so the numbers hold at every width. Two knobs: raise both for
   more motion, widen the gap between them for more separation, 0 to stand a
   print still. Nothing else in the header is tied to the scroll. */
.hero__photo--1 { --travel: 66; }
.hero__photo--2 { --travel: 34; }

/* The veil between the prints and the words.

   White display type over a photograph of a man dressed in white cannot be
   read, and the closer the prints sit to the headline the more of it they
   cover. So a violet wash of the backdrop's own colour lies over the prints and
   under the type: light at rest, where the photographs still have to read as
   photographs, and drawn up as the reader scrolls towards the paragraph, whose
   32px copy needs the contrast far more than the 154px headline does.

   `--scrim` is the strength of that wash. The value here is its resting state
   and the one a reader keeps if the bundle never arrives; `hero-intro.js`
   writes it inline from there up to 1 over the first screen of scroll. */
.hero { --scrim: 0.6; }
@media (prefers-reduced-motion: reduce) { .hero { --scrim: 0.86; } }
.hero::after {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  /* An ellipse centred on the headline — on the headline itself, through
     `--hero-top` and `--title-h`, not on a fixed fraction of the section, so it
     follows the type up a short window instead of staying where a 1457px frame
     would have put it — and a fall towards the foot of the frame, where the
     paragraph and the arrow sit. Both die out before the edges, so the wash
     never draws a border of its own around the section. */
  background:
    radial-gradient(132% calc(var(--title-h) * 1.35)
                    at 50% calc(var(--hero-top) + var(--title-h) * 0.5),
                    rgb(26 9 50 / 0.90) 0%, rgb(26 9 50 / 0.62) 52%, rgb(26 9 50 / 0) 88%),
    linear-gradient(180deg, rgb(26 9 50 / 0) 44%, rgb(26 9 50 / 0.52) 80%, rgb(26 9 50 / 0.66) 100%);
  opacity: var(--scrim);
}

.hero__scroll {
  margin-top: calc(var(--fs-display) * 0.45); color: var(--color-yellow);
  display: inline-flex; line-height: 0;
  animation: hero-bob 2.4s var(--ease) infinite;
}
.hero__scroll svg { inline-size: calc(81.5 * var(--u)); block-size: auto; min-inline-size: 42px; }
@keyframes hero-bob { 0%, 100% { translate: 0 0; } 50% { translate: 0 0.5rem; } }
@media (prefers-reduced-motion: reduce) { .hero__scroll { animation: none; } }

/* ---------- Hero: the opening ---------- */
/* Three beats, in the order the eye should take them. The prints arrive first,
   one after the other, out of focus and settling into the angle the file gives
   them. The headline sets itself line by line over the top of them. The
   paragraph is not part of the load at all: it belongs to the scroll, and
   `hero-intro.js` ties it to the first turn of the wheel.

   The hidden state below is written only under `.js-hero`, a class the inline
   script in the head adds when animation is both possible and wanted. Without
   JavaScript, or with prefers-reduced-motion set, the hero is simply there —
   and the same script drops the class after six seconds, so a bundle that
   never arrives leaves a readable page rather than an empty one.

   The entry uses the standalone `translate`, `scale` and `filter` properties.
   The scroll parallax that follows writes to `transform`, and the two compose
   instead of overwriting each other: the print can be arriving and drifting at
   the same time without either animation knowing about the other. */
.js-hero .hero__photo {
  opacity: 0; filter: blur(16px);
  translate: var(--in-x, 0) var(--in-y, 0); scale: 1.06;
}
.hero.is-open .hero__photo {
  opacity: 1; filter: blur(0); translate: 0 0; scale: 1;
  transition:
    opacity 0.8s var(--ease) var(--in-delay, 0s),
    filter 0.9s var(--ease) var(--in-delay, 0s),
    scale 1.25s var(--ease) var(--in-delay, 0s),
    translate 1.25s var(--ease) var(--in-delay, 0s);
}
.hero__photo--1 { --in-x: calc(96 * var(--u)); --in-y: calc(-62 * var(--u)); --in-delay: 0.10s; }
.hero__photo--2 { --in-x: calc(-88 * var(--u)); --in-y: calc(74 * var(--u)); --in-delay: 0.30s; }

/* The headline starts after the first print has landed, a line at a time. No
   clipping mask: at 0.851 leading the capitals overflow their own line box, and
   a mask would shave them. */
.js-hero .hero__title-line > span { opacity: 0; translate: 0 0.42em; }
.hero.is-open .hero__title-line > span {
  opacity: 1; translate: 0 0;
  transition: opacity 0.7s var(--ease), translate 0.85s var(--ease);
  transition-delay: calc(0.9s + var(--i, 0) * 0.11s);
}

/* The arrow last: it is the instruction, and it should arrive once there is
   something to scroll away from. */
.js-hero .hero__scroll { opacity: 0; }
.hero.is-open .hero__scroll { opacity: 1; transition: opacity 0.6s var(--ease) 1.75s; }

/* The paragraph's resting state before JavaScript takes it over. */
.js-hero .hero__intro { opacity: 0; }
/* Once it has: the block itself is simply present, and what arrives is the
   words inside it, one after the other — tied to the wheel on a laptop, where
   the paragraph is below the fold, and played as the third beat of the opening
   where it is not. `hero-intro.js` sets the word opacities; this rule only
   hands the block over, with no transition of its own to fight them. */
.hero.hero--intro-words .hero__intro { opacity: 1; }


/* ---------- Impact band ---------- */
/* Full width, unlike every other section: the map behind it is measured on the
   1440 artboard and has to reach the edges of the window. Held to the 1152
   column, which is what this was, the map stopped dead at 144px and at 1296px —
   two straight grey edges down the middle of a white page, which is the cut
   that was reported. The column comes back on the two wrappers inside. */
.impact { position: relative; isolation: isolate; padding-block: var(--sp-7) 0; }
.impact__outro { padding-block-end: var(--sp-7); }

/* The stage: one screenful under the header, holding the sentence, the slot
   under it and the link, with the map behind. Sticky, and only once the script
   is in — with no script there is no sequence to play, every figure is on show
   at once and the band is an ordinary stacking section.

   This is what the sequence was missing. Driven by page scroll, the second and
   third states arrived after the sentence had left the top of the screen, so
   the reader saw figures light up under a headline that was no longer there.
   Held still, the sentence is in front of them for all three. */
.impact__stage { position: relative; }
[data-impact-enhanced] .impact__stage {
  position: sticky; top: var(--header-h);
  min-block-size: calc(100svh - var(--header-h));
  /* `safe`: on a window too short for the composition, centring would push the
     first line of the headline up behind the header, where it cannot be
     scrolled back to — the stage is held still. Safe centring falls back to
     the top edge, so the sentence is always the part that is legible. */
  display: grid; align-content: safe center;
}
/* Short windows: the file's clear space above the link, and the air under the
   figures, give way before the composition does. */
@media (max-height: 53rem) {
  [data-impact-enhanced] .impact__more { margin-top: min(calc(11.7rem - 0.6 * var(--fs-h3)), 13svh); }
  [data-impact-enhanced] .impact__figures { margin-block-end: min(var(--sp-6), 6svh); }
}
@media (max-height: 45rem) {
  [data-impact-enhanced] .impact__more { margin-top: min(calc(11.7rem - 0.6 * var(--fs-h3)), 9svh); }
}
/* The runway: empty travel under the stage, and the only thing the sequence
   costs. The stage is sticky inside the track, so it lets go exactly where the
   track ends — which is where the closing sentence begins. No pin, no spacer,
   nothing above or below this band recomputing. */
[data-impact-enhanced] .impact__runway { block-size: var(--impact-runway, 200vh); }

/* The map is placed exactly as the design places it: at its own size, offset so
   that Chad — the one shape in the file drawn at full strength, while the other
   159 sit at a tenth — lands in the margin to the left of the opening copy.
   It rides inside the stage, so it holds still with the sentence rather than
   sliding out from under it. */
.impact__map {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  overflow: clip;
  /* Where the band stops is not where the map stops: a clip alone leaves four
     straight cuts through the continents. The map is masked instead — an
     ellipse centred on Chad that dissolves the land outward, crossed with a
     fade that empties the foot of the band — so it comes out of the white and
     goes back into it with no edge anywhere for the eye to catch, and it is
     gone before the sentence that closes the section. */
  --map-fade-top: 4%;
  --map-fade-start: 76%;
  --map-fade-end: 99%;
  --map-vignette: radial-gradient(116% 94% at 30% 46%, #000 0 38%, rgba(0,0,0,0) 86%);
  --map-foot: linear-gradient(to bottom, rgba(0,0,0,0) 0, #000 var(--map-fade-top),
                              #000 var(--map-fade-start), rgba(0,0,0,0) var(--map-fade-end));
  -webkit-mask-image: var(--map-vignette), var(--map-foot);
  -webkit-mask-composite: source-in;
  mask-image: var(--map-vignette), var(--map-foot);
  mask-composite: intersect;
}
/* 3619px wide at the design's 1440, offset -560px, which puts Chad at
   x=171..345 — the margin the indented paragraph leaves free. The vertical
   offset is the file's own: the map frame starts at y=-298 and this band at
   y=1446, so the frame hangs 1744px above the stage, 121.1vw at 1440. */
.impact__mapframe {
  position: absolute;
  inline-size: 251.34vw; aspect-ratio: 3619.2 / 3534.2;
  inset-inline-start: -38.89vw;
  inset-block-start: -121.1vw;
  /* The drift and the zoom happen around Chad, not around the middle of a map
     whose middle is in the Mediterranean. */
  transform-origin: 20.19% 58.71%;
}
.impact__world, .impact__chad { position: absolute; max-width: none; }
.impact__world {
  inset: 0; inline-size: 100%; block-size: 100%;
}
.impact__world, .impact__chad { transition: opacity 520ms var(--ease); }
/* Chad on its own, in the box the file gives it inside the frame. The world
   map behind carries the country at the same tenth as the other 159, so this
   is the only place the solid navy comes from — which is what lets it leave
   and come back on its own. */
/* In the box the file gives it inside the frame:
   730.7/3619.2 and 2074.9/3534.2, 172.5 x 269.7. The world behind it steps
   back while the figures are on show; this does not, so the country is the one
   solid shape in the band from the first state to the last. */
.impact__chad {
  inset-inline-start: 20.1897%; inset-block-start: 58.7091%;
  inline-size: 4.7662%; block-size: 7.6312%;
}
/* A half lit means the figures own the stage: the map drops back to a wash, so
   the yellow reads against paper rather than against the Sahara — and the
   silhouette goes with it, because a solid Chad cut in two by a row of cards
   reads as a mistake rather than as a backdrop. It comes back the moment the
   sentence does. */
[data-impact-lit] .impact__world { opacity: 0.45; }
[data-impact-lit] .impact__chad { opacity: 0; }

/* Indented to the design's 415px, which is what opens the margin the map fills. */
.impact__context { font-size: var(--fs-body); max-width: 46rem; }
@media (min-width: 62rem) {
  .impact__context { margin-inline-start: 23.44%; max-width: 76.56%; }
  .impact__transition { margin-inline-start: 14.32%; max-width: 71.3%; }
}
.impact__lead {
  position: relative;
  font-family: var(--font-display); font-weight: 700;
  /* `--lead-chars` is the sentence's longest word, full stop included, as the
     template will set it. A word wider than the phone is the one thing a line
     break cannot fix — the French "CONSIDÉRABLES." runs 361px on a 320px
     screen at the heading size — so the type gives way first, on the same
     0.8em-a-letter measure as the hero. English, at 11 letters, never hits it. */
  font-size: min(var(--fs-h3), (100vw - 2 * var(--gutter)) / (var(--lead-chars, 1) * 0.8));
  /* The file's 149px box holds three lines of 55px trimmed to cap and
     baseline — 55 + 55 + 39 of cap height — so the leading there is 55, and
     the outline's edges, 8px outside the caps, meet in the 16px between one
     baseline and the next cap line. Lines that carry an outline are set at
     1.2 here: the yellow then runs through 27px of clear space instead of
     16, and touches no letter at any size. */
  text-transform: uppercase; line-height: 1.2; margin-block: 0 5.25rem;
  /* No indent. `Component 9` is placed at x=99 on a 1242 frame, so the file
     puts the letters at 142.97 and the "learn more" under them at 144 — both
     on the column — and lets the yellow outline hang 7px into the margin
     (2.98% of the frame, x=136.01). The outline's edge is not what lands on
     the column; the letters are. */
}

/* The five expandable figures, wherever a chapter puts them. `.stat` below is
   the card itself and does not change; these two rules are only the grid the
   design draws around it — three across a chapter, or two beside its heading. */
.statcards { display: grid; align-items: start; margin-block: var(--sp-5); }
.statcards--row { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 21px; }
.statcards--beside { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 19px; margin-block: 0; }
.stat__value, .counter__value, .card__value {
  display: block; font-family: var(--font-display); font-weight: 700;
  font-size: var(--fs-h2); line-height: 1; color: var(--color-navy);
}
/* While a figure counts it borrows the font's tabular figures, so the digits
   stop shifting sideways from one frame to the next; at rest it returns to the
   proportional set the design is drawn with, which is the set the cell is
   measured against. */
.stat__value.is-counting, .counter__value.is-counting, .card__value.is-counting {
  font-variant-numeric: tabular-nums;
}

/* 20px navy, leading 1.2, 22–24px under the numeral: the same label under
   every figure in the file, expandable or not. */
.stat__label, .counter__label, .card__label { display: block; margin-top: var(--sp-3); font-size: var(--fs-body); line-height: 1.2; color: var(--color-navy); }

/* The figure as a disclosure. Closed it is the pale card with the numeral drawn
   as an outline; open it is the yellow card with the numeral filled in and the
   explanation underneath. Both states come from the Figma component's two
   variants, so the colour change is the state indicator, not decoration. */
/* Each card is its own sizing context: the numeral is set from the card's width,
   not the viewport's, so "15,000+" shrinks to fit while "63%" keeps the design's
   size. Without it the longest figure simply ran out over the card edge. */
.stat { display: flex; flex-direction: column; container-type: inline-size; }
.stat__toggle {
  all: unset; box-sizing: border-box; display: block; cursor: pointer;
  background: var(--color-mist); padding: var(--sp-3);
  /* The colour and the box travel together. The yellow used to arrive in 200ms
     over a panel that appeared in one frame; now the panel takes 420ms to grow
     and the card takes about as long to change colour, so the reader sees one
     movement rather than a jump followed by a fade. */
  transition: background-color 360ms var(--ease), color 360ms var(--ease);
}
.stat__toggle:focus-visible { outline: 3px solid var(--color-blue); outline-offset: 2px; }
/* Outlined numeral. `text-stroke` is prefixed everywhere that supports it; the
   fallback for anything that does not is simply the filled navy numeral, which
   is legible rather than invisible — hence the paint-order of the declarations. */
.stat__toggle .stat__value {
  /* `--fig-em` is the figure's real advance width in ems, measured glyph by
     glyph in the template. The design size is the cap, the card is the limit,
     and whichever bites first wins. */
  font-size: min(var(--fs-h2), calc((100cqw - 2 * var(--sp-3)) / var(--fig-em, 4)));
  -webkit-text-stroke: 1.5px var(--color-navy);
  transition: color 360ms var(--ease);
}
/* A one-line label next to a two-line one leaves the closed row ragged for no
   reason; reserving the second line costs nothing and settles the grid. */
.stat__toggle .stat__label { min-height: 2lh; }
@supports (-webkit-text-stroke: 1px black) {
  .stat__toggle[aria-expanded='false'] .stat__value { color: transparent; }
}
.stat__chevron {
  display: block; margin-top: var(--sp-2); color: var(--color-yellow);
  transition: rotate 420ms var(--ease), color 360ms var(--ease);
}
.stat__toggle[aria-expanded='true'] { background: var(--color-yellow); }
.stat__toggle[aria-expanded='true'] .stat__value { color: var(--color-navy); }
.stat__toggle[aria-expanded='true'] .stat__label { color: var(--color-navy); }
.stat__toggle[aria-expanded='true'] .stat__chevron { color: var(--color-navy); rotate: 180deg; }
.stat__toggle:hover { background: color-mix(in srgb, var(--color-yellow) 28%, var(--color-mist)); }
.stat__toggle[aria-expanded='true']:hover { background: var(--color-yellow); }
.stat__detail {
  background: var(--color-yellow); padding: 0 var(--sp-3) var(--sp-3);
  font-style: italic; color: var(--color-navy); font-size: var(--fs-body); line-height: 1.45;
}
.stat__detail p { margin: 0; }
.stat__detail strong { font-weight: 700; font-style: italic; }
@media (prefers-reduced-motion: reduce) {
  .stat__toggle, .stat__chevron, .stat__toggle .stat__value { transition: none; }
}
.impact__transition {
  /* Centred on the column, 821 of the design's 1152 — the margin above is what
     centres it, the alignment is what the file draws. Width and margin go
     together, desktop only: the width alone left the block against the left
     edge of a phone, with a third of the screen empty on its right. Below
     62rem it takes the whole column. */
  font-size: var(--fs-h6); margin-top: var(--sp-6); text-align: center;
}
.impact__transition strong { font-weight: 800; }

/* The two halves of the opening statement. With neither chosen, the design
   draws one yellow outline running from the first word of the first half to the
   full stop after the second — the conjunction between them is inside it — and
   that outline is the closed state of the whole phrase, which is why it sits on
   `.impact__phrase` and not on either button. Choosing a half fills that half
   and retires the outline: the same closed/open language the expandable figures
   use. `all: unset` because these are buttons that have to sit inside a
   sentence and inherit its type. */
.impact__phrase {
  /* A phrase that breaks over two lines has to carry its box onto the second,
     which is the whole job of box-decoration-break here. The design's outline
     is a single union path with no rule where the two lines meet; CSS draws
     that meeting edge. It is the one place this band departs from the file. */
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
  padding: 0.02em 0.1em;
  box-shadow: inset 0 0 0 2px var(--color-yellow);
  transition: box-shadow 280ms var(--ease);
}
[data-impact-lit] .impact__phrase { box-shadow: none; }
/* Once the script has traced the outline as one shape, the CSS boxes retire.
   The SVG sits over the title's box and over the text — in the file the
   stroke runs across the letters, not behind them — and takes no events. */
.impact__lead[data-outlined] .impact__phrase { box-shadow: none; }
.impact__outline {
  position: absolute; inset: 0; width: 100%; height: 100%;
  overflow: visible; pointer-events: none; z-index: 1;
}
.impact__outline path { fill: none; stroke: var(--color-yellow); stroke-width: 2; stroke-linejoin: miter; }
[data-impact-lit] .impact__outline { display: none; }
/* The fill arrives as a sweep from the first letter to the last, not as a box
   that appears: it is the same gesture as a highlighter, and it tells the eye
   which half of the sentence the figures underneath belong to. */
/* The yellow is painted on a span inside the button, not on the button. A
   button stays one atomic box whatever its `display` says, so a half that
   wrapped onto a second line became a yellow block as wide as the column, and
   the full stop after it fell onto a line of its own (client review, October
   2026). An inline span breaks with the words and paints only under them. */
.impact__mark {
  all: unset; box-sizing: border-box; cursor: pointer; color: inherit;
  transition: color 280ms var(--ease);
}
.impact__mark-text {
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
  padding: 0.02em 0.1em;
  background-image: linear-gradient(var(--color-yellow), var(--color-yellow));
  background-repeat: no-repeat; background-size: 0% 100%;
  transition: background-size 520ms var(--ease);
}
.impact__mark[data-lit] { color: var(--color-navy); }
.impact__mark[data-lit] .impact__mark-text { background-size: 100% 100%; }
/* Where the sequence does not play — narrow screens, reduced motion — both
   halves are lit for good and the buttons are disabled: there they are words
   in a sentence, and they flow as words, so the full stop stays on the line of
   the word it closes. */
.impact__mark:disabled { display: contents; }
/* Il giallo su queste due metà dice a che punto è la sequenza, non dove sta il
   mouse: la mano che passa sopra la frase lascia il segno fermo. Restano il
   cursore e il focus visibile, che sono l'unico avviso di cui la tastiera e lo
   screen reader hanno bisogno. */
.impact__mark:focus-visible { outline: 3px solid var(--color-blue); outline-offset: 3px; }
.impact__mark:disabled { cursor: auto; }

/* Il paragrafo sotto la frase nomina le stesse due idee che la frase separa in
   due metà: i problemi e il potenziale. Mentre il lettore attraversa il primo
   tempo, ciascuna viene ripresa dallo stesso gesto da evidenziatore — da
   sinistra a destra, una alla volta, nell'ordine in cui si leggono. Il giallo
   qui sta a metà forza: il testo di servizio non può gridare quanto la frase
   che lo introduce, e le due metà sopra restano la cosa più accesa della banda.
   Senza script il segno è già posato: nulla da aspettare, niente da premere. */
.impact__cue {
  box-decoration-break: clone; -webkit-box-decoration-break: clone;
  padding: 0.04em 0.1em;
  background-image: linear-gradient(
      color-mix(in srgb, var(--color-yellow) 50%, transparent),
      color-mix(in srgb, var(--color-yellow) 50%, transparent));
  background-repeat: no-repeat; background-size: 100% 100%;
}
[data-impact-enhanced] .impact__cue {
  background-size: 0% 100%;
  /* Più lento del tratto sulla frase: è un segno che accompagna la lettura di
     tre righe, non l'accensione di due parole. */
  transition: background-size 720ms var(--ease);
}
[data-impact-enhanced] .impact__cue[data-lit] { background-size: 100% 100%; }

/* The figures of context. The paragraph and both card groups occupy one grid
   area once the script is in — in the file they all start at the same y and only
   one is ever on show; until then they stack down the page and everything is
   readable. `start`, because the paragraph is shorter than a card row and the
   design hangs it from the top of the slot. */
.impact__figures { margin-block: 0 var(--sp-6); }
[data-impact-enhanced] .impact__figures { display: grid; }
[data-impact-enhanced] .impact__figures > * { grid-area: 1 / 1; align-self: start; }
[data-impact-enhanced] .impact__context {
  opacity: 0; translate: 0 1.25rem;
  transition: opacity 420ms var(--ease), translate 420ms var(--ease);
}
[data-impact-enhanced] .impact__context[data-shown] { opacity: 1; translate: 0 0; }
/* Stretch, not start: one card in three carries a note under its figure, and
   with the boxes sized to their contents that one card ends 28px lower than
   its neighbours — a ragged row where the design has a band. */
.impact__cards { display: grid; gap: 21px; align-items: stretch; }
.impact__cards[data-count='3'] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.impact__cards[data-count='4'] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* The row arrives figure by figure, left to right — one row of four fading in
   as a block reads as a panel being swapped; staggered, it reads as counting. */
[data-impact-enhanced] .impact__cards { opacity: 0; }
[data-impact-enhanced] .impact__cards[data-shown] { opacity: 1; }
[data-impact-enhanced] .impact__cards .indicator {
  opacity: 0; translate: 0 1.75rem;
  transition: opacity 460ms var(--ease), translate 460ms var(--ease);
}
[data-impact-enhanced] .impact__cards[data-shown] .indicator {
  opacity: 1; translate: 0 0;
  transition-delay: calc(var(--i, 0) * 80ms);
}
.indicator {
  container-type: inline-size;
  background: var(--color-yellow); color: var(--color-navy); padding: var(--sp-3);
}
/* Label, figure, note: 20px, 70px, 20px in the file, and the note is the only
   one of the three set bold. */
.indicator__label { display: block; font-size: var(--fs-body); line-height: 1.2; min-height: 2lh; }
.indicator__value {
  display: block; margin-top: var(--sp-2);
  font-family: var(--font-display); font-weight: 700; line-height: 0.8;
  /* Sized from the card, not the viewport: "92.66%" is half again as wide as
     "11%" and would otherwise run over the edge of its own card. */
  font-size: min(var(--fs-h2), calc((100cqw - 2 * var(--sp-3)) / 4.6));
}
.indicator__note {
  display: block; margin-top: var(--sp-2);
  font-size: var(--fs-body); font-weight: 800; line-height: 1.2;
}
/* The file puts 556px between the top of the headline and the link, and the
   clear space in the middle of that is where the silhouette of Chad sits. The
   headline is three lines: at leading 1.2 it stands 0.6 sizes taller than the
   file's, and that much comes off the margin here so the link keeps the
   file's distance from the top of the title rather than from its foot. */
/* On a short window the file's clear space would push the link off the stage,
   so it gives way to the height of the viewport before the composition does.
   No indent: the file sets this TCA at x=144, the column edge, like the four
   in the chapters. */
.impact__more {
  margin-top: min(calc(11.7rem - 0.6 * var(--fs-h3)), 21svh);
}

/* Narrow screens, where the seven figures stack under the sentence (client
   review, October 2026: two cards ran into each other and left a hole beside
   them). The two groups were each fitting as many 11rem columns as they could,
   so a group of three on two columns left its third card alone on a row, and
   the second group started flush under it. Now: one column on a phone, two
   from 30em with the odd card across the row — four across a tablet set the
   figures at 20px — and the gap between the groups is the gap between cards. */
@media (max-width: 62rem) {
  .impact__cards[data-count='3'], .impact__cards[data-count='4'] { grid-template-columns: minmax(0, 1fr); }
}
.impact:not([data-impact-enhanced]) .impact__cards + .impact__cards { margin-top: 21px; }
@media (min-width: 30em) and (max-width: 62rem) {
  .impact__cards[data-count='3'], .impact__cards[data-count='4'] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .impact__cards .indicator:last-child:nth-child(odd) { grid-column: 1 / -1; }
  /* Its figure keeps the size of its neighbours': it is sized from the card,
     and this card is two cards wide. */
  .impact__cards .indicator:last-child:nth-child(odd) .indicator__value {
    font-size: min(var(--fs-h2), calc(((100cqw - 21px) / 2 - 2 * var(--sp-3)) / 4.6));
  }
}
@media (prefers-reduced-motion: reduce) {
  .impact__mark, .impact__mark-text, .impact__cue, .impact__phrase, .impact__cards, .impact__context,
  .impact__world, .impact__cards .indicator { transition: none; }
}


/* ---------- Chapters ---------- */
/* Two of the chapter prints run off the edge of the canvas in the file — one
   to the left, one to the right — and they do here too. Off the canvas is not
   the same as off the page: at 1440, the width the file is drawn at, the
   right-hand print put 147px of empty page beyond the window and a horizontal
   scrollbar under it. Clipped on x only, so the same prints still climb over
   the band above without being cut. `clip` rather than `hidden`: it trims the
   overflow without making the chapter a scroll container, which `hidden` would
   do and which would break any sticky element placed inside it later. */
.chapter { padding-block: var(--sp-7); overflow-x: clip; }
/* No minimum height. With one, and the text resting on the band's lower edge,
   every extra line of title ate the space above it: the three-line chapters
   opened 60px higher than the one-line ones. The band now takes its height from
   its own text, so the 100px over the title is the same on all five. */
.chapter__intro { position: relative; display: grid; isolation: isolate; overflow: clip; }
/* Static backdrop. It carried a vertical parallax until the gradient was read
   properly: a 90deg gradient is uniform down every column, so vertical travel
   showed nothing — and with the travel gone the -16% bleed that concealed it
   has no job either. */
.chapter__band {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(90deg, var(--band));
}
.chapter__intro-text { position: relative; z-index: 1; }
[data-chapter="trust"]   { --band: #310c46, #241056, #141d77, #0b47a4, #087bcb; }
[data-chapter="crises"]  { --band: #605ec1, #432d99, #401878, #4c1061, #710f59; }
[data-chapter="climate"] { --band: #a11989, #53187b, #291976, #122179, #0a297b; }
[data-chapter="health"]  { --band: #0e7dc8, #2061bc, #3239a6, #411e87, #5a177b; }
[data-chapter="youth"]   { --band: #270c46, #221059, #1a1c77, #153796, #1c61bb; }
.chapter__intro-text {
  width: min(100% - (2 * var(--gutter)), var(--container));
  margin-inline: auto; color: var(--color-white);
  /* The design leaves 107px between the last line of the band's paragraph and
     the edge of the gradient, on every chapter. At an even padding the
     paragraph sat 43px lower, and the prints that climb into the band from the
     blocks below — chapters 2 and 3 — arrived on top of it. */
  padding-block: max(var(--sp-5), 6.94vw) max(var(--sp-5), 7.43vw);
}
/* 100px from the title to the paragraph in the file (142:2944 → 142:2943),
   against the 16px a heading carries by default. */
.chapter__title {
  font-family: var(--font-display); font-size: var(--fs-h3);
  text-transform: uppercase; margin-bottom: max(var(--sp-4), 6.94vw);
  /* 1057 of the 1152 column, as the file draws it (142:2944). The 18-character
     measure it had instead is what broke three of the five titles onto a third
     line in the first place. */
  max-width: 91.75%;
}
.chapter__lead { font-size: var(--fs-h6); font-weight: 500; line-height: 1.2; max-width: 42rem; }
/* The indent is the design's own: title on the column edge, paragraph set in to
   415px of the 1440 artboard and 820 wide. Below the two-column breakpoint the
   indent costs more than it says, so it is not applied. */
@media (min-width: 62rem) {
  .chapter__lead { margin-inline-start: 23.52%; max-width: 71.18%; }
}

/* The print in the health and youth bands (October 2026 debrief): under the
   title, left of the paragraph, hanging past the band's lower edge into the
   100px over the next title. It floats, so the band grows to hold it when it is
   deeper than the paragraph; the negative bottom margin is the hang plus the
   band's own bottom padding. `--art` is one artboard px of the column, as in
   the blocks. Its right edge is where the file puts it, clear of the
   paragraph's 415px indent; its left edge gives way to the window, so below
   the 1440 artboard the print narrows instead of running off the page. Its
   parallax travel is held to 4% of its height (`--travel`), less than the air
   over it, so it never climbs onto the title. */
.chapter__intro:has(.chapter__photo) { overflow: visible; }
@media (min-width: 62rem) {
  .chapter__intro-text:has(.chapter__photo) { container-type: inline-size; }
  .chapter__intro .chapter__photo {
    --art: calc(100cqw / 1152);
    --right: calc((var(--p-col) + var(--fw)) * var(--art));
    --w: min(calc(var(--fw) * var(--art)), calc(var(--right) + (100vw - 100%) / 2 - 1.5rem));
    float: left; max-inline-size: none; inline-size: var(--w);
    margin-inline: calc(var(--right) - var(--w)) 0;
    margin-block: calc(var(--top) * var(--art) - max(var(--sp-4), 6.94vw))
                  calc(-1 * (max(var(--sp-5), 7.43vw) + var(--hang) * var(--art)));
  }
}
/* On a phone the print follows the paragraph and the band stops short of its
   foot, so it still reads as hanging off the band. */
@media (max-width: 61.99rem) {
  .chapter__intro-text:has(.chapter__photo) {
    display: flex; flex-direction: column; padding-block-end: var(--sp-4);
  }
  .chapter__intro .chapter__photo {
    order: 1; align-self: flex-start; inline-size: min(78%, 24rem); margin: var(--sp-5) 0 0;
  }
  .chapter__intro:has(.chapter__photo) .chapter__band { inset-block-end: calc(var(--sp-4) + 2.5rem); }
}

/* Every block is a size container: `--art` is one px of the 1440 artboard as a
   share of the block's own width, and it is what turns the file's numbers into
   layout — usable by the children for widths and vertical offsets alike (a
   percentage would resolve against the height for the latter). */
.block { padding-block: var(--sp-6); --pad-top: var(--sp-6); container-type: inline-size; --art: calc(100cqw / 1152); }
/* The file's vertical rhythm is one number: 100px from a block's last line to
   the hairline, 100 from the hairline to the next title, 100 from a gradient
   band to the title under it and 100 from the last block to the next band. */
@media (min-width: 62rem) {
  .block { padding-block: 6.25rem; --pad-top: 6.25rem; }
  .chapter { padding-block: 0; }
}
/* Söhne Breit Fett 35px in the design — the twelve block titles were the one
   place where the display face had been left as body type. */
/* 50px from the title to whatever follows it — paragraph, figures or cards
   (136:255 → 136:275, 136:262 → 136:285). The default 16px is what made the
   twelve blocks read as one paragraph with a bold first line. */
.block__heading {
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h5);
  max-width: 24ch; margin-bottom: calc(50 * var(--art));
}
/* And 50px again from the last line to the link (136:275 → 136:294), measured
   in the file to the cap line: the touch target's own padding comes off it.
   Three blocks out of four had the link against the text. */
.block__text > .tca { margin-block-start: calc(50 * var(--art) - 0.5rem); }
.block__body { max-width: 40rem; }
/* Paragraphs inside a body: 21.5px apart at 20px in the file, 1.075em. */
.block__body p { margin: 0; }
.block__body p + p { margin-top: 1.075em; }
/* Bulleted bodies (the two health blocks): the paragraphs' spacing, native
   markers so the list keeps its semantics in every screen reader. */
.block__body--list { margin: 0; padding-inline-start: 1.2em; list-style: disc; }
.block__body--list li + li { margin-top: 1.075em; }

/* The yellow hairline the file draws between blocks: 1240 wide on the 1440
   artboard, so 100px in from each edge — wider than the 1152 column the text
   sits in, by 52px a side. It is the one element of a chapter that steps out of
   the column, and the only separator the design uses. */
.block-rule {
  border: 0; height: 0; margin: 0 auto;
  width: min(100% - 2 * clamp(1rem, 6.94vw, 100px), calc(var(--container) + 2 * 52px));
  border-top: 1px solid var(--color-yellow);
}

/* ---- Per-block geometry ----
   In the file every block has its own column, drawn by hand: the text of
   "Local governments" starts at 520 and runs 734 wide, "Smarter medicine" at
   624 for 540, the closing at 519 for 732 — none of them on a shared grid.
   `--col` and `--span` carry those two numbers from the content model, in px
   on the 1440 artboard, and are applied here as fractions of the 1152 column so
   the composition scales with it. Blocks without them keep the generic flow. */
@media (min-width: 62rem) {
  .block--placed .block__text {
    margin-inline-start: calc(var(--col, 0) * var(--art));
    width: calc(var(--span, 1152) * var(--art));
    max-width: none;
  }
  .block--placed .block__body, .block--placed .block__heading { max-width: none; }
}

.counters, .cards { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); margin-block: var(--sp-4); }
/* The design sets a figure at 100px when it has the full column and at 70px when
   it shares the row; the numeral is then capped by its own cell so a long value
   shrinks instead of running over. `--fig-em` is the figure's real advance
   width in ems, measured glyph by glyph in the template. */
.counter, .card { container-type: inline-size; min-width: 0; }
.counter__value { font-size: min(var(--fs-h2), calc(100cqw / var(--fig-em, 4))); }
.block--xl .counter__value { font-size: min(var(--fs-h1), calc(100cqw / var(--fig-em, 4))); }
.card__value { font-size: min(var(--fs-h2), calc(100cqw / var(--fig-em, 4))); }
/* 70 → 56px, 100 → 80px: Söhne Breit at leading 0.8 in the file, so the label
   hangs 80px under a 100px figure and 56 under a 70. */
.counter__value, .card__value { line-height: 0.8; }
/* A card is a pale box in the file — 297×224 beside "Making institutions",
   357×224 under "Young people" — with the text 30px in from the sides and 40px
   from the top. The one item drawn without a box (the Sahel Youth Pact line)
   is `card--bare`. */
.card { background: var(--color-mist); padding: 2.5rem 1.875rem 1.875rem; min-block-size: 14rem; }
.card--bare { background: none; padding-inline: 0; }
@media (max-width: 61.99rem) { .card { min-block-size: 0; padding: var(--sp-3); } }
.card__title { display: block; font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h5); line-height: 1.2; }
.card__title + .card__label { margin-top: var(--sp-3); }
/* Some figures are drawn as an outline in the file — 40+, 500+, 950+, 1,000+,
   7, 5 — and some filled: 96%, 350,000, 1,200, 30. Which is which is data on
   the figure, and the outline is the same stroke the expandable cards use. */
.counter--outline .counter__value, .card--outline .card__value {
  -webkit-text-stroke: 1.5px var(--color-navy);
}
@supports (-webkit-text-stroke: 1px black) {
  .counter--outline .counter__value, .card--outline .card__value { color: transparent; }
}

/* Cards beside a narrow title ("Making institutions more inclusive"): title in
   a 253px column at the left, three 297px cards from x=414 stepping 315, their
   top 23px above the title's; the link under everything, at the left. The
   card grid's percentages resolve against its own width, so they are written
   over (1152 − offset), not over the column. */
@media (min-width: 62rem) {
  .block--aside .block__text {
    display: grid; width: 100%; margin-inline-start: 0; align-items: start;
    grid-template-columns: calc(var(--span, 253) * var(--art)) minmax(0, 1fr);
    column-gap: calc((var(--card-col, 270) - var(--span, 253)) * var(--art));
  }
  .block--aside .block__heading { grid-column: 1; grid-row: 1; margin-bottom: 0; }
  .block--aside .cards {
    grid-column: 2; grid-row: 1; margin-block: calc(-23 * var(--art)) 0;
    grid-template-columns: repeat(3, calc(var(--card-w, 297) / (1152 - var(--card-col, 270)) * 100%));
    column-gap: calc((var(--card-step, 315) - var(--card-w, 297)) / (1152 - var(--card-col, 270)) * 100%);
  }
  .block--aside .tca { grid-column: 1 / -1; grid-row: 2; justify-self: start; margin-block-start: calc(40 * var(--art) - 0.5rem); }
}

/* Centred block ("Preventing conflict"): the title is set centred over 841px,
   the two 100px figures sit centred in two 401px cells stepping 419, and the
   labels are centred under them. */
@media (min-width: 62rem) {
  .block--centred .block__heading { text-align: center; max-width: none; }
  .block--centred .counters {
    justify-content: start;
    margin-inline-start: calc((var(--fig-col, 166) - var(--col, 155)) * var(--art));
    grid-template-columns: repeat(2, calc(var(--fig-w, 401) / (var(--span, 841) - var(--fig-col, 166) + var(--col, 155)) * 100%));
    column-gap: calc((var(--fig-step, 419) - var(--fig-w, 401)) / (var(--span, 841) - var(--fig-col, 166) + var(--col, 155)) * 100%);
  }
  .block--centred .counter { text-align: center; }
  .block--centred .counter__label { margin-inline: auto; max-width: 301px; }
}

/* Title beside the figures ("Protecting children against malaria"): title in a
   409px column, the two figures stacked in a 574px column from x=624, level
   with the title. The print takes the space under the title. */
@media (min-width: 62rem) {
  .block--beside .block__text {
    display: grid; align-items: start;
    grid-template-columns: calc(var(--span, 409) * var(--art)) calc(var(--fig-w, 574) * var(--art));
    column-gap: calc((var(--fig-col, 480) - var(--span, 409)) * var(--art));
    width: 100%;
  }
  .block--beside .block__heading { grid-column: 1; margin-bottom: 0; }
  .block--beside .counters { grid-column: 2; grid-row: 1; margin-block: 0; grid-template-columns: minmax(0, 1fr); gap: var(--sp-5); }
  /* The print under the title (October 2026 debrief): 50px below it, from
     x=-77 and 518 wide on the artboard, running 60px past the hairline under
     the block, as the other prints cross theirs. Its parallax
     travel is held to 4% of its height, under the air above it. */
  .block--beside:has(.polaroids) { display: block; }
  .block--beside:has(.polaroids) .block__text { grid-template-rows: auto 1fr; }
  .block--beside:has(.polaroids) .counters { grid-row: 1 / span 2; }
  .block--beside .polaroids {
    grid-column: 1; grid-row: 2; display: block;
    inline-size: calc(var(--p-fw) * var(--art));
    margin: calc(50 * var(--art)) 0 calc(-1 * (var(--pad-top) + 60 * var(--art))) calc(var(--p-col) * var(--art));
  }
  .block--beside .polaroids .polaroid { inline-size: 100%; margin: 0; }
}

/* Columns side by side ("Young people shaping regional dialogue", "Building
   digital skills for tomorrow"): each item has its own start and width in the
   file — 144/357, 519/357, 921/308 — so the list is a grid whose tracks are
   those widths and the gaps between them, written by the template from the
   content model (`--tracks`), and each item names its track. */
@media (min-width: 62rem) {
  .block--columns .counters, .block--columns .cards {
    grid-template-columns: var(--tracks); gap: 0; margin-inline: 0; width: 100%;
  }
  .block--columns .counter, .block--columns .card { grid-column: var(--track, auto); }
  /* The youth print runs 39px into the Sahel pact column in the file, and at
     1440 the title's widest line stops 14px short of its white border. Below
     the artboard the print shrinks with the column while the 35px titles did
     not: from 992 to 1200 the title wrapped wider and met the border. The
     row's titles now scale with the artboard as the print does, so they keep
     the file's wrap and its 14px. A worded card holds no figure, so it drops
     its container role and `--art` resolves against the block. */
  .block--columns:has(.polaroids--placed) .card:not(:has(.card__value)) { container-type: normal; }
  .block--columns:has(.polaroids--placed) .card:not(:has(.card__value)) .card__title {
    font-size: min(var(--fs-h5), calc(35.04 * var(--art)));
  }
}

.polaroids { display: flex; flex-wrap: wrap; gap: var(--sp-5); margin-block: var(--sp-5); }
/* From ~1000px the design puts the print beside the copy rather than under it;
   `--left`/`--right` come from the photo's side in the Figma composition. */
@media (min-width: 62rem) {
  .block--feature:has(.polaroids), .block--counters:has(.polaroids), .block--cards:has(.polaroids) {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--sp-6); align-items: center;
  }
  .block--feature:has(.polaroids) .block__body { max-width: none; }
  .polaroids { margin-block: 0; }
  /* Beside a print the figures stack one per row, 50px apart in the file
     (solar energy: 1,200 then 30, both 574 wide at x=144). */
  .block--counters:not(.block--columns):has(.polaroids) .counters,
  .block--cards:not(.block--columns):has(.polaroids) .cards { grid-template-columns: minmax(0, 1fr); gap: calc(50 * var(--art)); }
  /* A block whose print carries coordinates is not a 50/50 grid: the text
     column takes its numbers from the file and the print is laid where the
     file puts it — `--p-col` from the column start, `--p-dy` from the top of
     the title, both in px on the 1440 artboard. `--art` is one artboard px as
     a share of the column's width (a container unit, so it works for the
     vertical offset too — a percentage would resolve against the height).
     The prints run over the lines and past the column edges, as drawn; the
     block reserves the height of the print's bounding box (`--p-ext`) so it
     never runs into the next block's text. */
  :is(.block, .closing):has(.polaroids--placed) { display: block; position: relative; }
  /* The block is a container, so it is also a stacking context: whatever z its
     prints carry stays inside it, and the next chapter's band — positioned and
     later in the page — painted over the solar print where it runs down into
     the band. Lifting the block puts its prints in front of the band, as HQ
     asked (October 2026); the header (z 9) and the dialogs (top layer) still
     sit above it. */
  .block:has(.polaroids--placed) { z-index: 1; }
  /* The dialog is excluded on purpose: it lives in the top layer, where a
     `position: relative` becomes `absolute` against the top of the document.
     Opening it then focuses its close button up there, and the browser
     smooth-scrolls the whole page back to the start to show it. */
  :is(.block, .closing):has(.polaroids--placed) > :not(.polaroids, .modal) { position: relative; z-index: 1; }
  /* The prints cross the lines in the file ("Local governments" by 68px, the
     youth print by 334) and the closing's runs down over the footer band, so
     no depth is reserved for a print on the right: the next title starts at
     the left and never meets it. A print on the left shares the column with
     that title, and the file keeps 55px between the two — the block reserves
     exactly that: print depth, less the 100 of padding and the 55 of air. */
  .block:has(.polaroids--placed.polaroids--left) > .block__text {
    min-block-size: calc((var(--p-ext, 0) - 155) * var(--art));
  }
  .polaroids--placed {
    position: absolute; margin: 0; display: block; z-index: 0;
    inset-inline-start: calc(var(--p-col, 0) * var(--art));
    inset-block-start: calc(var(--pad-top) + var(--p-dy, 0) * var(--art));
    inline-size: calc(var(--p-fw, 470) * var(--art));
  }
  .polaroids--placed .polaroid { inline-size: 100%; margin: 0; }
  .polaroids--left { order: -1; }
}
/* In Figma the prints are not one size: they run 340–648px on the 1440 artboard,
   and that spread is a large part of how the page paces itself. `--fw` carries
   each print's Figma width, compressed here onto 78–100% of the column — the
   design's size hierarchy survives without the smallest print becoming a stamp.
   The white border stays a constant width, as it is in the design, so small
   prints read as proportionally thicker-framed. */
/* The prints tip on their horizontal axis as they pass (see parallax.js), and
   a tip only reads as depth under perspective: 1200px is a long lens — enough
   foreshortening to see the card turn, not so much that its edges skew. */
.polaroids { perspective: 1200px; }
.polaroid {
  margin: 0;
  transform-style: preserve-3d; backface-visibility: hidden;
  inline-size: calc(78% + (var(--fw, 470) - 340) * 0.0714%);
  max-inline-size: 100%;
  background: var(--color-white); padding: clamp(4px, 0.52vw, 7.4px);
  box-shadow: 0 12px 34px rgb(0 0 0 / 0.18);
  rotate: var(--rot, 0deg);
}
/* The photograph is scaled and counter-moved inside this box by the parallax
   layer; without the clip it would slide out over the white border. */
.polaroid__frame { display: block; overflow: hidden; overflow: clip; }
.polaroid--left  { margin-inline-end: auto; }
.polaroid--right { margin-inline-start: auto; }
.polaroid img { display: block; width: 100%; height: auto; }
/* The only two-print block in the design (solar energy) has the prints
   overlapping, not side by side. Stacking them here reproduces that, and since
   the two carry different parallax depths they separate as the page scrolls. */
.polaroids--stacked { display: block; position: relative; }
.polaroids--stacked .polaroid { inline-size: calc(66% + (var(--fw, 470) - 340) * 0.0714%); }
.polaroids--stacked .polaroid + .polaroid {
  margin-block-start: -14%; margin-inline-start: auto; position: relative; z-index: 1;
}
@media (min-width: 62rem) {
  .polaroids--placed.polaroids--stacked {
    position: absolute; inset-inline-start: 0; inset-block-start: var(--pad-top); inline-size: 100%; block-size: 0;
  }
  .polaroids--placed.polaroids--stacked .polaroid,
  .polaroids--placed.polaroids--stacked .polaroid + .polaroid {
    position: absolute; margin: 0;
    inline-size: calc(var(--fw, 470) * var(--art));
    inset-inline-start: calc(var(--p-col, 0) * var(--art));
    inset-block-start: calc(var(--p-dy, 0) * var(--art));
  }
  /* The later print in the file is the one on top. */
  .polaroids--placed.polaroids--stacked .polaroid + .polaroid { z-index: 1; }
}

/* Below the two-column breakpoint the print keeps a row of its own. */
.block--photos .polaroids { justify-content: center; margin-top: var(--sp-7); }
/* Chapter 3 puts the two figures beside the heading rather than under it: a
   narrow title column on the left, the cards on the right, in the design's own
   proportions (308px against 821 of the 1152 column). */
@media (min-width: 62rem) {
  .block__split { display: grid; grid-template-columns: 26.7% 1fr; column-gap: 2.3%; align-items: start; }
  /* In the design the print in these two blocks does not take a row: it climbs
     out of the block and over the gradient band above, and the figures run
     underneath the heading. Laid out in flow, as this was, the print pushed the
     figures ~420px below where the design puts them and left that much white
     between the band and the heading. The offsets below are the design's own,
     read off the 1440 artboard and expressed in vw so they hold on resize. The
     heading sits at the design's 100px under the band. */
  .block--photos-stats { position: relative; padding-block-start: 6.94vw; }
  .block--photos-stats .polaroids {
    position: absolute; margin: 0; inline-size: auto; z-index: 1;
  }
  /* Three figures across, chapter 2: the print is on the right and its lower
     corner falls over the empty top-right of the third card, which is where the
     design leaves it, clear of the third figure itself. The 2.5rem over the
     cards is what keeps it clear: the narrow space before "%" widened the
     figure, and at 1280–1440 its sign had reached under the corner. */
  .block--photos-stats:not(:has(.block__split)) .polaroids {
    inset-inline-start: 68.1%; inset-block-start: -3.93vw;
  }
  .block--photos-stats:not(:has(.block__split)) .block__heading { max-width: 58.33%; }
  .block--photos-stats:not(:has(.block__split)) .statcards { margin-block-start: calc(3.5vw + 2.5rem); }
  /* Two figures beside the heading, chapter 3: the print is on the left and
     runs off the canvas, as it does in the design. The design lifts it 163px
     over the band, at the design's own offset. The heading starts under the
     print's lower corner rather than across it: the design runs the two over
     each other, but our chapter titles wrap onto three lines where the Figma
     text box reports one, and the extra depth puts the heading over the crowd
     in the photograph instead of over the sand.
     The aerial view that replaced the school in October 2026 is wider at the
     top, and at the school's 163px its upper corner sat on the band's last
     line. It now hangs 117px over the band, the heading follows it down by the
     same amount, and both stop growing at the 1440 artboard: the paragraph
     does not grow past it either, and a lift in vw climbed onto it on wider
     screens. */
  .block--photos-stats:has(.block__split) { padding-block-start: min(17.2vw, 247.7px); }
  .block--photos-stats:has(.block__split) .polaroids {
    inset-inline-start: -14.9%; inset-block-start: -11.35vw; z-index: 0;
  }
  .block--photos-stats .block__split { position: relative; z-index: 1; }
  /* Since the October 2026 debrief chapter 3 opens on two prints: the aerial
     view takes the school's place on the left, and the school moves right,
     over the band's lower edge and clear of the cards. Each print is placed on
     its own, so the stack is a zero-height layer across the block. The right
     one keeps 1.5rem from the window rather than running off it. */
  .block--photos-stats:has(.block__split) .polaroids--stacked {
    inset-inline-start: 0; inset-block-start: 0; inline-size: 100%; block-size: 0;
  }
  .block--photos-stats:has(.block__split) .polaroids--stacked .polaroid {
    position: absolute; margin: 0; inset-inline-start: -14.9%; inset-block-start: max(-8.15vw, -117.4px);
  }
  .block--photos-stats:has(.block__split) .polaroids--stacked .polaroid + .polaroid {
    inset-inline-start: auto; inset-inline-end: max(-13.8%, calc((100% - 100vw) / 2 + 1.5rem));
    inset-block-start: -6.6vw; z-index: 1;
  }
}
@media (max-width: 61.99rem) {
  .statcards--row, .statcards--beside { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
  .block__split .block__heading { margin-bottom: var(--sp-4); }
}
.block--photos .polaroid {
  flex: 0 0 auto;
  inline-size: clamp(220px, calc(var(--fw, 470) * 0.0694vw), calc(var(--fw, 470) * 1px));
}

/* ---------- Priorities ---------- */
.priorities { padding-block: var(--sp-8); }
@media (min-width: 62rem) { .priorities { padding-block-start: 6.25rem; } }
.priorities__title { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3); line-height: 1.15; max-width: 30ch; }

/* Four panels over one continuous gradient, split by a white cross — which is
   how the design draws it: a single shape with two gutters cut out of it, not
   four cards that happen to be adjacent. The gradient therefore belongs to the
   grid, and the gutters are painted over it.
   The ramp is sampled across the design's own panel, in the same way the chapter
   bands are: a flat 90deg reading of an image that also darkens downwards. */
.priorities__grid {
  position: relative; isolation: isolate;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: 1fr;
  gap: 20px;
  background-image: linear-gradient(90deg, #177dca, #1648a6, #1c2585, #241265, #3e0b48);
}
.priorities__grid::before {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(var(--color-white), var(--color-white)) center / 20px 100% no-repeat,
    linear-gradient(var(--color-white), var(--color-white)) center / 100% 20px no-repeat;
}
.priority { position: relative; z-index: 2; color: var(--color-white); padding: 50px 43px; }
.priority__title { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h5); line-height: 1.15; margin-bottom: var(--sp-4); }
.priority__body { font-size: var(--fs-h6); font-weight: 500; line-height: 1.2; margin: 0; }

/* The air between the title and the panels. It belongs on a selector heavier
   than `ul[role="list"] { margin: 0 }` in base.css — an attribute outweighs a
   lone class, which is why the gap written on `.priorities__grid` alone never
   reached the page and the two sat 16px apart, on the title's margin alone.

   The file measures 210.76 from the baseline of the title to the top of the
   panels, and spends 110 of them on a centred mark — the same 81.52 x 40.76
   vector it repeats at y=1333.56 and y=2408 — which this page does not draw.
   Without the mark the panels take the file's own unit of air for this stretch,
   the 100 that also separates the panels from the closing text and the closing
   text from its link. Draw the mark and the number goes back to 210.76.

   Below the desktop breakpoint the file says nothing: 64px is a proposal, to
   validate with design. */
.priorities .priorities__grid { margin-top: var(--sp-6); }
@media (min-width: 62rem) { .priorities .priorities__grid { margin-top: 6.25rem; } }

/* One column on a phone: the cross has nothing to split, so the gutters go and
   each panel carries the ramp itself. */
@media (max-width: 52rem) {
  .priorities__grid { grid-template-columns: 1fr; gap: 12px; background-image: none; }
  .priorities__grid::before { content: none; }
  .priority { background-image: linear-gradient(90deg, #177dca, #1648a6, #1c2585, #241265, #3e0b48); padding: var(--sp-4) var(--sp-3); }
}

/* ---------- Closing ---------- */
.closing { padding-block: var(--sp-8); text-align: left; --pad-top: var(--sp-8); container-type: inline-size; --art: calc(100cqw / 1152); }
.closing__text { font-size: var(--fs-h6); line-height: 1.2; max-width: 63.54%; }
.closing__text p { margin: 0; }
.closing__text p + p { margin-top: 0.673em; } /* 21.5px at 32 */
/* The file: 100 from the priorities graphic to the text, 100 from the text to
   the link, 100 from the link to the download band. */
@media (min-width: 62rem) {
  .priorities { padding-block-end: 0; }
  .closing { padding-block: 6.25rem 5.5rem; --pad-top: 6.25rem; }
  .closing .tca { margin-block-start: calc(100 * var(--art) - 0.5rem); }
}
.closing__text strong { font-weight: 800; }
/* The closing sits in from the column edge in the design, like the chapter
   openings — and its "learn more" sits on the same line of the indent. */
@media (min-width: 62rem) {
  .closing__text, .closing .tca { margin-inline-start: 32.55%; }
}
@media (max-width: 61.99rem) { .closing__text { max-width: none; } }

/* ---------- Report download band ---------- */
/* The page's own ending, in the report's palette — distinct from the UNDP
   institutional footer that follows it. */
/* The same gradient as a chapter opening, read left to right — blue into
   magenta — and the same indent for the line that follows the kicker. */
.report-cta {
  color: var(--color-white);
  background-image: linear-gradient(90deg, #063b91, #0b47a4, #1c389b, #582ca0, #b72fa7);
  /* 142px over the kicker, as the file draws it. Under the link the file gives
     13px; at that the band reads as cut off, so the foot is the page's own
     vertical step of 100px. One number, if you want it deeper. */
  padding-block: clamp(3rem, 9.86vw, 8.875rem) clamp(2.5rem, 6.94vw, 6.25rem);
}
.report-cta__kicker {
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3);
  text-transform: uppercase; line-height: 1.1; margin: 0;
}
/* The design gives the download no button: the sentence is the link, set in at
   415px like a chapter paragraph. The underline is what makes it a link. */
.report-cta__action {
  margin: clamp(1.5rem, 4.5vw, 4.25rem) 0 0; max-width: 71.18%;
  font-size: var(--fs-h6); font-weight: 500; line-height: 1.2;
}
@media (min-width: 62rem) { .report-cta__action { margin-inline-start: 23.52%; } }
@media (max-width: 61.99rem) { .report-cta__action { max-width: none; } }
/* The design system's link (Foundation › Typography › Links), as its Storybook
   shows it and as undp.org uses it: a 2px dark-red rule drawn as a background
   under the words, which on hover runs out to the right and comes back from
   the left, on a loop (keyframes from assets/vendor/undp-ds). The system also
   has a white `.inverted` form for dark grounds; on this band it was
   indistinguishable from the plain underline the client asked to replace, and
   the red reads on every stop of the gradient. Inline, so a sentence that
   wraps carries the rule under every line. */
.report-cta__link {
  color: inherit; text-decoration: none;
  background-image:
    linear-gradient(var(--undpds-color-dark-red), var(--undpds-color-dark-red)),
    linear-gradient(var(--undpds-color-dark-red), var(--undpds-color-dark-red));
  background-position: 100% 100%, -30px 100%;
  background-repeat: no-repeat;
  background-size: 100% 2px, 0 1px;
}
.report-cta__link:is(:hover, :focus-visible) { animation: lineLoop-animation 2s linear infinite; }
[dir='rtl'] .report-cta__link:is(:hover, :focus-visible) { animation-name: lineLoop-animation-rtl; }

/* Finché il PDF del report non arriva dal cliente, i due richiami al download
   restano a video con la stessa forma ma senza il gesto: il cursore non cambia
   e il title dice quando il file sarà disponibile. Sostituito il segnaposto in
   assets/files, i template tornano da soli al link scaricabile. */
.download-link--pending, .report-cta__link--pending { cursor: default; }
.report-cta__link--pending:hover { animation: none; }

/* ---------- UNDP institutional footer ---------- */
/* The Footer organism of the UNDP Design System, "simple" variant, loaded from
   assets/vendor/undp-ds. What follows is what the system's base stylesheet
   would have set and the report does not load. Zero specificity on the reset,
   so every margin the component sets on its own lists still wins. */
:where(.footer) ul { margin: 0; }
.footer a { text-decoration: none; }
/* The design system's h5, which is what the FooterLogo molecule sets the name
   in: Proxima Nova regular, 20px and 24px from 48em, solid leading. */
.footer .footer-logo__name {
  margin: 0 var(--undpds-spacing-05);
  font-size: var(--undpds-font-size-20); font-weight: 400; line-height: 1.15;
  color: var(--undpds-color-text-inverse);
}
@media (min-width: 48em) { .footer .footer-logo__name { font-size: var(--undpds-font-size-24); } }

/* ---------- "learn more" dialogs ---------- */
/* Geometry from the file's own dialog frames — 158:3620 and 387:27, 387:120,
   387:203, 387:227, 387:236, drawn after the page and at the page's scale.
   There are two cards, not one: a 1240 x 678 card that sets its copy in two
   500px columns, and a 732 card with a single 604 column. Both have a 23.742px
   radius and the same shadow, and both hold their copy 111px below the top edge
   and 64px in from the left.

   Every number below is `--art`, one pixel of the card it is on, so the card
   scales as one object down to a phone and the type keeps the ratio the file
   draws it at. The previous reading of these dialogs came from the 1920
   artboards that preceded them (95:626, 95:729, 95:985), where the body is
   32px; on the frames that replaced them it is 20px on 28px of leading. */
.modal {
  container-type: inline-size;
  --card: 732;                       /* the file's width for this dialog */
  --art: calc(100cqw / var(--card)); /* one pixel of that card */
  --radius: max(12px, calc(23.742 * var(--art)));
  /* The file's 111px head and foot, kept as long as the window is tall enough
     to hold them. On a laptop the card would otherwise reach the 90vh ceiling
     and scroll on 20-50px of head and foot alone, with the copy itself fitting
     comfortably. Below roughly 1000px of window the head gives way before the
     text does. */
  --head: clamp(max(1.75rem, var(--radius)), calc(111 * var(--art)), 9vh);
  border: 0; padding: 0;
  max-width: min(calc(var(--card) * 1px), calc(100vw - 2 * var(--gutter)));
  width: 100%; max-height: min(90vh, 1000px);
  background: transparent; color: #fff; overflow: visible;
}
/* The two-column card, and the table of indicators, which is drawn on it. */
.modal--wide, .modal--table { --card: 1240; }
.modal::backdrop { background: rgb(17 20 35 / 0.55); backdrop-filter: blur(2px); }
/* The card and its backdrop fade in and out together, at the design system's
   own .3s ease for opacity. The fade out is held by ui/modal.js, which closes
   the dialog only once it has run: close() takes a <dialog> out of the top
   layer at once, leaving nothing on screen to fade. The global reduced-motion
   rule in base.css does not reach ::backdrop, hence the rule of its own. */
@keyframes modal-in { from { opacity: 0; } }
@keyframes modal-out { to { opacity: 0; } }
.modal[open], .modal[open]::backdrop { animation: modal-in 0.3s ease; }
.modal.is-closing, .modal.is-closing::backdrop { animation: modal-out 0.3s ease forwards; }
@media (prefers-reduced-motion: reduce) {
  .modal[open], .modal[open]::backdrop, .modal.is-closing, .modal.is-closing::backdrop { animation: none; }
}
/* The box is the card — gradient, rounded corners, shadow — and it is also
   the element that scrolls. A system scrollbar drawn on it cut straight
   through the rounded corner and the gradient. Two things fix that:

   1. The scrollbar is set in the card's own language: a thin yellow thumb on
      no track, drawn with `scrollbar-color` where the standard is supported
      (Firefox, Chrome 121+) and with the `::-webkit-scrollbar` parts
      elsewhere (Safari, older Chrome). Browsers that know the standard
      property ignore the pseudo-elements, so the two never fight.
   2. The card's padding keeps the thumb inside the rounded corner: it runs
      down the padding, not the edge. `scrollbar-gutter: stable` reserves the
      lane whether or not the content overflows, so a short popup and a long
      one have their text on the same line.

   Overlay scrollbars (macOS default, all phones) draw over the content and
   only while scrolling: there the rules below are simply what that overlay
   looks like when it appears. */
.modal__box {
  position: relative; border-radius: var(--radius);
  background: linear-gradient(82.85deg, #212e59 11.19%, #7347bf 181.35%);
  box-shadow: 0 0 max(4px, calc(8.14 * var(--art))) calc(0.678 * var(--art)) rgb(33 46 89 / 0.6);
  max-height: min(90vh, 1000px); display: grid; grid-template-rows: minmax(0, 1fr);
  overflow: hidden;
  /* The card's corner radius, kept clear above and below the scroll lane so
     the thumb never enters the curve. */
  padding-block: var(--radius);
}
/* The wide card's gradient runs at a shallower angle across its longer side. */
.modal--wide .modal__box, .modal--table .modal__box {
  background: linear-gradient(80.27deg, #212e59 11.19%, #7347bf 181.35%);
}
/* 111px down and 64px in from the card's edge, which is where the file puts
   the first line of every dialog. The foot mirrors the head. */
.modal__scroll {
  overflow-y: auto; overscroll-behavior: contain; min-height: 0;
  padding-inline: max(1.25rem, calc(64 * var(--art)));
  padding-block: calc(var(--head) - var(--radius));
  scrollbar-width: thin;
  scrollbar-color: rgb(252 201 0 / 0.55) transparent;
  scrollbar-gutter: stable;
  /* The lane sits a little in from the card's edge, under the close button. */
  margin-inline-end: max(0.5rem, calc(16 * var(--art)));
}
.modal--wide .modal__scroll { padding-inline: max(1.25rem, calc(64 * var(--art))) max(1.25rem, calc(89 * var(--art))); }
.modal__scroll:hover, .modal__scroll:focus-within { scrollbar-color: rgb(252 201 0 / 0.9) transparent; }
@supports not (scrollbar-color: red blue) {
  .modal__scroll::-webkit-scrollbar { width: 10px; }
  .modal__scroll::-webkit-scrollbar-track { background: transparent; }
  .modal__scroll::-webkit-scrollbar-thumb {
    background: rgb(252 201 0 / 0.55); border-radius: 999px;
    border: 3px solid transparent; background-clip: padding-box;
  }
  .modal__scroll:hover::-webkit-scrollbar-thumb, .modal__scroll:focus-within::-webkit-scrollbar-thumb {
    background-color: rgb(252 201 0 / 0.9);
  }
}
/* The card fades its last lines into the edge when there is more below — a
   cue that reads without a scrollbar at all, which is what a phone gives. */
.modal__scroll { mask-image: linear-gradient(to bottom, #000 calc(100% - 2.5rem), rgb(0 0 0 / 0.35)); }
.modal__scroll[data-at-end] { mask-image: none; }
/* The prose dialogs carry no heading of their own in the file; the block
   heading is kept for screen readers only, so the card looks like the frame. */
.modal__title {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---------- The two-column card ---------- */
/* 500 + 87 + 500 of the card's 1240. Which paragraphs go left, which go right
   and which side carries the figures are in the copy file, because the file
   draws them differently in each dialog: 387:27 sets its display sentence on
   the left and its two figures on the right, 387:120 does the opposite. */
.modal__cols {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: calc(87 * var(--art));
}
@media (max-width: 62rem) { .modal__cols { grid-template-columns: minmax(0, 1fr); row-gap: calc(44 * var(--art)); } }

/* ---------- Type ---------- */
/* 20px on 28px, the file's body. The floor is the smallest size worth reading
   on a phone, where the card is a third of the width it is drawn at. */
.modal__body, .modal__figure-label {
  font-size: max(1rem, calc(20 * var(--art))); line-height: 1.4; margin: 0;
}
.modal__body + .modal__body { margin-top: max(1.25rem, calc(44 * var(--art))); }
/* The sentence the file sets in the display face: 35px, solid leading. Its own
   size rather than a multiple of the body — the dialog's body is not the
   page's. */
.modal__lead {
  font-family: var(--font-display); font-weight: 700;
  font-size: max(1.375rem, calc(35 * var(--art))); line-height: 1;
}
.modal__lead + .modal__body, .modal__body + .modal__lead,
.modal__lead + .modal__lead { margin-top: max(1.25rem, calc(44 * var(--art))); }

/* ---------- Figures ---------- */
/* 70px in the display face with the name under it, indented 17px inside the
   column the file puts them in, and a rule between the rows. */
.modal__figures {
  margin-top: max(1.25rem, calc(44 * var(--art)));
  margin-inline-start: calc(17 * var(--art));
  display: grid; grid-template-columns: repeat(var(--fig-cols, 1), minmax(0, 1fr));
  column-gap: calc(66 * var(--art)); row-gap: max(1rem, calc(51 * var(--art)));
}
.modal__figures .modal__rule {
  grid-column: 1 / -1; margin: 0; border: 0; height: 1px;
  background: rgb(255 255 255 / 0.55);
}
/* The single figure of a one-column dialog is set in the flow of the prose and
   the file keeps it on one line. Söhne Breit Fett runs about 0.66em per
   character, so a string too long for the measure takes the size the measure
   allows instead of breaking in two — the same rule the hero headline uses.
   The measure is 573 and not the column's 604: the card spends 31 of its own
   pixels on the lane its scrollbar runs down. */
.modal__figure {
  margin: max(1.25rem, calc(44 * var(--art))) 0 0;
  --fig-fit: calc(573 * var(--art) / (var(--fig-chars, 10) * 0.66));
}
.modal__figures .modal__figure { margin: 0; }
.modal__figure-value {
  display: block; font-family: var(--font-display); font-weight: 700; line-height: 0.8;
  font-size: max(2.25rem, min(calc(70 * var(--art)), var(--fig-fit, 100vw)));
}
.modal__figure-label { display: block; margin-top: max(0.75rem, calc(22 * var(--art))); }
/* In the two-column card the name under a figure is a label and is set in
   semibold; in the single-column card the line under the figure is a sentence
   and stays in the body weight, as the file sets it. */
.modal--wide .modal__figure-label { font-weight: 600; }

/* ---------- The print inside a dialog ---------- */
/* 387:227 does not place a plain picture: it places a print, white-bordered and
   tipped 5.5°, like every other photograph in the report. 504.6 of the 604
   column, centred. */
.modal__print {
  margin: max(1.25rem, calc(44 * var(--art))) auto 0;
  inline-size: 83.5%;
  background: var(--color-white); padding: calc(10 * var(--art));
  box-shadow: 0 14px 38px rgb(0 0 0 / 0.3);
  rotate: 5.5deg;
}
.modal__print .polaroid__frame { display: block; overflow: hidden; overflow: clip; }
.modal__image { display: block; width: 100%; height: auto; }

.modal__close {
  /* Anchored to the <dialog>, which the browser positions: it stays put while
     the card scrolls under it. 37.3px across, 24.42 down, 23.74 in — the card's
     own radius. */
  position: absolute; z-index: 1;
  inset-block-start: max(0.75rem, calc(24.42 * var(--art)));
  inset-inline-end: max(0.75rem, calc(23.74 * var(--art)));
  width: max(36px, calc(37.309 * var(--art))); aspect-ratio: 1;
  display: grid; place-items: center;
  background: none; border: 2px solid currentColor; border-radius: 50%;
  /* Yellow ring and glyph, as in the frame — not white: on a purple card the
     white ring reads as part of the card's border, the yellow one reads as a
     control. */
  color: var(--color-yellow); font-size: 1.5rem; line-height: 1; cursor: pointer;
  transition: background var(--motion-fast) var(--ease);
}
.modal__close:hover { background: rgb(252 201 0 / 0.18); }

/* ---------- The table of national indicators (158:3620) ---------- */
/* The one dialog whose heading is drawn rather than carried for screen readers,
   because here the title is what tells you what the sixteen rows are. The file
   sets it at 24px in the display face, in the same yellow as the six group
   names — not at the page's heading size, and not in white. */
.modal--table .modal__scroll {
  padding-inline: max(1.25rem, calc(52 * var(--art)));
  padding-block: calc(clamp(var(--radius), calc(31.88 * var(--art)), 9vh) - var(--radius));
}
.modal--table .modal__title {
  position: static; width: auto; height: auto; margin: 0; overflow: visible;
  clip-path: none; white-space: normal;
  font-family: var(--font-display); font-weight: 700; text-transform: uppercase;
  color: var(--color-yellow);
  font-size: max(1rem, calc(24 * var(--art))); line-height: 0.8;
}
/* Three columns, in the proportions the file draws them: 411, 464 and 291 of
   the 1166 inside the card. Declared rather than balanced, because the third
   holds two figures set large instead of a table and no balancing algorithm
   would put them there. Two columns, then one, as the room goes. */
.modal__tables {
  margin-top: calc(87 * var(--art));
  display: grid; grid-template-columns: 1.41fr 1.59fr 1fr; column-gap: var(--sp-5);
}
.modal__col > * + * { margin-top: var(--sp-5); }
.modal__table { width: 100%; table-layout: fixed; border-collapse: collapse; }
/* The group names are Proxima Nova Extrabold at 16px in the file — sentence
   case, no tracking. They were being set in the display face, uppercased and
   spaced out, which is the page's treatment and not the table's. */
.modal__table caption, .modal__stats-caption {
  text-align: start; padding-bottom: 0.5em; border-bottom: 1px solid var(--color-yellow);
  color: var(--color-yellow); font-family: var(--font-body); font-weight: 800;
  font-size: max(0.875rem, calc(16 * var(--art))); line-height: 1.2;
}
.modal__stats-caption { margin: 0; }
.modal__table th, .modal__table td {
  text-align: start; font-weight: 400; line-height: 1.2;
  font-size: max(0.875rem, calc(16 * var(--art)));
  padding: 0.62em 0; border-bottom: 1px solid rgb(255 255 255 / 0.16);
}
/* The value starts at a column of its own — 70% across, as in the file — rather
   than ranging right: what the reader compares down the column is the first
   digit, and ranged right the first digit moves with the length of the number.
   Set in the display face, and kept on one line however narrow the dialog gets. */
.modal__table th { width: 70%; padding-inline-end: var(--sp-2); }
.modal__table td {
  white-space: nowrap; font-family: var(--font-display); font-weight: 700;
}

/* The third column. Two indices, not two rows: the file sets them at 70px with
   their names under them, the same weight it gives the seven figures in the
   opening band. */
.modal__stat { margin: var(--sp-4) 0 0; }
.modal__stat-value {
  display: block; font-family: var(--font-display); font-weight: 700; line-height: 0.8;
  font-size: max(2rem, calc(70 * var(--art)));
}
.modal__stat-label {
  display: block; margin-top: var(--sp-2);
  font-size: max(1rem, calc(20 * var(--art))); font-weight: 600; line-height: 1.2;
}

@media (max-width: 62rem) {
  .modal__tables { grid-template-columns: 1fr 1fr; row-gap: var(--sp-5); }
}
@media (max-width: 46rem) { .modal__tables { grid-template-columns: 1fr; } }

/* Holding the page still while a dialog is open, without the sideways jump that
   removing the scrollbar would otherwise cause. */
html.is-modal-open { overflow: hidden; padding-inline-end: var(--scrollbar-gap, 0px); }

/* ---------- Narrow screens ---------- */
/* The Figma file is a single 1440 artboard, so everything below is a reading of
   the design rather than a transcription of it — flagged for Sofia to confirm.
   Each rule is here because it was measured failing on a 360x740 phone, not
   because a breakpoint felt due. */

/* A print is rotated, and a rotated box is wider than the box it was laid out
   in: at full column width the corners of the widest prints pushed the document
   6px past the viewport and gave the whole page a horizontal scrollbar. */
@media (max-width: 61.99rem) {
  .polaroid { max-inline-size: 94%; }
  .polaroids--stacked .polaroid + .polaroid { margin-block-start: -10%; }
  /* Half a phone screen of gradient before a word of the chapter appears is a
     lot of nothing; the band keeps its proportions but not its desktop height. */
  .block { padding-block: var(--sp-5); }
  .chapter { padding-block: var(--sp-5); }
  /* Stacked, the print sits directly under the copy it belongs to and climbs
     towards it: measured at 390px it was ending 21px inside the last line. The
     headroom is the clearance for that climb, not decoration — a print must
     never come to rest under a paragraph. */
  .polaroids { margin-block: var(--sp-6) var(--sp-4); }
  /* The closing is the one place where the print comes before its copy, so it
     arrives from below towards the paragraph rather than climbing away from
     it: at 32px its tilted corner was inside "This is" on the way in. */
  .closing .polaroids { margin-block-end: var(--sp-7); }
}

/* Touch target. WCAG 2.5.8 asks for 24x24 CSS pixels; the box grows, the type
   does not. The footer's icons and legal links keep the design system's
   measures: they are 20px and 22px tall, and clear the bar on spacing — 24px
   or more between neighbours. */
.tca { padding-block: 0.5rem 0.6rem; }

@media (max-width: 40rem) {
  .report-cta { padding-block: var(--sp-6); }
}

/* ---------- Hero on narrow screens ---------- */
/* The frame's proportions stop being usable long before the phone does: at
   375px the whole 1457 scene is 379px tall. The composition is kept but
   re-hung — the prints at the top, where the design puts them relative to the
   type, and the copy centred in what is left of the first screen. */
@media (max-width: 64rem) {
  .hero {
    min-height: 100svh; align-content: center;
    padding-block: calc(var(--header-h) + 2rem) 3rem;
  }
  .hero__photos {
    block-size: calc(1440 * var(--u));
    inset-block-start: calc(56 * var(--u));
  }
}
