/* ==========================================================================
   FONTS
   Self-hosted, was Google Fonts. Same four faces, same rendering; what this buys
   is that no third-party origin has to be resolved before the first glyph paints,
   and that the visitor's IP no longer reaches a US server — which an EU-funded
   project site should not require.

   Each face is one variable font subset out of the Google Fonts ZIP, split latin
   and latin-ext on the same unicode-ranges Google uses, so only the latin file is
   fetched unless a page actually needs an extended character. wdth is pinned (no
   rule here uses it). opsz is NOT pinned, even though it costs more than half of
   each file: pinning it shifts text widths by up to 10% at 64px, which rewraps the
   hero headline. Fidelity was worth more than the 150 kB.
   349 kB for the four latin files, against 364 kB from Google.

   Renaming a file means the browser keeps the old one for a year (.htaccess), so
   change the filename, not just the contents.
   ========================================================================== */
@font-face {
    font-family: "Archivo";
    src: url("../fonts/web/archivo-latin.woff2") format("woff2");
    font-weight: 400 800;
    font-style: normal;
    font-display: swap;
    unicode-range:
        U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Bricolage Grotesque";
    src: url("../fonts/web/bricolage-latin.woff2") format("woff2");
    font-weight: 400 800;
    font-style: normal;
    font-display: swap;
    unicode-range:
        U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Source Serif 4";
    src: url("../fonts/web/sourceserif4-latin.woff2") format("woff2");
    font-weight: 400 600;
    font-style: normal;
    font-display: swap;
    unicode-range:
        U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Source Serif 4";
    src: url("../fonts/web/sourceserif4-italic-latin.woff2") format("woff2");
    font-weight: 400 600;
    font-style: italic;
    font-display: swap;
    unicode-range:
        U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
        U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Archivo";
    src: url("../fonts/web/archivo-latin-ext.woff2") format("woff2");
    font-weight: 400 800;
    font-style: normal;
    font-display: swap;
    unicode-range:
        U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "Bricolage Grotesque";
    src: url("../fonts/web/bricolage-latin-ext.woff2") format("woff2");
    font-weight: 400 800;
    font-style: normal;
    font-display: swap;
    unicode-range:
        U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "Source Serif 4";
    src: url("../fonts/web/sourceserif4-latin-ext.woff2") format("woff2");
    font-weight: 400 600;
    font-style: normal;
    font-display: swap;
    unicode-range:
        U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
    font-family: "Source Serif 4";
    src: url("../fonts/web/sourceserif4-italic-latin-ext.woff2") format("woff2");
    font-weight: 400 600;
    font-style: italic;
    font-display: swap;
    unicode-range:
        U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
        U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
        U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   Metric-matched fallback for the hero italic
   font-display is swap, so a system font paints first and Source Serif replaces it
   a moment later. For most of the page that swap is harmless — measured over the
   real headlines and paragraphs, Georgia lands within 3% of Source Serif and the
   default sans within 3% of Bricolage, which is why neither gets a fallback here.

   The exception is the italic <em> in the two hero headlines. It asks for weight
   600, which resolves to Georgia Bold Italic: 30% wider on average, 34% at 60px.
   The title visibly rewrapped when the real font arrived.

   This face is Times New Roman Bold Italic re-proportioned to Source Serif's
   measured width (93.3% of it), with ascent and descent rescaled to match, which
   brings that 30% error down to under 4%. Nothing about the loaded rendering
   changes; only the moment before it.

   src has to name the bold italic face explicitly: a descriptor claiming 600-800
   gets no synthetic bolding, so local("Times New Roman") would come out 11% narrow.
   Re-measure if the font files are rebuilt (include/fonts/build-fonts.js).
   -------------------------------------------------------------------------- */
@font-face {
    font-family: "Source Serif Fallback";
    src:
        local("Times New Roman Bold Italic"),
        local("TimesNewRomanPS-BoldItalicMT");
    font-style: italic;
    font-weight: 600 800;
    size-adjust: 93.3%;
    ascent-override: 111.5%;
    descent-override: 36.4%;
    line-gap-override: 0%;
}

/* ==========================================================================
   SHARED FOUNDATION
   The six CAPA colours, in the order they run round the logo arc:
   blue → green → yellow → red → orange → lime.
   ========================================================================== */
:root {
    --blue: #2f66ae;
    --green: #00783e;
    --yellow: #f9b510;
    --red: #dd1317;
    --orange: #ef7e09;
    --lime: #0b9c39;

    --ink: #0e1a24;
    --ink-2: #243441;
    --ink-3: #3c4c58;
    --muted: #5a6b78;
    --muted-2: #8a98a3;

    --sans: Archivo, system-ui, -apple-system, "Segoe UI", sans-serif;
    --serif: "Source Serif 4", Georgia, serif;
    --bric: "Bricolage Grotesque", Archivo, sans-serif;
    --inst: "Instrument Serif", Georgia, serif;
    --space: "Space Grotesk", Archivo, sans-serif;

    /* Sharp in-and-out curve for the button blob (demo/button.html, 04 A) */
    --ease-io: cubic-bezier(0.76, 0, 0.24, 1);
    /* Rise-in curve: the CSS equivalent of the easing the reveal used to run */
    --ease-rise: cubic-bezier(0.215, 0.61, 0.355, 1);

    /* Header height (.v4__hd): the 120px logo, nothing else — the padding it
       used to carry is gone. The hero of every page fills exactly the rest of
       the viewport (header + hero = 100vh), so the whole hero is on screen when
       the page loads, capped at --fold-max so it does not grow too tall on
       large screens. Keep in step with .v4__logo, here and at 1080px. */
    --hd-h: 120px;
    --fold-max: 700px;
}
* {
    box-sizing: border-box;
}
html {
    scroll-behavior: smooth;
}
/* The ground behind the page matches the variant's sand, so an
   over-scroll never flashes another colour. */
body {
    margin: 0;
    background: #fdf6ea;
    color: var(--ink);
    font-family: var(--sans);
    -webkit-font-smoothing: antialiased;
}
/* height: auto so the width/height attributes only serve as an aspect ratio: without
   it they are a presentational hint, and any image whose width is set in CSS keeps its
   attribute height and comes out stretched. */
img {
    max-width: 100%;
    height: auto;
    display: block;
}
a {
    text-decoration: none;
    color: inherit;
}
::selection {
    background: var(--yellow);
    color: var(--ink);
}
:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 3px;
}

.v4 {
    --sand: #fdf6ea;
    --sand-2: #f6e7d2;
    --clay: #efdcc4;
    --leaf: #e9f1e6;
    background: var(--sand);
    color: #22160c;
    font-family: var(--bric);
    overflow-x: clip;
    /* A stacking context of its own, so a section capa.js holds under a card
       (z-index -1) sits above this ground instead of vanishing behind it. */
    isolation: isolate;
}
/* That same section, at z-index -1, is painted under <main>, its own parent:
   an in-flow box with no ground still takes the pointer, so nothing in the
   held section could be hovered or clicked. <main> steps out of hit-testing
   and hands it back to its children; :where() keeps that at zero specificity
   so any child that opts out (pointer-events: none) still does. */
.v4 main {
    pointer-events: none;
}
:where(.v4 main) > * {
    pointer-events: auto;
}
.v4 .wrap {
    max-width: 1300px;
    margin: 0 auto;
    padding-left: 46px;
    padding-right: 46px;
}
/* Rise-in reveal. Below the fold, capa.js flags each element with .is-in as it
   scrolls into view and the transition below plays it. Above the fold the same
   movement is written as data-rise="now" and runs from this stylesheet, so the
   hero paints without waiting for a script — that wait was the whole LCP. */
.v4 [data-rise] {
    opacity: 0;
    transform: translateY(30px);
    transition:
        opacity 0.9s var(--ease-rise),
        transform 0.9s var(--ease-rise);
    transition-delay: var(--rise-delay, 0s);
}
.v4 [data-rise].is-in {
    opacity: 1;
    transform: none;
}
.v4 [data-rise="now"] {
    animation: v4rise 0.9s var(--ease-rise) var(--rise-delay, 0s) both;
}
@keyframes v4rise {
    from {
        opacity: 0;
        transform: translateY(30px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}
@media (prefers-reduced-motion: reduce) {
    .v4 [data-rise] {
        opacity: 1;
        transform: none;
        transition: none;
        animation: none;
    }
}
.v4 h1,
.v4 h2,
.v4 h3 {
    font-weight: 800;
    letter-spacing: -0.028em;
}

/* Organic mask, breathing slowly so nothing on the page is ever completely
   still. */
@keyframes v4blobA {
    0%,
    100% {
        border-radius: 58% 42% 46% 54%/47% 53% 47% 53%;
    }
    34% {
        border-radius: 44% 56% 62% 38%/58% 42% 58% 42%;
    }
    67% {
        border-radius: 63% 37% 38% 62%/41% 62% 38% 59%;
    }
}
@keyframes v4drift {
    0%,
    100% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-22px);
    }
}
@keyframes v4peb {
    0%,
    100% {
        border-radius: 110px 140px 120px 150px/130px 110px 140px 120px;
    }
    50% {
        border-radius: 140px 110px 150px 120px/110px 140px 120px 130px;
    }
}

/* --- Header ------------------------------------------------------------ */
.v4__hd {
    position: sticky;
    top: 0;
    z-index: 40;
    background: rgba(253, 246, 234, 0.9);
    backdrop-filter: blur(3px);
    transition: background-color 0.35s;
    /* padding: 16px 0; */
}
/* At the top of the page (scrollY = 0, .is-top set by config.ini.php and kept
   in sync by capa.js) the header is more see-through so the ribbons show
   through the blur; it fades back to the usual tint on the first scroll. */
.v4__hd.is-top {
    background: rgba(253, 246, 234, 0.6);
}
.v4__hdin {
    display: flex;
    align-items: center;
    gap: 12px;
}
.v4__logo {
    height: 120px;
    width: auto;
}
/* The nav keeps its 34px from the language toggle; the smaller row gap is
   for the toggle and the LinkedIn button, which read as one set. */
.v4__nav {
    margin-left: auto;
    margin-inline-end: 22px;
    display: flex;
    gap: 6px;
}
.v4__nav a {
    padding: 12px 22px;
    border-radius: 100px;
    font-size: 14px;
    font-weight: 600;
    transition: 0.28s;
}
.v4__nav a:hover {
    background: var(--clay);
}
.v4__nav a[aria-current] {
    background: var(--green);
    color: #fff;
}
/* --- Social ------------------------------------------------------------ */
/* One round button for the LinkedIn page, sized to the language toggle next
   to it but in LinkedIn's own blue (darker on hover), so the mark is read
   at a glance. The footer wears the same button outlined on the dark
   ground, filling with the footer's link yellow on hover. */
.v4__soc {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border: 1px solid #0a66c2;
    border-radius: 50%;
    background: #0a66c2;
    color: #fff;
    transition:
        background-color 0.28s,
        border-color 0.28s,
        color 0.28s;
}
.v4__soc:hover,
.v4__soc:focus-visible {
    background: #004182;
    border-color: #004182;
    color: #fff;
}
.v4__soc svg {
    display: block;
    width: 14px;
    height: 14px;
    fill: currentColor;
}
/* --- Ribbons ------------------------------------------------------------ */
.v4__ribbons {
    position: absolute;
    inset: -125px -200px auto -200px;
    height: 800px;
    z-index: 0;
    pointer-events: none;
    opacity: 0.5;
    -webkit-mask: linear-gradient(92deg, transparent 26%, #000 56%);
    mask: linear-gradient(92deg, transparent 26%, #000 56%);
}
.v4__ribbons svg {
    width: 100%;
    height: 100%;
}
.v4__ribbons path {
    fill: none;
    stroke-width: 26;
    stroke-linecap: round;
    animation: v4drift 12s ease-in-out infinite;
}
.v4__ribbons path:nth-child(2) {
    animation-duration: 14s;
    animation-delay: -2s;
}
.v4__ribbons path:nth-child(3) {
    animation-duration: 16s;
    animation-delay: -4s;
}
.v4__ribbons path:nth-child(4) {
    animation-duration: 13s;
    animation-delay: -6s;
}
.v4__ribbons path:nth-child(5) {
    animation-duration: 15s;
    animation-delay: -8s;
}
.v4__ribbons path:nth-child(6) {
    animation-duration: 17s;
    animation-delay: -10s;
}
/* Canvas monté (home) : le SVG statique est masqué, le moteur gère sa propre opacité */
.v4__ribbons.has-fx {
    opacity: 1;
    -webkit-mask: linear-gradient(
        92deg,
        transparent 26%,
        #000 56%,
        #000 72%,
        transparent 100%
    );
    mask: linear-gradient(
        92deg,
        transparent 26%,
        #000 56%,
        #000 72%,
        transparent 100%
    );
}
.v4__ribbons.has-fx > svg {
    display: none;
}
.fx-layer {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
}
/* Page head (.v4__ribbons directly followed by .v4__hero or .v4__phead): the ribbons start
   hidden, like [data-rise], so the static SVG never flashes before the canvas engine reveals the
   bands one by one (option `reveal` in capa.js). capa.js adds .is-revealed right after mounting —
   the canvas stays blank until its reveal starts — or at once when the canvas is unavailable. */
.v4__ribbons:has(+ .v4__hero),
.v4__ribbons:has(+ .v4__phead) {
    visibility: hidden;
}
.v4__ribbons.is-revealed {
    visibility: visible;
}

/* --- Hero --------------------------------------------------------------- */
.v4__hero {
    position: relative;
    /* min-height, not height: the hero fills the rest of the fold when the text fits,
       but grows when it does not. With a fixed height, align-content: center pushed the
       overflow out both ways and the first line of the title slid under the sticky
       header — visible on the longer titles (fr, ar) below ~1300px. */
    min-height: calc(min(100vh, var(--fold-max)) - var(--hd-h));
    align-content: center;
    display: grid;
    grid-template-columns: 1.02fr 0.98fr;
    gap: 64px;
    align-items: center;
    z-index: 1;
}
.v4__kick {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background: #fff;
    border-radius: 100px;
    padding: 11px 22px;
    font-size: 13px;
    font-weight: 700;
    box-shadow: 0 12px 30px -20px rgba(34, 22, 12, 0.7);
}
.v4__kick i {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--red);
    font-style: normal;
}
.v4__hero h1 {
    margin: 26px 0 0;
    font-size: 60px;
    line-height: 1.04;
}
.v4__hero h1 em {
    font-style: italic;
    font-family: "Source Serif 4", "Source Serif Fallback", serif;
    font-weight: 600;
    color: var(--green);
    letter-spacing: -0.01em;
}
.v4__sub {
    font-family: var(--serif);
    font-size: 20px;
    line-height: 1.65;
    color: #4a3a29;
    margin: 34px 0 0;
    max-width: 56ch;
    text-wrap: pretty;
}
.v4__acts {
    display: flex;
    gap: 14px;
    margin-top: 38px;
    flex-wrap: wrap;
}
.v4__b {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    padding: 12px 32px;
    border-radius: 100px;
    font-size: 14px;
    font-weight: 700;
    transition: color 0.3s 0.1s;
}
.v4__b i {
    font-style: normal;
    transition: transform 0.3s;
}
.v4__b:hover i {
    transform: translateX(5px);
}
.v4__b--1 {
    --blob: var(--yellow);
    background: var(--green);
    color: #fff;
}
.v4__b--1:hover {
    color: var(--ink);
}
.v4__b--2 {
    --blob: var(--yellow);
    background: #fff;
    color: #22160c;
    box-shadow: inset 0 0 0 2px rgba(34, 22, 12, 0.16);
}

/* Blob hover (demo/button.html, 04 A): a disc in --blob grows from the point
   where the pointer enters the button and shrinks back to the point where it
   leaves; capa.js writes that position into --x / --y. isolation keeps the
   z-index:-1 disc inside the button, above its own background. */
.v4__b,
.v4__arrow {
    --x: 50%;
    --y: 50%;
}
.v4__b::before,
.v4__arrow::before {
    content: "";
    position: absolute;
    z-index: -1;
    left: var(--x);
    top: var(--y);
    width: 260%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: var(--blob);
    transform: translate(-50%, -50%) scale(0);
    /* Not --ease-io, which the rest of the page uses: that curve holds its
       first control point at x = 0.76, so the disc spends its opening third a
       few pixels wide and the hover reads as late. Same in-and-out family —
       the gesture keeps its weight — with the control point pulled back and
       100 ms off the duration: the disc covers the button at 170 ms instead of
       283 ms. Keep in step with the return, which shares this rule. */
    transition: transform 0.5s cubic-bezier(0.45, 0, 0.24, 1);
}
.v4__b:hover::before,
.v4__arrow:hover::before {
    transform: translate(-50%, -50%) scale(1);
}
@media (prefers-reduced-motion: reduce) {
    .v4__b::before,
    .v4__arrow::before {
        transition-duration: 0.01ms;
    }
}

.v4__blob {
    position: relative;
    aspect-ratio: 1.1/1;
    width: 100%;
    max-width: 480px;
    margin-left: auto;
    overflow: hidden;
    /* animation: v4blobA 30s ease-in-out infinite; */
    border-radius: 50% 50% 21px 31px;
    box-shadow: 0 50px 100px -50px rgba(34, 22, 12, 0.6);
}
.v4__blob img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* Hero carousel: the slides are stacked and cross-fade on opacity every 4 s
   (timer in capa.js); only the .is-active one is visible. */
.v4__slides img {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 1s ease-in-out;
}
.v4__slides img.is-active {
    opacity: 1;
}

/* --- About --------------------------------------------------------------- */
.v4__about {
    max-width: 1300px;
    width: 80vw;
    margin: auto;
    background: var(--leaf);
    padding: 40px 0;
    position: relative;
    overflow: hidden;
    /* Same corner as the newsroom band, top and bottom, so the
   two coloured slabs read as the same object. */
    border-radius: 50px;
}
/* On the homepage the band holds only the prose, so it is drawn to the
   width of a comfortable text column rather than the full page, and
   it is pushed off the fold so it does not sit flush under the hero. */
.v4__about--narrow {
    max-width: 900px;
    margin-top: 5rem;
    padding: 45px 0;
}
/* The eyebrow is a kicker, never a heading — every section pairs it
   with a real h2 underneath. */
.v4 .v4__eye {
    margin: 0;
    font-size: 12.5px;
    font-weight: 800;
    letter-spacing: 0.16em;
    text-transform: uppercase;
}
/* The gap under a section title belongs to the title, not to
   whatever happens to follow it. */
.v4__h2 {
    margin: 14px 0 0;
    padding-bottom: 48px;
    font-size: 46px;
    line-height: 1.08;
    max-width: 15ch;
}
/* In a two-column head the padding sits on the head block instead,
   so the note or link stays bottom-aligned with the title. */
.v4__nhead .v4__h2,
.v4__conshead .v4__h2 {
    padding-bottom: 0;
}
/* Every section title carries a highlighter stroke: 30% of its width, in
   the palette orange. It is model 07 "Encre" of demo/underline.html — one
   bowed felt-tip stroke whose edges are roughened by an feTurbulence +
   feDisplacementMap filter — carried over as a background SVG so no page
   markup changes. Sized in em so it follows each heading's type (0.42em
   box, as in the demo). */
.v4__h2::after,
.v4__prose h2::after,
.v4 .head-row h2::after,
.v4 .v4__blank h2::after {
    content: "";
    display: block;
    width: 30%;
    height: 0.42em;
    margin-top: 0.26em;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 26' preserveAspectRatio='none'%3E%3Cfilter id='r' x='-5%25' y='-40%25' width='110%25' height='180%25'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.04 0.1' numOctaves='3' seed='2' result='n'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='7' xChannelSelector='R' yChannelSelector='G'/%3E%3C/filter%3E%3Cpath filter='url(%23r)' d='M5 13C90 6 200 6 295 12' fill='none' stroke='%23ef7e09' stroke-width='11' stroke-linecap='round' stroke-opacity='.9'/%3E%3C/svg%3E")
        no-repeat center / 100% 100%;
}
.v4 .v4__blank h2::after {
    margin-left: auto;
    margin-right: auto;
}
.v4__about p:first-of-type {
    margin-top: 0;
}
.v4__about p {
    font-family: var(--serif);
    font-size: 19px;
    line-height: 1.7;
    color: #3c2e20;
    margin: 24px 0 0;
    text-wrap: pretty;
}
.v4__arrow {
    --blob: #22160c; /* yellow ground, so the blob is the dark ink */
    position: relative;
    isolation: isolate;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    gap: 12px;
    margin-top: 32px;
    padding: 15px 26px;
    border-radius: 100px;
    background: var(--yellow);
    font-size: 13.5px;
    font-weight: 700;
    transition:
        color 0.3s 0.1s,
        gap 0.3s;
}
.v4__arrow:hover {
    color: var(--yellow);
    gap: 18px;
}

/* --- Figures ---------------------------------------------------------------- */
/* The slab card from variant 05 — same construction, every metric halved:
   the rounded box, the display number and the ring cropped out of the
   bottom-right corner all scale together, so the card keeps its proportions
   at half the footprint. Supporting type stops short of a true 50% cut,
   which would put it under 10px and out of reach. */
.v4__figs {
    padding: 104px 0 0;
}
.v4__viewport {
    overflow-x: auto;
    scroll-snap-type: x mandatory;
}
.v4__strip {
    display: flex;
    gap: 2rem;
    padding: 0 46px 78px;
    width: max-content;
    margin-inline: auto;
}
.v4__slab {
    scroll-snap-align: center;
    flex: 0 0 350px;
    min-height: 300px;
    border-radius: 23px;
    padding: 26px 23px 22px;
    display: flex;
    flex-direction: column;
    color: #fff;
    position: relative;
    overflow: hidden;
    box-shadow: 0 17px 35px -23px rgba(34, 22, 12, 0.85);
    transition: transform 0.5s;
}
.v4__slab::after {
    content: "";
    position: absolute;
    right: -45px;
    bottom: -60px;
    width: 170px;
    height: 170px;
    border-radius: 50%;
    border: 22px solid rgba(255, 255, 255, 0.16);
}
.v4__slab:hover {
    transform: translateY(-10px);
}
.v4__sn {
    font-size: 66px;
    line-height: 0.84;
    font-weight: 800;
    letter-spacing: -0.055em;
}
.v4__sl {
    font-size: 16px;
    font-weight: 700;
    margin-block: 10px;
}
.v4__srows {
    position: relative;
    /* margin-top: auto; */
    padding-top: 11px;
    border-top: 1.5px solid rgba(255, 255, 255, 0.34);
    display: grid;
    gap: 6px;
    font-size: 15px;
}
.v4__srows div {
    display: flex;
    gap: 8px;
}
.v4__srows b {
    font-weight: 800;
    min-width: 30px;
}

/* --- Newsroom --------------------------------------------------------------- */
/* Same card layout as variant 05: three even columns, no stagger, the tag
   sitting inside the top-left of the frame rather than under it. */
.v4__news {
    background: var(--sand-2);
    padding: 104px 0 110px;
    border-radius: 90px 90px 0 0;
}
.v4__nhead {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 40px;
    padding-bottom: 48px;
}
.v4__nnote {
    font-family: var(--serif);
    font-size: 16px;
    line-height: 1.55;
    color: #5a4632;
    max-width: 32ch;
    margin: 0;
}
.v4__ngrid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 30px;
}
.v4__item {
    display: block;
    transition: transform 0.45s;
}
.v4__item:hover {
    transform: translateY(-9px);
}
.v4__ifr {
    /* height: 280px; */
    aspect-ratio: 16/9;
    border-radius: 34px;
    overflow: hidden;
    position: relative;
}
.v4__ifr img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.9s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.v4__item:hover .v4__ifr img {
    transform: scale(1.08);
}
.v4__tag {
    position: absolute;
    left: 18px;
    top: 18px;
    border-radius: 100px;
    padding: 8px 16px;
    color: #fff;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}
.v4 .v4__it {
    margin: 22px 0 0;
    font-size: 24px;
    font-weight: 800;
    line-height: 1.2;
    letter-spacing: normal;
}
.v4__id {
    font-family: var(--serif);
    font-size: 16px;
    line-height: 1.6;
    color: #5a4632;
    margin: 11px 0 0;
}
.v4__im {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    margin-top: 16px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--green);
}

/* --- Consortium ------------------------------------------------------------- */
.v4__cons {
    background: var(--sand-2);
    /* 110px of band stays visible above the footer; the extra 90px
   is the strip the footer is pulled back over, so its rounded corners bite
   into this band rather than into the variant's paler ground. */
    padding: 0 0 200px;
}
/* On the consortium and results pages the band is itself a card before the
   footer: rounded like the newsroom, with the room above that the homepage
   band, which follows the newsroom directly, does not need. */
.v4__cons--card {
    padding-top: 104px;
    border-radius: 90px 90px 0 0;
}
.v4__conshead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 30px;
    padding-bottom: 48px;
}
.v4__mq {
    overflow: hidden;
    -webkit-mask: linear-gradient(
        90deg,
        transparent,
        #000 6%,
        #000 94%,
        transparent
    );
    mask: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.v4__track {
    display: flex;
    gap: 20px;
    width: max-content;
    animation: v4slide 76s linear infinite;
}
.v4__mq:hover .v4__track {
    animation-play-state: paused;
}
@keyframes v4slide {
    to {
        transform: translateX(calc(-50% - 10px));
    }
}
.v4__run {
    display: flex;
    gap: 20px;
}
.v4__lg {
    flex: 0 0 188px;
    /* The tile is a fixed frame the logo is fitted into (object-fit: contain below).
       Its height, and a row with a zero minimum, are what make that frame definite:
       without them the tile takes the intrinsic height of its image (a logo is up to
       402px tall) and the strip runs down the whole page. */
    height: 124px;
    /* background: var(--sand); */
    display: grid;
    grid-template-rows: minmax(0, 1fr);
    place-items: center;
    padding: 30px 38px;
    transition: 0.35s;
}
/* The pebble wobble animates a border-radius, which is only ever visible once
   the hover background is behind it — so it runs on hover instead of on all
   58 tiles at once, which cost a permanent repaint for nothing on screen. */
.v4__lg:hover {
    background: #fff;
    animation: v4peb 24s ease-in-out infinite;
}
.v4__lg:nth-child(even):hover {
    animation-delay: -8s;
}
.v4__lg img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    filter: grayscale(1);
    opacity: 0.7;
    transition: 0.35s;
}
.v4__lg:hover img {
    filter: none;
    opacity: 1;
}

/* --- Footer ------------------------------------------------------------------ */
/* Green earth rather than ink: the warm direction is carried all the way
   to the bottom of the page instead of reverting to a neutral dark. */
.v4__ft {
    background: #030303;
    color: rgba(255, 255, 255, 0.78);
    border-radius: 90px 90px 0 0;
    /* Pulled back over the consortium band by exactly the corner
   radius, so what shows through the curve is that band's colour. */
    margin-top: -90px;
    position: relative;
    overflow: hidden;
}
/* Same six ribbons as the page head, dimmed on the dark ground; the canvas
   engine (when mounted) sets its own opacity. */
.v4__ribbons--ft {
    top: -90px;
    opacity: 0.3;
}
.v4__ftcols {
    position: relative;
    display: grid;
    grid-template-columns: 1.45fr 1fr 1fr 1.75fr;
    gap: 52px;
    padding: 88px 0 44px;
}
.v4__ftlogo {
    height: 7rem;
    width: auto;
    /* margin-bottom: 20px; */
    margin-top: -20px;
    scale: 1.2;
    object-fit: contain;
}
.v4__ft p {
    margin: 0;
}
.v4__fttag {
    font-family: var(--serif);
    font-size: 15px;
    line-height: 1.62;
}
.v4__soc--ft {
    margin-top: 22px;
    width: 40px;
    height: 40px;
    border-color: rgba(255, 255, 255, 0.28);
    background: transparent;
    color: rgba(255, 255, 255, 0.88);
}
.v4__soc--ft:hover,
.v4__soc--ft:focus-visible {
    background: var(--yellow);
    border-color: var(--yellow);
    color: var(--ink);
}
.v4__soc--ft svg {
    width: 18px;
    height: 18px;
}
.v4__fttitle {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    margin-bottom: 16px;
}
.v4__ftlist {
    display: grid;
    gap: 10px;
    font-size: 15px;
    color: rgba(255, 255, 255, 0.88);
}
.v4__ftlist a:hover {
    color: var(--yellow);
}
.v4__ftfund {
    font-size: 12.5px;
    line-height: 1.68;
    color: rgba(255, 255, 255, 0.62);
}
.v4__ftbase {
    position: relative;
    display: flex;
    justify-content: space-between;
    gap: 20px;
    padding: 20px 0 42px;
    border-top: 1px solid rgba(255, 255, 255, 0.16);
    font-size: 12.5px;
    margin-top: 4rem !important;
}
.v4__ftbase a:hover {
    color: var(--yellow);
}
/* The cookie panel has to stay reachable after the first answer, so its
   opener sits in the legal line with the other links — and has to pass for
   one, button element or not. */
.v4__ftck {
    appearance: none;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    cursor: pointer;
}
.v4__ftck:hover {
    color: var(--yellow);
}

/* ==========================================================================
   INTERIOR PAGES
   Everything below is shared by About, Consortium, Project Results and
   News. Same vocabulary as the homepage — pebble radii, ribbon bands, serif
   prose on sand — so an interior page never reads as a different site.
   ========================================================================== */

/* --- Page head ------------------------------------------------------------ */
/* A banded hero: the ribbons run behind it exactly as they do on the
   homepage, and like the homepage hero it fills the viewport below the
   header (capped at --fold-max), its content centred. */
.v4__phead {
    position: relative;
    height: calc(min(100vh, var(--fold-max)) - var(--hd-h));
    align-content: center;
    z-index: 1;
}
/* Article headings use a shorter hero and grow if a long title needs more room. */
.v4__phead--article {
    height: auto;
    min-height: calc(min(60vh, var(--fold-max)) - var(--hd-h));
    padding: 32px 0;
}
.v4__phead h1 {
    margin: 14px 0 0;
    font-size: 58px;
    line-height: 1.06;
    max-width: 18ch;
}
.v4__phead--article h1 {
    max-width: 22ch;
}
.v4__article-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px 24px;
    margin-top: 24px;
}
.v4__article-meta .v4__plead {
    margin: 0;
}
.v4__phead h1 em {
    font-style: italic;
    font-family: "Source Serif 4", "Source Serif Fallback", serif;
    font-weight: 600;
    color: var(--green);
    letter-spacing: -0.01em;
}
/* About: two columns, the CAPA illustration on the right in place of the ribbons
   (same grid as the homepage hero). */
.v4__phead--img {
    display: grid;
    grid-template-columns: 1.02fr 0.98fr;
    gap: 64px;
    align-items: center;
}
.v4__phead__img img {
    display: block;
    width: 100%;
    max-width: 480px;
    margin-left: auto;
}
.v4__plead {
    font-family: var(--serif);
    font-size: 20px;
    line-height: 1.65;
    color: #4a3a29;
    margin: 28px 0 0;
    max-width: 58ch;
    text-wrap: pretty;
}
.v4__pkick {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    background: #fff;
    border-radius: 100px;
    padding: 11px 22px;
    font-size: 13px;
    font-weight: 700;
    box-shadow: 0 12px 30px -20px rgba(34, 22, 12, 0.7);
}
.v4__pkick i {
    width: 12px;
    height: 12px;
    border-radius: 50%;
    font-style: normal;
}

/* --- Long-form prose ------------------------------------------------------- */
.v4__prose p {
    font-family: var(--serif);
    font-size: 19px;
    line-height: 1.72;
    color: #3c2e20;
    margin: 26px 0 0;
    text-wrap: pretty;
}
.v4__prose p:first-child {
    margin-top: 0;
}
.v4__prose--narrow p {
    max-width: 74ch;
}
.v4__prose--narrow {
    max-width: 74ch;
    font-family: var(--serif);
    font-size: 19px;
}
.v4__prose h2,
.v4__prose h3 {
    font-family: var(--bric);
    text-wrap: balance;
}
.v4__prose h2 {
    margin: 56px 0 0;
    font-size: 32px;
    line-height: 1.12;
}
.v4__prose h3 {
    margin: 40px 0 0;
    font-size: 23px;
    line-height: 1.25;
}
.v4__prose h2 + p,
.v4__prose h3 + p {
    margin-top: 16px;
}
/* Lists and inline links inside prose (privacy policy). */
.v4__prose ul {
    margin: 16px 0 0;
    padding-left: 24px;
    font-family: var(--serif);
    font-size: 19px;
    line-height: 1.72;
    color: #3c2e20;
}
.v4__prose li + li {
    margin-top: 8px;
}
.v4__prose li::marker {
    color: var(--orange);
}
.v4__prose a:not(.v4__b) {
    color: var(--green);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.v4__prose .v4__b {
    font-family: var(--bric);
    text-decoration: none;
}
.v4__prose blockquote {
    margin: 44px 0 0;
    padding: 6px 0 6px 34px;
    border-left: 6px solid var(--green);
}
.v4__prose blockquote p {
    font-size: 23px;
    line-height: 1.5;
    font-style: italic;
}
.v4__prose blockquote cite {
    display: block;
    margin-top: 14px;
    font-family: var(--bric);
    font-style: normal;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--green);
}
.v4__prose figure {
    margin: 48px 0 0;
}
.v4__prose figure img {
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: 34px;
}
.v4__prose figcaption {
    margin-top: 14px;
    font-family: var(--serif);
    font-size: 15px;
    line-height: 1.5;
    color: #5a4632;
}

/* --- Article page: body on the left, sidebar on the right ------------------- */
.v4__artgrid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 400px;
    gap: 80px;
    align-items: start;
}
.v4__aside {
    display: grid;
    gap: 44px;
}
/* Newsletter card: the footer's dark ground and six ribbons, no form — the
   button is a plain link to the newsletter platform. */
.v4__nlcard {
    position: relative;
    isolation: isolate;
    overflow: hidden;
    padding: 40px 40px 44px;
    border-radius: 40px;
    background: #030303;
    color: rgba(255, 255, 255, 0.78);
}
.v4__ribbons--nl {
    inset: -30px -90px auto -90px;
    height: 150%;
    opacity: 0.45;
    -webkit-mask: none;
    mask: none;
}
.v4__nlin {
    position: relative;
    z-index: 1;
}
.v4 .v4__nlt {
    margin: 0;
    font-size: 24px;
    font-weight: 800;
    color: #fff;
}
.v4__nlx {
    font-family: var(--serif);
    font-size: 17px;
    line-height: 1.7;
    margin: 14px 0 0;
    text-wrap: pretty;
}
.v4__nlcard .v4__b {
    margin-top: 26px;
}
/* Latest posts: a white pebble card with the newsletter card's footprint,
   so the sidebar reads as one light card over one dark one. Each entry
   carries its post's palette colour in --pc (set inline from the JSON
   "color" key, the way the beneficiary cards do): the type pill wears it —
   the same pill as on the newsroom cards — and the title takes it on hover
   while the arrow nudges along. */
.v4__recentbox {
    background: #fff;
    border-radius: 40px;
    padding: 34px 40px 32px;
    box-shadow: 0 24px 50px -42px rgba(34, 22, 12, 0.85);
}
.v4__recentbox .v4__eye {
    margin-bottom: 12px;
}
.v4__recent {
    display: block;
    padding: 20px 0 22px;
    border-top: 1px solid rgba(34, 22, 12, 0.1);
}
.v4__recentm {
    display: flex;
    align-items: center;
    gap: 10px;
}
.v4__recenttag {
    border-radius: 100px;
    padding: 5px 10px;
    background: var(--pc);
    color: #fff;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}
.v4__recent time {
    font-family: var(--serif);
    font-size: 14px;
    color: #5a4632;
}
.v4__recentt {
    display: block;
    margin-top: 12px;
    font-size: 17px;
    font-weight: 800;
    line-height: 1.25;
    letter-spacing: -0.02em;
    text-wrap: pretty;
    transition: color 0.3s;
}
.v4__recentt i {
    display: inline-block;
    margin-left: 4px;
    font-style: normal;
    color: var(--pc);
    transition: transform 0.35s var(--ease-io);
}
.v4__recent:hover .v4__recentt {
    color: var(--pc);
}
.v4__recent:hover .v4__recentt i {
    transform: translateX(5px);
}
.v4__recentall {
    display: flex;
    align-items: center;
    gap: 9px;
    padding-top: 22px;
    border-top: 1px solid rgba(34, 22, 12, 0.1);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--green);
    transition: color 0.3s;
}
.v4__recentall span {
    transition: transform 0.35s var(--ease-io);
}
.v4__recentall:hover {
    color: var(--orange);
}
.v4__recentall:hover span {
    transform: translateX(5px);
}

/* --- Section bands ---------------------------------------------------------- */
/* The leaf slab from the homepage About, reusable wherever an interior page
   needs to change ground colour mid-scroll. */
.v4__band {
    margin: 8rem auto;
    width: 80%;
    background: var(--leaf);
    border-radius: 50px;
    padding: 40px 0;
    position: relative;
    overflow: hidden;
}
.v4__band--sand {
    background: var(--sand-2);
}
.v4__plain {
    padding: 104px 0;
}

/* --- Work packages ---------------------------------------------------------- */
/* Each WP is a pebble-cornered card carrying its own colour off the logo arc,
   set with --wp on the element. The number is displayed large in the left
   column the way the homepage figure slabs are, so the two card families read
   as one system. */
.v4__wps {
    display: grid;
    gap: 22px;
}
.v4__wp {
    position: relative;
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 44px;
    background: #fff;
    border-radius: 40px;
    padding: 40px 46px;
    overflow: hidden;
    box-shadow: 0 24px 50px -40px rgba(34, 22, 12, 0.8);
    transition: transform 0.45s;
}
.v4__wp:hover {
    transform: translateY(-6px);
}
.v4__wp::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 12px;
    background: var(--wp, var(--green));
}
.v4__wpwp {
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #8a7860;
    margin-bottom: 10px;
}
.v4__wpnum {
    font-size: 58px;
    line-height: 0.86;
    font-weight: 800;
    letter-spacing: -0.055em;
    color: var(--wp, var(--green));
}
.v4__wplead {
    margin-top: 18px;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    border-radius: 100px;
    padding: 9px 16px;
    background: var(--clay);
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.06em;
    color: #4a3a29;
}
.v4 .v4__wpt {
    margin: 0;
    font-size: 27px;
    line-height: 1.22;
    font-weight: 800;
}
.v4__wpx {
    font-family: var(--serif);
    font-size: 17px;
    line-height: 1.7;
    color: #4a3a29;
    margin: 16px 0 0;
    text-wrap: pretty;
}

/* --- Partner list ------------------------------------------------------------ */
.v4__psec + .v4__psec {
    margin-top: 82px;
}
.v4__pgrid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}
.v4__pcard {
    display: flex;
    flex-direction: column;
    background: #fff;
    border-radius: 34px;
    padding: 26px 28px 24px;
    position: relative;
    box-shadow: 0 24px 50px -42px rgba(34, 22, 12, 0.85);
    transition: transform 0.42s;
}
.v4__pcard:hover {
    transform: translateY(-7px);
}
.v4__pno {
    position: absolute;
    top: 22px;
    right: 26px;
    font-size: 13px;
    font-weight: 800;
    color: var(--muted-2);
}
.v4__pfr {
    height: 84px;
    display: grid;
    place-items: center start;
    margin-bottom: 20px;
}
.v4__pfr img {
    max-height: 84px;
    max-width: 190px;
    object-fit: contain;
}
.v4 .v4__pname {
    margin: 0;
    font-size: 17px;
    line-height: 1.32;
    font-weight: 800;
    padding-right: 26px;
}
.v4__pabbr {
    color: var(--green);
}
.v4__pmeta {
    font-family: var(--serif);
    font-size: 15px;
    line-height: 1.5;
    color: #5a4632;
    margin: 10px 0 0;
}
.v4__pgo {
    margin-top: auto;
    padding-top: 18px;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: 12px;
    font-weight: 800;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--green);
    transition: color 0.3s;
}
.v4__pcard:hover .v4__pgo {
    color: var(--orange);
}

/* --- Beneficiary card ---------------------------------------------------------- */
/* Carried over from indexcapa.html unchanged: a circular logo well, a quarter
   ring that swings round on hover, and two arcs that draw themselves in behind
   it. Everything that varies from one card to the next — accent colour, seeded
   rotations, arc length — arrives as a custom property on the element, so the
   whole hover state stays in CSS and no card needs its own listener. The three
   variables that sheet defines and the Weave sheet does not are supplied on the
   section. */
.v4 .cons {
    --line-2: rgba(14, 26, 36, 0.12);
    --r-pill: 100px;
    --r-sm: 14px;
}
.v4 .benef__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: 20px;
    align-items: start;
}
.v4 .benef {
    height: 100%;
    position: relative;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: var(--r-sm);
    padding: 22px 24px;
    display: flex;
    align-items: center;
    gap: 26px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.03);
    /* This rule outranks .v4 [data-rise] (same weight, later in the sheet), so
       the rise-in has to be restated here or the card would pop in at once. */
    transition:
        opacity 0.9s var(--ease-rise) var(--rise-delay, 0s),
        transform 0.9s var(--ease-rise) var(--rise-delay, 0s),
        box-shadow 0.3s ease,
        border-color 0.3s ease;
}
.v4 .benef:hover {
    border-color: #cbd5e1;
    box-shadow: 0 14px 36px -18px rgba(23, 49, 84, 0.16);
}
.v4 .benef__mark {
    position: relative;
    width: 112px;
    height: 112px;
    flex-shrink: 0;
}
.v4 .benef__well {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    /* background: #e9edf3; */
    overflow: hidden;
    z-index: 2;
    padding: 16px;
}
.v4 .benef__well img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}
/* The accent line rides the outer edge of the halo band, so its radius is
   pinned to the halo box (140px) rather than hugging the well:
   inset = (112 − 140) / 2. */
.v4 .benef__ring {
    position: absolute;
    inset: -14px;
    border: 2px solid var(--pc);
    /* Same pastel treatment as the halo arcs. */
    opacity: 0.3;
    border-radius: 50%;
    border-right-color: transparent;
    border-bottom-color: transparent;
    transform: rotate(45deg);
    transition:
        transform 0.5s ease-out,
        border-color 0.3s ease-out;
    z-index: 3;
    pointer-events: none;
}
.v4 .benef:hover .benef__ring {
    transform: rotate(220deg);
}
/* Sized 140px against a 160-unit viewBox (0.875px per unit). The lines are all
   thin (~2px) and sit on staggered radii with ~4px gaps so they never overlap:
   accent ring at 68→70px, first arc r=72 at 62→64px, second arc r=65 at 56→58px. */
.v4 .benef__halo {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 140px;
    height: 140px;
    transform: translate(-50%, -50%);
    pointer-events: none;
    z-index: 1;
}
.v4 .benef__halo svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    transform-origin: 50% 50%;
}
.v4 .benef__halo circle {
    fill: none;
    stroke-width: 2.3;
    /* Exact logo colours, lightened to a pastel by opacity (cards are white). */
    stroke-opacity: 0.3;
    stroke-linecap: round;
    /* 130 of the ~452-unit circumference (r=72): a 104° sweep, 115° on the
       r=65 circle — long enough to read as an arc at this thin stroke. The
       999 gap keeps it to one arc per circle. */
    stroke-dasharray: 130 999;
    stroke-dashoffset: 999;
    transform-origin: 50% 50%;
    transform: rotate(var(--rot));
    transition:
        stroke-dashoffset 0.7s ease-out var(--delay),
        transform 0.9s ease-out var(--delay);
}
.v4 .benef:hover .benef__halo circle {
    stroke-dashoffset: var(--doff);
    transform: rotate(var(--rot-on));
}
.v4 .benef__body {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}
.v4 .benef__num {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: #64748b;
}
.v4 .benef__name {
    font-size: 17px;
    font-weight: 500;
    line-height: 1.4;
    color: #173154;
    text-wrap: pretty;
}
.v4 .benef__country {
    font-size: 14px;
    color: #64748b;
    line-height: 1.5;
}
.v4 .benef__url {
    align-self: flex-start;
    margin-top: 4px;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 14px;
    font-weight: 500;
    color: #173154;
    transition: gap 0.3s ease;
}
/* The whole card is the link: the anchor's ::after is stretched over the card
   (.benef is its positioned ancestor), above the logo well and ring, so the
   markup keeps a single anchor and its hover state plays from anywhere on
   the card. */
.v4 .benef__url::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: var(--r-sm);
    z-index: 4;
}
.v4 .benef__url:hover {
    gap: 15px;
    color: var(--blue);
}

/* --- Deliverables ------------------------------------------------------------- */
/* Carried over from indexcapa.html unchanged: one collapsible group per work
   package, a colour-coded code pill, the deliverable count on the right and a
   +/− sign, with the rows appearing in an indented panel underneath. Only the
   two custom properties that sheet defines and this one does not are supplied
   locally; type resolves to the Weave families through `inherit` and --serif,
   so the component reads as part of this page rather than a transplant. */
.v4 .deliv {
    --line-2: rgba(14, 26, 36, 0.12);
    --r-pill: 100px;
}
.v4 .deliv__note {
    font-size: 13px;
    color: var(--muted);
    margin: 0 0 28px 42px;
}
.v4 .deliv__group {
    border-top: 1px solid var(--line-2);
}
.v4 .deliv__list {
    border-bottom: 1px solid var(--line-2);
}
.v4 .deliv__toggle {
    appearance: none;
    background: transparent;
    border: 0;
    font-family: inherit;
    cursor: pointer;
    width: 100%;
    text-align: left;
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 22px 4px;
    color: var(--ink);
}
.v4 .deliv__toggle:hover {
    color: var(--blue);
}
.v4 .deliv__code {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 32px;
    border-radius: var(--r-pill);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    flex-shrink: 0;
}
.v4 .deliv__title {
    font-size: 19px;
    font-weight: 600;
    letter-spacing: -0.01em;
    flex: 1;
    text-wrap: pretty;
}
.v4 .deliv__count {
    font-size: 12px;
    color: var(--muted-2);
    font-weight: 600;
    letter-spacing: 0.06em;
}
.v4 .deliv__sign {
    font-size: 20px;
    color: var(--muted-2);
    width: 20px;
    text-align: center;
}
.v4 .deliv__panel {
    padding: 0 4px 28px 64px;
    display: grid;
    gap: 1px;
}
.v4 .deliv__panel[hidden] {
    display: none;
}
.v4 .deliv__row {
    display: grid;
    grid-template-columns: 72px 1fr 100px;
    gap: 20px;
    align-items: baseline;
    padding: 12px 0;
    border-bottom: 1px solid rgba(14, 26, 36, 0.07);
}
.v4 .deliv__id {
    font-size: 13px;
    font-weight: 700;
}
.v4 .deliv__name {
    font-family: var(--serif);
    font-size: 16px;
    color: var(--ink-2);
    line-height: 1.45;
}
.v4 .deliv__status {
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--muted-2);
    font-weight: 600;
    text-align: right;
}

/* --- Empty shelf ---------------------------------------------------------------- */
/* Sections the consortium has not filled yet keep the silhouette of what
   will fill them rather than carrying a stand-in card. The Zenodo band
   pairs its text with a FAIR slab built like the homepage figures and
   draws the future link as a dashed outline in the arrow-button shape;
   the newsletter and the materials take the newsroom frame, empty: the
   status sits where the tag will, and what the frame is waiting for is
   ghosted along its foot. */
.v4__oa {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 350px;
    gap: 64px;
    align-items: center;
}
.v4__oa .v4__h2 {
    padding-bottom: 0;
}
/* Four rows instead of the figures' one to three: a touch larger, so the
   list fills the slab rather than floating in its upper half. */
.v4__oa .v4__srows {
    font-size: 14px;
    gap: 9px;
}
.v4__oalead {
    font-family: var(--serif);
    font-size: 19px;
    line-height: 1.7;
    color: #3c2e20;
    margin: 24px 0 0;
    max-width: 54ch;
    text-wrap: pretty;
}
.v4__slot {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
    margin-top: 32px;
    padding: 14px 26px;
    border-radius: 100px;
    border: 1.5px dashed rgba(34, 22, 12, 0.32);
    font-size: 13.5px;
    font-weight: 700;
    color: #4a3a29;
}
.v4__slot em {
    font-family: var(--serif);
    font-size: 15px;
    font-weight: 400;
    color: #8a7860;
}
.v4__shelf {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 30px;
}
.v4__shelf article {
    position: relative;
}
.v4__ifr--empty {
    background: var(--clay);
}
/* The ring cropped out of the slab corner, in ink this time, so the empty
   frame and the slab in the band above read as the same family. */
.v4__ifr--empty::after {
    content: "";
    position: absolute;
    right: -45px;
    bottom: -60px;
    width: 170px;
    height: 170px;
    border-radius: 50%;
    border: 22px solid rgba(34, 22, 12, 0.05);
}
.v4__ghost {
    position: absolute;
    left: 30px;
    bottom: 22px;
    font-size: 64px;
    line-height: 0.95;
    font-weight: 800;
    letter-spacing: -0.04em;
    color: rgba(34, 22, 12, 0.11);
}
/* Last in the article for reading order, drawn over the frame's top-left
   corner where the newsroom tag sits. */
.v4__wait {
    position: absolute;
    left: 18px;
    top: 18px;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    border-radius: 100px;
    padding: 9px 16px 9px 14px;
    background: #fff;
    font-size: 10.5px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    box-shadow: 0 12px 30px -20px rgba(34, 22, 12, 0.7);
}
.v4__wait i {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    font-style: normal;
}

/* --- Empty newsroom -------------------------------------------------------------- */
.v4__blank {
    text-align: center;
    padding: 90px 0 104px;
}
.v4__blankblob {
    width: 190px;
    height: 190px;
    margin: 0 auto 38px;
    background: var(--leaf);
    display: grid;
    place-items: center;
    animation: v4blobA 18s ease-in-out infinite;
}
.v4__blankblob img {
    width: 92px;
    opacity: 0.9;
}
.v4 .v4__blank h2 {
    margin: 0;
    font-size: 40px;
    line-height: 1.12;
}
.v4__blank p {
    font-family: var(--serif);
    font-size: 18px;
    line-height: 1.68;
    color: #4a3a29;
    margin: 20px auto 0;
    max-width: 58ch;
    text-wrap: pretty;
}

/* ==========================================================================
   COMPONENTS CARRIED OVER FROM indexcapa.html
   The header language switcher and the About page layout: mission lead with
   two-column prose, then one row per work package with a picture pasted
   behind the text. Scoped under .v4 so they win over the Weave heading rules.
   ========================================================================== */
:root {
    --surface: #f4f6f8;
    --line-2: rgba(14, 26, 36, 0.12);
    --r-pill: 100px;
    --r-sm: 14px;
}

/* --- Language switcher ----------------------------------------------------
   Five languages is too many for a row of pills, so the header carries a
   compact toggle that opens a list of endonyms (people look for the name in
   their own script). Languages that are not live yet stay visible but
   disabled — see $arrLang / $arrLangAll in config.ini.php. */
.lang {
    position: relative;
    flex-shrink: 0;
}
.lang__toggle {
    appearance: none;
    cursor: pointer;
    font-family: inherit;
    display: flex;
    align-items: center;
    gap: 7px;
    border: 1px solid rgba(14, 26, 36, 0.15);
    border-radius: var(--r-pill);
    background: var(--ink);
    color: #fff;
    padding: 7px 10px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
}
.lang__toggle:hover {
    background: var(--orange);
    border-color: var(--orange);
}
.lang__chev {
    display: block;
    width: 7px;
    height: 7px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
}
.lang__toggle[aria-expanded="true"] .lang__chev {
    transform: translateY(1px) rotate(-135deg);
}
.lang__menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 125px;
    background: #fff;
    border: 1px solid var(--line-2);
    border-radius: var(--r-sm);
    box-shadow: 0 14px 34px rgba(14, 26, 36, 0.14);
    padding: 6px;
    z-index: 60;
}
.lang__menu[hidden] {
    display: none;
}
.lang__opt {
    appearance: none;
    border: 0;
    background: transparent;
    font-family: inherit;
    cursor: pointer;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 10px 12px;
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
    text-align: left;
    border-radius: var(--r-pill);
}
.lang__opt:hover:not([disabled]) {
    background: var(--surface);
    color: var(--blue);
}
.lang__opt[aria-current="true"] {
    background: var(--ink);
    color: #fff;
}
.lang__opt[disabled] {
    cursor: default;
    color: var(--muted-2);
}
/* Arabic is right-to-left; its endonym must render as such even while the
   interface around it is still English. */
.lang__opt[lang="ar"] .lang__name {
    direction: rtl;
    font-size: 15px;
}

/* --- About: mission --------------------------------------------------------- */
.v4 .mission__lead {
    font-family: var(--serif);
    font-size: 24px;
    line-height: 1.5;
    color: var(--ink);
    margin: 0;
    max-width: 62ch;
    text-wrap: pretty;
}
.v4 .mission__cols {
    column-count: 2;
    column-width: 380px;
    column-gap: 56px;
    /* max-width: 1060px; */
}
.v4 .mission__cols p {
    font-family: var(--serif);
    font-size: 17.5px;
    line-height: 1.7;
    color: var(--ink-2);
    margin: 0 0 20px;
    text-wrap: pretty;
}

/* Lead row: the chapô on the left and, on the right, a small CAPA logo that
   assembles itself once the row scrolls into view — SVG from
   demo/3a-autonome.html, served from include/templates/capa-logo-anim.svg. */
.v4 .mission__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 48px;
    margin: 0 0 40px;
}
.v4 .mission__logo {
    flex: none;
}
.capa-logo {
    display: block;
    width: 55%;
    height: auto;
    margin-inline: auto;
}
/* The six segments fly in along their radius (90 ms apart), the thin arc
   draws itself, then the continents and the letters pop from their centre —
   a 2 s cascade timed by the SVG's inline styles. It is held paused until
   capa.js flags the [data-play] wrapper with .is-in. */
[data-play]:not(.is-in) .capa-logo * {
    animation-play-state: paused !important;
}
@keyframes capa-seg1 {
    from {
        transform: translate(-236px, -82px) rotate(-16deg);
    }
    to {
        transform: translate(0, 0) rotate(0);
    }
}
@keyframes capa-seg2 {
    from {
        transform: translate(-250px, 3px) rotate(-13deg);
    }
    to {
        transform: translate(0, 0) rotate(0);
    }
}
@keyframes capa-seg3 {
    from {
        transform: translate(-234px, 87px) rotate(14deg);
    }
    to {
        transform: translate(0, 0) rotate(0);
    }
}
@keyframes capa-seg4 {
    from {
        transform: translate(-191px, 162px) rotate(-14deg);
    }
    to {
        transform: translate(0, 0) rotate(0);
    }
}
@keyframes capa-seg5 {
    from {
        transform: translate(-146px, 251px) rotate(15deg);
    }
    to {
        transform: translate(0, 0) rotate(0);
    }
}
@keyframes capa-seg6 {
    from {
        transform: translate(-47px, 246px) rotate(-12deg);
    }
    to {
        transform: translate(0, 0) rotate(0);
    }
}
@keyframes capa-pop {
    from {
        transform: scale(0);
    }
    to {
        transform: scale(1);
    }
}
@keyframes capa-arc {
    from {
        stroke-dashoffset: 911;
    }
    to {
        stroke-dashoffset: 678;
    }
}
@media (prefers-reduced-motion: reduce) {
    .capa-logo * {
        animation: none !important;
    }
}

/* --- About: work packages --------------------------------------------------- */
.v4 .head-row {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 24px;
    margin-bottom: 44px;
}
.v4 .head-row h2 {
    margin: 0;
    font-size: 38px;
    line-height: 1.1;
    letter-spacing: -0.02em;
    font-weight: 700;
}
.v4 .head-row__note {
    font-size: 13px;
    color: var(--muted);
    max-width: 34ch;
    line-height: 1.5;
}
.v4 .wps__list {
    display: grid;
    gap: 2px;
}
.v4 .wp {
    position: relative;
    /* so the picture behind can sit at a negative z-index without sliding
       under the page itself */
    isolation: isolate;
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    gap: 56px;
    padding: 44px 0;
    border-top: 1px solid var(--line-2);
    scroll-margin-top: 116px;
}
/* Each work package carries its own picture, pasted along the left edge of
   the row: it overhangs the container (46px wrap padding) and the rule above,
   then dissolves diagonally before it reaches the prose. */
.v4 .wp__art {
    position: absolute;
    z-index: -1;
    top: -14px;
    bottom: 16px;
    left: -46px;
    width: min(34%, 420px);
    pointer-events: none;
    -webkit-mask-image: linear-gradient(
        96deg,
        #000 0%,
        #000 40%,
        transparent 94%
    );
    mask-image: linear-gradient(96deg, #000 0%, #000 40%, transparent 94%);
}
/* Black and white, and held back: the row reads as text with a picture
   behind it, and the six CAPA colours stay the only colour in the section. */
.v4 .wp__art img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: var(--art-pos, 50% 50%);
    opacity: 0.42;
    filter: grayscale(1) contrast(1.06);
}
/* A scrim (in the page's sand) on the corner the number and the lead land on. */
.v4 .wp__art::after {
    content: "";
    position: absolute;
    inset: 0;
    background: radial-gradient(
        130% 100% at 0% 0%,
        rgba(253, 246, 234, 0.82),
        rgba(253, 246, 234, 0) 62%
    );
}
.v4 .wp__n {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    border-radius: var(--r-pill);
    color: #fff;
    font-size: 24px;
    font-weight: 700;
    letter-spacing: -0.02em;
}
.v4 .wp__lead-label {
    font-size: 10.5px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted-2);
    font-weight: 700;
    margin-top: 16px;
}
.v4 .wp__lead {
    font-size: 15px;
    font-weight: 600;
    margin-top: 4px;
    color: var(--ink);
}
.v4 .wp__body {
    max-width: 760px;
}
.v4 .wp h3 {
    margin: 0 0 16px;
    font-size: 26px;
    line-height: 1.2;
    letter-spacing: -0.015em;
    font-weight: 600;
    max-width: 32ch;
    text-wrap: pretty;
}
.v4 .wp p {
    font-family: var(--serif);
    font-size: 16.5px;
    line-height: 1.7;
    color: var(--ink-3);
    margin: 0;
    max-width: 92ch;
    text-wrap: pretty;
}

/* --- Card stacking ---------------------------------------------------------- */
/* The bands with rounded top corners read as cards: .v4__news and
   .v4__cons--card slide over the section before them (capa.js holds that
   section sticky and sends it to z-index -1), the footer rests on the band
   it is pulled back over. Positioned above the page-head ribbons, which
   reach below the head, so those never show over a card. The header
   (z-index 40) stays above all. */
.v4__news,
.v4__cons--card,
.v4__ft {
    position: relative;
    z-index: 2;
}
/* A shadow along the top edge sells the overlap of the sliding cards; the
   footer does without, as it does not slide and the haze would only stain
   the band it sits on. */

.v4__cons--card {
    box-shadow: 0 -24px 60px -24px rgba(34, 22, 12, 0.32);
}

/* ==========================================================================
   NEWSLETTER POP-UP (home)
   The newsletter card of the article sidebar (.v4__nlcard, above) set down in
   the bottom corner of the screen, but on the ground of a figures slab
   (.v4__slab) rather than the sidebar's black: the project green, and the same
   off-centre ring in white at 16%. It carries the .v4 class so the card keeps
   the variant's face and colours outside the section the footer closes — only
   the section ground and its horizontal clip, which would cut the shadow, have
   to go.

   The panel is closed until capa.js opens it (4 s after load, and not at all
   when it was dismissed in the last 30 days). It rises the way [data-rise]
   does everywhere else; visibility is switched at the end of the fade so a
   closed panel is out of the tab order rather than merely transparent.
   Positioned by logical inset: bottom right, and bottom left in Arabic.
   ========================================================================== */
.v4__nlpop {
    position: fixed;
    z-index: 38;
    bottom: 28px;
    inset-inline-end: 28px;
    width: 380px;
    max-width: calc(100vw - 40px);
    background: none;
    overflow: visible;
    opacity: 0;
    visibility: hidden;
    transform: translateY(24px);
    transition:
        opacity 0.7s var(--ease-rise),
        transform 0.7s var(--ease-rise),
        visibility 0s 0.7s;
}
.v4__nlpop.is-open {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
}
/* The card is the sidebar one, one size down — it has a corner of the screen
   to live in, not a 400px column — and repainted as a figures slab. */
.v4__nlpop .v4__nlcard {
    padding: 34px 34px 36px;
    border-radius: 34px;
    background: var(--green);
    color: #fff;
    box-shadow: 0 30px 60px -30px rgba(34, 22, 12, 0.85);
}
/* The ring of .v4__slab, mirrored in Arabic with the rest of the panel. The
   card already clips its overflow, so it is cut by the corner the same way. */
.v4__nlpop .v4__nlcard::after {
    content: "";
    position: absolute;
    inset-inline-end: -45px;
    bottom: -60px;
    width: 170px;
    height: 170px;
    border-radius: 50%;
    border: 22px solid rgba(255, 255, 255, 0.16);
}
.v4__nlpop .v4__nlt {
    font-size: 22px;
    padding-inline-end: 40px;
}
/* Softer than the title, but not the 78% the black card could afford: on the
   green that would fall to 4.1:1, under the 4.5:1 body text has to clear. */
.v4__nlpop .v4__nlx {
    font-size: 16px;
    margin-top: 10px;
    color: rgba(255, 255, 255, 0.92);
}
.v4__nlpop .v4__b {
    margin-top: 22px;
    padding: 15px 26px;
}
/* The burger's cross, at the card's scale. */
.v4__nlclose {
    position: absolute;
    z-index: 2;
    top: 18px;
    inset-inline-end: 18px;
    display: grid;
    place-items: center;
    appearance: none;
    cursor: pointer;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.2);
    color: #fff;
    transition:
        background 0.3s,
        color 0.3s;
}
.v4__nlclose:hover {
    background: var(--yellow);
    color: #22160c;
}
.v4__nlclose span {
    grid-area: 1 / 1;
    width: 13px;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
}
.v4__nlclose span:first-child {
    transform: rotate(45deg);
}
.v4__nlclose span:last-child {
    transform: rotate(-45deg);
}
@media (prefers-reduced-motion: reduce) {
    .v4__nlpop {
        transition-duration: 0.01ms;
        transition-delay: 0s;
    }
}

/* ==========================================================================
   COOKIE CONSENT
   Three pieces, all rendered by config.ini.php and driven by capa.js: the
   badge that opens the question, the panel that puts it, and the block that
   stands in for an embed until its category is accepted.

   There is no bar across the foot of the page. Nothing is set before an
   answer, so there is nothing to obtain in advance, and the question is left
   where it actually arises: under the video or the map waiting for it, or
   behind the badge for anyone who wants to settle it now.
   ========================================================================== */

/* The way into the panel from a blocked embed, and from anywhere else a link
   rather than a pill is the right weight. */
.v4__cklink {
    appearance: none;
    padding: 4px;
    border: 0;
    background: none;
    font-family: inherit;
    font-size: 13px;
    font-weight: 700;
    color: var(--ink-2);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
    white-space: nowrap;
}
.v4__cklink:hover {
    color: var(--green);
}
/* --- Reopen badge --------------------------------------------------------- */
/* The way back into the panel once the bar is gone. It sits at the foot of
   the page on the inline-start side — the newsletter pop-up already holds the
   other corner, and in Arabic the two swap together. Shown by capa.js only
   after the question has been answered, and it fades in the way the bar
   rises, so a decision does not make one object vanish and another appear in
   the same frame. */
.v4__ckbadge {
    position: fixed;
    z-index: 39;
    bottom: 28px;
    inset-inline-start: 28px;
    display: grid;
    place-items: center;
    width: 46px;
    height: 46px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    appearance: none;
    cursor: pointer;
    background: #fff;
    color: #6b4f2a;
    box-shadow: 0 10px 26px -10px rgba(34, 22, 12, 0.55);
    opacity: 0;
    transform: translateY(10px);
    transition:
        opacity 0.5s var(--ease-rise),
        transform 0.5s var(--ease-rise),
        background 0.3s,
        color 0.3s;
}
.v4__ckbadge[hidden] {
    display: none;
}
.v4__ckbadge.is-in {
    opacity: 1;
    transform: none;
}
.v4__ckbadge:hover {
    background: var(--green);
    color: #fff;
}
.v4__ckbadge svg {
    width: 24px;
    height: 24px;
}

/* --- Preferences panel ---------------------------------------------------- */
/* A native <dialog>: the dimmed ground, the focus trap and the Escape close
   come with it. The card is the light one — the categories carry more text
   than a dark ground would hold comfortably. */
.v4__ckp {
    width: min(580px, calc(100vw - 32px));
    max-height: calc(100vh - 48px);
    padding: 0;
    border: 0;
    border-radius: 34px;
    background: #fff;
    color: var(--ink);
    box-shadow: 0 40px 80px -30px rgba(34, 22, 12, 0.55);
    overflow: auto;
    overscroll-behavior: contain;
}
.v4__ckp::backdrop {
    background: rgba(14, 26, 36, 0.55);
}
.v4__ckpin {
    position: relative;
    padding: 38px 38px 34px;
}
.v4 .v4__ckpt {
    margin: 0;
    font-size: 24px;
    font-weight: 800;
    padding-inline-end: 44px;
}
.v4__ckpx {
    font-family: var(--serif);
    font-size: 15px;
    line-height: 1.65;
    color: var(--ink-3);
    margin: 10px 0 0;
    text-wrap: pretty;
}
/* The site strips link underlines everywhere; the privacy policy is the one
   thing in this panel to leave it for, being the only way out of it. */
.v4__ckpx a {
    text-decoration: underline;
    text-underline-offset: 2px;
}
/* The cross of the newsletter pop-up, repainted for a light card. */
.v4__ckclose {
    background: var(--clay);
    color: var(--ink);
}
.v4__cklist {
    display: grid;
    gap: 24px;
    margin: 26px 0 28px;
    padding: 26px 0;
    border-top: 1px solid var(--clay);
    border-bottom: 1px solid var(--clay);
}
.v4__cksw {
    display: flex;
    align-items: center;
    gap: 14px;
    cursor: pointer;
}
.v4__cksw input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
}
.v4__cktrack {
    position: relative;
    flex-shrink: 0;
    width: 46px;
    height: 26px;
    border-radius: 100px;
    background: #d9cdba;
    transition: background 0.3s var(--ease-io);
}
/* The knob travels on inset-inline-start rather than a transform, so it
   still slides towards the "on" side when the page is in Arabic. */
.v4__cktrack::after {
    content: "";
    position: absolute;
    top: 3px;
    inset-inline-start: 3px;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 2px 5px rgba(34, 22, 12, 0.28);
    transition: inset-inline-start 0.3s var(--ease-io);
}
.v4__cksw input:checked + .v4__cktrack {
    background: var(--green);
}
.v4__cksw input:checked + .v4__cktrack::after {
    inset-inline-start: 23px;
}
.v4__cksw input:disabled + .v4__cktrack {
    background: var(--muted-2);
    cursor: default;
}
.v4__cksw input:focus-visible + .v4__cktrack {
    outline: 2px solid var(--blue);
    outline-offset: 3px;
}
.v4__ckname {
    font-size: 15px;
    font-weight: 700;
}
.v4__ckalways {
    margin-inline-start: auto;
    font-size: 12px;
    color: var(--muted);
    white-space: nowrap;
}
/* Indented to the width of the switch, so the description reads as the
   category's own line rather than the next item in the list. */
.v4__ckdesc {
    font-family: var(--serif);
    font-size: 14.5px;
    line-height: 1.6;
    color: var(--ink-3);
    margin: 8px 0 0;
    padding-inline-start: 60px;
    text-wrap: pretty;
}
.v4__ckpacts {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.v4__ckpacts .v4__b {
    padding: 15px 24px;
}

/* --- Blocked embed -------------------------------------------------------- */
/* What the page shows where a video or a map will go until its category is
   accepted (ckEmbed(), include/fonctions/helper.fct.php). It holds the
   frame's footprint through --ck-ar so nothing jumps when capa.js swaps in
   the iframe. */
.v4__ckem {
    position: relative;
    display: grid;
    place-items: center;
    aspect-ratio: var(--ck-ar, 16 / 9);
    padding: 32px;
    border-radius: 28px;
    background: var(--sand-2);
    box-shadow: inset 0 0 0 1px var(--clay);
    overflow: hidden;
}
.v4__ckemin {
    max-width: 46ch;
    text-align: center;
}
.v4__ckemx {
    font-family: var(--serif);
    font-size: 15px;
    line-height: 1.65;
    color: var(--ink-3);
    margin: 0;
    text-wrap: pretty;
}
.v4__ckemacts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 12px;
    margin-top: 22px;
}
.v4__ckemacts .v4__b {
    padding: 15px 26px;
}
/* Once the frame is in, the block is only its wrapper. */
.v4__ckem.is-loaded {
    padding: 0;
    background: none;
    box-shadow: none;
}
.v4__ckem iframe {
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

@media (max-width: 720px) {
    .v4__ckp {
        width: calc(100vw - 24px);
        border-radius: 28px;
    }
    .v4__ckpin {
        padding: 30px 24px 26px;
    }
    /* Under the name rather than beside it — at this width the two would
       otherwise sit a couple of characters apart. */
    .v4__ckalways {
        margin-inline-start: 0;
    }
    .v4__cksw {
        flex-wrap: wrap;
    }
    .v4__ckdesc {
        padding-inline-start: 0;
    }
    .v4__ckpacts .v4__b {
        flex: 1 1 100%;
        justify-content: center;
    }
    .v4__ckem {
        padding: 22px;
        border-radius: 22px;
    }
    /* At this width the newsletter card runs nearly the width of the screen
       and the badge would sit on top of it. The badge steps aside until the
       card is closed; the footer link is the way in until then. */
    .is-nl-open .v4__ckbadge {
        opacity: 0;
        visibility: hidden;
    }
}
@media (prefers-reduced-motion: reduce) {
    .v4__ckbadge {
        transition-duration: 0.01ms;
    }
}

/* ==========================================================================
   MOBILE
   Two steps: tablet (1080px) and phone (720px). Under 1080px the pill nav
   and the language toggle leave the header for a full-screen panel
   (rendered by config.ini.php, opened by capa.js with one class on <html>):
   the same sand ground, the six ribbons drifting along its foot, the pages
   set large in the display face with a dot from the logo arc, the
   languages as pills underneath. The burger is the dark pill of the
   language toggle, its two bars folding into a cross.
   ========================================================================== */

/* Two styles moved out of the pages so they can change with the viewport:
   the deliverables band of Project Results (a card like the newsroom) and
   the lead picture of an article. */
.v4__plain--card {
    position: relative;
    z-index: 1;
    background: var(--sand-2);
    padding: 104px 0 110px;
    border-radius: 90px 90px 0 0;
}
.v4__ifr--lead {
    height: 460px;
    margin-bottom: 48px;
}
.v4__ifr--contain img {
    object-fit: contain;
}
.v4__ifr.v4__ifr--lead.v4__ifr--contain {
    height: auto;
}
.v4__ifr--lead.v4__ifr--contain img {
    display: block;
    height: auto;
}
.v4__item:hover .v4__ifr--contain img {
    transform: none;
}

/* --- Burger and panel ------------------------------------------------------ */
.v4__burger {
    display: none;
    appearance: none;
    cursor: pointer;
    margin-left: auto;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--ink);
    color: #fff;
    place-items: center;
    flex-shrink: 0;
}
.v4__burger span {
    grid-area: 1 / 1;
    display: block;
    width: 18px;
    height: 2px;
    border-radius: 2px;
    background: currentColor;
    transition: transform 0.45s var(--ease-io);
}
.v4__burger span:first-child {
    transform: translateY(-3.5px);
}
.v4__burger span:last-child {
    transform: translateY(3.5px);
}
.is-menu-open .v4__burger span:first-child {
    transform: rotate(45deg);
}
.is-menu-open .v4__burger span:last-child {
    transform: rotate(-45deg);
}
.v4__menu {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 39;
    padding: calc(var(--hd-h) + 24px) 20px
        calc(28px + env(safe-area-inset-bottom));
    background: var(--sand);
    overflow: hidden auto;
    opacity: 0;
    visibility: hidden;
    transition:
        opacity 0.35s,
        visibility 0s 0.35s;
}
.is-menu-open .v4__menu {
    opacity: 1;
    visibility: visible;
    transition:
        opacity 0.35s,
        visibility 0s;
}
/* The ribbons along the foot of the panel, fading in from the top. Kept
   inside the panel (bottom: 0), which scrolls if the screen is short. */
.v4__ribbons--menu {
    inset: auto -160px 0 -200px;
    height: 420px;
    opacity: 0.45;
    -webkit-mask: linear-gradient(180deg, transparent 12%, #000 55%);
    mask: linear-gradient(180deg, transparent 12%, #000 55%);
}
/* Inline, the SVG would leave a few px of line space under it, enough to
   make the panel scroll. */
.v4__ribbons--menu svg {
    display: block;
}
.v4__mnav {
    position: relative;
    display: grid;
}
.v4__mnav a {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 18px 0;
    border-bottom: 1px solid rgba(34, 22, 12, 0.1);
    font-size: 34px;
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -0.028em;
    opacity: 0;
    transform: translateY(18px);
    transition:
        opacity 0.5s,
        transform 0.55s var(--ease-io);
}
/* One dot per page, in the order the colours run round the logo arc. */
.v4__mnav a::before {
    content: "";
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--dot, var(--blue));
    flex-shrink: 0;
}
.v4__mnav a:nth-child(2) {
    --dot: var(--green);
}
.v4__mnav a:nth-child(3) {
    --dot: var(--yellow);
}
.v4__mnav a:nth-child(4) {
    --dot: var(--red);
}
.v4__mnav a:nth-child(5) {
    --dot: var(--orange);
}
.v4__mnav a:nth-child(6) {
    --dot: var(--lime);
}
.v4__mnav a[aria-current] {
    color: var(--green);
}
.v4__mlangs {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 28px;
    opacity: 0;
    transform: translateY(18px);
    transition:
        opacity 0.5s,
        transform 0.55s var(--ease-io);
}
.v4__mlangs .lang__opt {
    width: auto;
    padding: 10px 16px;
    border: 1px solid rgba(34, 22, 12, 0.16);
    background: #fff;
    font-size: 13px;
}
.v4__mlangs .lang__opt[aria-current="true"] {
    background: var(--ink);
    border-color: var(--ink);
}
.v4__mlangs .lang__opt[disabled] {
    background: transparent;
    border-style: dashed;
}
/* Open: the links rise one after the other, the languages last. */
.is-menu-open .v4__mnav a,
.is-menu-open .v4__mlangs {
    opacity: 1;
    transform: none;
}
.is-menu-open .v4__mnav a:nth-child(2) {
    transition-delay: 0.06s;
}
.is-menu-open .v4__mnav a:nth-child(3) {
    transition-delay: 0.12s;
}
.is-menu-open .v4__mnav a:nth-child(4) {
    transition-delay: 0.18s;
}
.is-menu-open .v4__mnav a:nth-child(5) {
    transition-delay: 0.24s;
}
.is-menu-open .v4__mnav a:nth-child(6) {
    transition-delay: 0.3s;
}
.is-menu-open .v4__mlangs {
    transition-delay: 0.36s;
}
@media (prefers-reduced-motion: reduce) {
    .v4__menu,
    .v4__mnav a,
    .v4__mlangs,
    .v4__burger span {
        transition-duration: 0.01ms;
        transition-delay: 0s;
    }
}

/* --- Consortium map ------------------------------------------------------- */
/* Leaflet without a tile server: the ground is the GeoJSON of borders the site
   serves itself (include/data/world-af-eu.json), painted flat here so the map
   wears the palette instead of a stock basemap — and so the page still asks
   nothing of a third party.

   The card is two columns: the partner list on the left, the map on the right.
   That split is not decoration — Africa and Europe together are a tall, narrow
   block, and in a card the width of the page a map alone would have been mostly
   sea. The list fills that width with the thing the map is about.

   Two grounds only: a lighter tint of the project blue for the sea (same hue as
   --blue, lifted so the block reads softer), the page's clay for the land.
   No country is coloured and no border is drawn — the outlines are stroked in
   the fill so the polygons close up into one landmass. A map that shades
   countries one by one has to take a position on every disputed line it draws,
   and this one has nothing to gain by it: the dots carry the whole message. It
   is also why they wear the green — on clay, the blue would be the ground. */
.v4__cmap {
    padding: 0 0 104px;
}
.v4 .cmap {
    --cmap-sea: #739dd3;
    --cmap-land: var(--clay);
    --cmap-h: 660px;
}
/* z-index on a positioned box opens a stacking context, and that is the point:
   Leaflet numbers its own panes from 400 and its controls at 1000, which in the
   page's context would have put the map in front of the sticky header at 40.
   Kept inside, those numbers only order the map against itself, and the whole
   card sits at 1, under the header. */
.v4 .cmap__stage {
    position: relative;
    z-index: 1;
    border-radius: 40px;
    overflow: hidden;
    background: #fff;
    box-shadow: 0 24px 50px -40px rgba(34, 22, 12, 0.8);
}
/* The list is the section on its own; the map is what the script adds beside
   it. So the second column only exists once capa-map.js has run — with no
   JavaScript, or none that worked, the list stays and stands alone. */
.v4 .cmap.is-live .cmap__stage {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
}
.v4 .cmap__map {
    display: none;
    position: relative;
}
.v4 .cmap.is-live .cmap__map {
    display: block;
}
.v4 .cmap__canvas {
    height: var(--cmap-h);
    background: var(--cmap-sea);
}
/* Leaflet writes fill and stroke as presentation attributes; a stylesheet rule
   outranks those, so the whole ground stays here rather than in the script. */
.v4 .cmap__land {
    fill: var(--cmap-land);
    stroke: var(--cmap-land);
}

/* One dot per country, its diameter set by the script from the number of
   organisations; the count is written inside from two upwards. */
.v4 .cmap__pin {
    --dot: var(--green);
    --glow: rgba(0, 120, 62, 0.24);
}
.v4 .cmap__pin.is-sub {
    --dot: var(--orange);
    --glow: rgba(239, 126, 9, 0.22);
}
.v4 .cmap__dot {
    display: grid;
    place-items: center;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background: var(--dot);
    border: 2px solid #fff;
    box-shadow: 0 4px 10px -2px rgba(14, 26, 36, 0.45);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    line-height: 1;
    transition:
        transform 0.28s var(--ease-io),
        box-shadow 0.28s var(--ease-io),
        opacity 0.28s var(--ease-io);
}
/* The halo is the beneficiary card's ring idea at pin scale: it opens out of
   the dot rather than being drawn around it from the start. */
.v4 .cmap__pin:hover .cmap__dot,
.v4 .cmap__pin:focus-visible .cmap__dot,
.v4 .cmap__pin.is-active .cmap__dot {
    transform: scale(1.18);
    box-shadow:
        0 6px 14px -2px rgba(14, 26, 36, 0.5),
        0 0 0 8px var(--glow);
}
.v4 .cmap__pin:focus {
    outline: none;
}
/* Pendant une recherche, les pays sans résultat restent en place mais
   s'effacent : la carte montre où sont les réponses sans perdre le reste. */
.v4 .cmap__pin.is-dim .cmap__dot {
    opacity: 0.3;
    transform: scale(0.8);
    box-shadow: none;
}

/* --- The panel ------------------------------------------------------------ */
.v4 .cmap__panel {
    padding: 30px 30px 26px;
}
/* Beside the map the panel is exactly its height and carries its own scroll,
   so the two columns end together however long the list runs. */
.v4 .cmap.is-live .cmap__panel {
    height: var(--cmap-h);
    overflow-y: auto;
    overscroll-behavior: contain;
    border-inline-end: 1px solid #eef2f6;
}
/* Alone, it would otherwise run the full width of the page in one column. */
.v4 .cmap:not(.is-live) .cmap__panel {
    max-width: 660px;
}
.v4 .cmap__phead {
    padding-bottom: 20px;
    border-bottom: 1px solid #e6ebf0;
}
.v4 .cmap__ptitle {
    margin: 0;
    font-size: 26px;
    line-height: 1.1;
    color: var(--ink);
}
.v4 .cmap__pcount {
    margin: 7px 0 0;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: #8a98a3;
}
.v4 .cmap__pall {
    display: none;
    align-items: center;
    gap: 9px;
    margin-top: 16px;
    border-radius: 100px;
    padding: 10px 18px;
    background: var(--sand-2);
    font-size: 12.5px;
    font-weight: 700;
    color: var(--ink);
    transition:
        background 0.3s ease,
        color 0.3s ease,
        gap 0.3s ease;
}
.v4 .cmap.is-filtered .cmap__pall {
    display: inline-flex;
}
.v4 .cmap__pall:hover {
    background: var(--ink);
    color: #fff;
    gap: 13px;
}

/* Filtering hides the other countries rather than rebuilding anything: the
   list the script was read from is the list the reader ends up with. */
.v4 .cmap__country {
    padding-top: 20px;
}
.v4 .cmap.is-filtered .cmap__country {
    display: none;
}
.v4 .cmap.is-filtered .cmap__country.is-on {
    display: block;
    animation: cmapin 0.4s var(--ease-rise) both;
}
/* With one country left, its name is already the panel's title — and with the
   name goes the room it took, down to the rule that separated it. */
.v4 .cmap.is-filtered .cmap__cname {
    display: none;
}
.v4 .cmap.is-filtered .cmap__country.is-on {
    padding-top: 0;
}
.v4 .cmap.is-filtered .cmap__orgs {
    margin-top: 0;
}
.v4 .cmap.is-filtered .cmap__org:first-child {
    border-top: 0;
}
@keyframes cmapin {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}
/* La recherche masque de la même façon, mais garde les noms de pays : ses
   résultats peuvent venir de plusieurs pays à la fois. */
.v4 .cmap.is-searching .cmap__country:not(.is-hit),
.v4 .cmap.is-searching .cmap__org.is-miss {
    display: none;
}
/* Le total du pays contredirait la liste réduite en dessous ; le décompte des
   résultats est déjà en tête du panneau. */
.v4 .cmap.is-searching .cmap__cname span {
    display: none;
}
.v4 .cmap__empty {
    margin: 20px 0 0;
    font-family: var(--serif);
    font-size: 14.5px;
    line-height: 1.5;
    color: var(--muted);
}
.v4 .cmap__empty:empty {
    display: none;
}
/* Le compte tient le bord, pas le mot : sinon il colle à « Togo » et se
   retrouve au loin sous « République démocratique du Congo ». */
.v4 .cmap__cname {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: 0;
    font-size: 17px;
    line-height: 1.2;
    color: var(--ink);
}
.v4 .cmap__cname span {
    display: grid;
    place-items: center;
    min-width: 23px;
    height: 23px;
    padding: 0 7px;
    border-radius: 100px;
    background: var(--sand-2);
    font-size: 11px;
    font-weight: 700;
    color: var(--ink-3);
}
.v4 .cmap__orgs {
    list-style: none;
    margin: 0;
    padding: 0;
}
.v4 .cmap__org {
    display: grid;
    grid-template-columns: 54px minmax(0, 1fr);
    align-items: center;
    gap: 15px;
    padding: 13px 0;
    border-top: 1px solid #eef2f6;
}
.v4 .cmap__country .cmap__orgs {
    margin-top: 12px;
}
.v4 .cmap__ologo {
    display: grid;
    place-items: center;
    width: 54px;
    height: 54px;
}
.v4 .cmap__ologo img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}
.v4 .cmap__obody {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 7px;
    min-width: 0;
}
/* The arrow stays in the run of text, so on a name that wraps over three lines
   it follows the last word instead of hanging off the end of the first. */
.v4 .cmap__oname {
    display: block;
    font-size: 14px;
    font-weight: 500;
    line-height: 1.35;
    color: #173154;
    text-wrap: pretty;
    transition: color 0.3s ease;
}
.v4 .cmap__oname span {
    display: inline-block;
    margin-inline-start: 4px;
    transition: transform 0.3s ease;
}
.v4 .cmap__oname:hover {
    color: var(--green);
}
.v4 .cmap__oname:hover span {
    transform: translateX(5px);
}
/* En arabe la flèche est retournée (voir $mapArrows), le décalage aussi. */
[dir="rtl"] .v4 .cmap__oname:hover span {
    transform: translateX(-5px);
}
/* Same pill as the newsroom tag, carrying the colour the dot carries. */
.v4 .cmap__orole {
    border-radius: 100px;
    padding: 5px 10px;
    background: var(--green);
    color: #fff;
    font-size: 9.5px;
    font-weight: 800;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}
.v4 .cmap__org[data-role="s"] .cmap__orole {
    background: var(--orange);
}

/* --- On the map ----------------------------------------------------------- */
/* Physique et non logique : la carte n'est pas retournée en arabe — la
   géographie reste la géographie — et le bouton de zoom de Leaflet est lui
   aussi posé à droite en dur. En logique, les deux se retrouveraient du même
   côté sur les pages RTL. */
.v4 .cmap__key {
    position: absolute;
    z-index: 1001;
    left: 20px;
    bottom: 20px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    list-style: none;
    margin: 0;
    padding: 0;
}
.v4 .cmap__key li {
    display: flex;
    align-items: center;
    gap: 9px;
    background: #fff;
    border-radius: 100px;
    padding: 8px 15px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--ink-3);
    box-shadow: 0 16px 40px -30px rgba(14, 26, 36, 0.7);
}
.v4 .cmap__key i {
    width: 11px;
    height: 11px;
    border-radius: 50%;
}
/* Le champ de recherche, dans le blanc des pastilles de la légende. En haut à
   droite pour la même raison physique ; à l'intérieur, l'icône suit le sens de
   lecture et passe à droite en arabe. */
.v4 .cmap__search {
    position: absolute;
    z-index: 1001;
    top: 20px;
    right: 20px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 10px;
    width: 310px;
    max-width: calc(100% - 40px);
    height: 44px;
    margin: 0;
    padding-inline: 16px 8px;
    border: 1px solid transparent;
    border-radius: 100px;
    background: #fff;
    box-shadow: 0 16px 40px -26px rgba(14, 26, 36, 0.7);
    transition: box-shadow 0.3s ease;
}
.v4 .cmap__search:focus-within {
    box-shadow:
        0 16px 40px -26px rgba(14, 26, 36, 0.7),
        0 0 0 3px rgba(0, 120, 62, 0.28);
}
.v4 .cmap__sicon {
    flex: none;
    fill: none;
    stroke: var(--ink-3);
    stroke-width: 2;
    stroke-linecap: round;
}
.v4 .cmap__sinput {
    flex: 1;
    min-width: 0;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    outline: 0;
    background: none;
    font: inherit;
    font-size: 13.5px;
    font-weight: 500;
    color: var(--ink);
    -webkit-appearance: none;
    appearance: none;
}
.v4 .cmap__sinput::placeholder {
    color: #8a98a3;
    opacity: 1;
}
.v4 .cmap__sinput::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}
/* Le bouton qui vide le champ n'apparaît qu'une fois quelque chose tapé. */
.v4 .cmap__sclear {
    display: none;
    flex: none;
    place-items: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--sand-2);
    color: var(--ink-3);
    font: inherit;
    font-size: 17px;
    line-height: 1;
    cursor: pointer;
    transition:
        background 0.3s ease,
        color 0.3s ease;
}
.v4 .cmap__search.is-typed .cmap__sclear {
    display: grid;
}
.v4 .cmap__sclear:hover {
    background: var(--ink);
    color: #fff;
}
/* Leaflet's zoom buttons, redrawn as the site's pills. */
.v4 .cmap .leaflet-control-zoom {
    border: 0;
    border-radius: 100px;
    overflow: hidden;
    box-shadow: 0 16px 40px -26px rgba(14, 26, 36, 0.7);
}
.v4 .cmap .leaflet-control-zoom a {
    width: 38px;
    height: 38px;
    line-height: 38px;
    border: 0;
    background: #fff;
    color: var(--ink-3);
    font-weight: 500;
    transition:
        background 0.3s ease,
        color 0.3s ease;
}
.v4 .cmap .leaflet-control-zoom a:hover {
    background: var(--ink);
    color: #fff;
}
.v4 .cmap__credit {
    margin: 14px 0 0;
    font-size: 11.5px;
    color: var(--muted-2);
}

/* --- Tablet ------------------------------------------------------------- */
@media (max-width: 1080px) {
    :root {
        --hd-h: 80px;
    }
    html.is-menu-open {
        overflow: hidden;
    }
    .v4 .wrap {
        padding-left: 32px;
        padding-right: 32px;
    }
    /* Opaque and unblurred here: a backdrop-filter on a sticky element has to be
       repainted on the main thread every frame while the rest of the page scrolls
       on the compositor, so the bar lags behind the scroll and appears to shake.
       Nothing is lost — the page-head ribbons are already hidden below 720px, and
       further down the page the text passing under the bar was reading through it.
       will-change keeps the bar on a layer of its own, out of the .v4 clip. */
    .v4__hd,
    .v4__hd.is-top {
        padding: 12px 0;
        background: var(--sand);
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
        will-change: transform;
    }
    .v4__logo {
        height: 80px;
    }
    .v4__nav,
    .v4__hdin > .lang {
        display: none;
    }
    .v4__burger {
        display: grid;
        margin-left: 0;
    }
    /* With the nav gone the LinkedIn button takes the auto margin, and grows
       to the burger's size so the two make a matched pair. */
    .v4__soc {
        margin-inline-start: auto;
        width: 44px;
        height: 44px;
    }
    .v4__soc svg {
        width: 19px;
        height: 19px;
    }
    .v4__menu {
        display: block;
    }
    /* Page heads stack, the picture under the text, and take their own height
       (min-height for the hero, height for the page heads). */
    .v4__hero,
    .v4__phead {
        height: auto;
        min-height: 0;
        padding: 36px 0 64px;
    }
    .v4__hero,
    .v4__phead--img {
        grid-template-columns: 1fr;
        gap: 40px;
    }
    .v4__hero h1 {
        font-size: 48px;
    }
    .v4__phead h1 {
        font-size: 46px;
    }
    .v4__blob {
        margin-left: 0;
    }
    /* Stacked under the title, the illustration is narrower than the column:
       centred rather than flush left. margin-inline so it holds in RTL too. */
    .v4__phead__img img {
        margin-inline: auto;
        max-width: 360px;
    }
    .v4__ngrid,
    .v4__pgrid,
    .v4__aside {
        grid-template-columns: repeat(2, 1fr);
    }
    .v4__ftcols {
        grid-template-columns: 1fr 1fr;
        gap: 40px 48px;
    }
    .v4__artgrid,
    .v4__oa {
        grid-template-columns: 1fr;
    }
    .v4__artgrid {
        gap: 56px;
    }
    .v4__oa .v4__slab {
        max-width: 350px;
    }
    .v4 .wp {
        grid-template-columns: 160px minmax(0, 1fr);
        gap: 40px;
    }
    .v4 .wp__art {
        left: -32px;
        width: min(44%, 360px);
    }
    /* The mission lead loses its side-by-side logo: a small one above it. */
    .v4 .mission__head {
        flex-direction: column;
        align-items: flex-start;
        gap: 24px;
        margin-bottom: 28px;
    }
    .capa-logo {
        width: 110px;
        margin: 0;
    }
    .v4 .cmap {
        --cmap-h: 560px;
    }
    .v4 .cmap__panel {
        padding: 24px 22px 22px;
    }
}

/* --- Phone -------------------------------------------------------------- */
@media (max-width: 720px) {
    .v4 .wrap {
        padding-left: 20px;
        padding-right: 20px;
    }
    /* Page heads */
    .v4__hero,
    .v4__phead {
        padding: 20px 0 56px;
        gap: 36px;
    }
    .v4__phead--article {
        padding-bottom: 32px;
    }
    .v4__hero h1 {
        font-size: 38px;
    }
    .v4__sub,
    .v4__plead {
        font-size: 17px;
        margin-top: 20px;
    }
    .v4__acts {
        margin-top: 28px;
    }
    .v4__blob {
        max-width: none;
    }
    .v4__phead h1 {
        font-size: 36px;
    }
    .v4__phead__img img {
        max-width: 260px;
    }
    /* The ribbons behind the page head would run across the stacked text
       here, so they are left out; the menu and the footer still carry them. */
    .v4__ribbons:has(+ .v4__hero),
    .v4__ribbons:has(+ .v4__phead) {
        display: none;
    }
    /* Home */
    .v4__about {
        width: calc(100% - 32px);
        border-radius: 32px;
        padding: 28px 0;
    }
    .v4__about--narrow {
        margin-top: 3rem;
        padding: 28px 0;
    }
    .v4__about p {
        font-size: 17px;
        margin-top: 18px;
    }
    .v4__arrow {
        margin-top: 24px;
        padding: 13px 22px;
    }
    .v4__h2 {
        font-size: 30px;
        padding-bottom: 32px;
    }
    .v4__figs {
        padding-top: 64px;
    }
    .v4__strip {
        gap: 16px;
        padding: 0 20px 56px;
    }
    .v4__slab {
        flex-basis: 280px;
        min-height: 260px;
    }
    .v4__sn {
        font-size: 56px;
    }
    .v4__news {
        padding: 64px 0 72px;
        border-radius: 48px 48px 0 0;
    }
    .v4__nhead,
    .v4__conshead {
        flex-direction: column;
        align-items: flex-start;
        gap: 16px;
        padding-bottom: 32px;
    }
    .v4__ngrid {
        grid-template-columns: 1fr;
        gap: 36px;
    }
    .v4__ifr {
        height: 220px;
        border-radius: 26px;
    }
    .v4 .v4__it {
        font-size: 21px;
    }
    .v4__cons {
        padding-bottom: 120px;
    }
    .v4__cons--card {
        padding-top: 64px;
        border-radius: 48px 48px 0 0;
    }
    .v4__lg {
        flex-basis: 140px;
        padding: 18px 22px;
    }
    /* Footer */
    .v4__ft {
        border-radius: 48px 48px 0 0;
        margin-top: -48px;
    }
    .v4__ftcols {
        grid-template-columns: 1fr;
        gap: 36px;
        padding: 64px 0 24px;
    }
    .v4__ftlogo {
        /* height: 5rem; */
        margin-top: 0;
        scale: 1;
    }
    .v4__fttag {
        max-width: none;
    }
    .v4__ftbase {
        flex-direction: column;
        gap: 10px;
        padding: 20px 0 32px;
        margin-top: 2rem !important;
    }
    /* Interior pages */
    .v4__plain {
        padding: 64px 0;
    }
    .v4__plain--card {
        padding: 64px 0 72px;
        border-radius: 48px 48px 0 0;
    }
    .v4__prose p,
    .v4__prose ul,
    .v4__prose--narrow {
        font-size: 17px;
    }
    .v4__prose h2 {
        margin-top: 40px;
        font-size: 26px;
    }
    .v4__prose h3 {
        font-size: 21px;
    }
    .v4__prose blockquote {
        padding-left: 20px;
    }
    .v4__prose blockquote p {
        font-size: 20px;
    }
    .v4__prose figure img {
        border-radius: 22px;
    }
    .v4__ifr--lead {
        height: 240px;
        margin-bottom: 32px;
    }
    .v4__artgrid {
        gap: 48px;
    }
    .v4__aside {
        grid-template-columns: 1fr;
        gap: 28px;
    }
    .v4__nlcard,
    .v4__recentbox {
        padding: 28px 26px;
        border-radius: 28px;
    }
    .v4__band {
        width: calc(100% - 32px);
        margin: 4rem auto;
        border-radius: 32px;
        padding: 28px 0;
    }
    .v4 .mission__lead {
        font-size: 20px;
    }
    .v4 .mission__cols {
        column-gap: 32px;
    }
    .v4 .head-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 12px;
        margin-bottom: 32px;
    }
    .v4 .head-row h2 {
        font-size: 30px;
    }
    .v4 .wp {
        grid-template-columns: 1fr;
        gap: 20px;
        padding: 32px 0;
    }
    /* Stacked, the number and the lead sit on one line above the title. */
    .v4 .wp__meta {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        gap: 0 12px;
    }
    .v4 .wp__n {
        width: 48px;
        height: 48px;
        font-size: 18px;
        margin-right: 4px;
    }
    .v4 .wp__lead-label,
    .v4 .wp__lead {
        margin-top: 0;
    }
    .v4 .wp__art {
        top: -10px;
        bottom: 12px;
        left: -20px;
        width: min(80%, 320px);
    }
    .v4 .wp__art img {
        opacity: 0.3;
    }
    .v4 .wp h3 {
        font-size: 22px;
    }
    .v4 .wp p {
        font-size: 16px;
    }
    .v4 .benef__grid {
        grid-template-columns: 1fr;
    }
    .v4 .benef {
        padding: 18px;
        gap: 18px;
    }
    .v4 .benef__name {
        font-size: 16px;
    }
    .v4__pgrid {
        grid-template-columns: 1fr;
    }
    .v4 .deliv__note {
        margin-left: 0;
    }
    .v4 .deliv__toggle {
        gap: 14px;
        padding: 18px 0;
    }
    .v4 .deliv__title {
        font-size: 17px;
    }
    .v4 .deliv__count {
        display: none;
    }
    .v4 .deliv__panel {
        padding: 0 0 22px;
    }
    .v4 .deliv__row {
        grid-template-columns: 56px minmax(0, 1fr);
        gap: 4px 14px;
    }
    .v4 .deliv__status {
        grid-column: 2;
        text-align: left;
    }
    .v4__oa {
        gap: 36px;
    }
    .v4__shelf {
        grid-template-columns: 1fr;
    }
    .v4__ghost {
        left: 22px;
        font-size: 44px;
    }
    /* On a phone the panel is a strip across the foot of the screen: a 380px
       card in a corner would leave a sliver of page beside it. */
    .v4__nlpop {
        bottom: 16px;
        inset-inline-end: 16px;
        inset-inline-start: 16px;
        width: auto;
        max-width: none;
    }
    .v4__nlpop .v4__nlcard {
        padding: 26px 24px 28px;
        border-radius: 28px;
    }
    .v4__blank {
        padding: 64px 0 72px;
    }
    .v4 .v4__blank h2 {
        font-size: 30px;
    }
    .v4__blankblob {
        width: 140px;
        height: 140px;
        margin-bottom: 28px;
    }
    /* On a phone the two columns stack, the map first: side by side there is
       room for neither, and the map is what the section is announced by. */
    .v4__cmap {
        padding-bottom: 64px;
    }
    .v4 .cmap {
        --cmap-h: 420px;
    }
    .v4 .cmap__stage {
        border-radius: 28px;
    }
    .v4 .cmap.is-live .cmap__stage {
        grid-template-columns: minmax(0, 1fr);
    }
    .v4 .cmap.is-live .cmap__map {
        order: -1;
    }
    .v4 .cmap.is-live .cmap__panel {
        height: auto;
        max-height: 480px;
        border-inline-end: 0;
        border-top: 1px solid #eef2f6;
    }
    .v4 .cmap__panel {
        padding: 24px 20px 20px;
    }
    .v4 .cmap__ptitle {
        font-size: 22px;
    }
    /* At this width the two legend pills reach across the whole map: kept at
       the foot they sat on South Africa and ran into the zoom buttons, so they
       move up to the empty Atlantic. */
    /* Posé sur la carte, le champ couvrirait avec la légende la Norvège et le
       Royaume-Uni : il passe en tête de la carte blanche, au-dessus du fond.
       La légende reste à 14 px du haut du fond (14 + 44 + 14 de la recherche). */
    .v4 .cmap__search {
        position: relative;
        top: auto;
        right: auto;
        width: auto;
        max-width: none;
        margin: 14px;
        border-color: #e6ebf0;
        box-shadow: none;
    }
    .v4 .cmap__key {
        top: 86px;
        bottom: auto;
        left: 14px;
        right: 14px;
    }
    .v4 .cmap__key li {
        padding: 7px 12px;
        font-size: 11px;
    }
}
