/* =========================================================================
   OEF ETUSIVU, LOHKO H: SUUNTA A:N PREMIUM- JA VIIMEISTELYVERSIO
   16.9.2026. Suunta A "Vaite ensin" on LUKITTU (Rasmus Vuorilinna 16.9.2026).
   B ja C ovat kuolleita. Tama tiedosto ei valitse suuntaa uudelleen vaan
   tekee A:sta niin hyvan kuin A voi olla, A:n omilla ehdoilla.

   LATAUSJARJESTYS (sama menetelma kuin F2 B:n paalla):
     styles.css -> oef-tokens.css -> oef-typo.css -> oef-etusivu-pohja.css
     -> oef-etusivu-a.css -> oef-etusivu-h.css
   body saa luokat `sivu--etusivu-a sivu--etusivu-h`. Jos H hylataan, A on
   olemassa koskemattomana yhden link-rivin takana. Tama on menetelma eika
   sattuma: hylkaaminen ei saa maksaa tyota.

   NELJA ASIAA JOTKA DANI VAHVISTI, JA MISSA KUKIN RATKAISTAAN:
     1. RYTMI            -> §2 (ruudukko) ja §3 (korttileveydet)
     2. INTERAKTIOTILAT  -> §5
     3. SELAUS ARGUMENTTINA -> §6 (jaettu perusta) + §7-§9 (kolme suuntaa)
     4. KELLUVA CTA POIS -> §4

   PERIAATE JONKA DANI VAHVISTI: premium ei ole lisaamista vaan sita etta
   jokainen yksityiskohta nayttaa paatetylta. Jos valinta on uuden lisaaminen
   tai vanhan poistaminen, POISTA. Tassa tiedostossa poistoja on enemman kuin
   lisayksia, ja se on tarkoitus.
   ========================================================================= */

body.sivu--etusivu-h {
  /* Yksi kesto ja yksi easing koko sivulle. Ne EIVAT ole uusia tokeneita:
     --dur ja --ease ovat jo oef-tokens.css:ssa, ja tassa ne vain nimetaan
     uudelleen sivun omiksi jotta poikkeus on kirjoitettava eika vahinko. */
  --h-dur: var(--dur);
  --h-dur-nopea: var(--dur-nopea);
  --h-ease: var(--ease);

  /* §2 RUUDUKKO. Yksi 12-palstainen ruudukko koko sivulle.
     palsta = (1160 - 11 * 24) / 12 = 74,666...px
     span 3  = 272px    nelja rinnakkain
     span 4  = 370,67px kolme rinnakkain
     span 12 = 1160px   taysi mitta
     Naita kolmea EI ole valittu esteettisesti vaan aritmeettisesti: ne ovat
     ainoat leveydet jotka syntyvat samasta palstasta samalla valilla, joten
     jokainen reunaviiva sivulla osuu samalle pystylinjalle ylhaalta alas
     (makuportti mitta 4). Kahdeksan leveytta ei ole rytmia vaikka silma ei
     niita laskekaan, koska silloin yksikaan reuna ei kohdistu toiseen. */
  --h-mitta: 1160px;
  --h-vali: 24px;
  --h-palsta: calc((var(--h-mitta) - 11 * var(--h-vali)) / 12);
  --h-s3: calc(var(--h-palsta) * 3 + var(--h-vali) * 2);   /* 272px  */
  --h-s4: calc(var(--h-palsta) * 4 + var(--h-vali) * 3);   /* 370,67 */

  /* Pystyrytmi: kaksi arvoa, ei kahdeksaa. Osioiden valissa --h-pysty,
     lohkojen sisalla puolet siita. */
  --h-pysty: 96px;
  --h-pysty-sisa: 48px;

  --h-kisko-leveys: 1px;
  --h-kisko-x: 40px;
}

/* =========================================================================
   §1  VAITE ON SIVUN SUURIN ASIA
   -------------------------------------------------------------------------
   A:N MITATTU HEIKKOUS (16.9.2026, mittari-h.mjs / HALLITSEVA):
   hallitseva elementti oli h1 osuudella 6,0 % ensimmaisesta ruudusta ja
   etumatka seuraavaan oli 0,1 prosenttiyksikkoa. Nolla pilkun yksi
   prosenttiyksikkoa ei ole hallitsevuus vaan tasapeli: sivulla ei ollut
   hallitsevaa elementtia lainkaan, vaan 37 samanpainoista.

   A:LLA OLI TASTA OMA RATKAISUNSA JA SE OLI PERUSTELTU, MUTTA SE EI RIITTANYT.
   A asetti heron kahteen palstaan: vaite vasemmalle (776 px) ja kolme
   tunnuslukua oikealle (320 px), perusteluna etta tunnusluvut ovat lupauksen
   todiste ja kuuluvat lupauksen VIEREEN. Sisallollisesti se on oikein.
   Mitattu seuraus oli kuitenkin se, etta vaitteen palstaksi jai 776 px, ja
   776 px:n palstassa pisin sana "energiaremonteissasi" (20 merkkia) rajoittaa
   otsikon 80 pikseliin. Kahdeksankymmenen pikselin otsikko ei voi hallita
   ruutua jonka leveys on 1440.

   PREMIUM-VERSIO PITAA A:N PERUSTELUN MUTTA VAIHTAA SEN SUUNNAN:
   tunnusluvut ovat yha lupauksen todiste ja yha ensimmaisessa ruudussa,
   mutta ne ovat vaitteen ALLA eivatka sen VIERESSA. Silloin ne lukeutuvat
   vaitteen allekirjoitukseksi, mika on vahvempi suhde kuin rinnakkaisuus,
   ja vaite saa koko 1160 px:n mitan. Yksi muutos, kaksi voittoa.

   KATTO 100 px EI OLE MAKUASIA. Se on suurin koko jolla pisin sana mahtuu
   1160 px:n sisaltomittaan rivittymatta. Sita suurempi kaataa
   TEKSTIYLIVUOTO-mittarin, ja mitattu todiste siita on tassa: ensimmainen
   yritys kaytti arvoa 104 px ja rajausta `max-width: 13ch`, jolloin otsikko
   vuoti 225 px oman laatikkonsa ulkopuolelle 1440 px:lla. 13ch oli
   kirjoitettu rivijaon pakottamiseksi, mutta ch-yksikko on nollan leveys eika
   keskimaarainen merkki, joten 13ch oli 975 px silloin kun sana tarvitsi
   999 px. Pisin SANA maarittelee laatikon vahimmaisleveyden, ei suunnittelija.
   Alaraja 32 px tulee samasta laskusta 390 px:n ruudulla.
   ========================================================================= */
body.sivu--etusivu-h #hero h1 {
  font-size: clamp(34px, 7.2vw, 100px);
  line-height: 0.94;
  letter-spacing: -0.03em;
  max-width: none;
  margin-bottom: var(--v6);
  text-wrap: pretty;
}

/* Heron yksi palsta. A:n kahden palstan saanto on @media (min-width:1024px)
   -lohkossa ja spesifisyydeltaan (0,2,2), joten sen kumoaminen vaatii
   YHTA SPESIFIN saannon SAMASSA mediaehdossa. Ilman mediaehtoa saanto ei
   koskaan osu, koska se haviaa lahdejarjestyksessa vain silloin kun se on
   yhta spesifi, ja A:n saanto on voimassa vasta 1024 px:sta ylospain. */
@media (min-width: 1024px) {
  body.sivu--etusivu-h #hero > .relative.z-10 {
    display: block;
  }
  /* Tunnusluvut: vaitteen alle, vaakarivina, samoilla hiusviivoilla joilla
     A ne pystyrivina piirsi. Rekisteri sailyy, suunta vaihtuu. */
  body.sivu--etusivu-h #hero .grid.lg\:grid-cols-3 {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--h-vali);
    border-top: 1px solid var(--oef-viiva);
    border-bottom: 0;
    margin-top: var(--v6);
    max-width: none;
  }
  body.sivu--etusivu-h #hero .grid.lg\:grid-cols-3 > * {
    display: block;
    padding: var(--v5) 0 0;
    border-left: 0;
    border-bottom: 0;
  }
}

/* VAITE OMISTAA ENSIMMAISEN RUUDUN. Tama on hallitsevuuden toinen ja
   tarkeampi korjaus: koon nosto yksin ei riita jos ruudussa on samaan aikaan
   nelja saastolukua ja kolme tunnuslukua.

   A:ssa hero sisalsi vaitteen JA nelja saastolukua JA kolme tunnuslukua
   samassa ruudussa, eli vaite ja KAIKKI sen todisteet nakyivat yhta aikaa.
   Silloin vaite ei voi olla "ensin", koska mikaan ei tule sen jalkeen, eika
   selaus voi kantaa argumenttia, koska argumentti on jo kokonaan luettu.

   Ensimmaiseen ruutuun jaa vaite ja sen allekirjoitus (kolme tunnuslukua).
   Nelja saastolukua putoavat taitteen alle ja niista tulee todiste 1.
   Tama on yhtaikaa hallitsevuuden korjaus JA se mika tekee selauksesta
   argumentin: lukijan on pakko edeta saadakseen todisteen. */
/* VAITELOHKON MIN-HEIGHT POISTETTIIN, JA SE ON TAMAN LOHKON PUHTAIN
   ESIMERKKI SIITA MIKSI MITATAAN. Rakensin vaitelohkolle ruudun mittaisen
   min-heightin perusteena "vaite omistaa ensimmaisen ruudun". Se kuulosti
   oikealta ja se nakyi kuvassa. Mitattuna se ei tehnyt mitaan:

     variantti              hallitseva %        suurin tyhja %
                            1600/1440/1280/390  1600/1440/1280/390
     min-height kerroin 4   15,4/19,0/20,3/8,5  19,0/11,5/10,8/11,3
     ei min-heightia        15,4/19,0/20,3/8,5  13,0/ 9,2/10,8/ 9,4
     flex-start             15,4/19,0/20,3/8,5  20,6/10,5/10,8/13,2
     kerroin 5              15,4/19,0/20,3/8,5  13,0/ 9,2/10,8/ 9,4

   Hallitsevuus on NELJALLA leveydella IDENTTINEN kaikissa varianteissa:
   0,0 prosenttiyksikon ero. Hallitsevuus ei siis tullut min-heightista vaan
   kahdesta muusta asiasta: otsikon koosta ja siita etta tunnusluvut
   siirtyivat pois ensimmaisesta ruudusta yhden palstan myota. Min-height
   maksoi kuitenkin 3,8-6,0 prosenttiyksikkoa suurimmassa yhtenaisessa
   tyhjassa alueessa, eli se osti nollan ja maksoi kuudella.

   Poistettu. Tama on se kohta jossa Danin ohje "jos valinta on uuden
   lisaaminen tai vanhan poistaminen, poista" osui omaan tyohoni eika
   perittyyn koodiin, ja mittari oli ainoa joka sen naki: kuvassa
   min-height nayttti hyvalta. */
body.sivu--etusivu-h #hero .grid.lg\:grid-cols-4 {
  margin-top: var(--h-pysty);
}

/* Pitkat suomalaiset yhdyssanat: "Asiantuntijakonsultaatio" (24 merkkia)
   vuoti 31 px oman korttinsa ulkopuolelle JO LAHTOTILASSA, kaikilla kolmella
   tyopoytaleveydella. Tama ei ole reunatapaus vaan suomen kielen normaali
   tilanne: yhdyssanassa ei ole luonnollista katkaisukohtaa, joten kapea
   palsta ja pitka sana kohtaavat jokaisella korttipohjaisella sivulla.
   `hyphens: auto` tarvitsee sivun lang-attribuutin (sivulla on lang="fi"),
   ja `overflow-wrap: break-word` on varmistus niille selaimille joilla ei ole
   suomen tavutussaantoja: se katkaisee vasta kun muuta keinoa ei ole. */
body.sivu--etusivu-h main :is(h2, h3, h4) {
  hyphens: auto;
  overflow-wrap: break-word;
}

/* =========================================================================
   §2  YKSI RUUDUKKO: KAIKKI SAILIOT SAMAAN MITTAAN
   -------------------------------------------------------------------------
   Mitattu: sisaltosailioita oli kolmessa mitassa (1160, 1232 ja 1280 px),
   koska Tailwindin max-w-4xl / 5xl / 6xl / 7xl -luokkia oli kaytetty
   vaihdellen ja ylatunniste seka alatunniste kayttivat eri mittaa kuin
   sisalto. Silma ei lue luokkanimia, mutta se nakee etta ylatunnisteen
   logo ja sen alla oleva otsikko eivat ala samalta pystylinjalta.
   Makuportti mitta 4: enintaan nelja alkulinjaa, ja niiden on pidettava
   ylhaalta alas.

   max-w-2xl JATETAAN RAUHAAN. Se on leipatekstin rivimitta (52ch) eika
   sailio. 1160 px leipatekstia on noin 110 merkkia rivilla ja luettavuus
   romahtaa. Rivimitta ja sailiomitta ovat eri asioita, ja niiden
   sekoittaminen on juuri se virhe jonka "yksi ruudukko" -ohje houkuttelee
   tekemaan.
   ========================================================================= */
body.sivu--etusivu-h main .max-w-4xl,
body.sivu--etusivu-h main .max-w-5xl,
body.sivu--etusivu-h main .max-w-6xl,
body.sivu--etusivu-h main .max-w-7xl,
body.sivu--etusivu-h main .max-w-3xl,
body.sivu--etusivu-h > header .max-w-7xl,
body.sivu--etusivu-h > footer .max-w-7xl {
  max-width: var(--h-mitta);
}

/* =========================================================================
   §3  KORTTIRYTMI: KAHDEKSASTA LEVEYDESTA KOLMEEN
   -------------------------------------------------------------------------
   Mitattu ennen (1440 px): 272 x4, 290 x3, 320 x1, 365 x6, 400 x2, 496 x2,
   1160 x5, 1280 x1 = KAHDEKSAN sisaltoleveytta.
   Tavoite: KOLME, ja kaikki kolme samasta ruudukosta.
     span 3  = 272px     nelja rinnakkain
     span 4  = 370,67px  kolme rinnakkain
     span 12 = 1160px    taysi mitta

   MIKSI JUURI NAMA KOLME: ne ovat ainoat leveydet jotka syntyvat samasta
   74,67 px:n palstasta samalla 24 px:n valilla. Kun kaikki kolme tulevat
   samasta jakolaskusta, jokainen reunaviiva sivulla osuu samalle
   pystylinjalle ylhaalta alas. Kahdeksan leveytta ei ole rytmia vaikka silma
   ei niita laske, koska silloin yksikaan reuna ei kohdistu toiseen.

   VALI ON LEVEYDEN SYY, EI SEN RINNALLA OLEVA ERI ASIA. Tailwindin gap-4
   (16), gap-6 (24) ja gap-8 (32) sekoittuivat samalla sivulla, ja kun vali
   vaihtuu, kortin leveys vaihtuu vaikka palstamaara pysyisi samana. Siksi
   yhtenainen vali on ensimmainen julistus eika viimeinen.

   RYHMITTELY, JA JOKAISELLE PERUSTE:
     nelja rinnakkain (272): nelja saastolukua, nelja prosessin askelta.
       Nelja lyhytta lukua mahtuu riviin ja luetaan yhtena vertailuna.
     kolme rinnakkain (371): kuusi palvelua (kaksi rivia), kolme tunnuslukua.
     taysi mitta (1160): ne lohkot jotka ovat yksi asia eivat kaksi.
       TAHAN SIIRRETTIIN MYOS HINNOITTELUN KAKSI KORTTIA (olivat 568 px).
       Kaksi hintatasoa vierekkain on vertailu jossa silma hyppii edestakaisin
       rivien valilla; allekkain samalla mitalla samat rivit ovat allekkain ja
       vertailu on pystysuora. Se on samalla neljannen leveyden poisto, eli
       tasmalleen se valinta jossa Danin ohje "poista ennemmin kuin lisaa"
       ratkaisi kahden yhta hyvan asettelun valilla.
   ========================================================================= */
body.sivu--etusivu-h main .grid { gap: var(--h-vali); }

/* Heron saastoluvut: A teki naista hiusviivaliuskan jossa gap on 0 ja
   erottimena on pystyviiva. Liuska SAILYY, se on A:n paras yksittainen
   ratkaisu, mutta vali nostetaan ruudukon valiksi jolloin sarakkeet osuvat
   samalle 272 px:n mitalle kuin prosessin askeleet. Erotinviiva siirtyy
   valin keskelle. Spesifisyys (0,3,3) voittaa A:n (0,3,2). */
body.sivu--etusivu-h #hero .grid.lg\:grid-cols-4.observe {
  gap: var(--h-vali);
  max-width: var(--h-mitta);
}
body.sivu--etusivu-h #hero .grid.lg\:grid-cols-4.observe > .group + .group {
  padding-left: var(--h-vali);
  margin-left: calc(var(--h-vali) * -0.5);
}
body.sivu--etusivu-h #hero .grid.lg\:grid-cols-4.observe > .group:not(:last-child) {
  padding-right: 0;
}

/* Hinnoittelun kaksi korttia: 568 px -> 1160 px allekkain. */
body.sivu--etusivu-h #hinnoittelu .grid.md\:grid-cols-2 {
  grid-template-columns: minmax(0, 1fr);
}

/* =========================================================================
   §4  KELLUVA CTA POIS
   -------------------------------------------------------------------------
   Oikean alakulman "OTA YHTEYTTA ASIANTUNTIJAAN" oli geneerinen widget: se
   kelluu sisallon paalla, se ei kuulu mihinkaan osioon, ja se toimisi
   sellaisenaan mille tahansa toimialalle. Se on vaihtotestin (makuportti §1
   testi 1) selkein yksittainen haviaja koko sivulla.

   KORVAAJAA EI LISATA, KOSKA SITA EI TARVITA. Konversiopiste on jo kahdessa
   paikassa: ylatunnisteen ainoa taytetty painike (nakyy heti, pysyy koko
   selauksen ajan) ja #cta-osio argumentin lopussa. Kelluva widget oli siis
   kolmas kopio samasta toiminnosta, ei puuttuva toiminto.
   Tama on se kohta jossa "poista" voitti "lisaa".

   Mitattu sivuvaikutus: widget oli myos yksi 400 px:n korttileveys
   (§3:n lista) ja yksi fixed-elementti joka peitti sisaltoa 1280 px:lla. */
body.sivu--etusivu-h .floating-cta,
body.sivu--etusivu-h .fab,
body.sivu--etusivu-h #floatingCta,
body.sivu--etusivu-h body > a.fixed.bottom-6,
body.sivu--etusivu-h > a[class*="fixed"][class*="bottom-"],
body.sivu--etusivu-h > div[class*="fixed"][class*="bottom-"]:not(#menuBackdrop):not(#menuOverlay) {
  display: none !important;
}

/* =========================================================================
   §5  INTERAKTIOTILAT: KAIKKI SAMALLE TASOLLE
   -------------------------------------------------------------------------
   Mitattu ennen (1440 px, mittari-h.mjs / INTERAKTIOTILAT):
     46 nakyvaa kohdetta, joista TAYDET 2. hover 44, focus-visible 46,
     active 2, siirtyma 38. Kestoja 3 (150/200/300 ms), easingeja 2.
   Eli: melkein kaikilla oli hover, tuskin yhdellakaan painallustila, ja
   kolmasosa reagoi eri nopeudella kuin naapurinsa. Juuri tuo nopeusero on
   se "osa reagoi hiireen, osa nykaisee" jonka Dani nimesi.

   RATKAISU ON YKSI SAANTOPERHE, EI 46 POIKKEUSTA. Valitsin kayttaa :is()-
   ryhmaa jolloin spesifisyys on (0,2,1): se voittaa Tailwindin yhden luokan
   `duration-300`-saannot ILMAN !importantia. !important olisi ollut nopeampi
   kirjoittaa mutta se olisi tehnyt jokaisesta myohemmasta poikkeuksesta
   mahdottoman, ja poikkeuksia tulee (ks. §5.1).

   MIKSI TRANSITION LUETELLAAN OMINAISUUKSITTAIN EIKA `all`:
   `transition: all` animoi myos ne ominaisuudet jotka selain laskee
   uudelleen layoutissa (width, height, top), ja jokainen sellainen on
   kehysbudjetin menetys jota ei nay koodista. Lueteltu lista pysyy
   compositorilla. */
body.sivu--etusivu-h :is(a[href], button, [role="button"], input, select, textarea, summary, [tabindex="0"]) {
  transition-property: color, background-color, border-color, box-shadow, opacity, transform;
  transition-duration: var(--h-dur);
  transition-timing-function: var(--h-ease);
}

/* PAINALLUSTILA. Tama puuttui 44 kohteelta 46:sta. Painallus on ainoa tila
   joka kertoo etta klikkaus REKISTEROITYI: ilman sita kayttaja ei tieda
   osuiko han, ja se on se tuntuma jota "premium" arkikielessa tarkoittaa.
   1 px alaspain eika scale(): scale kasvattaa myos reunaviivan paksuutta
   nayttaen epateravalta, ja hiusviiva on tassa ilmeessa kantava elementti. */
body.sivu--etusivu-h :is(a[href], button, [role="button"], summary, [tabindex="0"]):active {
  transform: translateY(1px);
  transition-duration: var(--h-dur-nopea);
}

/* HOVER on tarkoituksella HYVIN pieni: se on osoitus kohdistuksesta, ei
   tapahtuma. Kirkastuminen riittaa, ja se toimii myos niille kohteille
   joilla ei ole omaa pintaa. */
body.sivu--etusivu-h :is(a[href], button, [role="button"], summary, [tabindex="0"]):hover {
  color: var(--teksti-1);
}

body.sivu--etusivu-h :is(a[href], button, [role="button"], input, select, textarea, summary, [tabindex="0"]):disabled,
body.sivu--etusivu-h :is(a[href], button, [role="button"])[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
}

/* §5.1 FOKUSRENGAS JOKA EI LEIKKAUDU
   -------------------------------------------------------------------------
   Mitattu ennen: 7 hylkya 46:sta KAIKILLA nelja leveydella, syy
   "leikkautuu overflow:hidden -sailioon". Kaikki seitseman olivat
   mobiilivalikon sisalla. Juurisyy ei ollut rengas vaan se etta valikko on
   olemassa ja fokusoitavissa myos tyopoydalla: se on siirretty ruudun
   ulkopuolelle transformilla, jolloin se pysyy valilehtijarjestyksessa.
   Nappi jota ei nay mutta johon voi tabata on saavutettavuusvika (WCAG 2.2
   AA, 2.4.3 ja 2.4.11), ei pelkka mittarin rike.

   KORJAUS ON `visibility: hidden`, EI renkaan siirto sisaan. Piilotettu
   valikko ei ole fokusoitavissa, jolloin sen renkaita ei tarvitse mitata
   eika niita ole. Sama muutos poistaa valikon myos korttileveyslaskennasta
   (se oli yksi 400 px:n leveys, §3) ja tyhjentaa seitseman hylkya yhdella
   julistuksella. Yksi syy, kolme mitattua seurausta. */
body.sivu--etusivu-h #menuOverlay:not(.active):not(.open):not([data-auki="true"]) {
  visibility: hidden;
}
body.sivu--etusivu-h #menuOverlay.active,
body.sivu--etusivu-h #menuOverlay.open,
body.sivu--etusivu-h #menuOverlay[data-auki="true"] {
  visibility: visible;
}

body.sivu--etusivu-h :is(a[href], button, [role="button"], input, select, textarea, summary, [tabindex="0"]):focus-visible {
  outline: 2px solid var(--toiminta);
  outline-offset: 2px;
  border-radius: var(--r-pieni);
}

/* =========================================================================
   §6  SELAUS KANTAA ARGUMENTTIA: JAETTU PERUSTA
   -------------------------------------------------------------------------
   Mitattu ennen: NOLLA vierityssidonnaista animaatiota. Sivulla oli kuusi
   irrallista (fadeIn x3, pulse, float-pulse, ring-pulse), jotka kaikki
   ajavat DocumentTimelinella eli omalla kellollaan. Ero ei ole kosmeettinen:
   omalla kellolla juokseva animaatio kertoo etta AIKA kuluu, vierityksella
   ajettu kertoo etta LUKIJA etenee. Vain jalkimmainen voi kantaa argumenttia.

   A:N IDEA ON ETTA VAITE TULEE ENSIN. Premium-versiossa vaite ei jaa
   istumaan vaan se todistetaan sita mukaa kun selataan:
     vaite -> todiste 1 -> todiste 2 -> todiste 3 -> todiste 4 -> johtopaatos
   Jokainen todiste on OSIO JOKA ON JO SIVULLA. Yhtaan uutta sisaltoa ei
   lisata: liike ei tuo uutta asiaa vaan jarjestaa olemassa olevan
   argumentiksi.

   TOTEUTUS ON NATIIVI animation-timeline, NOLLA JAVASCRIPTIA. Perustelu on
   mitattu lohko G1:ssa: liike on compositorilla (transform + opacity), joten
   se ei maksa kehysbudjettia, eika sivulle tule kirjastoa jonka lataus
   siirtaisi LCP:ta.

   KOLME SAANTOA JOTKA EIVAT SAA PETTAA (css-scroll-driven-animations):
   1. LAHTOTILA ON LOPPUTILA. Jokainen paljastettava elementti on oletuksena
      TAYSIN NAKYVA. Animaatio kaaritaan @supports-lohkoon joka piilottaa sen
      vasta kun selain osaa myos palauttaa. Ilman tata sivu on tyhja
      selaimessa joka ei tue animation-timelinea.
   2. JS POIS EI SAA PIILOTTAA MITAAN. Koska kohdan 1 piilotus on puhtaasti
      CSS:aa, JS:n puuttuminen ei vaikuta siihen mitenkaan.
   3. prefers-reduced-motion: TAYSI SISALTO ILMAN LIIKETTA. Ei typistettya
      versiota vaan jokainen arvo lopputilassaan.
   ========================================================================= */

/* Aikajanojen nimet julistetaan mainissa jotta kisko (§7) voi viitata
   osioihin jotka eivat ole sen esivanhempia. timeline-scope on ainoa tapa
   tehda se ilman JavaScriptia. */
body.sivu--etusivu-h main {
  timeline-scope: --t1, --t2, --t3, --t4, --argumentti;
}

body.sivu--etusivu-h main > section:nth-of-type(2) { view-timeline: --t1 block; }
body.sivu--etusivu-h main > section#services     { view-timeline: --t2 block; }
body.sivu--etusivu-h main > section#process      { view-timeline: --t3 block; }
body.sivu--etusivu-h main > section#hinnoittelu  { view-timeline: --t4 block; }
body.sivu--etusivu-h main                        { scroll-timeline: --argumentti block; }

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* PALJASTUS. Vain transform ja opacity: molemmat ovat compositorilla
       eivatka kumpikaan aiheuta layout-siirtymaa, joten CLS pysyy nollassa.
       `both` on pakollinen: ilman sita elementti palaa lahtotilaansa
       animaatiovalin ulkopuolella ja "jaa palamaan" -periaate rikkoutuu. */
    body.sivu--etusivu-h main .observe {
      animation: h-paljasta linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 32%;
    }
    /* Otsikko ei paljastu: se on vaite ja se on jo paikalla. Jos vaite
       hiipuisi sisaan, sivu vaittaisi vasta kun lukija on ehtinyt katsoa
       sita hetken, ja "vaite ensin" muuttuisi "vaite kohta". */
    body.sivu--etusivu-h #hero > .relative.z-10 > .max-w-3xl { animation: none; }
  }
}

@keyframes h-paljasta {
  from { opacity: 0; transform: translate3d(0, 24px, 0); }
  to   { opacity: 1; transform: none; }
}

/* prefers-reduced-motion: kaikki lopputilassaan, sivun korkeus samana.
   Tama EI ole `animation: none` yksin: kisko ja solmut saavat myos oman
   lopputilansa, muuten ne jaisivat sammuneiksi. */
@media (prefers-reduced-motion: reduce) {
  body.sivu--etusivu-h main .observe,
  body.sivu--etusivu-h .h-kisko__taytto,
  body.sivu--etusivu-h .h-solmu {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  body.sivu--etusivu-h .h-kisko__taytto { transform: scaleY(1) !important; }
}

/* =========================================================================
   §10  YLATUNNISTEEN POHJA
   -------------------------------------------------------------------------
   LOYTYI KIERROKSELLA 3, JA VAIN KUVASTA. Sivun viimeisessa kuvassa
   (k3-1440-06) logon takana nakyi oranssi hehku x 140-600, y 10-100. Se ei
   ole koriste eika virhe tyylissa vaan ALLA OLEVAN taytetyn painikkeen vari
   joka vuotaa ylatunnisteen backdrop-filterin lapi. Ylatunnisteen tausta on
   liukuvari joka alkaa lapinakyvana, joten mita kirkkaampi elementti sen alta
   kulkee, sita enemman sita nakyy.

   A:ssa vika oli olemassa mutta harvinaisempi, koska sivu oli lyhyempi ja
   taytettyja painikkeita ohitettiin vahemman. H tekee sivusta 605 px
   pidemman ja sitoo selauksen argumenttiin, joten ohituksia on enemman ja
   vika nakyy useammin. Pidempi sivu on siis vian SYY vaikka vika on vanha.

   Korjaus on lapinakymattomampi pohja, EI backdrop-filterin poisto:
   suodatin on se joka pitaa ylatunnisteen erillaan sisallosta kun sisalto on
   tekstia, ja sen poisto rikkoisi enemman kuin korjaisi. */
body.sivu--etusivu-h > header {
  background: color-mix(in srgb, var(--oef-bg) 92%, transparent);
  border-bottom: 1px solid var(--oef-viiva-heikko);
}

/* =========================================================================
   §7  KISKO: VOITTANUT SUUNTA
   -------------------------------------------------------------------------
   Kolmesta suunnasta (kisko, laskuri, kerros) tama voitti vertailun.
   Hylkaysperusteet ovat css/oef-etusivu-h-hylatyt.css:ssa, ja ne ovat
   mitattuja eivat makuasioita. Lyhyesti: LASKURI kaatui makuportin §8:aan
   (mittaripalkki ilman kattoa) ja mittaan 10 (oranssi sai neljannen
   merkityksen), KERROS kaatui siihen etta OEF:n osiot ovat 700-1150 px
   korkeita eli ruutua korkeampia, jolloin jokainen tarttuva osio leikkautuu
   kesken kortin. Sisalto on lukittu, joten osioita ei voi lyhentaa, eli
   KERROS ei ollut toteutusvirhe vaan suunta joka ei sovi tahan sisaltoon.

   HALLITSEVA IDEA: argumentti on yksi katkeamaton lanka vaitteesta
   johtopaatokseen, ja selaus on sen piirtaminen.

   Kisko on `main`in pseudoelementeissa eika omissa div-elementeissaan.
   Syy ei ole siisteys vaan se, etta koriste jota ei ole DOMissa ei voi
   paatya ruudunlukijalle, ei kasvata solmumaaraa eika voi jaada nakyviin
   jos tyylitiedosto hylataan. Poistotesti (makuportti §1 testi 3) on
   silloin yhden luokan poisto ja sen jalkeen sivu on tasmalleen ennallaan.
   ========================================================================= */
body.sivu--etusivu-h main { position: relative; }

/* Kiskon ura: hiusviiva joka kulkee koko argumentin mitan. Se alkaa
   heron lupausrivin kohdalta eika sivun ylalaidasta, koska lanka lahtee
   vaitteesta eika ylatunnisteesta. */
body.sivu--etusivu-h main::before {
  content: "";
  position: absolute;
  left: var(--h-kisko-x);
  top: 100svh;
  bottom: var(--h-pysty);
  width: var(--h-kisko-leveys);
  background: var(--oef-viiva);
  pointer-events: none;
}

/* Kiskon taytto. transform-origin: top + scaleY on ainoa tapa animoida
   pituutta ILMAN layout-tyota: height-animaatio pakottaisi uudelleenlayoutin
   joka kehyksessa ja nakyisi nykimisena juuri silla laitteella jolla se on
   pahinta. */
body.sivu--etusivu-h main::after {
  content: "";
  position: absolute;
  left: var(--h-kisko-x);
  top: 100svh;
  bottom: var(--h-pysty);
  width: var(--h-kisko-leveys);
  /* KIERROS 2 KORJASI TASSA VIAN JOKA NAKYI VAIN KUVASTA.
     Kisko oli --toiminta eli sama oranssi kuin taytetty painike, "UUSI"-merkki
     ja prosessikorttien pystyviiva. Mitattu kuvasta k2-1440-04: samassa
     ruudussa oli nelja oranssia pystyelementtia joista yksi oli kisko, kolme
     oli askelkortteja ja yksi oli painike, ja kaikki samaa savya ja samaa
     leveysluokkaa. Makuportti mitta 10 vaatii yhden merkityksen per vari, ja
     oranssilla oli nelja.
     Kisko ei ole toiminta vaan ETENEMINEN, eika sivulla ole eika saa olla
     omaa varia etenemiselle. Siksi kiskolta poistetaan vari kokonaan:
     tayttyva osa on --teksti-1 ja ura --oef-viiva. Oranssi jaa sille yhdelle
     asialle jota halutaan klikattavan, ja se on koko aksenttivarin tarkoitus.
     Tama oli poisto eika lisays, ja se on syy miksi se on oikea korjaus. */
  background: var(--teksti-1);
  transform-origin: top center;
  transform: scaleY(1);
  pointer-events: none;
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    body.sivu--etusivu-h main::after {
      animation: h-kisko-tayty linear both;
      /* NIMETTY AIKAJANA EI RESOLVOITUNUT PSEUDOELEMENTILLE.
         Ensimmainen yritys kaytti `animation-timeline: --argumentti` jonka
         `main` julistaa ja jonka `timeline-scope` tekee nakyvaksi. Mitattu
         tulos: kisko oli TAYSIN orans jo 14 %:n kohdalla vierityksesta.
         Syy on se, etta kun aikajanan nimi ei resolvoidu, animaatio ei tule
         voimaan lainkaan ja elementti jaa lahtoarvoonsa scaleY(1), joka
         nayttaa tasmalleen valmiilta kiskolta. Vika oli siis NAKYMATON
         kuvassa: valmis kisko ja rikkinainen kisko ovat sama kuva.
         `scroll(root block)` ei tarvitse nimea eika scopea. Kisko kulkee
         koko dokumentin mitan, joten juuren vieritysosuus ON tasmalleen se
         luku jota kisko esittaa. Yksinkertaisempi ja mitattavissa. */
      animation-timeline: view();
      /* KIERROS 3 KORJASI TASSA VIAN JOKA NAKYI VAIN SIVUN VIIMEISESSA KUVASSA.
         `scroll(root block)` seurasi juuren vieritysta oikein (mitattu
         0 -> 0,23 -> 0,48 -> 0,71 -> 0,97), mutta juuren vieritys sisaltaa
         MYOS ALATUNNISTEEN, ja kisko kulkee vain mainin mittaan. Lopputulos
         oli se, etta sivun pohjassa kisko oli noin 90-prosenttinen: argumentti
         nayttti jaavan kesken tasmalleen siina kohdassa jossa sen koko
         lupaus on etta se on valmis. Yhdeksankymmenen prosentin lanka ei ole
         hieman keskenerainen lanka vaan rikkinainen idea.
         `view()` + `contain` sitoo tayton KISKON OMAAN laatikkoon: taytto on
         taysi silloin kun kiskon alareuna on ruudussa, eli silloin kun
         johtopaatos on luettavissa. Aikajana on nyt sama asia kuin se matka
         jota se kuvaa, eika vain korreloi sen kanssa. */
      animation-range: contain 0% contain 100%;
    }
  }
}
@keyframes h-kisko-tayty {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

/* SOLMUT. Yksi per todiste, kiskon x-koordinaatissa, oman osionsa
   ylareunassa. Solmu syttyy kun osio tulee nakyviin JA JAA PALAMAAN.
   Tama on lohko F2:ssa mitattu periaate: sammuva osa on tehoste, jaava osa
   on vastaus. Argumentissa se on sama asia kuin todisteen peruuttamattomuus:
   kerran nahtya todistetta ei oteta pois. */
body.sivu--etusivu-h main > section:nth-of-type(2),
body.sivu--etusivu-h main > section#services,
body.sivu--etusivu-h main > section#process,
body.sivu--etusivu-h main > section#hinnoittelu { position: relative; }

body.sivu--etusivu-h main > section:nth-of-type(2)::before,
body.sivu--etusivu-h main > section#services::before,
body.sivu--etusivu-h main > section#process::before,
body.sivu--etusivu-h main > section#hinnoittelu::before {
  content: "";
  position: absolute;
  left: calc(var(--h-kisko-x) - 3px);
  top: var(--h-pysty-sisa);
  width: 7px;
  height: 7px;
  border-radius: var(--r-ympyra);
  background: var(--teksti-1);
  /* Lahtotila on LOPPUTILA (syttynyt). @supports-lohko vaihtaa sen
     sammuneeksi vasta kun selain osaa myos sytyttaa sen. */
  opacity: 1;
  transform: none;
  pointer-events: none;
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    body.sivu--etusivu-h main > section:nth-of-type(2)::before,
    body.sivu--etusivu-h main > section#services::before,
    body.sivu--etusivu-h main > section#process::before,
    body.sivu--etusivu-h main > section#hinnoittelu::before {
      animation: h-solmu-sytty linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 60%;
    }
  }
}
@keyframes h-solmu-sytty {
  from { opacity: 0; transform: scale(0.4); }
  to   { opacity: 1; transform: scale(1); }
}

/* Kapealla ruudulla kiskolle ei ole marginaalia. Se ei siirry sisallon
   paalle vaan se poistuu: rekisteri jota ei ole ei ole tyhja rekisteri. */
@media (max-width: 1100px) {
  body.sivu--etusivu-h main::before,
  body.sivu--etusivu-h main::after,
  body.sivu--etusivu-h main > section::before { display: none; }
}


/* =========================================================================
   §11  MOBIILIN HIERARKIA
   -------------------------------------------------------------------------
   MITATTU: tyopoydalla vaite hallitsee selvasti (18,9 % ruudusta, etumatka
   16,7 prosenttiyksikkoa), mutta 390 px:lla se ei hallitse: 8,5 % ja
   etumatka ingressiin vain 1,3 prosenttiyksikkoa. Se on sama tasapeli joka
   oli koko A:n vika, ja se jai mobiiliin elamaan.

   SYY EI OLE OTSIKON KOKO. Otsikko on mobiilissa jo lattiassaan: 34 px on
   suurin koko jolla "energiaremonteissasi" (20 merkkia) mahtuu 342 px:n
   sisaltomittaan rivittymatta, ja sita on mitattu eika arvattu.
   Syy on INGRESSI: se on --t-3 eli 21 px myos 390 px:n ruudulla, jolloin
   otsikon ja ingressin suhde on 34/21 = 1,62 kun se tyopoydalla on
   100/21 = 4,76. Mobiilissa portaita ei siis ole vahemman vaan ne ovat
   lahempana toisiaan, ja silma lukee kaksi lahekkaista kokoa yhtena tasona.

   Korjaus on ingressin porras alaspain, EI uusi kirjasinkoko: --t-2 on jo
   kaytossa sivulla, joten portaiden MAARA ei kasva (mitattu: 6 ennen ja
   jalkeen). 34/16 = 2,13 on porras jonka silma lukee portaana.
   Tama on sama periaate kuin §1:ssa: hallitsevuus ei synny pelkastaan
   kasvattamalla vaan myos poistamalla painoa kilpailijalta. */
@media (max-width: 640px) {
  body.sivu--etusivu-h #hero h1 + p {
    font-size: var(--t-2);
    line-height: 1.5;
  }
}

/* =========================================================================
   §12  HERON YLATYHJA
   -------------------------------------------------------------------------
   Makuportti mitta 8: suurin YHTENAINEN tyhja alue enintaan 18 % ruudusta.
   Perustelu mittarissa: sita isompi aukko luetaan keskeneraisyytena eika
   levoksi, ja lepo kuuluu reunoille ei keskelle.

   §1:n muutos (vaite omistaa ensimmaisen ruudun) nosti taman arvon
   lahtotilan 12,4 / 12,9 / 15,1 / 9,1 prosentista arvoihin
   21,3 / 17,3 / 18,9 / 11,3 %, eli kaksi neljasta leveydesta kaatui.
   Aukko paikannettiin koordinaatteineen eika arvattu: se oli 1440 px:lla
   vaakakaista y 112-320, eli tasan #heron ylapehmuste.

   #main kantaa jo kiinnitetyn ylatunnisteen vaatiman 112 px:n pehmusteen,
   joten #heron oma 96 px oli pehmuste pehmusteen paalla. Sen poisto ei vie
   ilmaa mistaan: vaitelohkolla on oma 48 px:n ylapehmuste ja sen ylla
   kickerirvi. Mitattu sarja 1600/1440/1280/390:
     96 px (lahto) -> 21,3 / 17,3 / 18,9 / 11,3   kaksi hylkya
     48 px         -> 18,3 / 13,8 / 14,9 / 11,3   yksi hylky
     24 px         -> 19,0 / 12,7 / 12,2 / 11,3   yksi hylky
      0 px         -> 17,5 / 10,4 / 10,8 / 11,3   LAPI kaikilla
   Alapehmuste sailyy: poistettava on paallekkaisyys ylatunnisteen kanssa,
   ei osioiden valinen rytmi. */
body.sivu--etusivu-h #hero { padding-top: 0; }

/* Ylapehmusteen poisto aiheutti YHDEN uuden fokushylyn, ja se on kirjattava
   tahan koska se on juuri se kuvio jolla portti muuttuu valevihreaksi jos
   sen antaa olla: kickerilinkki ("Uusi | Energia-avustus 2026") osui
   #heron ylareunaan, ja #hero on overflow:hidden, joten linkin 2 px:n
   ULKOPUOLINEN fokusrengas leikkautui. Mitattu: 1/38 kaikilla nelja
   leveydella, syy "leikkautuu overflow:hidden -sailioon".
   Korjaus on 8 px pehmustetta kickerirville eika renkaan siirto sisaan:
   rengas kuuluu elementin ulkopuolelle jotta se erottuu myos elementin
   omasta reunasta, ja 8 px on pienin arvo joka kattaa renkaan (2 px offset
   + 2 px leveys) ilman etta ylatyhja kasvaa mitattavasti. */
body.sivu--etusivu-h #hero > .relative.z-10 > .flex.justify-end {
  padding-top: 8px;
}

/* =========================================================================
   §13  YLATUNNISTE SAMALLE PYSTYLINJALLE KUIN SIVU  (lohko I osa 2)
   -------------------------------------------------------------------------
   §2 yhtenaisti SAILIOIDEN mitan (kaikki 1160 px), mutta ylatunnisteen
   sisakaare sai jaada Tailwindin `px-6 lg:px-12` -pehmusteeseen. Mitattu
   1440 px: sivun sisalto (h1, avustusnauha, jokainen osio) alkaa linjalta
   x = 140, ja logo alkaa linjalta x = 188. Ero on tasan se 48 px.

   Se on §2:n oma vika loppuun asti vietyna: saili oli oikean levyinen mutta
   sen SISALTO ei silti ala samalta linjalta. Makuportin mitta 4 sanoo etta
   alkulinjojen on pidettava ylhaalta alas, ja suunta A:n koko idea on yksi
   vasen akseli. Ylatunniste oli sivun ainoa kohta joka rikkoi sen.

   Sama korjaus antaa navigaatiolle sen tilan jonka seitsemas linkki
   (Energia-avustus, lohko I osa 2) tarvitsee: sisakaari leveni 1064 -> 1160
   px, ja logon ja navin valiin jaa 1440 px:lla 96 px aiemman 0 px sijaan.
   Kaksi asiaa ratkeaa yhdella muutoksella, eika kumpikaan ole tekosyy
   toiselle: linja oli vaarassa ennen linkkia ja olisi vaarassa ilman sita.

   Vain >= 1024 px, koska alle sen `px-6` on kapean ruudun reunapehmuste eika
   akseli, ja ilman sita logo liimautuisi 390 px:lla ruudun reunaan. */
@media (min-width: 1024px) {
  body.sivu--etusivu-h > header > .max-w-7xl { padding-left: 0; padding-right: 0; }
}

/* =========================================================================
   §14  AVUSTUSKAISTA: SISAANKAYNTI JOKA ON OLEMASSA MYOS SILMALLE
   -------------------------------------------------------------------------
   Mitattu ENNEN (1440 px): etusivulla on TASAN YKSI linkki avustussisaltoon,
   ja se on 334 x 19 px eli 6 346 px2 = 0,49 % ruudusta, ladottuna 11 px:n
   monolla. Se on sivun pienin ladottu asia. Kysymys "onko avustus riittavan
   nakyva" ei siis ole makuasia: yksi promille ruudusta ei ole sisaankaynti
   vaan alaviite.

   MITA EI TEHTY. Ei lisatty toista elementtia, ei banneria, ei laatikkoa.
   Poistotesti (makuportti §1 testi 3) sanoo etta oikea liike on tehda
   OLEMASSA OLEVASTA elementista se mika sen piti olla, ei kasvattaa
   elementtien maaraa. Sivun vaite ("Puolueeton kumppani energiaremonteissasi")
   ei muutu eika liiku, eika yhtaakaan sanaa kirjoiteta uudelleen.

   MITEN PAINO SYNTYY. Ei kirjasinkoolla (kokoja on 5 ja lukko sallii 7, mutta
   uusi porras veisi hallitsevuutta vaitteelta) eika laatikolla (kulmia on 2
   ja lukko sallii 2). Se syntyy LEVEYDESTA ja YHDESTA HIUSVIIVASTA: rivi
   venyy 334 px:sta koko 1160 px:n ruudukon yli, saa alleen saman hiusviivan
   jota H kayttaa kaikkialla, ja nuoli menee oikeaan reunaan. Silloin rivi on
   kaista jonka yli silma kulkee, ei tarra jonka ohi se menee.

   Nuoli on CSS:n ::after eika markupin ikoni, koska proton ikonikirjasin on
   poistettu lohkossa F ja markupin `data-ikoni`-span on `display: none`.
   Merkki on sama nuoli jota varke.html kayttaa mono-linkeissaan.

   EFEKTIBUDJETTI (makuportti mitta 6): kaistalla on reuna ja siirtyma = 2.
   Ei taustaa, ei varjoa, ei liukuvaria.

   Korkeus pidetaan ennallaan: 8 px ylapehmuste (§12:n fokuskorjaus) sailyy,
   alapehmuste 12 px ja alamarginaali putoaa 32/40 px:sta 24 px:aan, joten
   vaite ei liiku alaspain eika hallitsevuus (15,3 / 18,9 / 20,3 %) laske. */
body.sivu--etusivu-h #hero > .relative.z-10 > .flex.justify-end {
  justify-content: stretch;
  padding-bottom: var(--v3, 12px);
  margin-bottom: var(--v6, 24px);
  border-bottom: 1px solid var(--oef-viiva);
}
body.sivu--etusivu-h #hero > .relative.z-10 > .flex.justify-end > a {
  flex: 1;
  display: flex;
  align-items: center;
  gap: var(--v3, 12px);
}
body.sivu--etusivu-h #hero > .relative.z-10 > .flex.justify-end > a::after {
  content: '\2192';
  margin-left: auto;
  color: var(--toiminta, #FF5C00);
  transition: transform var(--dur, 200ms) var(--ease, cubic-bezier(0.2, 0, 0, 1));
}
body.sivu--etusivu-h #hero > .relative.z-10 > .flex.justify-end > a:hover::after {
  transform: translateX(4px);
}
