/* =========================================================================
   components.css — Wave 3
   -------------------------------------------------------------------------
   Numerolaatta, kolme reittiä ja kiinteä palkki. Mikään täällä ei koske
   #body-emulate-ruudukkoon: laatat ovat olemassa olevien .col1-laatikoiden
   sisältöä, palkki on position: fixed eikä ole ruudukossa alun perinkään.

   Poistettavissa kahdella <link>-rivillä header.html.twig:stä.
   ========================================================================= */

/* -------------------------------------------------------------------------
   Liikkeen sanasto
   Kolme animaatiota (lukujen rullaus, paneelin avautuminen, palkin liuku)
   jakavat yhden keston ja yhden kiihdytyskäyrän, jotta niistä tulee yksi
   järjestelmä eikä kolme irrallista efektiä.
   ------------------------------------------------------------------------- */
:root {
    --motion-fast: 180ms;
    --motion-slow: 1400ms;
    --motion-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* -------------------------------------------------------------------------
   Numerolaatta

   Laatta kantaa myös vanhaa .col1-luokkaa (ks. stats_tile.html.twig), joten
   spesifisyys pitää voittaa erikseen kahdesta eri kilpailijasta — kumpaakaan
   ei saa jättää <link>-järjestyksen varaan, koska se on hauras (Tasks 3–5
   muokkaavat samoja tiedostoja):

   1) Teksti (koko, väri). style.css:n ".col1 p" (font-size 15px, margin
      0 20px) ja paljas "p" (color #222) ovat vähintään yhtä spesifejä kuin
      yhden luokan valitsin, joten .stats-tile__lead ynnä muut tarvitsevat
      .stats-tile-esi-isän kaksinkertaistamaan luokkamäärän niitä vastaan.

   2) Marginaali (margin-top). Tässä samassa tiedostossa hieman ylempänä oleva
      oma nollaus ".stats-tile .stats-tile__figures p" (kaksi luokkaa + p)
      voittaisi label/support/live-rivien margin-topin, vaikka legacy-CSS ei
      olisi edes pelissä. Siksi nuo kolme on kirjoitettu kolmen luokan
      ketjuna (esim. ".stats-tile .stats-tile__figures .stats-tile__label"),
      ei !important:lla — kolme luokkaa voittaa kahden luokan + p:n aina.

   3) Taustaväri. ".col1.logo" (kaksi luokkaa) on yhtä spesifi kuin
      ".col1.stats-tile" olisi ollut; juuri-valitsin on siksi
      ".col1.logo.stats-tile" (kolme luokkaa), joka voittaa varmasti eikä
      vain siksi että tämä tiedosto sattuu latautumaan myöhemmin.
   ------------------------------------------------------------------------- */
/* --- Kierros 7D: "Nykyinen viritettynä" ----------------------------------
   Isompi tunnus, valkoiset tekstit, luvut reunoille. Arvot ovat suoraan
   designin #7d-lohkosta (Campaign Card.dc.html); poikkeamat on merkitty
   kohdalleen.

   Kortti ei enää käytä justify-content: space-between -asettelua. 7D
   pinoaa sisällön ylhäältä alas ja antaa tunnuksen negatiivisten
   marginaalien hoitaa rytmin; space-between olisi työntänyt painikkeen
   kortin alalaitaan riippumatta siitä mitä sen yläpuolella on. */
.col1.logo.stats-tile {
    display: flex;
    flex-direction: column;
    padding: 20px;
    background-color: var(--bg-inverse);
    color: #fff;
    overflow: hidden;
    /* Numbers now render final on first paint (no count-up), but this still
       guards against shift from font swap / number updates between loads. */
    contain: layout paint;
    /* style.css's listing-page rule ("#body-emulate:not(:has(.leftside))
       { align-items: stretch }") stretches every .col1 in a row to match
       its tallest row-mate. This card's internal layout (the logo's
       negative-margin overlap, the CTA's margin-top) is tuned for ITS OWN
       content height, not an arbitrary taller neighbour — at wide
       viewports where more columns fit, it can land in the same row as
       .col1.navi (which genuinely needs ~428px) and get stretched taller
       than its ~400px design, adding dead space and shifting the CTA
       down. align-self: start opts this one card out of the stretch so
       its height (and internal proportions) stay constant regardless of
       viewport width / row-mates. */
    align-self: start;
}

/* Tunnus vuotaa yli kortin paddingin: -29px vasemmalle ja -28px ylös vie
   sen kortin reunoja vasten, ja -76px alas nostaa luvut sen tyhjän
   alaosan päälle. Juuri siksi tiedoston on oltava LÄPINÄKYVÄ valkoinen
   versio — vanhassa mesenaatti_logo.svg:ssä on oma tumma taustansa, joka
   piirtyisi nyt näkyväksi laatikoksi kortin päälle. */
/* Ei hover-tilaa: tämä on etusivun oma tunnus, ja linkki vie etusivulle —
   sivu jolla ollaan jo. Ilman tätä se peri tokens.css:n yleisen "a:hover"
   -säännön (syaani + alaviiva-border), joka piirtyi tunnuksen alle vaikka
   klikki ei veisi mihinkään. */
.stats-tile__brand,
.stats-tile__brand:hover {
    display: block;
    flex: none;
    color: inherit;
    border-bottom-color: transparent;
}

.stats-tile__brand img {
    width: 241px;
    height: auto;
    display: block;
    margin: -28px 0 -86px -29px;
}

.stats-tile .stats-tile__figures p {
    margin: 0;
}

.stats-tile .stats-tile__lead {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 31px;
    line-height: 1;
    font-weight: 600;
    letter-spacing: -.01em;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    color: #fff;
}

/* Valkoinen, ei syaani. 7D:ssä kortin kaikki teksti on valkoista, ja
   syaani kuuluu tässä järjestelmässä hover-tilaan eikä perustilaan. */
.stats-tile .stats-tile__figures .stats-tile__label {
    font-size: 13px;
    line-height: 1.3;
    color: #fff;
    margin-top: 5px;
}

/* Luvut kortin vastakkaisiin reunoihin. Ei yläviivaa: 7D erottaa ryhmät
   välistyksellä, ei viivoilla — kortissa oli ennen kaksi jakoviivaa. */
.stats-tile .stats-tile__row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
    margin-top: 12px;
}

.stats-tile .stats-tile__figures .stats-tile__stat {
    margin: 0;
    display: flex;
    flex-direction: column;
}

/* Oikeanpuoleinen luku tasataan oikeaan reunaan, jolloin kortin molemmat
   pystyreunat ovat suoria. */
.stats-tile .stats-tile__row .stats-tile__stat:last-child {
    text-align: right;
}

.stats-tile .stats-tile__stat-value {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 21px;
    line-height: 1.1;
    font-weight: 600;
    color: #fff;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

/* Täysi valkoinen, ei .6 opacityä: 7D:ssä myös selitteet ovat valkoisia,
   ja himmennys pudotti ne 12px:n koossa lähelle kontrastirajaa. */
.stats-tile .stats-tile__stat-label {
    font-size: 12px;
    line-height: 1.3;
    color: #fff;
    margin-top: 2px;
}

/* Sama koko kuin kampanjasivun .statusbox-cta (style.css): 19px/600,
   padding 10px 0. 7D:ssä tämä oli kutistettu 13px:ään, mikä teki napista
   ohuemman kuin kampanjasivun vastineensa JA huononsi saavutettavuutta:
   valkoinen --brand-oranssin (#ec6f2b) päällä on kontrastiltaan 3,05:1,
   ja WCAG AA sallii 3:1 vain "isolle tekstille" (18,66px lihavoituna).
   19px/600 ylittää sen rajan (kuten .statusbox-cta jo tekee); 13px ei
   ylitä — se vaatisi 4,5:1. Koon palauttaminen korjaa siis sekä ulkoasun
   että tämän aiemmin auki jätetyn kontrastiongelman.

   Ei omaa line-height-arvoa: .statusbox-cta ei aseta sitä ollenkaan, joten
   se perii html:n 1.6:n (tokens.css --lh-relaxed) ja mittautuu 30,4px:ksi
   19px:llä. Tämän sääntö asetti 1.2:n (22,8px) — sama fontti/koko/padding
   mutta 7,6px matalampi nappi kuin kampanjasivulla, mikä luki "ohuempana". */
/* padding-inline + no nowrap: unlike .statusbox-cta's fixed "RAHOITA",
   this button's text is a live count ("N kampanjaa käynnissä") in a
   316px card — at 19px/uppercase/0,03em it measured EXACTLY 276px (the
   card's full content width) for a 1-digit count with the old padding: 10px
   0, i.e. text already touched both edges with zero room to spare, and a
   3-digit count (rare, but not impossible) overflowed by 10px past the
   card's own overflow: hidden, silently clipping the end of the text.
   Font-size can't shrink to fix this: 19px is the WCAG "large text" floor
   this button relies on for its 3:1 (not 4,5:1) contrast exemption — see
   the note above. So: letter-spacing dropped (bought back ~11px) and a
   smaller 6px inline padding — together that keeps the realistic 1-2
   digit range ("3", "37") on one line with breathing room at both edges;
   an unlikely 3-digit count (measured with "237") wraps to two lines
   instead of clipping or touching the edge, since nowrap is gone too. */
.stats-tile .stats-tile__figures .stats-tile__live {
    display: block;
    margin-top: 13px;
    padding: 10px 6px;
    text-align: center;
    text-decoration: none;
    background-color: var(--brand);
    color: var(--fg-on-brand);
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 16px;
    font-weight: 600;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
}

.stats-tile .stats-tile__figures a.stats-tile__live:hover {
    background-color: var(--brand-hover);
    color: var(--fg-on-brand);
}


/* -------------------------------------------------------------------------
   Mesenaatti KK -noste (Kierros 12A, campaign-card-tuning-designista)
   Okra pohja, /kk-merkin toistuva vesileima taustalla, keskitetty kremmi-
   paneeli sisällöllä. .kk-card__tile toistaa yhden SVG:n taustakuvana sen
   sijaan että kymmeniä <img>-elementtejä laitettaisiin auki DOMiin, kuten
   designin canvas-esitys teki — sama visuaalinen tulos, kevyempi merkintä.
   ------------------------------------------------------------------------- */
.col1.noste.kk-card {
    background: var(--ms-amber-500, #dca937);
    padding: 22px;
    position: relative;
    overflow: hidden;
}

.kk-card__tile {
    position: absolute;
    inset: 0;
    background-image: url(../images/kk_big-ink.svg);
    background-repeat: repeat;
    background-size: 62px 62px;
    background-position: 6px 6px;
    opacity: 0.16;
}

.kk-card__panel {
    position: relative;
    background: var(--ms-ink-50, #faf9f5);
    padding: 26px 22px 22px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 13px;
    text-align: center;
}

.col1.noste.kk-card h2 {
    margin: 0;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 19px;
    line-height: 1.35;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: #282929;
}

/* Added to explain the CTA's benefit up front. gap dropped from 18px to
   13px across the panel (was tuned for 3 children/2 gaps) to make room for
   this 4th child's own height without pushing the card past its 400px row
   baseline — kk-card lost its align-self: start opt-out earlier, so any
   growth here now drags the whole first row taller with it.

   Three classes, same reason as .col1.noste.kk-card h2 above: style.css's
   ".col1 p" (one class + tag) sets font-size: 15px, line-height: 20px and
   a 20px side margin on every <p> inside a .col1 card, and a single class
   selector loses to that. */
.col1.noste.kk-card .kk-card__intro {
    margin: 0;
    font-size: 13px;
    line-height: 1.4;
    color: var(--ms-ink-700, #4a4a4a);
}

.kk-card__mark {
    display: block;
    width: 168px;
    height: auto;
}

.kk-card__cta {
    display: flex;
    width: 100%;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px 22px 10px;
    background: var(--brand, #ec6f2b);
    color: #fff;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-weight: 600;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
    box-sizing: border-box;
}

.kk-card__cta:hover {
    background: var(--brand-hover, #d35a18);
    color: #fff;
}

/* -------------------------------------------------------------------------
   Tähtikampanjat-noste (Kierros 10E, campaign-card-tuning-designista)
   Kremmipohja, tumma 2px reunus, summa kantaa kortin. Pylväskuvio on
   koristeellinen (ei sidottu oikeaan dataan), samoin kuin designin omassa
   canvas-esityksessä.
   ------------------------------------------------------------------------- */
.col1.noste.star-card {
    background: var(--ms-ink-50, #faf9f5);
    padding: 20px;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.star-card__label {
    display: flex;
    align-items: center;
    gap: 9px;
    color: var(--ms-amber-500, #dca937);
}

.star-card__label span {
    font-family: var(--font-sans, "adelle-sans", sans-serif);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.11em;
    font-weight: 700;
    color: var(--ms-ink-700, #403f3b);
}

.star-card__amount {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 44px;
    line-height: 0.95;
    white-space: nowrap;
    color: #282929;
    font-weight: 600;
}

.star-card__rule {
    height: 4px;
    background: var(--ms-amber-500, #dca937);
}

.col1.noste.star-card p {
    margin: 0;
    font-family: var(--font-sans, "adelle-sans", sans-serif);
    font-size: 15px;
    line-height: 1.5;
    color: var(--ms-ink-800, #282828);
}

.star-card__bars {
    margin-top: auto;
    display: flex;
    align-items: flex-end;
    gap: 5px;
    height: 62px;
}

.star-card__bars span {
    display: block;
    flex: 1 1 0;
}

.star-card__cta {
    display: flex;
    width: 100%;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 14px 22px 10px;
    background: var(--brand, #ec6f2b);
    color: #fff;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-weight: 600;
    font-size: 14px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    text-decoration: none;
    box-sizing: border-box;
}

.star-card__cta:hover {
    background: var(--brand-hover, #d35a18);
    color: #fff;
}


/* -------------------------------------------------------------------------
   Pro-banneri / "Maksettu nosto" (Kierros 17C, campaign-card-tuning-designista)
   Korvaa vanhan WP CMS -bannerin, jota piti päivittää käsin (kuva-URL,
   kampanjalinkki, oma CSS per kierros). Kuva täyttää koko kortin, tumma
   liuku-paneeli kelluu pohjalla — sama rakenne kuin designin 17C-variantissa,
   paitsi ilman rahoitusmittaria (etusivun banneri saa vain kuvan, otsikon,
   ingressin ja linkin kampanjadatasta, ei rahoitusprosenttia).
   ------------------------------------------------------------------------- */
.col2_pro.pro-banner {
    position: relative;
    display: block;
    overflow: hidden;
    color: inherit;
    text-decoration: none;
    background: var(--ms-ink-100, #ececec);
}

/* object-position 50% 22% (ei 50% 50%): kampanjakuvat ovat useimmiten
   muotokuvia, joissa kasvot ovat kuvan yläkolmanneksessa. Keskitetty rajaus
   leikkasi kasvot pois lähes kokonaan — sama yläpainotteinen arvo kuin
   designin 17C-esimerkkikuvassa (assets/banda.jpg). Ei täydellinen jokaiselle
   kuvalle, mutta oikea oletus useimmille. */
.pro-banner__media {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 50% 22%;
    display: block;
}

/* Piilotettu (ks. index_page.html.twig) — sääntö säilyy jos badge halutaan
   myöhemmin takaisin. */
.pro-banner__badge {
    position: absolute;
    top: 0;
    left: 0;
    background: var(--ms-ink-1000, #111111);
    color: #fff;
    font-family: var(--font-sans, "adelle-sans", sans-serif);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    padding: 5px 9px;
}

/* Liuku kiinteän 82%-mustan sijaan: yhtenäinen läpikuultava taso ei erottunut
   kuvasta kun kuvan oma sävy oli jo tumma (esim. tumma vaatetus, ilta-
   valaistus) — paneeli näytti "läpinäkyvältä" koska mikään ei merkinnyt sen
   yläreunaa. Liuku nollasta lähes täyteen mustaan piirtää selvän, aina
   näkyvän rajan riippumatta kuvan omasta sävystä, ja korkeampi loppu-
   opasiteetti (0.94) takaa tekstin kontrastin myös vaaleiden kuvien päällä. */
.pro-banner__panel {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(180deg, rgba(17, 17, 17, 0) 0%, rgba(17, 17, 17, 0.4) 30%, rgba(17, 17, 17, 0.74) 100%);
    padding: 56px 22px 20px;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
}

.pro-banner__text {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}

.col2_pro.pro-banner h2.pro-banner__title {
    margin: 0;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 21px;
    line-height: 1.15;
    color: #fff;
}

.col2_pro.pro-banner p.pro-banner__ingress {
    margin: 0;
    font-size: 14px;
    line-height: 1.45;
    color: #fff;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.pro-banner__cta {
    flex: none;
    display: inline-flex;
    align-items: center;
    gap: 9px;
    background: var(--brand, #ec6f2b);
    color: #fff;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-weight: 600;
    font-size: 13px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 11px 14px;
    box-sizing: border-box;
}

.col2_pro.pro-banner:hover .pro-banner__cta {
    background: var(--brand-hover, #d35a18);
}

/* Below 688px .col2_pro drops to a single column with no fixed height
   (see style.css), so the panel switches from an absolute overlay to a
   static block under a shorter image — otherwise the image would collapse
   to 0 height and the panel would float with nothing behind it. */
@media (max-width: 687px) {
    .pro-banner__media {
        position: static;
        width: 100%;
        height: 200px;
    }

    .pro-banner__panel {
        position: static;
        flex-direction: column;
        align-items: stretch;
    }

    .pro-banner__cta {
        justify-content: center;
    }
}


/* -------------------------------------------------------------------------
   Kolme reittiä
   Tausta on tekstitön kolibri; turkoosi tulee blendistä, ei kuvasta.
   Näin sanat voivat olla markupia eikä kuvaa tarvitse tehdä uusiksi.

   Juuri on ".col1.routes", ei ".col1.banner". style.css:n
   "div.col1.banner" (0,2,1) ja varsinkin sen englannin
   "#body-emulate.currentLang-en div.col1.banner" (1,3,1) piirtäisivät
   vanhan poltetun lintu.jpg/lintu_en.jpg-kuvan takaisin näkyviin, eikä
   yhden luokan ".routes" voittaisi kumpaakaan. banner-luokka on siis
   pudotettu templatesta kokonaan (se esiintyi vain tässä yhdessä
   templatessa) — älä lisää sitä takaisin. min-height: 400px korvaa sen
   mitä ".col1.banner" antoi altapäin (688px alle .col1:lla ei ole
   sisäsyntyistä korkeutta); 688px ja siitä ylös ".col1 { height: 400px }"
   hoitaa saman.
   ------------------------------------------------------------------------- */
/* Kaksi taustakerrosta: mustaan liukuva peite (normal-blend, päällimmäinen)
   ja sen alla itse kolibrikuva (multiply-blend taustaväriä vasten, kuten
   ennenkin). background-blend-mode-lista vastaa background-image-listaa
   ylhäältä alas; taustaväri on aina alin, implisiittinen kerros.

   Peite on mitattu minimi: sanojen huonoin näyte kuvan päällä oli 2,17:1
   valkoista tekstiä vasten (vaatimus 4,5:1). alpha 0,42 pohjalla, häivytys
   nollaan yläreunassa, riittää jokaiselle kolmelle sanalle niiden omalla
   Y-korkeudella (ks. .routes__word-kommentti). Lintu pysyy tunnistettavana
   yläosassa, jossa peite on lähes läpinäkyvä. */
.col1.routes {
    background-image: linear-gradient(to top, rgba(0, 0, 0, .12), transparent),
                       url(/images/lintu2.jpg);
    /* background-color: #95d7df; */
    background-blend-mode: normal, multiply;
    background-size: 100% 100%, cover;
    background-position: center top, center top;
    background-repeat: no-repeat, no-repeat;
    display: flex;
    align-items: flex-end;
    padding: 20px;
    min-height: 400px;
    /* Paneeli kasvaa ylöspäin (align-items: flex-end). Testattu lisäämällä
       neljäs reitti pidemmällä tekstillä: laatan yläreunan yli valuva osuus
       kasvoi kymmenistä pikseleistä yli sataan sisällön pituuden mukaan.
       Rajaus laatan sisään on ennakoitava epäonnistuminen (teksti katkeaa);
       sisällön valuminen yläpuolisen ruudukkorivin päälle ei ole. */
    overflow: hidden;
}

.routes__list {
    list-style: none;
    margin: 0;
    padding: 0;
    width: 100%;
}

/* style.css:n paljas "li" antaa 5px padding-bottomin ja 440px
   max-widthin kaikille <li>-elementeille; kumpikaan ei ole tarkoitettu
   tänne eikä mikään muu sääntö kumoaisi niitä, joten nollaus tehdään
   eksplisiittisesti. */
.routes__item {
    padding: 0;
    max-width: none;
}

.routes__item + .routes__item {
    margin-top: 2px;
}

.routes__link {
    display: block;
    text-decoration: none;
    color: #fff;
}

/* Kirjautumaton "Luo" on <button> (ks. parts/create_fund_enable.html.twig).
   Natiivin napin oma kromi pois, jotta se on pikselintarkasti sama laatta
   kuin sisaruslinkit: koko leveys, ei taustaa/reunusta/paddingia, peritty
   fontti, vasen tasaus. */
button.routes__link {
    width: 100%;
    margin: 0;
    padding: 0;
    background: none;
    border: 0;
    font: inherit;
    text-align: left;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

/* style.css:n paljas "a:hover" (tyyppi+pseudoluokka, spesifisyys 0,1,1)
   on spesifimpi kuin ".routes__link" yksinään (0,1,0) ja veisi hover-tilan
   takaisin siniseksi (#61c8d5). ".routes__link:hover" on 0,2,0 ja voittaa
   sen ilman !important:ia. */
.routes__link:hover {
    color: #fff;
}

/* tokens.css:n globaali "a:focus-visible { outline: none; box-shadow:
   var(--focus-ring) }" (--focus-ring = 0 0 0 3px #83cfd9, sama väri kuin
   sivun oma turkoosi #95d7df) antaa laatalla mitattuna vain 1,10:1-
   kontrastin — WCAG 2.4.11 vaatii 3:1. #2b2b2b-ääriviiva mitattiin
   8,81:1 turkoosia taustaa vasten — hyvin yli vaatimuksen.

   Yllä lisätty peite kuitenkin tummentaa laatan alaosaa (jopa 42%
   mustalla "Mahdollista"-linkin kohdalla), ja juuri siellä tumma
   #2b2b2b-reunus mitattiin vain 1,43:1 kuvan tummimman todellisen
   kosketuspisteen päällä — epäonnistuu. Yksivärinen reunus ei siis
   riitä koko laatalle, koska tausta vaihtelee vaalean turkoosin ja
   peitteen tummentaman kuvan välillä. Ratkaisu on kaksisävyinen rengas:
   2px valkoinen "halo" ohuen (2px) outline-offsetin täytteenä, ja sen
   ulkopuolella 3px tumma outline. Vaalealla taustalla tumma outline
   kantaa (8,81:1); tummalla taustalla valkoinen halo kantaa — mitattu
   9,88:1 samaa tumminta kosketuspistettä vasten, jossa tumma outline
   yksinään epäonnistui. box-shadow korvaa tokens.css:n oman
   heikkokontrastisen renkaan sen sijaan että kaksi rengasta näkyisi
   päällekkäin. */
.routes__link:focus-visible {
    outline: 3px solid #2b2b2b;
    outline-offset: 2px;
    box-shadow: 0 0 0 2px #fff;
}

.routes__word {
    display: block;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 21px;
    line-height: 1.28;
    letter-spacing: .02em;
    text-transform: uppercase;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .28);
    transition: opacity var(--motion-fast) var(--motion-ease);
}

/* Paneeli on suljettuna nollakorkuinen. grid-auto-rows-animaatio antaa
   pehmeän avautumisen ilman kiinteää korkeutta — sisällön pituus saa
   vaihdella kielen mukaan.

   grid-template-rows (yksikäsitteinen, alkuperäisen suunnitelman mukainen)
   määrittää vain YHDEN eksplisiittisen rivin. Paneelilla on kaksi lasta
   (.routes__body ja .routes__cta), joten toinen niistä asettuisi
   implisiittiseen riviin, jota grid-template-rows ei ohjaa — implisiittinen
   rivi jäisi aina auto-kokoiseksi eikä koskaan collapsoituisi. grid-auto-rows
   ohjaa sekä eksplisiittisiä että implisiittisiä rivejä samalla funktiolla,
   joten molemmat lapset collapsoituvat/avautuvat yhdessä. */
.routes__panel {
    display: grid;
    grid-auto-rows: 0fr;
    overflow: hidden;
    transition: grid-auto-rows var(--motion-fast) var(--motion-ease);
    background: rgba(255, 255, 255, .94);
    color: #222;
    border-radius: 3px;
}

.routes__panel > * {
    min-height: 0;
}

.routes__body,
.routes__cta {
    display: block;
    font-family: var(--font-sans, system-ui, sans-serif);
}

/* Pysty-padding/margin on suljettuna nolla ja siirtyy avoimeksi vasta
   alla olevassa avattu-tila-säännössä. min-height: 0 (yllä) collapsoi
   tekstin rivilaatikot, mutta ei paddingia eikä marginaalia — ne ovat
   aina osa laatikkoa riippumatta sisällön korkeudesta. Jos ne pysyisivät
   kiinteinä täällä, suljettu paneeli jäisi niiden summan (42px) korkuiseksi
   nollan sijaan, vaikka teksti itse olisikin piilossa. */
.routes__body {
    font-size: 12.5px;
    line-height: 1.45;
    padding: 0 11px;
    transition: padding var(--motion-fast) var(--motion-ease);
}

.routes__cta {
    font-size: 11.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #fff;
    background: var(--ms-orange-500);
    text-align: center;
    margin: 0 11px;
    padding: 0 6px;
    border-radius: 2px;
    transition: margin var(--motion-fast) var(--motion-ease),
                padding var(--motion-fast) var(--motion-ease);
}

/* Avattu tila. .is-open asetetaan JS:llä; hover ja focus-within toimivat
   myös ilman JS:ää. Rivikorkeus ja pysty-padding/margin avautuvat samaan
   aikaan, jotta paneeli kasvaa yhtenä kappaleena eikä nykien. */
.routes__item:hover .routes__panel,
.routes__link:focus-within .routes__panel,
.routes__item.is-open .routes__panel {
    grid-auto-rows: 1fr;
}

.routes__item:hover .routes__panel .routes__body,
.routes__link:focus-within .routes__panel .routes__body,
.routes__item.is-open .routes__panel .routes__body {
    padding-top: 10px;
}

.routes__item:hover .routes__panel .routes__cta,
.routes__link:focus-within .routes__panel .routes__cta,
.routes__item.is-open .routes__panel .routes__cta {
    margin-top: 9px;
    margin-bottom: 11px;
    padding-top: 6px;
    padding-bottom: 6px;
}

/* Muut sanat himmenevät kun yhtä katsotaan. */
.routes__list:hover .routes__item:not(:hover) .routes__word,
.routes__list.has-open .routes__item:not(.is-open) .routes__word {
    opacity: .42;
}

/* Nuoli sanan perässä seuraa muiden etusivun CTA-linkkien tapaa
   (.kk-card__cta, .star-card__cta käyttävät samaa &rarr;-merkkiä
   koristeaffordanssina). aria-hidden markupissa: ruudunlukija saa sanan
   ilman merkkiä. Nytkähtää oikealle kun reitti on aktiivinen — sama ele
   kuin paneelin avautuminen. */
.routes__arrow {
    display: inline-block;
    /* .routes__word on 21px otsikkokokoa; .kk-card__cta / .star-card__cta
       -nuolet ovat 14px. 0.7em (~14.7px) tuo nuolen samaan visuaaliseen
       kokoon muun etusivun CTA-nuolten kanssa ja skaalautuu sanan mukana. */
    font-size: .7em;
    /* Pienempi nuoli istuisi perusviivalla eli optisesti liian alhaalla ison
       versaalisanan rinnalla. middle keskittää sen sanan keskiviivalle;
       top nostaa vielä pari pikseliä, jotta se osuu versaalin optiseen
       keskikohtaan. */
    vertical-align: middle;
    position: relative;
    top: -2px;
    transition: transform var(--motion-fast) var(--motion-ease);
}

.routes__item:hover .routes__arrow,
.routes__link:focus-visible .routes__arrow,
.routes__item.is-open .routes__arrow {
    transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
    .routes__word,
    .routes__panel,
    .routes__arrow { transition: none; }
}

/* -------------------------------------------------------------------------
   Kiinteä palkki

   style.css:n paljas "a" (0,1,0) on yhtä spesifi kuin yksittäinen luokka,
   joten ".sticky-bar__brand" yksinään voittaisi sen vain latausjärjestyksen
   ansiosta (components.css tulee header.html.twig:ssä style.css:n jälkeen).
   Sama koskee "a:hover" (0,1,1) suhteessa ".sticky-bar__nav a" (myös
   0,1,1) — hover-tilassa linkit muuttuisivat turkoosiksi (#61c8d5) pelkän
   järjestyksen varassa. Molemmat juuret on siis kirjoitettu ".sticky-bar"
   -esi-isän kautta, jotta spesifisyys ratkaisee eikä <link>-järjestys.
   ------------------------------------------------------------------------- */
.sticky-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 900;
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 7px 10px 7px 20px;
    background: var(--bg-inverse, #2b2b2b);
    color: #fff;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .22);
    transform: translateY(-100%);
}

.sticky-bar.is-visible {
    transform: translateY(0);
}

.sticky-bar[hidden] {
    display: none;
}

/* Rajattu 40px korkeaksi mustejäljeksi — SAMA korkeus ja SAMAT crop-luvut
   kuin kampanjapalkin logossa (ks. .sticky-bar--campaign .sticky-bar__brand
   alla): kahden palkin piti näyttää saman kokoiselta tunnukselta, ja koska
   kohdekorkeus on nyt sama 40px molemmissa, koko rajaus on identtinen eikä
   kampanjaversiolle tarvita enää omaa ohitusta. mesenaatti-logo-white.svg
   kantaa reunustilaa viewBoxissaan (288x365; musteala 226,41x196,3 alkaen
   22,39/37,8:sta — SVGGraphicsElement.getBBox()), joten kääre rajaa sen
   overflow: hiddenillä ja img siirretään negatiivisilla top/left-arvoilla.
   Skaalaus 40/196,3 ≈ 0,2038: koko SVG renderöityy 58,7x74,4:ksi, crop
   -7,7px/-4,6px. Tämän ansiosta myös palkkien korkeus tasaantuu: sama
   40px-korkuinen rivisisältö + sama 7px pystypadding kummassakin, sen
   sijaan että lyhyempi tekstirivi olisi kompensoitu isommalla paddingilla
   (mikä teki tästä palkista aiemmin korkeamman KUIN kampanjapalkin,
   vaikka sen oma sisältö oli matalampi). */
/* Ei hover-tilaa: tämä on palkin oma tunnus, ja linkki vie etusivulle —
   usein sivu jolla ollaan jo. Ilman tätä se perisi tokens.css:n yleisen
   "a:hover" -säännön (syaani + alaviiva-border), joka piirtyisi rajatun
   kuvan alle vaikka klikki ei useinkaan veisi mihinkään — sama korjaus
   kuin stats_tile.html.twig:n etusivutunnuksella (ks. .stats-tile__brand,
   components.css). */
.sticky-bar .sticky-bar__brand,
.sticky-bar .sticky-bar__brand:hover {
    display: block;
    position: relative;
    flex-shrink: 0;
    width: 46px;
    height: 40px;
    overflow: hidden;
    text-decoration: none;
    border-bottom-color: transparent;
}

.sticky-bar .sticky-bar__brand img {
    display: block;
    position: absolute;
    top: -7.7px;
    left: -4.6px;
    width: 58.7px;
    height: 74.4px;
    max-width: none;
}

.sticky-bar__nav {
    margin-left: auto;
    display: flex;
    gap: 16px;
}

.sticky-bar .sticky-bar__nav a {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    color: #fff;
    text-decoration: none;
    font-size: 13.5px;
    white-space: nowrap;
}

/* .is-current tulee components.js:n initCurrentCategory():sta (laajennettu
   kattamaan .sticky-bar__nav). Sama oranssi kuin työpöytävalikon aktiivisen
   kohdan merkki (#menu-menu > li.current-menu-item > a, components.css
   ~2508: #ec6f2b). */
.sticky-bar .sticky-bar__nav a.is-current {
    color: var(--brand, #ec6f2b);
}

/* -------------------------------------------------------------------------
   Kampanjavariantti
   ------------------------------------------------------------------------- */
.sticky-bar--campaign {
    gap: 8px;
}

/* #body-emulate drops to a single full-bleed column below 688px (same
   breakpoint as the campaign-card fix above), and .leftside.view — the
   white content column the bar sits over — lands its own left/right edges
   20px in from the viewport (8px UA-default body margin + #wrapper's own
   12px padding; measured via getBoundingClientRect(), stable across this
   whole breakpoint since #wrapper doesn't hit its 1004px max-width down
   here). The bar's base padding (7px 10px 7px 20px, shared with the
   non-campaign variant) only matches that on the left by coincidence —
   the right side sits 10px short, so the CTA's right edge hung 10px past
   .leftside.view's. Symmetric 20px here lines both the logo and the CTA
   up with the column it overlays. */
@media (max-width: 687px) {
    .sticky-bar--campaign {
        padding-left: 20px;
        padding-right: 20px;
    }
}

/* Kampanjapalkin logomerkki on nyt kooltaan ja rajaukseltaan identtinen
   yleisen palkin kanssa (ks. .sticky-bar .sticky-bar__brand yllä) — sama
   40px korkuinen mustejälki kummassakin, joten oma ohitus poistettiin
   duplikaattina. .sticky-bar__cta (RAHOITA, mitattu ~38,6px) tasaantuu
   samaan korkeuteen. */

/* margin-left: auto (not flex: 1) pushes the title+progress block up
   against the CTA instead of stretching it left-aligned across the whole
   gap after the logo — the auto margin absorbs the leftover space before
   it, so it sits right next to .sticky-bar__cta with just the bar's own
   8px gap between them. flex-shrink keeps it truncatable (min-width: 0
   overrides the default content-based floor) once a long title + the CTA
   no longer both fit. */
.sticky-bar__campaign {
    flex: 0 1 auto;
    min-width: 0;
    margin-left: auto;
}

.sticky-bar__title {
    display: block;
    font-weight: 600;
    font-size: 13.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sticky-bar__meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 4px;
}

.sticky-bar__progress {
    display: block;
    flex: 1;
    max-width: 160px;
    height: 4px;
    border-radius: 0;
    background: rgba(255, 255, 255, .18);
}

.sticky-bar__progress-fill {
    display: block;
    height: 100%;
    border-radius: 0;
    background: var(--brand, #00bcca);
}

.sticky-bar__pct {
    font-size: 11.5px;
    opacity: .85;
    white-space: nowrap;
}

.sticky-bar__cta {
    background: var(--brand, #ec6f2b);
    color: #fff;
    text-decoration: none;
    font-weight: 600;
    font-size: 13.5px;
    padding: 8px 16px;
    border-radius: 0;
    white-space: nowrap;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.sticky-bar__cta:hover {
    background: var(--brand-hover, #d35a18);
    color: #fff;
}

/* -------------------------------------------------------------------------
   Hampurilaisvalikko (Wave 4)
   ------------------------------------------------------------------------- */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* font-size(29) + padding(8 top/bottom) = 45px — 5px over the 40px logo/
   CTA scale used elsewhere in the bar, per request. align-items: center
   on .sticky-bar centers it against the row's other children regardless
   of this being the tallest one now. */
.sticky-bar__menu-toggle {
    background: none;
    border: none;
    color: #fff;
    font-size: 29px;
    line-height: 1;
    padding: 8px;
    cursor: pointer;
}

.sticky-bar__overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    /* Ilman tätä overlaylla ei ole omaa korkeutta (fixed + ei "bottom", joten
       laatikko kutistuu sisältönsä mittaiseksi) — taso 1 näkyy silti, koska
       se on normaalissa virtauksessa, mutta absoluuttisesti sijoitetut
       taso 2/2b ("bottom: 0") laskevat korkeutensa TÄMÄN laatikon
       (kutistuneen) alareunasta ja renderöityvät 0 px:n korkuisina —
       mitattu: teemataso ja info-taso olivat molemmat näkymättömiä ennen
       tätä. */
    bottom: 0;
    z-index: 899;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 66px 16px 16px;
    background: rgba(43, 43, 43, .74);
    transform: translateY(-100%);
    transition: transform var(--motion-fast) var(--motion-ease);
}

.sticky-bar__overlay.is-open {
    transform: translateY(0);
}

.sticky-bar__overlay[hidden] {
    display: none;
}

.sticky-bar__overlay a {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    color: #fff;
    text-decoration: none;
    font-size: 15px;
    padding: 10px 4px;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
}

/* Kielivalitsin — vaakapari alarivissä, ei täysleveä listalinkki kuten
   muut. Placed after .sticky-bar__overlay a so it wins (equal specificity). */
.sticky-bar__overlay-lang {
    display: flex;
    gap: 20px;
    padding: 14px 4px 0;
    margin-top: 4px;
}

.sticky-bar__overlay .sticky-bar__overlay-lang a {
    color: #ec6f2b;
    padding: 0;
    border-bottom: 0;
}

.sticky-bar__overlay .sticky-bar__overlay-lang a[aria-current="true"] {
    color: #fff;
    font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
    .sticky-bar__overlay { transition: none; }
}

/* -------------------------------------------------------------------------
   .progress / .progress_bar — the OLD grid-card progress bar. Still used
   directly (not through campaign_card.html.twig) by several other
   templates with their own hand-rolled markup and inline widths:
   campaign_index_parts/campaign_legacy_card.html.twig,
   campaign_index_parts/campaign_card_preparing.html.twig,
   campaign_index_pilot_page.html.twig, and a handful of pro/*.html.twig
   landing pages. Out of scope for the kampanjakortti redesign below, so
   left in place rather than replaced — the redesign's bar lives under new
   .grid-card-progress* class names instead of reusing these.
   ------------------------------------------------------------------------- */
.progress {
    background: #e3e3e3;
    border-radius: 2px;
    height: 3px;
    margin-top: 8px;
    overflow: hidden;
}

.progress_bar {
    background: #00b7c6;
    height: 100%;
    border-radius: 2px;
    transition: width var(--motion-fast) var(--motion-ease);
}

@media (prefers-reduced-motion: reduce) {
    .progress_bar { transition: none; }
}

/* -------------------------------------------------------------------------
   Kampanjakortti (ruudukko) — 2026-08 redesign.

   Unified with the campaign-page status card (campaign_page.html.twig's
   .statusbox-* rules, style.css ~line 780 on): same two-phase progress-bar
   math (fills against min_goal until reached, then re-bases against
   target_goal with a marker at the min_goal point), same "minimitavoite" /
   "tavoite" vocabulary, same real design-system tokens (tokens.css) rather
   than the aspirational skill-doc hex values. No shared Twig/JS component
   layer exists in this codebase (no build step), so the Vue expressions are
   duplicated between the two templates rather than truly shared — kept
   byte-for-byte identical on purpose; if the math changes in one, change it
   in the other.

   Differences from the status card, all deliberate: 6px track (not 8px —
   this card is smaller), no width transition (twelve bars animating at once
   in a grid is restless, one bar on a campaign page reads as feedback), and
   light-surface colors instead of the status card's dark panel.

   The whole card is one <a> (campaign_card.html.twig) instead of the three
   overlapping links the old markup had (image/title/description each their
   own <a> to the same destination) — a screen reader no longer announces
   the same destination three times. That anchor is inserted by the include
   itself; every including template still wraps it in the existing
   <div class="col1 project_white_box card">, so the grid, the fixed 400px
   tile height and the stage_6/9 amber overrides (style.css ~5026) are
   unchanged.
   ------------------------------------------------------------------------- */
.col1.project_white_box.card {
    padding: 0;
    height: 400px;
}

/* style.css's "#body-emulate:not(:has(.leftside)) .col1 { height: auto;
   min-height: 400px }" (1 id + 2 classes via :not(), beats the plain rule
   above) is what actually governed this card's height until now — auto let
   it grow to fit its content, which is why it settled at ~423px rather than
   the 400px the rule above asked for. Matching its selector, with this
   card's own 3 classes added, is what makes 400px actually stick: title is
   already clamped to exactly 2 lines (min-height + -webkit-line-clamp: 2)
   and the description to at most 2 (-webkit-line-clamp: 2), so content
   height is bounded/predictable enough that a hard height here doesn't
   risk clipping the way it would on a card with genuinely unbounded
   content. */
#body-emulate:not(:has(.leftside)) .col1.project_white_box.card {
    height: 400px;
}

/* Below 688px #body-emulate drops to a single full-bleed column
   (style.css ~597: "the fixed track only earns its keep once two of them
   fit"), so the card's width — and with it .grid-card-media's 16:9-driven
   height — grows with the viewport instead of staying at the ~316px the
   400px budget above was measured against. At ~600px card width the media
   box alone is already ~320px, pushing total content past 500px against a
   card capped at height:400px; overflow stays visible (nothing here sets
   hidden), so the excess spills into the next card's box instead of being
   clipped — the two visually run together. There is no sibling row to
   keep equal-height for below this breakpoint (one card per row), so
   nothing is lost by letting height track content again; min-height keeps
   short cards (e.g. no-funding/subscribe variants) from looking clipped-
   thin. */
@media (max-width: 687px) {
    .col1.project_white_box.card,
    #body-emulate:not(:has(.leftside)) .col1.project_white_box.card {
        height: auto;
        min-height: 400px;
    }
}

.project_white_box.card > .grid-card-link {
    display: flex;
    flex-direction: column;
    height: 100%;
    color: inherit;
    text-decoration: none;
}

.project_white_box.card {
    transition: transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}

.project_white_box.card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-3);
}

/* Neutralize the legacy hover-opacity rule (style.css ~832) on new cards */
.project_white_box.card .grid-card-link:hover .grid-card-image {
    opacity: 1;
}

/* Same fix as .grid-card-shell > a:hover above: the whole card is one
   block-level <a> (.grid-card-link), so tokens.css's generic a:hover
   { border-bottom-color: currentColor } painted a teal line across the
   full card width on hover instead of the intended inline-text underline. */
.project_white_box.card > .grid-card-link:hover {
    border-bottom-color: transparent;
}

/* gap is the tight title->description spacing; .grid-card-funding adds its
   own margin-top on top of this gap for a more generous gap before the
   amount/progress/meta block specifically — verified against the 400px
   budget: media(160) + margin-top(16) + this padding + title(46, clamped
   to exactly 2 lines) + gap + description(<=41, clamped to 2 lines) + gap
   + funding's own margin-top + funding(86) must total <= 400 or the block
   overflows the card's now-fixed height (it did, at gap: 16px uniform —
   measured 8px overflow past the card's bottom edge). */
.grid-card-body {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px 16px 16px;
    flex: 1;
}

.grid-card-link:focus-visible {
    outline: 2px solid var(--ms-cyan-800);
    outline-offset: 2px;
}

/* 16:10 ratio box. 16px margin on the top/left/right insets the image from
   the card edges (the old live card's look) instead of running it
   full-bleed; the body below supplies its own top gap via .grid-card-body's
   gap, so no bottom margin here. `aspect-ratio` (not the old padding-top
   hack) because padding-top's percentage is relative to the CONTAINING
   block's width, not this element's own post-margin width, so it can't
   track a margin-narrowed box the way aspect-ratio does. */
.grid-card-media {
    display: block;
    position: relative;
    width: calc(100% - 32px);
    aspect-ratio: 16 / 9;
    margin: 16px 16px 5px;
    background-color: var(--ms-ink-200);
    overflow: hidden;
    flex-shrink: 0;
}

.col1.project_white_box.card .grid-card-image {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    aspect-ratio: auto;
    object-fit: cover;
}

/* Legacy card image (campaign_legacy_card.html.twig, campaign_card_preparing
   .html.twig, campaign_index_pilot_page.html.twig, and a handful of
   pro/*.html.twig landing pages) had no aspect-ratio rule of its own, unlike
   .grid-card-media above — nothing pinned the 284x189 (1.503:1) crop ratio
   the CDN request itself uses, so below the fixed-284px multi-column grid
   the <img> stretched to whatever height its container happened to impose
   instead of scaling the same ratio the >=688px grid shows. Same fix as
   .grid-card-media: pin the ratio, crop overflow via object-fit. */
.attachment-card {
    display: block;
    width: 100%;
    aspect-ratio: 284 / 189;
    object-fit: cover;
}

/* Set by the @error handler in campaign_card.html.twig when the recorded
   image 404s — hides the broken <img> so .grid-card-media's own background
   shows through as the flat fill, instead of swapping to a placeholder
   graphic (spec: no placeholder icon, no text). */
.col1.project_white_box.card .grid-card-image--broken {
    display: none;
}

/* .col1.project_white_box.card is prefixed on the four selectors below
   (title/description/ratio+time/hybrid/subscribe-label/image) because
   style.css already has generic h2/p/img rules scoped to
   .col1.project_white_box(.card) (lines ~675, 709, 722, 685) that would
   otherwise win on specificity and silently override these — .grid-card-x
   alone is a single class, weaker than that 3-class-plus-element combo. */
.col1.project_white_box.card .grid-card-title {
    margin: 0;
    font-family: var(--font-display);
    font-size: 19px;
    line-height: 1.2;
    font-weight: 600;
    color: var(--fg-1);
    min-height: calc(1.2em * 2);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Stage 6/9 reuses style.css's existing amber title override (.card-title,
   ~line 5031) by carrying that class too — restated here at matching
   specificity so it isn't lost to source order against the rule above. */
.col1.project_white_box.card.stage_6 .grid-card-title,
.col1.project_white_box.card.stage_9 .grid-card-title {
    color: var(--ms-amber-500);
}

.col1.project_white_box.card .grid-card-link:hover .grid-card-title,
.col1.project_white_box.card .grid-card-link:focus-visible .grid-card-title {
    color: var(--fg-2);
}

.col1.project_white_box.card .grid-card-description {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 13px;
    line-height: 1.45;
    color: var(--fg-2);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.grid-card-progress {
    position: relative;
    height: 6px;
    margin: 0;
    background-color: var(--ms-ink-200);
    flex-shrink: 0;
}

.grid-card-progress-fill {
    height: 100%;
    background-color: var(--brand);
    animation: grid-card-fill-in 200ms var(--ease-out) both;
}

@keyframes grid-card-fill-in {
    from { width: 0 !important; }
}

@media (prefers-reduced-motion: reduce) {
    .grid-card-progress-fill { animation: none; }
}

.grid-card-progress-marker {
    position: absolute;
    top: -3px;
    width: 2px;
    height: 12px;
    background-color: var(--ms-paper);
    transform: translateX(-1px);
}

/* Funding block: amount row → progress bar → meta row. */
.grid-card-funding {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: auto;
}

.grid-card-amount-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

.grid-card-amount {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 600;
    color: var(--fg-1);
}

.grid-card-badge {
    display: flex;
    align-items: center;
    gap: 3px;
    flex-shrink: 0;
    font-family: var(--font-display);
    font-size: 16px;
    font-weight: 600;
    color: var(--ms-cyan-600, #00bcca);
    white-space: nowrap;
}

.grid-card-badge svg {
    flex-shrink: 0;
}

.grid-card-meta {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

.grid-card-meta-goal {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--fg-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.grid-card-meta-time {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--fg-2);
    white-space: nowrap;
    flex-shrink: 0;
}

.grid-card-meta-ended {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--fg-3);
    white-space: nowrap;
    flex-shrink: 0;
}


/* Hybrid-funding label (match_funding campaigns) — was absolutely positioned
   over the old image/data footer (style.css:3852, responsive.css:258); the
   new card has no absolute-positioned footer to collide with, so it's back
   in normal flow, right above the title like a category eyebrow. */
.col1.project_white_box.card .grid-card-hybrid {
    margin: 0;
    font-family: var(--font-sans);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ms-cyan-700);
}

.col1.project_white_box.card .grid-card-hybrid + .grid-card-title {
    margin-top: -8px;
}

/* Stage 6/9 (mesenaatti/kk subscription) cards keep their own separate
   subscribe-button link rather than joining the single-anchor pattern above
   — nesting that <a> inside the card's own <a> would be invalid HTML and
   would break the click target. Matches the amber accent already used for
   this stage elsewhere (style.css:5026, .subscribe-button). */
.grid-card-shell {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* tokens.css's generic a:hover { border-bottom-color: currentColor } is an
   inline-text-link affordance (a { border-bottom: 1px solid transparent }
   base state) — this card's whole media+body block is one block-level <a>,
   so hovering anywhere on the image or description painted that hover
   border as a teal line across the full card width, right at the anchor's
   bottom edge (between the description and the mesenaatti/kk label below
   it) — verified, reads as a broken/stray underline, not a link hint. */
.grid-card-shell > a:hover {
    border-bottom-color: transparent;
}

.col1.project_white_box.card .grid-card-subscribe-label {
    margin: auto 16px 0;
    padding-top: 8px;
    font-family: var(--font-sans);
    font-size: 12px;
    color: var(--fg-3);
}

.col1.project_white_box.card .grid-card-subscribe-button {
    display: block;
    margin: 8px 16px 16px;
    padding: 10px 0;
    background-color: var(--ms-amber-500);
    color: var(--ms-paper);
    font-family: var(--font-display);
    font-size: 15px;
    font-weight: 600;
    text-align: center;
    text-decoration: none;
}

/* -------------------------------------------------------------------------
   Ended-card overrides — keyed off .card-ended on the <a> or its container.
   Applied to cards whose funding deadline has passed.
   ------------------------------------------------------------------------- */


/* Image tag — flush to top-left corner of the image area */
.grid-card-tag {
    position: absolute;
    top: 0;
    left: 0;
    padding: 5px 9px;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ms-paper);
    background-color: var(--bg-inverse);
    line-height: 1;
    z-index: 1;
}

/* Legacy: keep old class name working for ended-card status badges */
.grid-card-status {
    position: absolute;
    top: 0;
    left: 0;
    padding: 5px 9px;
    font-family: var(--font-display);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ms-paper);
    background-color: rgba(40, 40, 40, 0.75);
    line-height: 1;
    z-index: 1;
}

/* 2. Progress bar: teal fill on ended cards */
.card-ended .grid-card-progress-fill {
    background-color: #00bcca;
}

/* 3. Title: dark but not full gray */
.col1.project_white_box.card .card-ended .grid-card-title,
.col1.project_white_box.card.card-ended .grid-card-title,
.card-ended .grid-card-title {
    color: #333;
}

/* 4. Description: muted */
.col1.project_white_box.card .card-ended .grid-card-description,
.col1.project_white_box.card.card-ended .grid-card-description,
.card-ended .grid-card-description {
    color: var(--ms-ink-500);
}

/* 5. Amount: keep black */
.card-ended .grid-card-amount {
    font-weight: 600;
    color: #222;
}

/* 6. Badge ("Toteutui"/"Toteutuu"): teal now comes from the base
   .grid-card-badge rule for every card, ended or not — no override needed
   here any more. */

/* 7. No hover lift on ended cards */
.project_white_box.card:has(> .card-ended):hover,
.project_white_box.card.card-ended:hover {
    transform: none;
    box-shadow: none;
}

/* -------------------------------------------------------------------------
   Loading skeleton — matches the loaded card's own layout 1:1 (same
   reasoning as the status card's skeleton, style.css ~845) so nothing
   shifts once real data swaps in.
   ------------------------------------------------------------------------- */
.grid-card-skeleton-block {
    background: linear-gradient(90deg, var(--ms-ink-100) 25%, var(--ms-ink-200) 37%, var(--ms-ink-100) 63%);
    background-size: 400% 100%;
    animation: grid-card-shimmer 1.6s ease-in-out infinite;
}

@keyframes grid-card-shimmer {
    0% { background-position: 100% 50%; }
    100% { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
    .grid-card-skeleton-block {
        animation: none;
        background: var(--ms-ink-100);
    }
}

.grid-card-skeleton-media {
    width: 100%;
    aspect-ratio: 16 / 10;
    flex-shrink: 0;
}

.grid-card-skeleton-title {
    margin: 16px 16px 0;
    width: calc(100% - 32px);
    height: calc(1.2em * 2);
}

.grid-card-skeleton-description {
    margin: 12px 16px 0;
    width: calc(100% - 32px);
    height: calc(1.45em * 2);
}

.grid-card-skeleton-amount {
    margin: 12px 16px 0;
    width: 40%;
    height: 26px;
}

.grid-card-skeleton-progress {
    margin: 8px 16px 0;
    width: calc(100% - 32px);
    height: 8px;
}

.grid-card-skeleton-line {
    margin: 8px 16px 0;
    width: calc(100% - 32px);
    height: 13px;
}

/* -------------------------------------------------------------------------
   pro/parhaat.html.twig's two hero cards (logo.gif, hof2.png). Bare <img>
   with no width/height HTML attributes and no scaling rule of its own, so
   it rendered at its native pixel size (316x400) inside a .col1 that's
   full viewport width below 687px — same ratio at every width (nothing
   distorts it), but a growing gap opens up next to it as the card outgrows
   the fixed image, which is what reads as "wrong proportions" against the
   full-width desktop card. width: 100% + height: auto fills the card at
   any width while keeping the image's own aspect ratio intact. */
.parhaat-hero img {
    display: block;
    width: 100%;
    height: auto;
}

/* Decorative /kk cards — both the existing rotate cards (rotate.html.twig) and
   the fillers grid-fill.js injects. The frame SVGs come in a few aspect ratios
   (most ~315/316x400, each set's 5.svg is 257x400), so a plain <img> either
   gaps or reads as vertically stretched. Fill the card undistorted with
   object-fit:cover.

   The <img> is absolutely positioned so it NEVER contributes to the card's
   height. `height: 100%` alone was enough while .col1 was a definite
   `height: 400px`, but the card listings later switched .col1 to
   `height: auto; min-height: 400px` with the row stretched to its tallest
   tile (style.css, "#body-emulate:not(:has(.leftside))"). Against an
   auto-height parent `height: 100%` resolves to auto, so the image fell back
   to its intrinsic ratio — ~401.7px for a 118x150 viewBox in a 316px column —
   which is 1-2px over 400 and dragged the whole first row up with it. Out of
   flow, the card is sized purely by the grid and the image fills whatever
   that comes to. #body-emulate/.col1 already give the card
   position:relative. */
.col1.rotate { overflow: hidden; }
.col1.rotate img {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}


/* =========================================================================
   Campaign recommendations + Creator CTA
   ========================================================================= */
/* Both this block and .creator-cta are direct children of #body-emulate
   (campaign_page.html.twig includes them after </campaign-page>), so they
   are grid items, and two separate things kept them narrow:

   1. No column span, so each took a single 316px track. That pinned the
      inner auto-fill card grid to one column — the cards looked
      deliberately small but were only boxed in.
   2. "margin: ... auto ..." on a GRID item absorbs the free space in its
      area and overrides stretch alignment, so even spanning 1 / -1 the box
      stayed shrink-to-fit (541px of a 980px area) and merely centred
      itself. Measured: dropping the auto margins alone restores 980.

   width: 100% restores the stretch while keeping the auto margins useful if
   the area is ever wider than max-width; border-box keeps the 16px padding
   inside that width instead of pushing the total to 1012. */
.recommendations {
    grid-column: 1 / -1;
    width: 100%;
    max-width: 980px;
    box-sizing: border-box;
    margin: 48px auto 0;
    /* No horizontal padding: this block spans the same 980px the card grid
       above it does, so its own 16px inset pushed every card 16px in from
       the page's content edge (cards started at x=166 against the grid's
       150). Flush edges + the 16px grid gap put the 4-up row on the same
       vertical lines as the 3-up card grid. */
    padding: 0;
}

.recommendations-heading {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 24px;
    font-weight: 600;
    color: #292929;
    margin: 0 0 24px;
}

.recommendations-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
}

.recommendations-card {
    background: #fff;
    text-decoration: none;
    color: inherit;
    display: flex;
    flex-direction: column;
}

/* .grid-card-media is a padding-top ratio box (height: 0 + padding-top:
   62.5%, see ~line 677), so its content box has NO height: an in-flow child
   starts below the padding and is clipped away by overflow: hidden — which
   is why these cards showed only the grey placeholder background. The image
   has to be taken out of flow and pinned over the padding, exactly as
   .col1.project_white_box.card .grid-card-image does for the campaign card.
   height: 100% (not a fixed 180px) so it tracks the ratio box at any width. */
.recommendations-card .grid-card-image {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    aspect-ratio: auto;
    object-fit: cover;
}

.recommendations-card .grid-card-body {
    padding: 16px;
    flex: 1;
    display: flex;
    flex-direction: column;
}

/* Match campaign_card.html.twig's title exactly: ink, sentence case, Adelle
   600/19px. This is an <h3> (correct level under the section's <h2>), and
   style.css's bare "h3" rule paints every h3 cyan + uppercase — that rule
   was showing through because the override only set a size. Two classes
   (0-2-0) beat the element selector regardless of load order. */
.recommendations-card .grid-card-title {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 19px;
    line-height: 1.2;
    font-weight: 600;
    color: var(--ms-ink-1000);
    text-transform: none;
    margin: 0 0 auto;
}

.recommendations-card .grid-card-funding {
    margin-top: 12px;
}

.creator-cta {
    grid-column: 1 / -1;
    width: 100%;
    max-width: 980px;
    box-sizing: border-box;
    margin: 0px auto 0;
    padding: 32px 16px;
    text-align: center;
    /* Every other block on the page is a white surface on the teal canvas;
       this one declared no background at all and sat straight on the teal. */
    background: var(--ms-paper, #fff);
}

.creator-cta-heading {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 24px;
    font-weight: 600;
    color: #292929;
    margin: 0 0 12px;
}

.creator-cta-body {
    font-size: 16px;
    color: #555;
    max-width: 480px;
    margin: 0 auto 24px;
    line-height: 1.5;
}

/* Rendered as an <a> when signed in and a <button> when signed out (see
   campaign_recommendations.html.twig), so the UA button chrome has to be
   reset for the two to look identical. */
.creator-cta-button {
    display: inline-block;
    border: 0;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    line-height: normal;
    background: #ec6f2b;
    color: #fff;
    text-decoration: none;
    font-weight: 600;
    font-size: 16px;
    padding: 14px 32px;
    font-family: var(--font-display, "Adelle", Georgia, serif);
}

.creator-cta-link {
    display: block;
    margin-top: 12px;
    font-size: 14px;
    color: #00bcca;
    text-decoration: none;
}

/* ============================================================================
   Hakusivu (/haku/)
   ---------------------------------------------------------------------------
   Replaces the Google Programmable Search embed, which brought its own
   stylesheet and rendered a Google-branded results list inside the site's
   content column. Everything here is site-native so results read like the rest
   of the site — same display face, same progress bar, same orange accent.

   Design reference: "Campaign Card.dc.html" sections 13A (results) and 13B
   (before search). The filter chips in 13A are deliberately not built: no
   filtering was wanted in this round.
   ========================================================================== */

.search-page h1 {
    margin-bottom: 20px;
}

.search-form {
    display: flex;
    gap: 10px;
    align-items: stretch;
}

.search-field {
    flex: 1 1 0;
    /* Without min-width: 0 a flex item refuses to shrink below its content's
       intrinsic width, which for a text input is its `size` attribute default
       (~20 chars) — the field would push the Hae button off the edge on
       narrow viewports instead of shrinking. */
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 12px;
    background: #fff;
    border: 1.5px solid var(--ms-ink-300, #cfcfcf);
}

.search-field:focus-within {
    border-color: var(--ms-ink-1000, #292929);
}

.search-field-icon {
    display: block;
    flex: none;
    color: var(--ms-ink-500, #8a8a8a);
}

.search-field-input {
    flex: 1 1 0;
    min-width: 0;
    padding: 12px 0;
    border: 0;
    outline: 0;
    background: transparent;
    font-family: inherit;
    /* 16px exactly: iOS Safari zooms the page in on focus for anything
       smaller, which on a search field means the first tap of every search
       jumps the layout. */
    font-size: 16px;
    color: var(--ms-ink-1000, #292929);
    -webkit-appearance: none;
    appearance: none;
}

/* The UA's own clear button for type="search" — suppressed in favour of the
   × link, which is a real navigation and therefore also works without JS. */
.search-field-input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
}

.search-field-clear {
    display: flex;
    flex: none;
    padding: 4px;
    color: var(--ms-ink-500, #8a8a8a);
    text-decoration: none;
}

.search-field-clear:hover {
    color: var(--ms-ink-1000, #292929);
}

.search-submit {
    flex: none;
    border: 0;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    line-height: normal;
    background: #ec6f2b;
    color: #fff;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-weight: 600;
    font-size: 16px;
    padding: 12px 28px;
}

.search-summary {
    margin: 18px 0 10px;
    font-size: 14px;
    color: var(--ms-ink-600, #6b6b6b);
}

.search-summary b {
    color: var(--ms-ink-1000, #292929);
}

.search-results {
    display: flex;
    flex-direction: column;
    border-top: 1px solid var(--border, #e5e5e5);
}

.search-result {
    display: grid;
    grid-template-columns: 96px 1fr auto;
    gap: 16px;
    align-items: center;
    padding: 14px 0;
    border-bottom: 1px solid var(--border, #e5e5e5);
    color: inherit;
    text-decoration: none;
}

.search-result:hover .search-result-title {
    text-decoration: underline;
}

.search-result-media {
    width: 96px;
    height: 60px;
    background: var(--ms-ink-100, #f0f0f0);
    overflow: hidden;
}

.search-result-image {
    display: block;
    width: 96px;
    height: 60px;
    max-width: none;
    object-fit: cover;
}

.search-result-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* Same reason as .search-field: without this the long titles below set the
       track's minimum width and the funding column gets pushed out of view. */
    min-width: 0;
}

/* Two class selectors, not one: the row title is an <h2> inside .leftside, and
   `.leftside h2` (style.css:2354, plus the margin rule at 2379) is more
   specific than a lone class. It was winning outright — uppercasing every
   result title, forcing 17px/22px, and adding 22px top + 14px side margins
   that broke the row grid. Everything it sets has to be overridden explicitly;
   `all: unset` is not an option here because the clamp needs display. */
.search-results .search-result-title {
    margin: 0;
    padding-bottom: 0;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 16px;
    font-weight: 600;
    line-height: 1.25;
    /* Campaign titles are user-written and many are already shouted in full
       caps. Uppercasing the rest as well removes the only signal left that
       tells one from the other. */
    text-transform: none;
    letter-spacing: normal;
    color: var(--ms-ink-1000, #292929);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.search-result-meta {
    font-size: 13px;
    color: var(--ms-ink-600, #6b6b6b);
}

.search-result-progress {
    position: relative;
    height: 4px;
    width: 100%;
    max-width: 220px;
    background: var(--ms-ink-200, #e0e0e0);
}

.search-result-progress-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    background: #ec6f2b;
}

.search-result-funding {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: right;
}

.search-result-amount {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 17px;
    color: var(--ms-ink-1000, #292929);
    white-space: nowrap;
}

.search-result-pct {
    font-size: 12px;
    font-weight: 700;
    color: #ec6f2b;
}

.search-more-row {
    display: flex;
    justify-content: center;
    margin-top: 20px;
}

.search-more,
.search-browse {
    display: inline-block;
    border: 1.5px solid var(--ms-ink-300, #cfcfcf);
    padding: 10px 20px;
    font-size: 14px;
    font-weight: 600;
    color: var(--ms-ink-1000, #292929);
    text-decoration: none;
}

.search-more:hover,
.search-browse:hover {
    border-color: var(--ms-ink-1000, #292929);
}

.search-empty {
    margin: 20px 0 16px;
    font-size: 15px;
    line-height: 1.5;
    color: var(--ms-ink-700, #4a4a4a);
}

.search-suggest {
    margin-top: 22px;
}

.search-suggest-label {
    margin-bottom: 10px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ms-ink-500, #8a8a8a);
}

.search-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.search-chip {
    display: inline-block;
    border: 1px solid var(--ms-ink-300, #cfcfcf);
    padding: 6px 12px;
    font-size: 13px;
    color: var(--ms-ink-1000, #292929);
    text-decoration: none;
}

.search-chip:hover {
    border-color: var(--ms-ink-1000, #292929);
}

/* Narrow: the 96px thumbnail and the right-hand funding column together leave
   too little for a two-line title, so the funding figures move under the title
   and the row becomes two columns. */
@media (max-width: 480px) {
    .search-result {
        grid-template-columns: 72px 1fr;
        gap: 12px;
        /* Not centred here: once the funding figures wrap onto their own line
           the row is tall enough that a vertically-centred thumbnail floats
           beside the middle of the text instead of reading as the title's
           image. Top alignment ties it back to the title. */
        align-items: start;
    }

    .search-result-media,
    .search-result-image {
        width: 72px;
        height: 45px;
    }

    .search-result-funding {
        grid-column: 2;
        flex-direction: row;
        align-items: baseline;
        gap: 8px;
        text-align: left;
    }

    .search-submit {
        padding: 12px 18px;
    }
}

/* Suodatinchipsit ja sisältöosumat (/haku/) ------------------------------- */

.search-filters {
    margin: 0 0 18px;
}

.search-chip.is-active {
    border-color: var(--ms-ink-1000, #292929);
    background: var(--ms-ink-1000, #292929);
    color: #fff;
}

.search-content {
    margin-top: 32px;
}

/* Two classes for the same reason .search-result-title needs them: `.leftside
   h2` (style.css:2354) would otherwise impose its own margins and size. Here
   the uppercase IS wanted — it matches the section headings elsewhere on the
   site — so only the box model is reset. */
.search-content .search-content-heading {
    margin: 0 0 4px;
    padding-bottom: 0;
    font-size: 13px;
    letter-spacing: 0.06em;
    color: var(--ms-ink-600, #6b6b6b);
}

.search-content-item {
    display: block;
    padding: 12px 0;
    border-bottom: 1px solid var(--border, #e5e5e5);
    color: inherit;
    text-decoration: none;
}

.search-content-item:first-of-type {
    border-top: 1px solid var(--border, #e5e5e5);
}

.search-content-title {
    display: block;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 15px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--ms-ink-1000, #292929);
}

.search-content-item:hover .search-content-title {
    text-decoration: underline;
}

.search-content-excerpt {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-top: 3px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--ms-ink-600, #6b6b6b);
}

/* ============================================================================
   Valmistelussa-näkymä (/kampanjat/preparing/) — vain ylläpidolle
   ---------------------------------------------------------------------------
   Tiivis taulukko sen korttiruudukon tilalle, joka toisti julkisen listauksen
   muotoa ~2000 kertaa. Rivin korkeus n. 34 px vastaan kortin n. 330 px: sama
   joukko mahtuu noin kymmenesosaan pystytilasta.

   Suodattimet ovat radio-inputteja ja sisarvalitsimia, eivät JS:ää —
   <campaign-index-v2> on minifioidussa bundlessa eikä inline-template voi
   lisätä sille uutta reaktiivista propertyä. Radiot kantavat tilan itse.
   ========================================================================= */

/* Sama kuvio kuin .recommendations: grid-item, joka levittäytyy koko riville.
   width + border-box ovat pakolliset — pelkkä grid-column: 1 / -1 jättäisi
   laatikon shrink-to-fit-levyiseksi. */
/* #body-emulate mukaan, koska tasakorkeussääntö
   "#body-emulate:not(:has(.leftside)) .col1 { min-height: 400px }"
   (style.css:658) on spesifisyydeltään (1,2,0) ja pelkkä .col1.prep-admin
   (0,2,0) häviäisi sille — mitattuna laatikko jäi 400 px:iin vaikka taulukko
   oli 188 px, eli kolmen rivin listan alle jäi 200 px tyhjää. Tämä sivu on
   ylläpitolista eikä korttiruudukko, joten rivin tasakorkeus ei koske sitä. */
#body-emulate .col1.prep-admin {
    grid-column: 1 / -1;
    width: 100%;
    box-sizing: border-box;
    background: #fff;
    padding: 20px;
    height: auto;
    min-height: 0;
}

.prep-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}

.prep-admin .prep-heading {
    margin: 0;
    padding-bottom: 0;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 20px;
    line-height: 1.2;
    color: var(--ms-ink-1000, #292929);
}

.prep-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Radiot ovat piilossa mutta eivät display:none — ne pysyvät
   näppäimistöfokusoitavina, ja label toimii klikkialueena. */
.prep-filters input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    pointer-events: none;
}

.prep-filters label {
    display: inline-block;
    border: 1px solid var(--ms-ink-300, #cfcfcf);
    padding: 5px 11px;
    font-size: 13px;
    color: var(--ms-ink-700, #4a4a4a);
    cursor: pointer;
}

.prep-filters label b {
    margin-left: 5px;
    font-variant-numeric: tabular-nums;
}

.prep-filters input[type="radio"]:checked + label {
    border-color: var(--ms-ink-1000, #292929);
    background: var(--ms-ink-1000, #292929);
    color: #fff;
}

.prep-filters input[type="radio"]:focus-visible + label {
    outline: 2px solid var(--ms-cyan-600, #00bcca);
    outline-offset: 1px;
}

/* Taulukko saa vierittyä vaakasuunnassa omassa laatikossaan; sivun runko ei
   koskaan vierry. */
.prep-scroll {
    overflow-x: auto;
}

.prep-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    line-height: 1.35;
}

.prep-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: #fff;
    border-bottom: 1.5px solid var(--ms-ink-1000, #292929);
    padding: 6px 8px;
    text-align: left;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ms-ink-600, #6b6b6b);
    white-space: nowrap;
}

.prep-table td {
    border-bottom: 1px solid var(--border, #e5e5e5);
    padding: 6px 8px;
    vertical-align: top;
}

.prep-table tbody tr:hover {
    background: var(--ms-cyan-50, #f2fbfc);
}

/* --- suodatus: radion tila ohjaa rivien näkyvyyttä -------------------------
   :has() eikä sisarvalitsin ~. Radiot ovat .prep-filters- ja .prep-toolbar
   -kääreiden sisällä, joten ne eivät ole taulukon sisaruksia — "#prep-f-review
   :checked ~ .prep-scroll" ei osunut mihinkään ja koko suodatus jäi
   toimimatta (mitattu: kaikki 5 riviä näkyvissä, kun 2 olisi pitänyt).
   Sitominen esi-isään toimii riippumatta siitä, miten syvälle inputit on
   kääritty. Sama :has()-kuvio on jo käytössä style.css:n
   #body-emulate:not(:has(.leftside)) -säännöissä. */
.prep-admin:has(#prep-f-review:checked) .prep-table tbody tr:not(.is-review),
.prep-admin:has(#prep-f-norewards:checked) .prep-table tbody tr:not(.is-norewards) {
    display: none;
}

/* --- solut ---------------------------------------------------------------- */
.prep-badge {
    display: inline-block;
    padding: 2px 7px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Tarkistusta odottava on ainoa tila joka vaatii toimintaa, joten se on ainoa
   joka saa täyden värin. Oranssi valkoisella on sama pari kuin .statusbox-cta:
   11px lihavoituna se ei ylitä ison tekstin rajaa, joten tausta on tummempi
   --ms-orange-600 kontrastin vuoksi. */
.prep-badge-review {
    background: var(--ms-orange-600, #d95d1a);
    color: #fff;
}

.prep-badge-ready {
    border: 1px solid var(--ms-ink-400, #a8a8a8);
    color: var(--ms-ink-700, #4a4a4a);
}

.prep-badge-draft {
    border: 1px solid var(--border, #e5e5e5);
    color: var(--ms-ink-500, #8a8a8a);
}

.prep-id {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.prep-id a {
    color: var(--ms-ink-600, #6b6b6b);
}

.prep-title {
    min-width: 220px;
}

.prep-title a {
    color: var(--ms-ink-1000, #292929);
    font-weight: 600;
}

.prep-title a.prep-untitled {
    color: var(--ms-ink-400, #a8a8a8);
    font-weight: 400;
}

.prep-tag {
    display: inline-block;
    margin-left: 6px;
    border: 1px solid var(--ms-cyan-500, #00bcca);
    padding: 0 5px;
    font-size: 10px;
    text-transform: uppercase;
    color: var(--ms-cyan-700, #0093a0);
}

.prep-creator {
    min-width: 180px;
}

.prep-creator-name {
    display: block;
    color: var(--ms-ink-1000, #292929);
}

.prep-mail {
    display: block;
    font-size: 12px;
    color: var(--ms-cyan-700, #0093a0);
    word-break: break-all;
}

.prep-mail-alt {
    color: var(--ms-ink-500, #8a8a8a);
}

.prep-goal,
.prep-date {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Mennyt päivämäärä on valmistelussa hyvin tavallinen (1507/2120), joten se ei
   ole virhe vaan lajitteluperuste — merkitään yliviivauksella, ei värillä. */
.prep-date-past {
    color: var(--ms-ink-500, #8a8a8a);
    text-decoration: line-through;
}

.prep-ready {
    white-space: nowrap;
}

.prep-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 3px;
    border: 1px solid var(--ms-ink-400, #a8a8a8);
    border-radius: 50%;
}

.prep-dot.is-on {
    background: var(--ms-ink-1000, #292929);
    border-color: var(--ms-ink-1000, #292929);
}

@media (max-width: 687px) {
    .col1.prep-admin {
        padding: 14px;
    }

    /* Sähköpostit ovat pisin yksittäinen kenttä ja vievät kapealla näytöllä
       koko leveyden; ylläpitäjä pääsee niihin riviltä auki. */
    .prep-creator {
        min-width: 0;
    }

    .prep-mail {
        max-width: 140px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

/* Tyhjät tilat. .prep-empty on oletuksena piilossa ja Vue näyttää
   "ei kampanjoita" -version v-if:llä; suodatinversio nostetaan esiin
   :has()-ehdolla alla. */
.prep-empty {
    margin: 16px 0 0;
    padding: 14px 0 0;
    border-top: 1px solid var(--border, #e5e5e5);
    font-size: 13px;
    color: var(--ms-ink-600, #6b6b6b);
}

.prep-empty-filter {
    display: none;
}

/* Näytetään vain kun aktiivinen suodatin ei osu yhteenkään riviin. Ilman tätä
   suodatin, jonka ehtoa aineisto ei täytä, näyttää täsmälleen samalta kuin
   rikkinäinen sivu — juuri se tapahtui, kun "odottaa tarkistusta" oli oletus ja
   meta.requestReview puuttui vastauksesta.

   ":has(.prep-table tbody tr)" on molemmissa ehtona eikä erillisenä
   kumoavana sääntönä: kumoava versio hävisi spesifisyydessä, koska
   ":has(#prep-f-review:checked)" tuo id-tason (1,3,1) ja pelkillä luokilla
   kirjoitettu kumoaja jäi tasolle (0,4,1). Mitattuna se näytti "rajaus ei osu
   yhteenkään riviin" myös silloin kun rivejä ei ollut haettu lainkaan — eli
   väärän selityksen väärään vikaan. Positiivisena ehtona sitä ei voi hävitä. */
.prep-admin:has(#prep-f-review:checked):has(.prep-table tbody tr):not(:has(.prep-table tbody tr.is-review)) .prep-empty-filter,
.prep-admin:has(#prep-f-norewards:checked):has(.prep-table tbody tr):not(:has(.prep-table tbody tr.is-norewards)) .prep-empty-filter {
    display: block;
}

/* Pikkukuva, vastikepuute ja aloituspäivä (valmistelussa-listaus) ---------- */

.prep-th-thumb {
    width: 64px;
}

.prep-thumb {
    width: 64px;
}

.prep-thumb img {
    display: block;
    width: 64px;
    height: 40px;
    max-width: none;
    object-fit: cover;
    background: var(--ms-ink-100, #f0f0f0);
}

/* Ei paikkamerkkigrafiikkaa kun kuva puuttuu — sijainen peittäisi juuri sen
   signaalin, jota tästä sarakkeesta haetaan. Tyhjä ruutu ja viiva. */
.prep-thumb-none {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 40px;
    border: 1px dashed var(--ms-ink-300, #cfcfcf);
    color: var(--ms-ink-400, #a8a8a8);
    font-size: 12px;
}

/* Vastikkeiden puuttuminen estää hyväksynnän, joten se saa sanan eikä vain
   pistettä. Punainen reunus ilman täyttöä: huomio ilman hälytystä, koska
   valmistelussa se on odotettavaa eikä vika. */
.prep-tag-warn {
    border-color: var(--ms-red-500, #d0021b);
    color: var(--ms-red-500, #d0021b);
}

/* Kolmas tila pisteelle: kenttää ei ole vastauksessa lainkaan, jolloin "ei
   vastikkeita" ja "ei tiedetä" eivät saa näyttää samalta. */
.prep-dot.is-unknown {
    border-style: dashed;
    border-color: var(--ms-ink-300, #cfcfcf);
}

/* Sarakeotsikko on ruudunlukijalle, ei silmälle: pikkukuvasarake on
   itsestäänselvä ja teksti veisi siltä leveyden. */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

/* Esikatselumerkintä valmistelussa olevan kampanjan statuskortissa --------- */

/* Kortin ylälaidassa, ennen kaikkea muuta: se on kehys jonka läpi loput
   luetaan. Tummalla kortilla oranssi täyttö erottuu ilman että se huutaa —
   julkaisematon luonnos ei ole virhetila vaan normaali vaihe. */
.statusbox-preview-note {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
    padding-bottom: 12px;
    border-bottom: 1px solid rgba(255, 255, 255, .15);
}

.statusbox-preview-badge {
    display: inline-block;
    padding: 2px 8px;
    background: var(--ms-orange-600, #d95d1a);
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.statusbox-preview-text {
    font-size: 13px;
    color: rgba(255, 255, 255, .75);
}

/* Aloituspäivä ottaa sen paikan jossa kerätty summa oli, samalla painolla —
   se on ainoa luku jolla on merkitystä ennen käynnistymistä. */
.statusbox-preview-startlabel {
    display: block;
    font-size: 13px;
    color: rgba(255, 255, 255, .75);
}

.statusbox-preview-startdate {
    display: block;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 32px;
    line-height: 1.1;
    color: #fff;
    font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Päävalikko, kaksi tasoa (suunnittelukierros 9A työpöytä / 9B mobiili)
   ---------------------------------------------------------------------------
   Teemat olivat ennen oma .col1.navi2-laattansa valikkokortin vieressä, ja
   yhdeksän templatea sisällytti sen erikseen. Nyt ne ovat saman kortin toinen
   taso: kortti ei kasvata naapuria vaan vaihtaa sisältönsä ja palaa
   "< Valikko" -rivistä.

   Tasonvaihto on valintaruutu + sisarvalitsin, ei JS:ää. Kaksi syytä: <navbar>
   on inline-template minifioidun bundlen komponentin päällä, eikä sille voi
   lisätä reaktiivista propertyä; ja CSP:ssä ei ole 'unsafe-inline'-arvoa
   script-src:ssä, joten inline-skriptikään ei ole vaihtoehto.
   ========================================================================= */

/* (Valintaruutupohjainen tasonvaihto poistettu. Se ei toiminut täällä:
   valikkokortti on <navbar inline-template>, eli Vue omistaa DOM-haaran ja
   luo solmut uudelleen renderöidessään, jolloin checked-tila katosi. Tila on
   nyt .is-themes-luokka, jonka components.js:n delegoitu kuuntelija asettaa.) */

/* (Teematason display: none poistettu — se on nyt display: flex + visibility,
   jotta tasonvaihto voi liukua. Sääntö jäi tähän kuolleena ja luki päinvastoin
   kuin todellisuus.) */

/* Taso 1 jää virtaukseen näkymättömänä, taso 2 asetellaan sen päälle.
   display: none tasolle 1 romahduttaisi kortin korkeuden ja teemataso
   määräisi sen itse — mitattuna 409 px -> 641 px, eli tasan se hyppy jonka
   9A kieltää. Näin kortti on aina täsmälleen sen korkuinen kuin päävalikko
   ja rivin tasakorkeus sen tekevät, riippumatta siitä kumpi taso näkyy. */
/* Tasonvaihto liukuu, ei leikkaa. display: none ei ole animoitavissa, joten
   teemataso on aina DOM:issa ja piilotetaan visibilityllä + siirrolla oikealle:
   visibility poistaa sen myös tabjärjestyksestä ja ruudunlukijalta, toisin
   kuin pelkkä opacity.

   visibilityn transitio on askelfunktio, ei liuku — siksi se ajoitetaan
   viiveellä: piiloon mentäessä vasta liikkeen JÄLKEEN (muuten paneeli katoaisi
   heti ja liuku jäisi näkymättä), esiin tullessa heti (0s).

   Kesto ja käyrä ovat tiedoston omat --motion-fast / --motion-ease, jotta
   tämä kuuluu samaan liikesanastoon kuin numerolaatan ja palkin animaatiot
   eikä ole neljäs irrallinen efekti. */




/* Kortti on 400 px kummassakin tilassa, jotta ruudukkorivi ei hyppää tasoa
   vaihdettaessa — mitattuna se oli 434 px sisällön mukaan, ja teematasolla
   eri. Vain siitä leveydestä ylöspäin jossa ruudukko on monipalstainen:
   kapeammalla kortti saa kasvaa sisällön mukaan kuten ennenkin.
   min-height nollataan erikseen, koska tasakorkeussääntö
   "#body-emulate:not(:has(.leftside)) .col1 { min-height: 400px }"
   (style.css:658) muuten venyttäisi sitä. */
/* Kortin korkeutta EI aseteta tässä lainkaan. Kaksi kokeiltua vaihtoehtoa
   olivat kumpikin väärin, ja molemmat mitattiin:

     height: 400px  → kortti irtosi rivin tasakorkeudesta; naapurilaatta oli
                      492 px ja kortti jäi 92 px lyhyemmäksi kuin rivinsä.
     flex: 1 vapaana → kortti venyi 1017 px:iin, koska ruudukkorivi jossa se
                      on voi olla paljon laattaa korkeampi.

   Oikea korkeus on se jonka #body-emulate:n oma tasakorkeussääntö antaa
   kaikille .col1-laatoille — sama kuin ennen tätä kierrosta. Tasojen
   yhtenäinen korkeus hoidetaan sillä, että kumpikin taso täyttää kortin
   (min-height: 100%), ei sillä että kortille sanellaan pikselimäärä. */
/* Alle 688px:ssä (sama raja kuin muuallakin 1-palstaisen ruudukon kohdalla)
   kortti on täysin päällekkäinen sisällöltään kiinteän palkin
   hampurilaisvalikon kanssa — sama päävalikko, sama Kampanjantekijälle-
   selite+linkit, sama kielivalitsin (ks. sticky_bar.html.twig:n
   .overlay-menu / .overlay-foot). Kortti näytti tälle kohtaa sivua
   kahteen kertaan; piilotettu turhana. */
@media (max-width: 687px) {
    #body-emulate .col1.navi {
        display: none;
    }
}

#body-emulate .col1.navi {
    position: relative;
    overflow: hidden;
}

#body-emulate .col1.navi .navi-level {
    box-sizing: border-box;
    min-height: 100%;
}

#body-emulate .col1.navi {
    position: relative;
}

/* --- Taso 1: aktiivisen kohdan merkki -------------------------------------

   Palkki poistettu: se istui left:0 (kortin reunassa), kun kaikki muu
   kortilla (kielirivi, tilivyöhyke, muiden rivien teksti) alkaa 16 px:n
   sisennyksestä — palkki näytti irralliselta, reunaan livahtaneelta
   yksityiskohdalta eikä osalta samaa 16 px -rytmiä. Oranssi teksti (alla,
   li.current-menu-item > a) riittää yksinään merkiksi. */
.col1.navi #menu-menu > li {
    position: relative;
}

.col1.navi #menu-menu > li.current-menu-item::before,
.col1.navi #menu-menu > li.is-current::before {
    display: none;
}

.col1.navi #menu-menu > li.current-menu-item > a,
.col1.navi #menu-menu > li.is-current > a {
    /* !important: pidetty varotoimena. Väri näytti hetken aikaa hävitetyltä
       yhdessä testiselaimen välilehdessä spesifisyydestä huolimatta — osoittautui
       lopulta pelkäksi vanhentuneeksi CSS-välimuistiksi kyseisessä välilehdessä
       (tuore välilehti näytti oikean oranssin heti ilman !importantia), mutta
       tämä jää tänne ylimääräisenä varmistuksena. */
    color: #ec6f2b !important;
}

/* --- "14 teemaa >" Kampanjat-rivillä ------------------------------------- */

.col1.navi .menu-item--themes {
    display: flex;
    align-items: center;
    gap: 10px;
}

.navi-themes-open,
.overlay-themes-open {
    margin-left: auto;
    padding: 2px 0 2px 8px;
    /* Ilman tätä .navi-themes-open perii style.css:n legacy ".nav {
       font-family: adelle }" -säännön #menu-menu:n kautta (id="menu-menu"
       class="nav") ja renderöityy serif-fontilla, vaikka mikään sääntö ei
       sitä tarkoituksella aseta — mitattu: kortilla "14 teemaa" oli serif,
       overlayssa sans, koska overlaylla ei ole .nav-luokkaa periytymässä.
       Eksplisiittinen sans-arvo pitää molemmat samana eikä nojaa siihen
       mitä esi-isä sattuu asettamaan. */
    font-family: var(--font-sans, "adelle-sans", sans-serif);
    font-size: 12px;
    color: var(--ms-ink-500, #8a8a8a);
    cursor: pointer;
    white-space: nowrap;
    user-select: none;
}

.navi-themes-open:hover,
.overlay-themes-open:hover {
    color: var(--ms-ink-1000, #292929);
}

/* --- Taso 2: teemat, tumma ----------------------------------------------- */

/* Ei negatiivista marginaalia: .col1.navi:n oma padding on 0, joten taso on
   jo valmiiksi kortin reunoissa kiinni. Aiempi margin: -16px oli kompensaatio
   paddingille jota ei ole, ja se veti ylätunnisteen kortin ulkopuolelle —
   "Valikko" ja "TEEMAT" leikkautuivat ylhäältä overflow: hidden -rajauksessa. */
/* --- Tasonvaihdon liike ---------------------------------------------------
   JÄRJESTYS ON MERKITSEVÄ: perustila ensin, :checked-tila heti perään. Nämä
   olivat aiemmin päinvastoin ja hajallaan kolmessa lohkossa, jolloin
   lopputila jäi sekavaksi — mitattuna opacity 0 (perussäännöstä) mutta
   visibility visible (:checked-säännöstä) samaan aikaan, eikä paneeli
   liikkunut lainkaan. Yksi lohko, oikea järjestys, ei arvailua.

   display: none ei ole animoitavissa, joten teemataso on aina DOM:issa ja
   piilotetaan visibilityllä — se poistaa sen myös tabjärjestyksestä ja
   ruudunlukijalta, toisin kuin pelkkä opacity.

   visibilityn siirtymä on askel, ei liuku, joten se ajoitetaan viiveellä:
   piiloon vasta liikkeen JÄLKEEN (muuten paneeli katoaisi heti eikä liukua
   näkisi), esiin heti. Kesto ja käyrä ovat tiedoston omat --motion-fast /
   --motion-ease, jotta tämä kuuluu samaan liikesanastoon kuin muut. */
/* --- Tasonvaihto ja sen liike --------------------------------------------
   Näkyvyys hoidetaan display-vaihdolla ja LIIKE keyframe-animaatiolla, ei
   transitiolla.

   Transitiopohjainen versio ei toiminut: transform jäi pysyvästi alkuarvoonsa
   (316 px) eikä edennyt kohti maalia, vaikka sääntö osui ja voitti kaskadissa
   — sen todisti se, että "transition: none" lennossa asetti arvon välittömästi
   oikein. Siirtymä siis käynnistyi mutta ei koskaan edennyt. Animaatio ei kärsi
   samasta: se ajetaan kun elementti tulee näkyviin, eikä sen tarvitse
   interpoloida piilotetusta lähtötilasta.

   Taso 1 jää virtaukseen näkymättömänä (visibility), jotta kortin korkeus
   pysyy sen määräämänä — display: none tasolle 1 romahduttaisi kortin ja
   teemataso määräisi korkeuden itse (mitattu 409 px -> 641 px). */
.navi-level--dark {
    display: none;
    flex-direction: column;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}

/* Kaksi mahdollista alatasoa: Kampanjat -> teemat, Info -> osion sivut.
   Ulkoasu on yhteinen (--dark), tunniste erillinen, jottei toisen avaaminen
   näytä molempia. */
.col1.navi.is-themes .navi-level--main,
.col1.navi.is-info .navi-level--main {
    visibility: hidden;
}

.col1.navi.is-themes .navi-level--themes,
.col1.navi.is-info .navi-level--info {
    display: flex;
    animation: naviLevelIn var(--motion-fast) var(--motion-ease);
}

@keyframes naviLevelIn {
    from { transform: translateX(100%); opacity: 0; }
    to   { transform: translateX(0);    opacity: 1; }
}

/* Paluu päätasolle: sama liuku peilattuna. components.js lisää
   ".is-returning"-luokan takaisin-painikkeen klikkauksesta ja poistaa sen
   animaation päätyttyä (ks. initStickyMenu). */
.col1.navi.is-returning .navi-level--main {
    animation: naviLevelBackIn var(--motion-fast) var(--motion-ease);
}

@keyframes naviLevelBackIn {
    from { transform: translateX(-100%); opacity: 0; }
    to   { transform: translateX(0);     opacity: 1; }
}

.navi-level--dark {
    height: 100%;
    background: #282828;
    margin: 0;
    padding: 0;
}

.navi-themes-head,
.overlay-head--themes {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    border-bottom: 1px solid rgba(255, 255, 255, .15);
}

.navi-themes-back,
.overlay-themes-back {
    font-size: 12px;
    color: rgba(255, 255, 255, .7);
    cursor: pointer;
    user-select: none;
}

.navi-themes-back:hover,
.overlay-themes-back:hover {
    color: #fff;
}

.navi-themes-title,
.overlay-themes-title {
    margin-left: auto;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 12px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: #fff;
}

/* grid-auto-rows: 1fr jakaa jäljellä olevan korkeuden tasan 14 rivin kesken,
   joten lista täyttää kortin täsmälleen eikä vierry — se oli koko syy tehdä
   teemoista oma taso. */
.navi-themes-list {
    flex: 1;
    display: grid;
    grid-auto-rows: 1fr;
    margin: 0;
    padding: 6px 0;
    list-style: none;
    min-height: 0;
}

.navi-themes-list .navi-theme {
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0;
    border: 0;
}

.navi-themes-list .navi-theme > a {
    display: flex;
    align-items: center;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    padding: 0 12px 0 16px;
    border-left: 3px solid transparent;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 12px;
    line-height: 1.15;
    color: #fff;
    text-decoration: none;
}

.navi-themes-list .navi-theme > a:hover {
    background: rgba(255, 255, 255, .07);
    color: #fff;
}

/* .is-current tulee components.js:n initCurrentCategory():sta — sama merkintä
   jota vanha vaakasirurivi käytti. */
.navi-themes-list .navi-theme > a.is-current {
    background: rgba(255, 255, 255, .07);
    border-left-color: #ec6f2b;
    color: #ec6f2b;
}

/* Päättyneet on tila, ei aihe: viiva erottaa sen teemoista ja väri vaimentaa. */
.navi-theme--ended > a {
    border-top: 1px solid rgba(255, 255, 255, .15);
    color: rgba(255, 255, 255, .65) !important;
}

/* --- 9B: mobiilioverlay, kaksi tasoa ------------------------------------- */

.overlay-level--themes,
.overlay-level--info {
    display: none;
}

.sticky-bar__overlay.is-themes .overlay-level--main,
.sticky-bar__overlay.is-info .overlay-level--main {
    display: none;
}

.sticky-bar__overlay.is-themes .overlay-level--themes {
    display: block;
}

.sticky-bar__overlay.is-info .overlay-level--info {
    display: block;
}

.overlay-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 14px;
    border-bottom: 1px solid var(--border, #e5e5e5);
}

.overlay-brand {
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 13px;
    color: var(--ms-ink-1000, #292929);
}

.overlay-close {
    border: 0;
    background: transparent;
    padding: 0;
    font: inherit;
    font-size: 13px;
    color: var(--ms-ink-600, #6b6b6b);
    cursor: pointer;
}

.overlay-menu {
    display: flex;
    flex-direction: column;
}

/* Rivit ovat 17px display-fonttia ja erottuvat viivalla — sama rytmi kuin
   9B:ssä. Vasemman reunan 3px varaus pitää aktiivisen merkin linjassa. */
.overlay-menu > a,
.overlay-menu-row > a {
    padding: 14px 14px 14px 0;
    border-left: 3px solid transparent;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 17px;
    color: var(--ms-ink-1000, #292929);
    text-decoration: none;
}

.overlay-menu > a,
.overlay-menu-row {
    border-bottom: 1px solid var(--border, #e5e5e5);
}

.overlay-menu > a:last-child,
.overlay-menu-row:last-child {
    border-bottom: 0;
}

.overlay-menu-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding-right: 14px;
}

.overlay-menu-row > a {
    flex: 1;
    border-bottom: 0;
}

.overlay-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    border-top: 1px solid var(--border, #e5e5e5);
    padding: 13px 14px;
    font-size: 14px;
    color: var(--ms-ink-700, #4a4a4a);
}

/* Kaksi vaihtoehtoista ryhmää (anon/authed) — vain toinen näkyvissä
   kerrallaan, ks. components.js:n syncOverlayAuthLinks. Sama gap kuin
   .overlay-foot:n omissa lapsissa, jotta ryhmän linkit istuvat samaan
   riviin muun rivin kanssa saumattomasti. */
.overlay-foot-auth {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
}

/* [hidden] on selaimen OMA, matalan etusijan sääntö — ilman tätä yllä oleva
   author-tyylin display:flex voittaa sen aina, jolloin hidden-attribuutilla
   piilotettu ryhmä näkyisi silti (todennettu: molemmat ryhmät renderöityivät
   yhtä aikaa). Sama author-alkuperä + korkeampi spesifisyys tarvitaan
   voittamaan oma display:flex-sääntö takaisin. */
.overlay-foot-auth[hidden] {
    display: none;
}

/* Kirjautumattoman ryhmä on ainoa jolla on oma selite (label+note), joten
   vain se saa pinota pystyyn — .overlay-foot-auth--authed pysyy yllä
   olevan jaetun säännön rivinä. align-items: flex-start koska teksti on
   nyt vasemmalle tasattu leveä kappale, ei enää yksittäinen inline-rivi. */
.overlay-foot-auth--anon {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
}

/* Sama koko/väri-pari kuin työpöytäkortin .navi-account-label/-note
   (ks. .col1.navi alempana) — sama sisältö, joten sama ulkoasu. */
.overlay-foot-guide-label {
    display: block;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ms-ink-500, #8a8a8a);
}

.overlay-foot-guide-note {
    display: block;
    margin-top: 2px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--ms-ink-700, #4a4a4a);
}

.overlay-foot-guide-links {
    display: flex;
    gap: 10px;
    margin-top: 4px;
}

.overlay-lang {
    display: flex;
    align-items: center;
    gap: 5px;
    margin-left: auto;
    color: var(--ms-ink-500, #8a8a8a);
}

.overlay-lang a {
    color: var(--ms-ink-500, #8a8a8a);
    text-decoration: none;
}

.overlay-lang a[aria-current] {
    color: var(--ms-ink-1000, #292929);
    font-weight: 600;
}

.overlay-level--themes,
.overlay-level--info {
    background: #282828;
}

/* Kaksi palstaa, ei vaakavieritystä. Vanha sirurivi näytti 14 teemasta kolme
   kerrallaan eikä vihjannut lopuista mitenkään; ruudukossa ne ovat kaikki
   näkyvissä yhdellä kertaa. */
.overlay-themes-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    margin: 0;
    padding: 0;
    list-style: none;
}

.overlay-themes-grid .navi-theme {
    margin: 0;
    padding: 0;
    border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.overlay-themes-grid .navi-theme:nth-child(odd) {
    border-right: 1px solid rgba(255, 255, 255, .12);
}

.overlay-themes-grid .navi-theme > a {
    display: block;
    padding: 13px 12px;
    box-shadow: inset 3px 0 0 transparent;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 14px;
    line-height: 1.3;
    color: #fff;
    text-decoration: none;
}

.overlay-themes-grid .navi-theme > a.is-current {
    background: rgba(255, 255, 255, .07);
    box-shadow: inset 3px 0 0 #ec6f2b;
    color: #ec6f2b;
}

.overlay-themes-grid .navi-theme--ended > a {
    border-top: 0;
    font-family: inherit;
    font-size: 13px;
    color: rgba(255, 255, 255, .7) !important;
}

/* --- 9A taso 1: kortin ilme ----------------------------------------------
   Legacy-tyylit tekevät valikosta 26px/600 versaalia oranssia (.nav +
   .nav a, style.css ~2727 ja ~2788), ja korostavat aktiivisen kohdan
   TUMMANHARMAAKSI (li.current-menu-item a { color: #333 }) — eli päinvastoin
   kuin 9A, jossa perusrivi on tummaa 15px display-tekstiä ja aktiivinen on
   oranssi. Kaikki kolme pitää siis kumota erikseen.

   Valitsin on ".col1.navi #menu-menu > li > a" (0,3,2) vastaan ".nav a"
   (0,1,1) ja "li.current-menu-item a" (0,2,1) — voittaa molemmat
   riippumatta tiedostojen latausjärjestyksestä. Rajaus .col1.navi:iin,
   koska .nav-luokkaa käytetään muuallakin. */
.col1.navi #menu-menu {
    font-size: inherit;
    line-height: inherit;
    font-weight: 400;
    margin: 0;
    padding: 8px 0;
    list-style: none;
}

.col1.navi #menu-menu > li {
    margin: 0;
    padding: 0;
}

.col1.navi #menu-menu > li > a {
    display: block;
    /* 3 px merkkipalkin ura + 13 px väli = teksti alkaa 16 px:stä, myös
       silloin kun palkkia ei ole. Ilman uraa aktiivinen rivi hyppäisi
       sivusuunnassa. */
    padding: 5px 16px 5px 16px;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 15px;
    line-height: 1.35;
    font-weight: 400;
    text-transform: none;
    color: var(--ms-ink-1000, #292929);
    text-decoration: none;
    /* Nollaa tokens.css:n yleinen "a:hover { border-bottom-color:
       currentColor }" -alleviivausmekanismi (a { border-bottom: 1px solid
       transparent }) — sama korjaus kuin .navi-account-links a:ssa. */
    border-bottom: 0;
}

.col1.navi #menu-menu > li > a:hover {
    background: var(--ms-ink-100, #f0f0f0);
    color: var(--ms-ink-1000, #292929);
    border-bottom: 0;
}

/* Aktiivinen: oranssi teksti ja oranssi palkki riittävät merkiksi. Vaalea
   rivitausta on nyt yksinomaan :hoverin oma vihje (yllä) — aktiivinen rivi
   ei enää pidä sitä pysyvästi päällä, jottei se sekoitu osoitinpalautteeseen
   silloin kun osoitin ei ole edes rivin päällä. */
.col1.navi #menu-menu > li.current-menu-item > a,
.col1.navi #menu-menu > li.is-current > a {
    /* !important: pidetty varotoimena. Väri näytti hetken aikaa hävitetyltä
       yhdessä testiselaimen välilehdessä spesifisyydestä huolimatta — osoittautui
       lopulta pelkäksi vanhentuneeksi CSS-välimuistiksi kyseisessä välilehdessä
       (tuore välilehti näytti oikean oranssin heti ilman !importantia), mutta
       tämä jää tänne ylimääräisenä varmistuksena. */
    color: #ec6f2b !important;
}

/* Kirjautuneen valikon alaosa (Tee oma kampanja / Omat kampanjani / ...)
   erottuu viivalla ja on pienempää, kuten 9A:ssa — ne ovat oman tilin
   toimintoja, eivät sivuston osioita. Vuen <div v-if> kääre on se, jonka
   sisällä nämä ovat. */
.col1.navi #menu-menu > div {
    border-top: 1px solid var(--border, #e5e5e5);
    margin-top: 9px;
    padding-top: 9px;
}

.col1.navi #menu-menu > div > li > a {
    display: block;
    padding: 2px 16px;
    font-family: inherit;
    font-size: 13px;
    line-height: 1.5;
    text-transform: none;
    color: var(--ms-ink-1000, #292929);
    text-decoration: none;
}

.col1.navi #menu-menu > div > li > a:hover {
    color: #ec6f2b;
}

/* Kielivalitsin kortin alalaitaan, oikeaan alakulmaan — sama FI/EN-
   pistevalikko kuin mobiilivalikon .overlay-lang (sticky_bar.html.twig),
   samaa mieltä kahden valikon välillä. Ei omaa viivaa yläpuolella: rivi
   lukee tilivyöhykkeen (.navi-account) jatkeena eikä uutena osiona — kortti
   sai näin yhden vaakaviivan vähemmän kuin entinen yläreunan langmenu +
   tilivyöhykkeen oma viiva. */
.col1.navi .navi-langmenu {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 6px;
    padding: 8px 16px 16px;
}

.col1.navi .navi-langmenu a {
    font-size: 12px;
    color: #ec6f2b;
    text-decoration: none;
    /* Ks. .navi-account-links a: sama tokens.css:n hover-alleviivauksen nollaus. */
    border-bottom: 0;
}

.col1.navi .navi-langmenu a[aria-current] {
    color: var(--ms-ink-1000, #292929);
    font-weight: 600;
}

.col1.navi .navi-langmenu-sep {
    color: var(--ms-ink-400, #a8a8a8);
    font-size: 12px;
}

/* --- Modaalin otsikkovälistys --------------------------------------------
   Modaali suurentaa perusotsikot omista koistaan: .modal-title on 26 px
   (tokens.css:n h5 on 15 px) ja .signout h6 on 16 px (h6 on 11 px). Koska
   versaalin kirjainväli on kääntäen verrannollinen kokoon, kumpikin siirtyy
   yhden askelman alaspäin tokens.css:n versaaliasteikolla — se on koko
   sääntö, ei modaalikohtainen poikkeus.

   Perusarvot itsessään korjattiin tokens.css:ään (h5 sai --tracking-caps-m:n
   --tracking-overlinen tilalle), joten tämä lohko ei enää paikkaa sivuston
   laajuista ongelmaa vaan pelkän kokoeron. */
.modal-dialog .modal-title {
    letter-spacing: var(--tracking-caps-l);
}

.modal-dialog h6 {
    letter-spacing: var(--tracking-caps-m);
    line-height: 1.35;
}

/* --- Navikortin viimeistely: väri ja yksityiskohdat -----------------------
   Perus-9A oli oikea rakenne mutta liian vaisu: yhtä oranssia korostusta
   lukuun ottamatta kaikki oli mustaa harmaalla. Referenssissä väri kantaa
   merkitystä — oranssi = missä olet, syaani = tilin toiminnot — ja nuolet
   kertovat mikä rivi vie tasolle. Tässä lohkossa vain se; rakenne yllä. */

/* Isompi rivi ja väljempi rytmi. 19px on sama aste kuin sivuston muissa
   display-otsikoissa; 15px luki kortissa alaviitteeltä. */
.col1.navi #menu-menu > li > a {
    padding: 9px 16px;
    font-size: 19px;
    font-weight: 600;
}

.col1.navi #menu-menu > li.current-menu-item::before,
.col1.navi #menu-menu > li.is-current::before {
    height: 24px;
    width: 4px;
}

/* Nuoli rivin oikeassa laidassa. Peri väri linkiltä, jolloin se on oranssi
   aktiivisella rivillä ja harmaa muualla ilman erillistä sääntöä. */
.navi-themes-open {
    display: flex;
    align-items: center;
    padding: 9px 16px 9px 8px;
    color: var(--ms-ink-400, #a8a8a8);
}

.col1.navi #menu-menu > li.is-current .navi-themes-open,
.col1.navi #menu-menu > li.current-menu-item .navi-themes-open {
    color: #ec6f2b;
}

/* Tilin toiminnot ovat syaaneja ja saavat kuvakkeen: ne eivät ole sivuston
   osioita vaan sinun omia toimintojasi, ja väri erottaa ne ilman otsikkoa.
   Erotinviiva samaa syaania vaimennettuna. */
.col1.navi #menu-menu > div {
    border-top: 1px solid var(--ms-cyan-300, #7fd8e0);
}

.col1.navi #menu-menu > div > li > a {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 16px;
    font-size: 15px;
    color: var(--ms-cyan-700, #0093a0);
}

.col1.navi #menu-menu > div > li > a:hover {
    color: var(--ms-cyan-800, #007680);
}

.col1.navi #menu-menu > div > li > a svg {
    flex: none;
}

/* --- Teemataso: väljemmät rivit, nuoli aktiivisella, näytä kaikki -------- */

.navi-themes-head {
    padding: 11px 16px;
}

.navi-themes-back {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 15px;
}

.navi-themes-title {
    font-size: 13px;
}

/* Ei enää grid-auto-rows: 1fr — se puristi 14 riviä 25 px:iin. Kiinteä
   rivikorkeus, yhdeksän näkyvissä, loput "Näytä kaikki" -rivin takana. */
.navi-themes-list {
    display: block;
    flex: 1;
    padding: 0;
    overflow: hidden;
}

/* Mitoitettu niin että kaikki 14 riviä mahtuvat kortin korkeuteen ilman
   vieritystä: kortti on rivin korkuinen (~409 px), otsikkorivi vie ~44,
   joten riville jää noin 26 px. 14px/600 sopii siihen ja pysyy selvästi
   isompana kuin sivuston 13px-apuotsikot. */
.navi-themes-list .navi-theme > a {
    height: auto;
    padding: 3px 12px 3px 16px;
    border-left-width: 4px;
    font-size: 14px;
    line-height: 1.2;
    font-weight: 600;
}



/* Nuoli aktiivisen teeman perään, samalla logiikalla kuin päävalikossa. */
.navi-themes-list .navi-theme > a.is-current::after {
    content: "";
    margin-left: auto;
    width: 8px;
    height: 8px;
    border-top: 2.5px solid #ec6f2b;
    border-right: 2.5px solid #ec6f2b;
    transform: rotate(45deg);
}

.navi-themes-list .navi-theme > a {
    display: flex;
    align-items: center;
}



/* Rivirytmi mitoitettu siihen, että kortti mahtuu 400 px:iin myös
   kirjautuneena, jolloin alaosassa on neljä kohtaa kahden sijaan —
   mitattuna 19px/9px leikkasi "Rekisteröidyn" jo kirjautumattomana.
   Kortti ei saa vieriä: se on 400 px, koska ruudukkorivi ei saa hypätä
   tasoa vaihdettaessa (9A). */
.col1.navi #menu-menu > li > a {
    padding: 6px 16px;
    font-size: 18px;
}

.col1.navi #menu-menu > div {
    margin-top: 6px;
    padding-top: 6px;
}

.col1.navi #menu-menu > div > li > a {
    padding: 4px 16px;
    font-size: 14px;
}

.col1.navi .navi-langmenu {
    padding: 6px 16px 16px;
}

.col1.navi .loggedin {
    padding: 2px 16px 6px;
}

.navi-themes-open {
    padding: 6px 16px 6px 8px;
}

/* --- 9B: tason 1 pohja valkoiseksi ----------------------------------------
   Overlay on ollut tumma (rgb(43,43,43)), ja tyylitin tason 1 sisällön 9B:n
   mukaan vaalealle pohjalle — mutta pohjaa ei vaihdettu. Tulos oli mustaa
   mustalla: mitattuna KYMMENEN elementtiä kontrastilla 1,33-2,65, eli
   valikon jokainen rivi, tunnus, Sulje ja kielivalitsin. Yksi puuttuva
   taustaväri, kymmenen lukukelvotonta riviä.

   9B:ssä taso 1 on valkoinen ja taso 2 tumma, mikä on myös se mitä
   työpöytäkortti tekee — sama kaksijakoisuus molemmissa. Tausta annetaan
   tasoille eikä overlaylle, jotta ne voivat olla eri värisiä. */
.overlay-level--main {
    background: rgba(255, 255, 255, 1);
    /* Sama varjo kuin .sticky-bar:ssa — valkoinen paneeli tarvitsee saman
       vihjeen kelluvasta reunasta kuin kiinteä palkki, muuten se päättyy
       teräväksi rajaksi tumman overlay-taustan päälle. */
    box-shadow: 0 2px 8px rgba(0, 0, 0, .22);
}

.overlay-level--themes,
.overlay-level--info {
    background: rgba(40, 40, 40, .94);
}

/* Ei enää ".sticky-bar__overlay:not(.is-themes) { background: #fff }"
   -kikkaa: se oletti overlayn olevan sisältönsä mittainen (vain kapea reuna
   tasojen alla saattoi näyttää overlayn oman taustan), mikä piti paikkansa
   ennen kuin overlaylle annettiin "bottom: 0" (taso 2/2b:n korkeusbugin
   korjaus, ks. yllä) — sen jälkeen overlay on aina koko ruudun korkuinen, ja
   sääntö maalasi valkoisen koko ruudun yli tason 1 alle, myös kaukana
   valikkosisällön alapuolella. Overlayn oma #2b2b2b (perussääntö yllä) on nyt
   oikea oletus aina: tason 1 oma valkoinen tausta + varjo riittää erottamaan
   sen, eikä tumma tausta sen alla ole enää virhe vaan haluttu efekti. */

/* Aktiivinen teema tummalla tasolla: --ms-orange-500 antaa 14px:n tekstille
   vain 3,05:1 (mitattu), mikä riittää vain isolle tekstille. Vaaleampi
   --ms-orange-300 nostaa sen selvästi yli 4,5:1 rajan säilyttäen värin
   merkityksen. Sama koskee työpöytäkortin teematasoa, joka on yhtä tumma. */
.overlay-themes-grid .navi-theme > a.is-current,
.navi-themes-list .navi-theme > a.is-current {
    color: var(--ms-orange-300, #f3a574);
}

.navi-themes-list .navi-theme > a.is-current::after {
    border-top-color: var(--ms-orange-300, #f3a574);
    border-right-color: var(--ms-orange-300, #f3a574);
}

/* Vanha ".sticky-bar__overlay a { color: #fff }" (rivi ~543) värittää kaikki
   overlayn linkit valkoisiksi — se oli oikein kun koko overlay oli tumma.
   Tason 1 valkoisella pohjalla se tarkoittaa valkoista valkoisella:
   mitattuna kontrasti 1,0 (eli sama väri) linkeillä kirjaudu, Rekisteröidy
   ja FI. Kaksi luokkaa voittaa yhden luokan + elementin. */
.overlay-level--main a {
    color: var(--ms-ink-1000, #292929);
}

.overlay-foot a {
    color: var(--ms-cyan-700, #0093a0);
    font-family: inherit;
    font-size: 14px;
}

.overlay-foot a:hover {
    color: var(--ms-cyan-800, #007680);
}

/* Kielivalitsin: valittu tumma, toinen linkkisyaani. Oranssi jäi tässä
   3,05:1:een valkoista vasten (mitattu), mikä ei riitä 14px:n tekstille. */
.overlay-lang a {
    color: var(--ms-cyan-700, #0093a0);
}

.overlay-lang a[aria-current] {
    color: var(--ms-ink-1000, #292929);
    font-weight: 600;
}

.overlay-lang-sep {
    color: var(--ms-ink-400, #a8a8a8);
}

/* Kolmen luokan ketju, koska legacy ".sticky-bar__overlay-lang a" voitti
   kahden luokan version — mitattuna FI jäi valkoiseksi valkoisella (1,0).
   Sama oranssi kuin valikkokortin kieli- ja tili-linkeissä (.col1.navi
   .langmenu a / .navi-account-links a, molemmat #ec6f2b) — synkronoi kahden
   valikon ulkoasun täsmälleen. HUOM: #ec6f2b jää 3,05:1:een valkoista
   vasten, alle WCAG AA:n 4,5:1-vaatimuksen 14px:n tekstille — sama mittaus
   kuin kortilla, jolla on jo tämä sama puute. Tietoinen valinta
   yhdenmukaisuuden vuoksi, ei korjattu tässä. */
.overlay-level--main .overlay-foot a,
.overlay-level--main .overlay-lang a {
    color: var(--brand, #ec6f2b);
}

.overlay-level--main .overlay-foot .sticky-bar__overlay-signin:hover,
.overlay-level--main .overlay-foot .sticky-bar__overlay-signup:hover {
    color: var(--ms-cyan-400, #61c8d5);
}

.overlay-level--main .overlay-lang a[aria-current] {
    color: var(--ms-ink-1000, #292929);
    font-weight: 600;
}

.overlay-level--main .overlay-lang-sep {
    color: var(--ms-ink-600, #6b6b6b);
}

/* Legacy "li#menu-item-1077" (style.css:2739) piirtää Haku-riville oman
   syaanin alaviivan ja 52 px alapaddingin — se oli vanhassa kortissa se
   erotin joka päätti sivuston osiot. Nyt erotin on tilitoimintojen
   yläreunassa (#menu-menu > div), joten viivoja oli kaksi kuuden pikselin
   päässä toisistaan, ja ylempi näytti kuuluvan Haku-riville. Poistetaan
   legacy-viiva ja sen paddingi; ID-valitsin vaatii ID:n myös tässä. */
.col1.navi #menu-menu > li#menu-item-1077 {
    padding-bottom: 0;
    border-bottom: 0;
    margin-bottom: 0;
}

/* Kaksitasoisena sisältö on paneeli, jonka pitää ulottua reunaan asti —
   mitattuna taso 1 alkoi x=16 ja päättyi x=374 390 px:n ruudulla. Sivut ja
   alaosa nollataan ja rivien oma padding hoitaa sisennykset.

   Ylätila väistää kiinteän palkin, jonka korkeus on mitattava uudelleen
   (bar.getBoundingClientRect().height) aina kun logon/hampurilaisen
   korkeus muuttuu — tämä EI seuraa .sticky-bar:n omaa korkeutta
   automaattisesti (fixed-position sisarukset, ei document flow'ta), joten
   pysyy jäljessä hiljaa jos vain toista muutetaan. 59px on tämänhetkinen
   palkin korkeus (7px+7px padding + 40px logo/45px hampurilainen rivi
   korkeimman elementin mukaan pyöristettynä ylös). Vanha arvo (66px) oli
   3–7px liikaa ja jätti näkyvän raon palkin ja overlayn väliin. */
.sticky-bar__overlay {
    padding: 59px 0 0;
    gap: 0;
}

/* Paneeli täyttää jäljelle jäävän korkeuden, jolloin tumma teematasokin
   ulottuu alareunaan asti eikä jätä kaistaletta. */
.overlay-level {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

/* Paneeli sisällön korkuiseksi, ei venytettynä: flex: 1 jätti valikon alle
   tyhjää ruudun loppuun asti, koska taso 1 on lyhyempi kuin ruutu. Vieritys
   jää tarpeen varalle (pitkä valikko kirjautuneena, matala ruutu). */
.overlay-level {
    flex: 0 0 auto;
    max-height: 100%;
    overflow-y: auto;
}

/* Teematason ruudukko saa täyttää loppuruudun, koska se on tumma paneeli
   jonka reunan pitää olla ruudun reunassa — vaalea taso 1 sen sijaan päättyy
   sisältöönsä. */
.overlay-level--themes,
.overlay-level--info {
    flex: 1 1 auto;
}

/* Tiiviimpi rivijako. 17px/14px oli väljä ruudulla jossa rivejä on kuusi
   plus alarivi; 16px ja pienempi pystypadding tuo koko valikon kerralla
   näkyviin myös matalilla puhelimilla. */
.overlay-menu > a,
.overlay-menu-row > a {
    padding: 10px 14px 10px 16px;
    font-size: 16px;
    line-height: 1.3;
}

.overlay-head {
    padding: 10px 14px;
}

/* Sulje yksin rivillä, oikeaan laitaan. */
.overlay-head--main {
    justify-content: flex-end;
}

.overlay-foot {
    padding: 11px 14px;
}

/* ============================================================================
   Valikkokortti spesifikaation mukaan (suunnittelukierros 14A / 14B)
   ---------------------------------------------------------------------------
   Korvaa aiemman "enemmän väriä" -viimeistelyn, joka meni kolmessa kohdassa
   ohi spesifikaation ja kasvatti kortin yli yhden laatan korkeuden:

     - Rivit 18-19px. 14A sanoo 15px; isompi koko oli se, mikä ei mahtunut
       400 px:iin kirjautuneena (mitattuna "Rekisteröidy" leikkautui).
     - Tilikohdat syaanilla. Spesifikaatiossa syaani on HOVER-tila; linkin
       perustila on oranssi.
     - Tervehdys valui Haku-rivin päälle ja siinä oli emoji. Tili on nyt oma
       vyöhykkeensä 1,5 px viivan alla, ja tila merkitään syaanilla neliöllä.

   Korkeusbudjetti 400 px:ään: kielirivi 33 + navigaatio 196 + tili 146 = 375.
   ========================================================================= */

/* --- Navigaatio ---------------------------------------------------------- */
.col1.navi #menu-menu {
    padding: 8px 0;
}

/* Etusivu (ensimmäinen rivi) 4px alemmas — pyydetty suoraan. */
.col1.navi #menu-menu > li:first-child {
    margin-top: 4px;
}

.col1.navi #menu-menu > li > a {
    padding: 6px 16px 6px 16px;
    font-size: 15px;
    font-weight: 500;
    line-height: 0.9;
}

.col1.navi #menu-menu > li.current-menu-item::before,
.col1.navi #menu-menu > li.is-current::before {
    width: 3px;
    height: 17px;
}

/* "14 teemaa >" on 12px harmaata, ei nuoli-ikoni. */
.navi-themes-open {
    padding: 5px 16px 5px 8px;
    font-size: 12px;
    color: var(--ms-ink-500, #8a8a8a);
}

.col1.navi #menu-menu > li.is-current .navi-themes-open,
.col1.navi #menu-menu > li.current-menu-item .navi-themes-open {
    color: var(--ms-ink-500, #8a8a8a);
}

/* --- Tilivyöhyke --------------------------------------------------------- */

/* Kiinteä 2 em -väli yläpuolella navigaation jälkeen, EI enää margin-top:
   auto. Auto työnsi lohkon aina kortin ehdottomaan alalaitaan riippumatta
   rivimäärästä yläpuolella — kun kortin oma rivikorkeus (min-height: 100%,
   naapurilaatan sanelemana) on navigaation+tilin yhteenlaskettua korkeutta
   suurempi, koko ylijäämä kertyi näkymättömästi TÄMÄN lohkon YLÄPUOLELLE.
   Kiinteä väli jättää ylijäämän sen sijaan näkyväksi tilaksi kortin
   ALALAITAAN, tilivyöhykkeen alle — rehellisempi kuin nielty väli, eikä
   vyöhyke enää roiku kiinni ihan reunassa. 1,5 px viiva on spesifikaation
   raja navigaation ja tilin välillä — paksumpi kuin rivien 1 px, jotta se
   lukee vyöhykkeen rajana eikä listan erottimena.

   Negatiivinen margin-bottom vetää .navi-langmenun tarkoituksella päällekkäin
   tämän lohkon alapaddingin kanssa — kielirivi ja tilivyöhyke saavat jakaa
   saman alalaidan tilan sen sijaan että kumpikin varaisi oman.

   position: relative + z-index: 1 tässä (langmenu jää oletus-z:hen) keeps
   this block's TEXT painting over .navi-langmenu in the overlap, which is
   what the negative margin above is for. It used to also decide which
   block WON CLICKS in the overlap — whichever had the higher effective
   z-index took every click there, link or not. That flipped the bug
   instead of fixing it: raising this block above langmenu fixed "Kirjaudu
   ulos" (previously swallowed by langmenu) but then swallowed FI/EN
   itself — verified, clicking "FI"/"EN" opened the register modal.
   pointer-events: none here (with pointer-events: auto restored on this
   block's own <a> tags, right below) takes stacking out of the click
   question entirely: this block's empty space no longer intercepts
   anything, so a click always reaches whichever link — this block's own,
   or langmenu's beneath — actually sits under the pointer. */
.col1.navi .navi-account {
    position: relative;
    z-index: 1;
    margin-top: 14px;
    border-top: 1.5px solid var(--border, #e5e5e5);
    padding: 12px 16px 0px;
    margin-bottom: -1.2em;
    pointer-events: none;
}

.col1.navi .navi-account a {
    pointer-events: auto;
}

.col1.navi .navi-greeting {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0 0 8px;
    padding: 0;
    font-size: 13px;
    line-height: 1.35;
    color: var(--ms-ink-700, #4a4a4a);
}

/* Syaani neliö emojin tilalla. */
.col1.navi .navi-greeting::before {
    content: "";
    width: 7px;
    height: 7px;
    flex: none;
    background: var(--accent, #00bcca);
}

.col1.navi .navi-account-label {
    margin-bottom: 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--ms-ink-500, #8a8a8a);
}

.col1.navi .navi-account-note {
    margin: 0 0 8px;
    padding: 0;
    font-size: 12px;
    line-height: 1.45;
    color: var(--ms-ink-600, #6b6b6b);
    text-wrap: pretty;
}

/* Harmaa pystyviiva sitoo tilikohdat yhteen ryhmäksi ilman omaa otsikkoa.
   align-items: flex-start keeps each <li>/<a> sized to its own text
   instead of the flex column's default stretch-to-full-width — mostly
   cosmetic now that .navi-account (see above) handles the click-through
   itself, but it also keeps hover/focus outlines fitted to the visible
   link text rather than the full card width. */
.col1.navi .navi-account-links {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    margin: 0;
    padding: 0 0 0 11px;
    border-left: 3px solid var(--ms-ink-200, #e0e0e0);
    list-style: none;
}

.col1.navi .navi-account-links li {
    margin: 0;
    padding: 0;
}

.col1.navi .navi-account-links a {
    display: block;
    padding: 0;
    font-family: inherit;
    font-size: 13px;
    line-height: 1.3;
    text-transform: none;
    color: #ec6f2b;
    text-decoration: none;
    /* Nollaa tokens.css:n yleinen "a:hover { border-bottom-color:
       currentColor }" -alleviivausmekanismi (a { border-bottom: 1px solid
       transparent }) — se piirsi tummanharmaan/syaanin viivan koko rivin
       levyiselle linkkielementille hoverissa, kun perustila jo hoitaa
       hover-vihjeen värillä. */
    border-bottom: 0;
}

/* Syaani on hover, ei perustila. */
.col1.navi .navi-account-links a:hover {
    color: var(--ms-cyan-400, #61c8d5);
    border-bottom: 0;
}

/* Nykyisen sivun merkki tilikohdissa, sama idea kuin päävalikon
   current-menu-item:ssa. Väri ei voi kantaa merkitystä täällä (linkit ovat
   jo oletuksena oranssia), joten lihavointi hoitaa saman roolin. */
.col1.navi .navi-account-links li.current-menu-item > a {
    font-weight: 700;
}

/* Kirjautuneen ensisijainen toiminto. Sama oranssi ja sama muoto kuin
   sivuston muissa päätoiminnoissa (.creator-cta-button, etusivun kortin
   painike), pienennettynä valikkokortin mittakaavaan. Kolmasosaleveä —
   täysleveä versio luki liian raskaalta kapealla kortilla.

   Sticky barin CTA vaihtuu kirjautuneelle samaan "Luo kampanja" -tekstiin
   (sticky_bar.html.twig, data-auth-label), joten päätoiminto on sama
   molemmissa valikoissa eikä kahta eri ensisijaista polkua synny.

   width: auto + inline-block sen sijaan että pakotettaisiin prosenttiluku:
   33% katkaisi "Tee oma kampanja" -tekstin kahdelle riville kapealla
   kortilla. Sisältöön sovittuva leveys pysyy aina yhdellä rivillä
   riippumatta tarkasta tekstin/fontin mitasta. */
.col1.navi .navi-account-cta {
    display: inline-block;
    width: auto;
    white-space: nowrap;
    margin: 0 0 10px;
    padding: 9px 12px;
    background: #ec6f2b;
    color: #fff;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 14px;
    font-weight: 600;
    line-height: 1.2;
    text-align: center;
    text-decoration: none;
    border-bottom: 0;
    transition: background-color var(--motion-fast) var(--motion-ease);
}

.col1.navi .navi-account-cta:hover {
    background: #d85f1d;
    color: #fff;
}

/* Loput tilikohdat harmaiksi: oranssi on nyt varattu ensisijaiselle
   toiminnolle, ja neljä samanarvoista oranssia riviä oli juuri se mikä teki
   kirjautuneen valikosta järjestämättömän. Syaani hover säilyy — se on
   sivustolla tilin toimintojen väri. */
.col1.navi .navi-account-links--secondary a {
    color: var(--ms-ink-700, #4a4a4a);
}

.col1.navi .navi-account-links--secondary a:hover {
    color: var(--ms-cyan-400, #61c8d5);
}

/* Uloskirjautuminen ei ole sivuston toiminto vaan istunnon päättäminen —
   harmaa ja hieman erotettuna muista. */
.col1.navi .navi-account-signout {
    padding-top: 4px !important;
}

.col1.navi .navi-account-signout a {
    color: var(--ms-ink-600, #6b6b6b);
}

/* Taso 1 flex-pylvääksi, jotta .navi-account:n margin-top: auto työntää
   tilivyöhykkeen kortin alalaitaan. Ilman tätä taso on display: block ja
   auto-marginaali laskee nollaksi — mitattuna vyöhyke jäi kiinni
   navigaatioon eikä kortin alareunaan, jolloin 14A:n "oma vyöhyke" -jako ei
   näkynyt lainkaan lyhyellä valikolla. */
.navi-level--main {
    display: flex;
    flex-direction: column;
}

/* Sama liuku mobiilioverlaylle. Siellä kontrasti on suurin — valkoinen
   päätaso ja musta teemataso vaihtuvat koko ruudun kokoisina, ja kova
   leikkaus niiden välillä oli se mikä tuntui kömpelöltä. */
.overlay-level--themes,
.overlay-level--info {
    display: none;
    position: absolute;
    top: 66px;
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: auto;
    background: rgba(40, 40, 40, .94);
}

.sticky-bar__overlay.is-themes .overlay-level--main,
.sticky-bar__overlay.is-info .overlay-level--main {
    display: none;
}

.sticky-bar__overlay.is-themes .overlay-level--themes {
    display: block;
    animation: naviLevelIn var(--motion-fast) var(--motion-ease);
}

.sticky-bar__overlay.is-info .overlay-level--info {
    display: block;
    animation: naviLevelIn var(--motion-fast) var(--motion-ease);
}

/* Paluu päätasolle: sama liuku peilattuna, ks. .col1.navi.is-returning
   yllä samasta syystä. */
.sticky-bar__overlay.is-returning .overlay-level--main {
    animation: naviLevelBackIn var(--motion-fast) var(--motion-ease);
}

/* Rivien osoitinpalaute: tausta ja merkkipalkin väri liukuvat, jolloin
   hover ei ole yhtä napsahtava kuin ennen. Vain väri ja tausta — mitään ei
   liikuteta, koska rivin siirtyminen hoverissa on levotonta listassa. */
.col1.navi #menu-menu > li > a,
.navi-themes-list .navi-theme > a,
.overlay-themes-grid .navi-theme > a,
.col1.navi .navi-account-links a {
    transition: background-color var(--motion-fast) var(--motion-ease),
                color var(--motion-fast) var(--motion-ease);
}

/* "14 teemaa ›" nykäisee hieman oikealle, kun rivi on osoitettuna: se on
   vihje siitä mihin suuntaan taso avautuu. */
.navi-themes-open,
.overlay-themes-open {
    transition: color var(--motion-fast) var(--motion-ease),
                transform var(--motion-fast) var(--motion-ease);
}

.col1.navi .menu-item--themes:hover .navi-themes-open,
.overlay-menu-row:hover .overlay-themes-open {
    transform: translateX(3px);
}

/* Liike pois, tila jää: kaikki päätyvät samaan lopputilaan ilman siirtymää. */
@media (prefers-reduced-motion: reduce) {
    .navi-level--main,
    .navi-level--themes,
    .navi-level--info,
    .overlay-level--main,
    .overlay-level--themes,
    .overlay-level--info,
    .navi-themes-open,
    .overlay-themes-open {
        transition: none;
    }

    .col1.navi.is-returning .navi-level--main,
    .sticky-bar__overlay.is-returning .overlay-level--main {
        animation: none;
    }

    .col1.navi .menu-item--themes:hover .navi-themes-open,
    .overlay-menu-row:hover .overlay-themes-open {
        transform: none;
    }
}

/* Päävalikon rivit vielä isommiksi: 18 -> 23 px. Rivinväli tiivistetty
   samalla (1,35 -> 1,2 yllä), joten iso koko ei syö riviä yhtä paljon kuin
   suoraan skaalattuna — rivi on nyt 6 + 23*1,2 + 6 = 39,6 px, kuusi riviä
   ~238 px. Kortti kasvaa tämän myötä korkeammaksi kuin naapurilaattansa,
   mikä on tarkoituksellista tässä layoutissa (ei enää yhteiskorkeuspakko,
   ks. .navi-account:n kiinteä margin-top yllä) — kortilla oli mitattu
   ylimääräistä tilaa naapureihinsa nähden ennen tätäkin muutosta. */
.col1.navi #menu-menu > li > a {
    font-size: 23px;
}

.col1.navi #menu-menu > li.current-menu-item::before,
.col1.navi #menu-menu > li.is-current::before {
    height: 19px;
}


/* Tasonvaihdon painikkeet olivat <label>-elementtejä; nyt ne ovat <button>,
   koska tila ei enää ole valintaruudussa vaan luokassa (ks. initNaviLevels()
   components.js:ssä). Selaimen oma painiketyyli pitää nollata. */
button.navi-themes-open,
button.navi-themes-back,
button.overlay-themes-open,
button.overlay-themes-back {
    border: 0;
    background: transparent;
    font: inherit;
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
}

/* "font: inherit" yllä nollaa KOKO fonttilyhenteen, myös font-family — se
   ottaa sen käytöstä poistuneen selaimen napkinityylin sijaan esi-isältä,
   ja työpöytäkortilla se esi-isä on "#menu-menu.nav" (style.css:n legacy
   ".nav { font-family: adelle }"), joten "14 teemaa"/"5 sivua" palasi
   serifiksi tästä säännöstä huolimatta että se on kirjoitettu alempaan
   .navi-themes-open/.overlay-themes-open-sääntöön (rivi ~2200): tämä
   button.*-valitsin on erikoisempi (elementti+luokka) ja tulee myöhemmin,
   joten se voittaa. Sama eksplisiittinen sans tähänkin, jottei se enää
   riipu esi-isän fontista. */
button.navi-themes-open,
button.overlay-themes-open {
    font-family: var(--font-sans, "adelle-sans", sans-serif);
}

button.navi-themes-back,
button.overlay-themes-back {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0;
}

/* ==========================================================================
   Profile page forms (edit profile / change password)
   ---------------------------------------------------------------------------
   These were bare, unstyled legacy markup (no field borders, no spacing
   rhythm — labels sat flush against inputs with a stray light-blue browser
   autofill tint as the only visual cue). Restyled to match the site's two
   other reference forms rather than invent a third look: field structure
   and values from #pledgeform (reward-view.css — the final pledge/"rahoita"
   step), submit-button prominence from the same source, general clean-input
   spirit shared with .search-field (search.html.twig / components.css).
   ========================================================================== */
.profileupdateform,
.passwordupdateform {
    max-width: 420px;
    margin: 12px 0 24px 14px;
}

.profileupdateform fieldset,
.passwordupdateform fieldset {
    border: 0;
    margin: 0 0 14px;
    padding: 0;
    min-width: 0;
}

.profileupdateform fieldset > label,
.passwordupdateform fieldset > label {
    display: block;
    font-family: var(--font-sans, "adelle-sans", sans-serif);
    font-size: 13px;
    font-weight: 600;
    color: var(--ms-ink-1000, #292929);
    margin: 0 0 4px;
    text-transform: none;
}

.profile-field {
    box-sizing: border-box;
    width: 100%;
    height: 44px;
    padding: 0 12px;
    font-size: 16px;
    font-family: var(--font-sans, "adelle-sans", sans-serif);
    color: var(--ms-ink-1000, #292929);
    background: #fff;
    border: 1px solid var(--ms-ink-300, #C0C0C0);
    border-radius: 4px;
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
}

.profile-field:focus {
    outline: none;
    border-color: var(--ms-cyan-600, #1BA3B0);
    box-shadow: 0 0 0 2px var(--ms-cyan-50, #E8F6F8);
}

.profile-field.error {
    border-color: #cc3333;
}

.profileupdateform fieldset > label.error,
.passwordupdateform fieldset > label.error {
    display: block;
    color: #cc3333;
    font-size: 12px;
    font-weight: 400;
    margin: 4px 0 0;
    text-transform: none;
}

.profile-form-actions {
    display: flex;
    gap: 10px;
    margin-top: 4px;
}

/* Ei omaa font-familya: legacy "button.submit { font-family: adelle }"
   (style.css) periytyy tänne ja renderöityy luotettavasti (todennettu vierekkäin
   "Vaihda salasanani" -painikkeen kanssa). "adelle-sans" tässä kohtaa renderöityi
   geneerisenä selaimen oletusfonttina — Typekit ei ilmeisesti ollut hakenut
   sitä painoa/tyyliä tälle uudelle valitsimelle. */
.profile-form-actions .button.submit {
    height: auto;
    padding: 11px 20px;
    font-size: 14px;
}

/* ==========================================================================
   Homepage "Miten se toimii?" — rahoittaja/tekijä-rinnakkaislohkot
   ---------------------------------------------------------------------------
   Korvaa yhden pitkän, vain tekijän polkua kuvanneen kappaleen kahdella
   lyhyemmällä, rinnakkaisella lohkolla (rahoittaja + tekijä). Pinoutuu
   yhdeksi palstaksi kapealla näytöllä, samalla rajalla kuin muu sivusto
   (687px). ========================================================================== */
.how-it-works-split {
    display: flex;
    gap: 32px;
    margin-top: 8px;
}

.how-it-works-col {
    flex: 1 1 0;
    min-width: 0;
    border-left: 3px solid var(--ms-ink-200, #e0e0e0);
    padding-left: 14px;
}

/* Rahoittaja/tekijä-lohkot erotellaan värikoodilla: oranssi (brand) on jo
   sivun ensisijainen toimintaväri, syaani sen vakiovastapari (ks. mm.
   .navi-account-links a:hover). */
.how-it-works-col:first-child {
    border-left-color: var(--brand, #ec6f2b);
}

.how-it-works-col:last-child {
    border-left-color: var(--ms-cyan-600, #00bcca);
}

/* Vaalea, ei tumma: .col2c.statement.noste on tumma kortti (valkoinen
   leipäteksti, style.css:n .col2c.statement p { color: white }) — tumma
   ms-ink väri oli lähes lukukelvoton tummaa taustaa vasten, mitattu. */
.how-it-works-col h4 {
    margin: 0 0 6px;
    font-family: var(--font-display, "Adelle", Georgia, serif);
    font-size: 17px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.75);
}

.how-it-works-col p {
    margin: 0;
}

@media (max-width: 687px) {
    .how-it-works-split {
        flex-direction: column;
        gap: 16px;
    }
}

/* Kortti kääntyi vaaleaksi: valkoinen tausta, musta teksti — päinvastoin
   kuin yllä oleva "Vaalea, ei tumma" -kommentti kuvaa (kortti oli silloin
   tumma). .col2c (valkoinen) ja .noste (tumma #292929) ovat molemmat yhden
   luokan taustavärisääntöjä samasta tiedostosta (style.css) — kolme luokkaa
   voittaa kummankin varmasti sen sijaan että lähdejärjestys ratkaisisi.
   .col2c.statement.noste h1/h3 -selektoreillä on jo oma sääntönsä
   style.css:ssä (väri mm. h1:lle); tämä tulee myöhemmin komponenttitiedostossa
   ja samalla spesifisyydellä, joten se voittaa lähdejärjestyksellä. */
.col2c.statement.noste {
    background-color: #fff;
}

.col2c.statement.noste h1,
.col2c.statement.noste p {
    color: #111;
}

/* Every <p> in this card is immediately followed by an <h3> ("Kenelle?" or
   "Miten se toimii?"), so tightening the gap before each heading means
   tightening tokens.css's site-wide "p { margin-bottom: 16px }" baseline,
   scoped to just this card. The whole .col2c.statement.noste box ran 21px
   over the homepage's 400px row baseline; first attempt tried the
   headings' own margin-top instead, but a heading's margin-top collapses
   with the preceding <p>'s margin-bottom (standard adjacent-sibling
   behaviour) and the LARGER value wins — so margin-top: 8px on the heading
   still collapsed up to the paragraph's 16px and saved almost nothing.
   Then padding-top: 8px on the heading (below, since padding never
   collapses) made it worse: 16px margin + 8px padding both landed, for
   24px total. This is what actually controls the gap. */
.col2c.statement.noste p {
    margin-bottom: 8px;
}

/* "Kenelle?" / "Miten se toimii?" — kept blue instead of black, tokens.css's
   --ms-cyan-600 is documented as the canonical heading teal for H2/H3. */
.col2c.statement.noste h3 {
    color: var(--ms-cyan-600, #00bcca);
    margin-top: 0;
}

.col2c.statement.noste .how-it-works-col h4 {
    color: rgba(0, 0, 0, 1);
}
