/*
Theme Name: Niko yhtiöt
Theme URI: https://nikoy.fi/
Author: Niko yhtiöt Oy
Description: Yksisivuinen esittely. Itsenäinen klassinen teema, ei riippuvuuksia. Tuotekuvat on renderöity kerran tiedostoiksi, joten sivu on samaan aikaan näyttävä ja kevyt.
Version: 2.0.0
Requires at least: 6.5
Requires PHP: 8.0
License: GPL-2.0-or-later
Text Domain: nikoy2
*/

/* ==========================================================================
   MISTÄ ARVOT OVAT PERÄISIN

   Kaikki alla oleva on MITATTU apple.com/iphone-18-pro -sivulta selaimessa
   17.–18.9.2026: computed styles jokaisesta lehtielementistä, vieritysprofiili
   41 askeleella, leveyskoe 734 px ja 1440 px, latausmittaus.

   TYPOGRAFIA
     Vahvuuksia on VAIN KAKSI: 600 ja 400. Kevyempää leikkausta ei esiinny.
     Kokoportaat ovat kokonaislukuja ja vaihtuvat media queryllä — Applella
     hero on 1440 px:llä 80 px ja 734 px:llä 24 px, eli porras, ei liuku.
     Kokokohtainen kirjainväli ja riviväli:
       96px −0.015em/1.04 · 80px −0.015/1.05 · 56px −0.005/1.07
       48px −0.003/1.08  · 32px +0.004/1.13 · 28px +0.007/1.14
       24px +0.009/1.17  · 21px +0.011/1.00 · 19px +0.012/1.21
       17px −0.022/1.18  · 14px −0.016/1.29 · 12px −0.010/1.33

   LIIKE
     Applella EI OLE PARALLAKSIA. 48 seuratusta elementistä vain kaksi liikkui
     suhteessa sivuun, ja molemmat olivat kiinnitettyjä.
     Saapuminen on vierityssidonnainen, ei kellosidonnainen: lopputilassa
     transition-duration on 0s, eli JavaScript asettaa arvon vieritysasemasta.
     Mitattu käyrä: 200 px ruudun alalaidasta = 0 %, 930 px = 100 %,
     matka 730 px, siirtymä translateY(30px).
     Siirtymät: opacity/transform .24s ease · color .32s cubic-bezier(.4,0,.6,1)

   VÄRI
     Musta ja kohotettu vuorottelevat, ja kohdassa 23 652 px sivu kääntyy
     vaaleaksi: siitä eteenpäin ei kerrota tuotteesta vaan asioidaan.
     Käännös on liuku — se on koko sivun ainoa gradientti.

   SUORITUSKYKY — kalliisti opittu
     Aiemmassa yrityksessä oli 450 hiukkaselementtiä, 300 box-shadowia,
     162 filter: blur() -sääntöä ja 485 will-change-merkintää. Jokainen
     will-change luo oman kompositointikerroksen; sadat kerrokset täyttävät
     GPU-muistin ja pudottavat renderöinnin ohjelmistolle. Siksi täällä on
     nolla hiukkasta, nolla ajonaikaista sumennusta ja will-change vain siellä,
     missä jokin oikeasti liikkuu.

     Kaikki raskas on kuvissa. Ne renderöitiin kerran.
   ========================================================================== */


/* ==========================================================================
   1. TOKENIT
   ========================================================================== */

/* ──────────────────────────────────────────────────────────────────────────
   0. REKISTERÖIDYT MUUTTUJAT

   `--alkukynnys` on pituus, ja se lasketaan calc()-lausekkeella, jossa on
   sekä vh- että em-osuus. Rekisteröimätön custom property olisi selaimelle
   pelkkä merkkijono: `getComputedStyle` palauttaisi lausekkeen sellaisenaan
   eikä JS saisi siitä lukua. Rekisteröinti kertoo tyypin, jolloin selain
   laskee arvon pikseleiksi ennen kuin JS lukee sen.

   initial-value on sama 80px, jota käytettiin ennen vakiona, joten jokainen
   elementti, jolle arvoa ei erikseen aseteta, käyttäytyy täsmälleen kuten
   ennenkin. ────────────────────────────────────────────────────────────── */
@property --alkukynnys {
  syntax: "<length>";
  inherits: true;
  initial-value: 80px;
}
@property --porras {
  syntax: "<length>";
  inherits: true;
  initial-value: 32px;
}
@property --matka {
  syntax: "<length>";
  inherits: true;
  initial-value: 250px;
}

:root {
  --kirjasin: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
              "Helvetica Neue", Helvetica, Arial, sans-serif;

  --kayra:      cubic-bezier(.4, 0, .6, 1);
  --kayra-ulos: cubic-bezier(.25, .1, .3, 1);

  --nopea: .16s;
  --perus: .24s;

  /* Saapumisliikkeen mitatut arvot. nikoy.js lukee nämä täältä, jotta liikettä
     säädetään yhdessä paikassa eikä kahdessa. */
  /* Saapumisen matka. Applen mitattu arvo on 730 px, mutta heidän osionsa
     ovat 547–4713 px korkeita ja teksti istuu osion yläosassa, jolloin se
     ehtii kirkastua. Meidän osiomme ovat 413–1248 px, joten sama matka jätti
     tekstin mitattavasti puolikirkkaaksi juuri siinä kohdassa, jossa se
     luetaan. Mitatut arvot ovat nikoy.js:n kommentissa. */
  /* 🔴 SUHTEELLISIKSI 18.9.2026. Omistaja: «sivun toiminnallisuuksien ja
     esiintulojen pitäisi olla kokemuksena käyttäjälle sama, riippumatta
     tietokoneen näytön koosta. ja sama mobiilissa.»

     Nämä olivat pikselivakioita, ja pikselivakio tarkoittaa eri kokemusta eri
     näytöillä: 250 px:n liike on 21 % 1200 px:n ruudusta mutta 36 % 700 px:n
     ruudusta — samalla vierityksellä tapahtuu eri määrä. Ruudun korkeuteen
     sidottuna osuus on sama kaikkialla. Arvot on valittu niin, että 1200 px:n
     ruudulla ne tuottavat täsmälleen entiset 250 px ja 80 px, eli tähän asti
     hyväksytty tuntuma säilyy sillä koolla ja siirtyy muille suhteessa. */
  --matka: 20.834vh;
  --alkukynnys: 6.667vh;
  --nousu: 30px;

  --kulma-nappi:  980px;   /* Applen mitattu napin kulma */
  --kulma-kortti: 22px;
  --kulma-kuva:   clamp(14px, 1.6vw, 22px);

  --fokus:    #0071e3;      /* mitattu: 2px solid #0071e3, offset 1px */
  --korostus: #ff6b00;

  --rajaus:       1240px;
  --rajaus-kapea: 660px;
  --reuna:        24px;
}

/* Tumma osa sivusta */
body {
  --pohja:     #000000;
  --kohotettu: #0c0c0e;
  --teksti:    #f5f5f7;
  --teksti-2:  #86868b;        /* 5,9:1 mustalla — #6e6e73 olisi 4,05:1 eli alle AA */
  --hiusviiva: rgba(255,255,255,.12);
  --kortti:    #141416;
  --nappi:     #f5f5f7;
  --nappi-tx:  #000000;
  color-scheme: dark;
}

/* Vaalea osa: sama muuttujajoukko, eri arvot. Yksikään sääntö alempana ei
   tiedä kumpaa puolta se palvelee. */
.nikoy-kaanne {
  --pohja:     #f5f5f7;
  --kohotettu: #ffffff;
  --teksti:    #1d1d1f;
  --teksti-2:  #6e6e73;
  --hiusviiva: rgba(0,0,0,.12);
  --kortti:    #ffffff;
  --nappi:     #1d1d1f;
  --nappi-tx:  #ffffff;
  color-scheme: light;
}


/* ==========================================================================
   2. PERUSTA
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-padding-block-start: 24px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--pohja);
  color: var(--teksti);
  font-family: var(--kirjasin);
  font-size: 17px;
  line-height: 1.18;
  letter-spacing: -.022em;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;

  /* Vaakavuoto on aina vika. Edellinen toteutus vuoti 73 px ja tuotti
     vaakavierityspalkin koko sivulle. Gallerian rata vierittää omassa
     kentässään, joten mitään ei menetetä. */
  overflow-x: clip;
}

p { margin: 0; }
h1, h2 { margin: 0; font-weight: 600; }

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--fokus);
  outline-offset: 1px;
  border-radius: 4px;
}

.nikoy-ohita {
  position: absolute;
  inset-block-start: 8px; inset-inline-start: 8px;
  padding: 10px 16px;
  background: var(--nappi); color: var(--nappi-tx);
  border-radius: 8px; font-size: 14px; text-decoration: none;
  z-index: 60;
  clip-path: inset(50%);   /* säilyy ruudunlukijalle, toisin kuin display:none */
}
.nikoy-ohita:focus { clip-path: none; }


/* ==========================================================================
   3. TYPOGRAFIA — kokonaislukuportaat, vain vahvuudet 400 ja 600
   ========================================================================== */

/* Jättiotsikko: sivun suurin teksti. Rivit ovat erillisiä elementtejä, jotta
   kukin voi saapua omalla ajoituksellaan. */
.nikoy-jatti {
  display: flex; flex-direction: column;
  font-size: 40px; line-height: 1.06; letter-spacing: -.012em; font-weight: 600;
}
.nikoy-jatti-rivi { display: block; }

/* Yleinen kiinteä rivinvaihto leipätekstissä. Omistaja on katkaissut
   yksittäisiä virkkeitä käsin siitä kohdasta, jossa ajatus taittuu — ei siitä,
   mihin selaimen automaattinen rivitys sattuu osumaan. Span eikä <br>, koska
   teksti kulkee esc_html():n läpi eikä saa sisältää merkintää.

   Kapealla ruudulla katkaisu perutaan: käsin valittu katkaisukohta on mitattu
   leveälle ruudulle, ja 390 px:n näytöllä se tuottaisi yhden sanan rivejä. */
.nikoy-rivi { display: block; }
@media (max-width: 734px) {
  .nikoy-rivi { display: inline; }
  .nikoy-rivi + .nikoy-rivi::before { content: " "; }
}

.nikoy-iso, .nikoy-keski {
  font-size: 32px; line-height: 1.13; letter-spacing: .004em; font-weight: 600;
  text-wrap: balance;
}
/* 🔴 Luokan nimi lupasi keskityksen, mutta säännössä oli pelkkä fonttikoko:
   `.nikoy-keski` jakoi rivin `.nikoy-iso`:n kanssa eikä tasannut mitään.
   Aiheiden otsikko oli siis vasemmalla koko ajan, vaikka merkintä sanoi muuta
   — eikä sitä huomannut tyylitiedostosta, koska väärää arvoa ei ollut
   missään: oikea puuttui.

   Keskitys on omalla rivillään, koska `.nikoy-iso` on väiteosion ja
   yhteysosion otsikko eikä niitä keskitetä. */
.nikoy-keski { text-align: center; }

/* 🔴 OMISTAJAN OHJE 18.9.2026: «lisää riviväliä ennen jokaista näistä
   neljästä». Väli oli 2px — käytännössä pelkkä rivikorkeus.

   🔴 GAP EI KELPAA TÄHÄN, mitattu ennen julkaisua. `gap: .16em` laskettaisiin
   tämän elementin omasta fonttikoosta, ja `.nikoy-manifesti` ei aseta
   fonttikokoa: se perii bodyn 17 px. Väli olisi ollut 2,7 px — eli sama 2 px
   kuin ennenkin, ja ohje olisi jäänyt hiljaa toteutumatta. Marginaali kuuluu
   RIVEILLE, joilla on oma 128 px:n koko. */
.nikoy-manifesti { display: flex; flex-direction: column; }
/* Osuu riveihin 2–5. 🔴 KASVATETTU 18.9.2026 .16em → .32em omistajan ohjeella:
   «voitko lisätä riviväliä ennen jokaista näistä kolmesta rivistä? Sinun
   tietosi / Sinun päätöksesi / Faktasta». Ne ovat rivit 2, 3 ja 4; rivi 5
   («Nyt») saa oman arvonsa alempaa, joten tämä sääntö ohjaa käytännössä juuri
   niitä kolmea, jotka omistaja luetteli. */
.nikoy-mrivi + .nikoy-mrivi { margin-block-start: .32em; }
.nikoy-mrivi {
  display: block;
  font-size: 40px; line-height: 1.06; letter-spacing: -.012em; font-weight: 600;
}
/* Kaksi viimeistä riviä ovat päätelmä ja saavat korostusvärin. Erottelu on
   rakenteellinen: jos rivejä lisätään, korostus pysyy viimeisissä. */
.nikoy-mrivi:nth-last-child(-n+2) { color: var(--korostus); }

/* 🔴 OMISTAJAN OHJE 18.9.2026: «Faktasta. / Nyt. välinen riviväli voisi olla
   35 % enemmän kuin nyt.» Viimeinen rivi on lauseen piste, ja se saa hengittää.

   Mitattu ennen: 124,9 px (rivi 122,88 + gap 2). +35 % = 168,6 px, eli lisäystä
   43,7 px. Arvo on `em` eikä pikseliä, koska manifestin koko vaihtuu neljässä
   portaassa 40 → 168 px: 43,7 / 128 = 0,341em pitää suhteen 1,35:ssä joka
   portaalla.

   🔴 Mittaus piti tehdä kahdesti. Ensimmäisellä kerralla viimeinen rivi oli
   vielä kesken saapumistaan (--ny = 0,466), ja sen laatikko oli 16 px alempana
   kuin lopullisessa tilassaan. Mittari näytti siis tälle parille 140,9 px,
   vaikka todellinen väli oli sama 124,9 px kuin muillakin. Vasta arvojen
   pakottaminen valmiiksi (--n, --ny = 1) antoi oikean luvun. */
/* 🔴 PÄIVITETTY 18.9.2026: perusväli kasvoi, joten tämä luku oli laskettava
   uudelleen — muuten «+35 %» olisi hiljaa kutistunut, vaikka mitään ei
   näennäisesti koskettu.

   🔴 LASKETTU UUDELLEEN 18.9.2026, toisen kerran samasta syystä. Perusväli
   kasvoi taas (.16em → .32em), ja jos tämä luku olisi jäänyt .552em:iin, niin
   “Faktasta → Nyt” olisi ollut enää +18 % muita suurempi eikä +35 %, vaikka
   sitä sääntöä ei olisi kukaan koskenut. Perusväli on nyt rivikorkeus .96em +
   marginaali .32em = 1,28em. Tavoite 1,28 × 1,35 = 1,728em, josta rivikorkeus
   vie .96em, joten marginaali on .768em.

   Tämä sääntö KORVAA edellisen .32em:n (sama spesifisyys, myöhempi voittaa),
   se ei summaudu siihen. Siksi luku on .768em eikä .448em. */
.nikoy-mrivi:last-child { margin-block-start: .768em; }

.nikoy-silma {
  font-size: 19px; line-height: 1.21; letter-spacing: .012em; font-weight: 600;
  color: var(--teksti-2);
  margin-block-end: 12px;
}

.nikoy-leipa {
  font-size: 19px; line-height: 1.42; letter-spacing: .012em; font-weight: 400;
  color: var(--teksti-2);
}

.nikoy-saate {
  font-size: 14px; line-height: 1.29; letter-spacing: -.016em;
  color: var(--teksti-2);
}

/* 🔴 MITATTU VIKA 18.9.2026. Vaiheteksti oli 40 px ja se hukkui kuvan päälle:
   kuva on tässä koko ruudun kokoinen, joten teksti joutuu kilpailemaan sen
   kanssa. Applen vastaavat lauseet ovat 56–96 px. Nostettu samaan luokkaan. */
.nikoy-vaihe {
  font-size: 34px; line-height: 1.11; letter-spacing: .004em; font-weight: 600;
}

/* --- Portaat. Applen mitattu tapa: kokonaisluku media queryllä, ei liuku. --- */

@media (min-width: 735px) {
  .nikoy-jatti, .nikoy-mrivi { font-size: 64px; line-height: 1.05; letter-spacing: -.014em; }
  .nikoy-iso, .nikoy-keski   { font-size: 40px; line-height: 1.10; letter-spacing: .002em; }
  .nikoy-vaihe               { font-size: 48px; line-height: 1.08; letter-spacing: -.003em; }
  .nikoy-silma               { font-size: 21px; }
  .nikoy-leipa               { font-size: 21px; line-height: 1.38; letter-spacing: .011em; }
  .nikoy-saate               { font-size: 17px; letter-spacing: -.022em; }
}

@media (min-width: 1069px) {
  .nikoy-jatti, .nikoy-mrivi { font-size: 80px; line-height: 1.05; letter-spacing: -.015em; }
  .nikoy-iso, .nikoy-keski   { font-size: 48px; line-height: 1.08; letter-spacing: -.003em; }
  .nikoy-vaihe               { font-size: 64px; line-height: 1.05; letter-spacing: -.014em; }
  .nikoy-leipa               { font-size: 24px; line-height: 1.38; letter-spacing: .009em; }
}

@media (min-width: 1441px) {
  .nikoy-jatti, .nikoy-mrivi { font-size: 96px; line-height: 1.04; letter-spacing: -.015em; }
}


/* ==========================================================================
   4. ASETTELU
   ========================================================================== */

.nikoy-osio {
  position: relative;
  background: var(--pohja);
  color: var(--teksti);
  padding-inline: var(--reuna);
}

/* Korkeudet eivät toistu. Applen sivulla yksikään osio ei ole saman mittainen
   kuin edellinen, ja juuri se pitää vierityksen elävänä. */
 /* 🔴 Oli `justify-content: space-between` ja `padding-block: 84px 0`. Se
    toimi, kun osiossa oli KAKSI lasta: teksti työntyi ylös ja hero-kuva alas.
    Kun hero poistettiin 18.9.2026, lapsia jäi yksi — ja space-between ei tee
    yhdelle lapselle mitään. Sisältö olisi jäänyt ruudun yläreunaan ja alle
    olisi auennut noin 280 px tyhjää juuri siihen kohtaan, jota omistaja on
    kahdesti pyytänyt karsimaan.

    Nyt sisältö on pystysuunnassa keskellä. Avaus on typografinen: iso otsikko
    mustalla, ei kuvaa — ja silloin keskitys on ainoa asettelu, joka ei jätä
    toispuoleista aukkoa. */
.nikoy-avaus        { padding-block: 84px; min-height: 100svh;
                      display: flex; flex-direction: column; justify-content: center; }
.nikoy-kelausosio   { padding: 0; }
/* 🔴 MITATTU 18.9.2026. Laskin jokaisen osion täyttöasteen ja osioiden
   rajalle syntyvän YHTENÄISEN tyhjän vyöhykkeen (edellisen alapadding +
   seuraavan yläpadding):

     väite   → kuvaus     232 px      väiteosiosta 62 % oli tyhjää
     kuvaus  → manifesti  248 px      manifestista 40 % oli tyhjää
     manifesti → aiheet   256 px

   Neljännes ruudusta oli siis tyhjää joka rajalla. Omistaja on sanonut tästä
   suoraan: «ei iPhone-sivuillakaan ole noin paljon väliä vaan scrollatessa
   koko ajan tapahtuu». Uudet arvot vievät välit noin 155 pikseliin, mikä on
   17 % ruudusta — väljyys säilyy, tyhjä ruutu ei. */
.nikoy-vaiteosio    { padding: 0; text-align: center; }

/* Osio, jossa teksti on valokuvan päällä. Kuva täyttää osion, säde tummentaa
   sen tekstin kohdalta ja teksti on kolmannessa kerroksessa. Sama kolmijako
   kuin kelausosiossa — ja samasta mitatusta syystä: valokuvassa on vaaleita
   kohtia, joiden päällä valkoinen teksti katoaa. */
.nikoy-kuvatausta {
  position: relative;
  display: grid;
  place-items: center;
  min-block-size: min(76svh, 720px);
  overflow: hidden;
  padding-block: 96px;
  padding-inline: var(--reuna);
}
.nikoy-kuva--tausta {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%;
  object-fit: cover;
  z-index: 0;
}
.nikoy-kuvatausta::before {
  content: '';
  position: absolute; inset: 0;
  z-index: 1;
  background:
    radial-gradient(64% 54% at 50% 50%, rgba(0,0,0,.80), rgba(0,0,0,.44) 56%, rgba(0,0,0,.24) 82%),
    linear-gradient(180deg, rgba(0,0,0,.55) 0%, transparent 26%, transparent 74%, rgba(0,0,0,.65) 100%);
  pointer-events: none;
}
.nikoy-kuvatausta-sisalto { position: relative; z-index: 2; }
.nikoy-kuvausosio   { padding-block: 76px; }
.nikoy-manifestiosio{ padding-block: 84px; }
/* 🔴 OMISTAJAN OHJE 18.9.2026: «"Sivuiltamme löydät jatkossa vastaukset
   ideasta..." ennen oleva tyhjä tila edellisen osan jälkeen voisi olla 80 %
   enemmän kuin nyt.»

   Mitattu ennen: 168 px = manifestin alapadding 84 + tämän yläpadding 84.
   +80 % = 302 px. Manifestin alapadding jää 84:ään, joten tämän yläpadding on
   302 − 84 = 218 px.

   Tämä on tarkoituksellinen poikkeus omaan sääntööni, jonka mukaan osioiden
   rajalle jäävä yhtenäinen tyhjä vyöhyke pidetään noin 170 pikselissä.
   Manifesti päättyy sanaan «Nyt.» ja aiheet alkaa uudella ajatuksella — tauko
   on tässä sisältöä, ei unohtunutta väljyyttä.

   Alapadding on 168 px eikä 112: käännekohdan liuku (140 px) alkaa
   lupausosion yläpuolelta ja leikkasi mitattavasti korttien alareunan. */
.nikoy-aiheosio     { padding-block: 218px 168px; }
.nikoy-lupausosio   { padding-block: 96px 0; text-align: center; }
.nikoy-yhteysosio   { padding-block: 76px; }

.nikoy-kohotettu { background: var(--kohotettu); }

/* Käännekohta tummasta vaaleaan. Liuku tehdään omalla kerroksellaan, jotta
   osion taustaväri pysyy yhtenä muuttujana eikä kahtena. */
.nikoy-lupausosio::before {
  content: "";
  position: absolute; inset-inline: 0;
  inset-block-start: -140px; block-size: 140px;
  background: linear-gradient(180deg, #000000, var(--pohja));
  pointer-events: none;
}

.nikoy-rajaus {
  max-inline-size: var(--rajaus);
  margin-inline: auto;
  inline-size: 100%;
}
.nikoy-rajaus--kapea { max-inline-size: var(--rajaus-kapea); }

.nikoy-iso + .nikoy-leipa,
.nikoy-keski + .nikoy-saate   { margin-block-start: 20px; }
.nikoy-jatti + .nikoy-saate   { margin-block-start: 24px; }
/* 🔴 MITATTU AUKKO. Tälle parille ei ollut sääntöä lainkaan, joten
   margin-block-start oli 0 px. Lupausosiossa jättiotsikkoa seuraa juuri
   `.nikoy-leipa`, ja tekstit koskettivat toisiaan. */
.nikoy-jatti + .nikoy-leipa   { margin-block-start: 28px; }
.nikoy-leipa + .nikoy-saate   { margin-block-start: 24px; }

.nikoy-palstat { display: grid; gap: 28px; }
@media (min-width: 900px) {
  .nikoy-palstat { grid-template-columns: 1fr 1fr; gap: 56px; }
}


/* ==========================================================================
   5. KUVAT — sivun koko visuaalinen paino

   Kuvat on renderöity kerran 2400 × 1600 -kokoisina ja pakattu WebP-muotoon.
   Koko kuvasto on 176 kt; Applen iphone-18-pro lataa 9,4 Mt.

   Jokaisella kuvalla on width ja height -attribuutit, joten selain varaa
   tilan ennen latausta eikä sivu hyppää kuvien saapuessa.
   ========================================================================== */

.nikoy-kuvalava {
  position: relative;
  inline-size: 100%;
  margin-inline: auto;
}

.nikoy-kuva {
  inline-size: 100%;
  border-radius: var(--kulma-kuva);
}

/* 🔴 HERO-KUVAN SÄÄNNÖT POISTETTU 18.9.2026 (omistajan ohje: «tämä kuva ja
   osa sivussa on liikaa. poista se»). Avaus on nyt pelkkää typografiaa, ja
   ensimmäinen kuva on kelausosion kuva. */

/* 🔴 Mitattu selaimesta: perspektiivikuva sulautui taustaansa eikä erottunut.
   Suodatin on staattiselle, animoimattomalle kuvalle kertaluonteinen kustannus
   rasteroinnissa — toisin kuin vieritettäessä muuttuvalle elementille. */
.nikoy-kuvalava--kapea {
  max-inline-size: 980px; margin-block-start: 56px;
  filter: brightness(1.14) contrast(1.05);
}
.nikoy-kuvalava--loppu { max-inline-size: 1100px; margin-block-start: 64px; }


/* ==========================================================================
   6. SAAPUMISLIIKE — vierityssidonnainen

   nikoy.js asettaa jokaiselle .nikoy-saapuu-elementille muuttujan --n
   välille 0…1 sen mukaan, missä se on ruudulla. CSS ei tiedä ajasta mitään.

   Ilman JavaScriptiä --n puuttuu ja varasarvo 1 tarkoittaa täysin näkyvissä.
   Sivu on siis kokonaan luettavissa ilman skriptejä — tarkistettu mittaamalla.
   ========================================================================== */

/* 🔴 PEHMEYS 18.9.2026. Omistaja: «pehmeys liikkeessä puuttuu, erittäin
   äkkinäinen liike.» Syy ei ollut ajoituksessa vaan käyrässä: --n kasvoi
   TASAISESTI vierityksen mukana ja pysähtyi `clamp`iin. Lineaarinen liike
   käynnistyy ja pysähtyy terävästi — nopeus hyppää nollasta täyteen ja
   takaisin nollaan — ja juuri se luetaan nykäisynä. Ajoitusta säätämällä
   sitä ei voi korjata: liike alkaa eri hetkellä mutta yhtä äkkinäisesti.

   Tässä on smoothstep 3n² − 2n³, sama käyrä, jota CSS:n `ease-in-out`
   approksimoi. Sen derivaatta on nolla molemmissa päissä, eli liike lähtee
   ja pysähtyy pehmeästi. Se lasketaan CSS:ssä eikä JS:ssä, jotta selain saa
   pitää arvon omalla puolellaan ja JS jää pelkäksi lukijaksi.

   Päätepisteet eivät muutu: n = 0 → 0 ja n = 1 → 1, joten jokainen tähän
   mennessä mitattu valmistumiskohta pätee edelleen. Ilman JavaScriptiä --n
   puuttuu ja lauseke antaa 1·1·(3−2) = 1 eli täysin näkyvän. */
.nikoy-saapuu {
  --pehmea:  calc(var(--n, 1)  * var(--n, 1)  * (3 - 2 * var(--n, 1)));
  --pehmeay: calc(var(--ny, 1) * var(--ny, 1) * (3 - 2 * var(--ny, 1)));
  opacity: var(--pehmea);
  /* Siirtymällä on oma etenemisensä --ny. Mitattu syy: Applella translateY
     saavuttaa nollan jo silloin, kun opacity on vasta 0,73. */
  transform: translate3d(0, calc((1 - var(--pehmeay)) * var(--nousu)), 0);
}

/* Avausosio saapuu kellolla eikä vierityksellä.
   🔴 MITATTU VIKA: ensimmäisen ruudun sisältö on jo valmiiksi ruudulla eikä
   sen alle voi vierittää, joten vierityssidonnainen laskenta jäi pysyvästi
   kesken ja avaus näkyi 40-prosenttisena. Applella on sama jako: hero on heti
   näkyvissä, ja vierityssidonnainen saapuminen koskee vasta sitä seuraavia. */
.nikoy-avaus .nikoy-silma,
.nikoy-avaus .nikoy-jatti-rivi,
.nikoy-avaus .nikoy-saate {
  animation: nikoy-saapuu .55s var(--kayra-ulos) both;
}
/* 🔴 Avaus oli valmis vasta 1,30 s kohdalla (viive .5 s + kesto .8 s). Se on
   ensivaikutelma, ja odottaminen tuntuu hitaudelta eikä tyylikkyydeltä.
   Nyt viimeinen elementti on paikallaan 0,87 s kohdalla. */
.nikoy-avaus .nikoy-jatti-rivi { animation-delay: calc(.04s + var(--v) * .06s); }
.nikoy-avaus .nikoy-saate         { animation-delay: .22s; }

@keyframes nikoy-saapuu {
  from { opacity: 0; transform: translate3d(0, var(--nousu), 0); }
  to   { opacity: 1; transform: none; }
}


/* ==========================================================================
   7. KELAUS — kiinnitetty, vieritys ajaa --t:tä välillä 0…1

   Rakenne mitattu Applen `.section-pro-camera`-osiosta: 4713 px korkea osio,
   jonka sisällä viewportin korkuinen kiinnitetty kontti. Videon currentTime
   kulki 0,00 → 4,98 s vierityksen mukana.
   ========================================================================== */

.nikoy-jakso {
  /* 🔴 Varasarvo on 1 eli VALMIS. Jos JavaScript ei aja, kuva on paikallaan ja
     kaikki tekstit näkyvissä — ei koskaan puolivalmista. Alkutilan asettaa
     nikoy.js luokalla, jonka se lisää vasta alustettuaan jakson. */
  --t: 1;
  position: relative;
  inline-size: 100%;
  /* 🔴 Kaksi mitattua säätöä. Ensin 300svh = 2700 px kolmelle lauseelle, siis
     900 px vieritystä per lause — pitkä osuus tuntui pysähtyneeltä, ja arvo
     laskettiin 240svh:hon.

     Kun rivit alkoivat KERTYÄ vaihtumisen sijaan, tarve lyheni uudelleen:
     vaihtuvat tekstit tarvitsivat matkaa myös poistuakseen, kertyvät eivät.
     Viimeinen rivi valmistuu 73 %:n kohdalla, ja loppuun jää hetki jossa koko
     virke seisoo paikallaan luettavana. 200svh antaa sille noin 270 px. */
  block-size: 200svh;
}
.nikoy-kelaus-kaynnissa .nikoy-jakso { --t: 0; }

.nikoy-liima {
  position: sticky;
  inset-block-start: 0;
  block-size: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
  padding-inline: var(--reuna);
}

.nikoy-kuvalava--kelaus {
  grid-area: 1 / 1;
  max-inline-size: min(92vw, 1400px);
  /* Kuva lähenee hitaasti ja kirkastuu. Vain transform ja opacity muuttuvat,
     joten selain hoitaa liikkeen kompositoinnissa. */
  /* 🔴 Oli scale .88→1,00 ja opacity .42→1,00. Osion alussa kuva oli siis
     42-prosenttisena ja teksti 40-prosenttisena: lukija saapui osioon, jossa
     kumpikaan ei ollut valmis. Lisäksi 12 %:n skaalausväli pakottaa selaimen
     rasteroimaan kerroksen matkan varrella uudelleen.

     Kapeampi väli on sekä halvempi että luettavampi: kuva on alusta asti
     näkyvä ja liike on hienovarainen, ei zoomaus. */
  transform: scale(calc(.94 + var(--t) * .06));
  opacity: calc(.72 + var(--t) * .28);
  will-change: transform, opacity;
}

/* Vaihetekstit ovat päällekkäin samassa ruudussa, jotta seuraava ei työnnä
   edellistä. Näkyvyys lasketaan etäisyytenä vaiheen omasta keskikohdasta. */
.nikoy-vaiheet {
  grid-area: 1 / 1;
  z-index: 2;
  inline-size: 100%;
  max-inline-size: none;
  text-align: center;
}

/* 🔴 RAKENNE MUUTTUI 18.9.2026. Vaiheet olivat päällekkäin samassa
   grid-ruudussa ja vaihtuivat vieritettäessä: yksi näkyvissä kerrallaan,
   edellinen liukui pois kun seuraava tuli.

   Omistajan ohje: «"Tiedot, faktat ja tapahtumat" yhdelle riville. normi
   riviväli ennen "kaikista käyttämistäsi järjestelmistä."» — ja perustelu
   sille, mitä hän tavoittelee: «se on jo tässä, valmiiksi koottuna ja
   hyödynnettynä ja jalostettuna.»

   Riviväli on käsitteenä olemassa vain, jos rivit ovat allekkain. Nyt ne
   ovat: rivit KERTYVÄT vieritettäessä yksi kerrallaan ja JÄÄVÄT näkyviin,
   ja osion lopussa koko virke on luettavissa kerralla. Se on sama asia mitä
   ohjelma lupaa tehdä tiedolle — kokoaa sen yhteen — ja siksi se on oikeampi
   liike tähän osioon kuin vaihtuminen.

   Kaksi mitattua seurausta: päällekkäisyyttä ei voi enää syntyä (rivit ovat
   eri riveillä, eivät samassa ruudussa), eikä lukukelvotonta väliä ole
   (mikään ei häivy pois). Aiempi 420 px:n erotus oli olemassa vain
   päällekkäisyyden takia, ja se poistui tarpeettomana. */
.nikoy-vaihe {
  display: block;

  /* 🔴 Oli 16ch = 655 px, ja se pakotti rivit taittumaan: «Tiedot, faktat ja
     tapahtumat» vei 2 riviä ja «kaikista käyttämistäsi järjestelmistä.» vei
     neljä — vaikka palstaa oli 1240 px. Mitatut leveydet yhdellä rivillä
     64 px:n koossa ovat 754, 990 ja 359 px, joten 1240 px riittää kaikille.
     Rivinpituuden rajaus mitataan tämän elementin omassa koossa. */
  max-inline-size: 100%;

  /* Rivi ilmestyy ja jää. `--kpl` tulee sivupohjasta, jottei vaiheiden määrän
     muuttaminen tekstivarastossa riko ajoitusta hiljaisesti.

     Kerroin 1,2 ja siirto −0,6 on valittu niin, että ensimmäinen rivi on
     täysin näkyvissä heti osion alussa ja viimeinen valmistuu noin 73 %:n
     kohdalla — loppuun jää hetki, jossa koko virke seisoo paikallaan. */
  /* 🔴 KAKSI SÄÄDINTÄ, KAKSI ERI HAVAINTOA (18.9.2026).

     «"kaikista käyttämistäsi järjestelmistä" lähtee liikkeelle liian myöhään»
        → `--alku`-kerroin .9 → .6. Kerroin levittää vaiheiden ALOITUSkohdat
          osion kelattavalle matkalle. Toinen vaihe lähti 144 px:n kohdalla,
          nyt 96 px:n.

     «"Reaaliajassa" jälkeen sivun liike lähtee liikkeelle liian myöhään»
        → `--voima` 2·kpl → .667·kpl, eli häivytys kestää kolme kertaa
          pidempään. Tämä on se säädin, joka poistaa tyhjän lopun: viimeinen
          vaihe oli valmis jo 704 px:n kohdalla, ja loput 496 px vieritettiin
          ilman että mitään tapahtui. Nyt se valmistuu 936 px:n kohdalla, ja
          tyhjää jää 264 px.

     Huomaa, että aloituksen aikaistaminen YKSIN olisi pahentanut toista
     ongelmaa: kaikki olisi valmistunut vielä aiemmin ja tyhjää loppua olisi
     tullut lisää. Siksi kerroin ja voima säädettiin vastakkaisiin suuntiin.

     Vaiheet ovat nyt pidempään päällekkäin liikkeessä, mikä sopii tähän
     osioon: rivit KERTYVÄT päällekkäin eivätkä vaihdu, joten yhtä aikaa
     liikkuvat rivit ovat sama lause muodostumassa, eivät kaksi kilpailevaa. */
  /* 🔴 VIKA JA KORJAUS 18.9.2026. Omistaja: «"Tiedot, faktat ja tapahtumat"
     on nyt heti scrollatessa näkyvissä pienellä opacitylla kun sen pitäisi
     lähteä nollasta täyteen opacityyn.»

     Kaavassa oli vakio −,6, joka siirsi jokaisen vaiheen aloitusta taaksepäin.
     Ensimmäiselle vaiheelle (v = 0) se antoi aloituskohdan −,12 eli ENNEN
     osion alkua, joten heti kun osio tuli ruudulle, teksti oli jo 24 %
     kirkas. Vakio oli näkymätön niin kauan kuin kerroin oli iso: se siirsi
     aloitusta, mutta ensimmäinen vaihe ehti silti nollaan. Kun kerrointa
     pienennettiin 1,2 → ,9 → ,6 aloitusten aikaistamiseksi, vakio jäi
     paikalleen ja työnsi lopulta ensimmäisen vaiheen miinukselle.

     Nyt `--v` kerrotaan suoraan: vaihe 0 alkaa täsmälleen kohdasta 0, eikä
     mikään arvo voi enää valua negatiiviseksi kerrointa säädettäessä.
     Kerroin ,4 on valittu niin, että toinen vaihe lähtee 160 px:n kohdalla
     (omistajan hyväksymä tuntuma oli 144 px) ja viimeinen on valmis 920 px:n
     kohdalla, jolloin osion loppuun jää 280 px tyhjää — alkutilanteessa sitä
     oli 496 px. */
  --alku:  calc(var(--v) * .4 / var(--kpl, 3));
  --voima: calc(.667 * var(--kpl, 3));
  --n: clamp(0, calc((var(--t) - var(--alku)) * var(--voima)), 1);

  opacity: var(--n);
  transform: translate3d(0, calc((1 - var(--n)) * 28px), 0);

  /* Kolme elementtiä omalle kompositointikerrokselleen: opacity ja transform
     muuttuvat silloin ilman uudelleenmaalausta. Kolme kerrosta on turvallinen
     määrä — aiemmassa toteutuksessa niitä oli 485 ja GPU-muisti loppui. */
  will-change: opacity, transform;
}

/* Yksi sana virkkeen sisällä samalla oranssilla kuin manifestin «Faktasta.»
   ja «Nyt.». Sivulla on yksi korostusväri ja se tarkoittaa yhtä asiaa: tässä
   on lupauksen ydin. Väri peritään korostusmuuttujasta, jottei sävyjä ole
   kahta. */
.nikoy-vaihe-korostus { color: var(--korostus); font-weight: inherit; }

/* 🔴 OMISTAJAN OHJE 18.9.2026: «Lisää riviväliä ennen "Reaaliajassa."» Se on
   oma virkkeensä kahden ensimmäisen rivin muodostaman virkkeen jälkeen, ja
   tauko tekee sen näkyväksi. Kapealla ruudulla vaiheet ovat `display: inline`,
   jolloin tämä ei vaikuta — siellä rivejä ei ole erotettu lainkaan. */
.nikoy-vaihe:last-child { margin-block-start: .16em; }

/* Varjo yksin ei riittänyt: kuvassa on vaaleita kohtia (kaavion viiva, oranssi
   pylväs), joiden päällä valkoinen teksti katosi. Säde on yksi liukuväri yhdessä
   elementissä — ei suodatin eikä sekoitustila, joten se maksaa kerran. */
.nikoy-liima::before {
  content: '';
  /* 🔴 KAKSI MITATTUA VIKAA TÄSSÄ YHDESSÄ SÄÄNNÖSSÄ.

     1. ::before on elementin ensimmäinen lapsi, joten se piirtyisi ilman
        z-indexiä KUVAN ALLE eikä tekisi mitään. Kerrokset: kuva 0, säde 1,
        teksti 2.

     2. Ensin säde oli grid-item (`grid-area: 1/1`) leveydellä 1500 px. Rata
        venyy leveimmän itemin mukaan, joten 1377 px:n säiliöön syntyi 1500 px:n
        rata — ja KAIKKI sen sisältö siirtyi 61 px oikealle. Teksti ja kuva
        olivat mitattavasti pois keskeltä, eikä syy näkynyt kummankaan omissa
        säännöissä. Absoluuttinen sijoitus ottaa säteen pois radasta: se ei
        enää voi vaikuttaa siihen, mihin mikään muu asettuu. */
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(62% 52% at 50% 50%, rgba(0,0,0,.82), rgba(0,0,0,.44) 54%, transparent 80%);
  /* 🔴 Oli `opacity: var(--t)`. Kaksi vikaa yhdessä arvossa:

     1. Koko ruudun kokoinen liukuväri maalattiin uudelleen joka
        ruudunpäivityksellä — tämä oli osa mitattua pätkimistä.
     2. Se oli väärin päin. Säde on tekstin luettavuutta varten, ja teksti on
        kuvan päällä KOKO osion ajan. Osion alussa (t=0) sädettä ei ollut
        lainkaan, eli juuri siellä missä sitä eniten tarvittiin.

     Nyt säde on staattinen ja hieman vahvempi, koska se kantaa yksin sen
     luettavuuden, joka ennen jaettiin tekstin varjon kanssa. */
  opacity: 1;
  pointer-events: none;
}


/* ==========================================================================
   8. NAPPI — mitattu: kulma 980px, padding 12/22px, 17px vahvuus 400
   ========================================================================== */

/* 🔴 EI TÄLLÄ HETKELLÄ KÄYTÖSSÄ: avauksen «Ota yhteyttä» -painike poistettiin
   18.9.2026 omistajan ohjeella, ja lomakkeen lähetyspainike on `.nikoy-laheta`.
   Sääntö säilytetään, koska sen arvot on MITATTU Applen napista — kulma 980px,
   padding 12/22px, 17px vahvuudella 400, fokus 2px #0071e3 — eivätkä ne ole
   johdettavissa uudelleen ilman samaa mittausta. */
.nikoy-nappi {
  display: inline-block;
  padding: 12px 22px;
  border-radius: var(--kulma-nappi);
  background: var(--nappi); color: var(--nappi-tx);
  font-size: 17px; line-height: 1.18; letter-spacing: -.022em;
  font-weight: 400;              /* mitattu: Apple ei lihavoi nappitekstiä */
  text-decoration: none;
  transition: opacity var(--nopea) var(--kayra);
}
.nikoy-nappi:hover  { opacity: .86; }
.nikoy-nappi:active { opacity: .72; }


/* ==========================================================================
   9. AIHEGALLERIA

   Kortti on typografiaa reunasta reunaan. 🔴 Mitattu vika edellisestä
   toteutuksesta: kortit olivat noin 75 % tyhjiä, ja juuri se sai sivun
   näyttämään rakentamattomalta.
   ========================================================================== */

/* Johdatus on otsikon LAUSEEN JATKE, ei erillinen saate: se johtaa suoraan
   kortteihin, jotka ovat lauseen loppu. Pienenä harmaana tekstinä se näytti
   katkelmalta — nyt se on otsikon kokoluokassa ja sijoitettu lähelle kortteja. */
.nikoy-johdatus {
  margin-block-start: 18px;
  font-size: 24px; line-height: 1.17; letter-spacing: .009em; font-weight: 400;
  color: var(--teksti-2);
  text-align: center;
}
@media (min-width: 1069px) {
  .nikoy-johdatus { font-size: 28px; letter-spacing: .007em; }
}

.nikoy-galleria { position: relative; margin-block-start: 40px; }

.nikoy-rata {
  display: flex;
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;

  /* 🔴 MITATTU VIKA 18.9.2026. Omistaja näytti kaksi kuvakaappausta samasta
     karusellista: «lähtöasettelu on [tämä] kun sen pitäisi olla [tuo]». Kortit
     ja niiden välit olivat kuvissa pikselilleen samat — ero oli tasan 200 px
     siinä, mistä ensimmäinen kortti alkaa.

     Syy: sisennys oli sidottu ikkunan leveyteen ilman kattoa, jotta rata
     linjaisi tekstipalstan kanssa. Se toimii 1440 px:iin asti, mutta jatkaa
     kasvamistaan loputtomiin:

         1280 px →  24 px       1728 px → 244 px
         1440 px → 100 px       1990 px → 375 px
         1512 px → 136 px       2560 px → 660 px

     Leveällä näytöllä karuselli valui siis keskelle ruutua ja näytti alkavan
     satunnaisesta kohdasta. Kumpikin kuvakaappaus oli samasta koodista, vain
     eri levyiseltä ikkunalta — vika ei ollut asetuksessa vaan siinä, ettei
     asetuksella ollut kattoa.

     Katto on 100 px, koska se on sama arvo, johon kaava päätyy 1440 px:n
     ruudulla: linjaus tekstipalstan kanssa säilyy siihen asti, ja sitä
     leveämmillä ruuduilla ilme pysyy muuttumattomana. */
  --rata-sisennys: min(max(var(--reuna), calc((100vw - var(--rajaus)) / 2)), 100px);
  scroll-padding-inline: var(--rata-sisennys);
  padding-inline: var(--rata-sisennys);

  padding-block: 4px 16px;
  scrollbar-width: none;
}
.nikoy-rata::-webkit-scrollbar { display: none; }

/* 🔴 KOLMAS VERSIO, kaksi mitattua epäonnistumista takana.
   1. Pieni kuvio + nimi → kortti oli 75 % tyhjä.
   2. Iso himmeä järjestysluku + nimi → luku oli niin himmeä, ettei se
      erottunut mustasta, ja kortti näytti yhä tyhjältä. Mitattu selaimesta.
   3. Nyt kortissa on KUVA reunasta reunaan. Kuva täyttää kortin, teksti on
      sen päällä siinä kohdassa, johon kuvan oma alahäivytys on tehty. */
.nikoy-kortti {
  position: relative;
  flex: 0 0 auto;
  inline-size: min(76vw, 300px);
  aspect-ratio: 4 / 5;
  scroll-snap-align: center;
  border-radius: var(--kulma-kortti);
  background: var(--kortti);
  border: 1px solid var(--hiusviiva);
  overflow: hidden;
  padding: 26px;
  display: flex; flex-direction: column; justify-content: space-between;
  transition: border-color var(--perus) var(--kayra), transform var(--perus) var(--kayra);
}
.nikoy-kortti:hover { border-color: rgba(255,255,255,.28); }

.nikoy-kortti-kuva {
  position: absolute; inset: 0;
  inline-size: 100%; block-size: 100%;
  object-fit: cover;
  /* Kuva on kortin alla, teksti sen päällä. Ei suodattimia eikä sekoitustiloja
     — ne piirrettäisiin uudelleen joka ruudulla. */
  z-index: 0;
}

/* 🔴 VÄLTTÄMÄTÖN VALOKUVILLE. Aiemmat kuvat olivat itse tehtyjä, ja niihin oli
   leivottu alahäivytys jo kuvatehtaassa. Valokuvaa ei voi valita sen mukaan,
   mitä sen alareunassa sattuu olemaan: yhdessä on betoniseinä, toisessa
   iltataivas, kolmannessa valaistu ikkuna. Ilman tätä kerrosta kortin nimi
   katoaisi osassa kuvista.

   Yksi liukuväri yhdessä pseudoelementissä — ei suodatin, ei sekoitustila. */
.nikoy-kortti::after {
  content: '';
  position: absolute; inset: 0;
  z-index: 0;
  background: linear-gradient(180deg,
    rgba(0,0,0,.30) 0%, rgba(0,0,0,.10) 34%, rgba(0,0,0,.62) 72%, rgba(0,0,0,.88) 100%);
  pointer-events: none;
}

/* 🔴 KIRKAS KORTTI. Tumma häivytys vaalean kuvan päällä ei tummenna vaan
   likaa: kuvan alareunasta tulee harmaa liuku. Mitattu selaimesta — «Rahoitus»
   ja «Sopimukset» näyttivät haalistuvan. Vaalea kuva saa siksi saman kohtelun
   kuin sivun vaalea puolisko: tumma teksti, vaalea häivytys. */
.nikoy-kortti--kirkas::after {
  background: linear-gradient(180deg,
    rgba(245,245,247,0) 0%, rgba(245,245,247,.08) 46%, rgba(245,245,247,.80) 78%, rgba(245,245,247,.96) 100%);
}
.nikoy-kortti--kirkas .nikoy-kortti-nimi {
  color: #1d1d1f;
  text-shadow: 0 1px 18px rgba(245,245,247,.9);
}
.nikoy-kortti--kirkas .nikoy-kortti-luku { color: rgba(0,0,0,.42); }
.nikoy-kortti--kirkas { border-color: rgba(255,255,255,.22); }
.nikoy-kortti--kirkas:hover { border-color: rgba(255,255,255,.45); }

/* Järjestysluku, ei tunnusluku: se kertoo sijainnin listassa kuten
   sisällysluettelossa, eikä väitä mitään tuotteesta. */
.nikoy-kortti-luku {
  position: relative; z-index: 1;
  font-size: 15px; line-height: 1; letter-spacing: .06em; font-weight: 600;
  color: rgba(255,255,255,.42);
}
.nikoy-kortti-nimi {
  position: relative; z-index: 1;
  font-size: 26px; line-height: 1.14; letter-spacing: .004em; font-weight: 600;
  text-wrap: balance;
  text-shadow: 0 1px 24px rgba(0,0,0,.75);
}
@media (min-width: 1069px) {
  .nikoy-kortti     { inline-size: 332px; }
  .nikoy-kortti-nimi { font-size: 28px; letter-spacing: .007em; }
}

/* Nuolet: mitattu Applen paddlenavista — rgba(66,66,69,.72), pyöreä. */
.nikoy-nuoli {
  position: absolute;
  inset-block-start: calc(50% - 30px);
  inline-size: 44px; block-size: 44px;
  border: 0; border-radius: 50%;
  background: rgba(66,66,69,.72);
  backdrop-filter: saturate(180%) blur(20px);
  cursor: pointer; z-index: 3;
  transition: opacity var(--nopea) var(--kayra);
}
.nikoy-kaanne .nikoy-nuoli { background: rgba(255,255,255,.86); }
.nikoy-nuoli[disabled] { opacity: .42; cursor: default; }   /* mitattu: .42 */
.nikoy-nuoli--taakse { inset-inline-start: 12px; }
.nikoy-nuoli--eteen  { inset-inline-end: 12px; }

.nikoy-nuoli span {
  position: absolute; inset: 0; margin: auto;
  inline-size: 11px; block-size: 11px;
  border-inline-end: 2px solid #fff;
  border-block-start: 2px solid #fff;
}
.nikoy-kaanne .nikoy-nuoli span { border-color: #1d1d1f; }
.nikoy-nuoli--eteen  span { rotate: 45deg;   translate: -3px 0; }
.nikoy-nuoli--taakse span { rotate: -135deg; translate: 3px 0; }

.nikoy-pisteet { display: flex; justify-content: center; gap: 9px; margin-block-start: 22px; }
.nikoy-piste {
  inline-size: 9px; block-size: 9px;
  padding: 0; border: 0; border-radius: 50%;
  background: var(--hiusviiva); cursor: pointer;
  transition: background var(--nopea) var(--kayra), transform var(--nopea) var(--kayra);
}
.nikoy-piste[aria-current="true"] { background: var(--teksti); transform: scale(1.3); }


/* ==========================================================================
   10. LOMAKE
   ========================================================================== */

.nikoy-lomake { margin-block-start: 30px; display: grid; gap: 18px; }
.nikoy-lomake p { display: grid; gap: 7px; margin: 0; }

.nikoy-lomake label {
  font-size: 14px; line-height: 1.29; letter-spacing: -.016em;
  color: var(--teksti-2);
}

.nikoy-lomake input[type="text"],
.nikoy-lomake input[type="email"],
.nikoy-lomake textarea {
  inline-size: 100%;
  min-block-size: 44px;          /* kosketuskohteen vähimmäiskoko */
  padding: 11px 14px;
  border-radius: 12px;
  border: 1px solid var(--hiusviiva);
  background: var(--kohotettu);
  color: var(--teksti);
  font-family: inherit; font-size: 17px; line-height: 1.18; letter-spacing: -.022em;
  transition: border-color var(--nopea) var(--kayra);
}
.nikoy-lomake textarea { min-block-size: 132px; resize: vertical; }
.nikoy-lomake :is(input, textarea):focus { border-color: var(--fokus); }

.nikoy-laheta {
  justify-self: start;
  padding: 12px 22px; border: 0; border-radius: var(--kulma-nappi);
  background: var(--nappi); color: var(--nappi-tx);
  font-family: inherit; font-size: 17px; line-height: 1.18;
  letter-spacing: -.022em; font-weight: 400;
  cursor: pointer;
  display: inline-grid; gap: 2px; justify-items: center;
}
.nikoy-laheta[disabled] { opacity: .42; cursor: not-allowed; }
.nikoy-laskuri {
  display: block; font-size: 12px; line-height: 1.33; letter-spacing: -.010em;
  font-variant-numeric: tabular-nums;   /* laskuri ei nyi leveyttään */
  opacity: .8;
}

/* Hunajapurkki. Näytöltä pois mutta ei display:none — osa boteista jättää
   piilotetut kentät väliin, jolloin ansa ei laukea. */
.nikoy-hp {
  position: absolute; inline-size: 1px; block-size: 1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

p.nikoy-tietosuoja {
  font-size: 12px; line-height: 1.33; letter-spacing: -.010em;
  color: var(--teksti-2); max-inline-size: 52ch;
}
p.nikoy-ilmoitus {
  padding: 14px 16px; border-radius: 12px;
  background: var(--kohotettu); border: 1px solid var(--hiusviiva);
  font-size: 17px; letter-spacing: -.022em;
}


/* ==========================================================================
   11. ALATUNNISTE JA VERSIOVALIKKO
   ========================================================================== */

.nikoy-alatunniste {
  background: #f5f5f7; color: #6e6e73;
  padding: 30px var(--reuna) 42px;
  text-align: center;
  font-size: 12px; line-height: 1.33; letter-spacing: -.010em;
}

/* 🔴 VERSIOVALIKON SÄÄNNÖT POISTETTU 18.9.2026: valikkoa ei enää ole. */


/* ==========================================================================
   12. ILME

   🔴 OMISTAJAN PÄÄTÖS 18.9.2026, verbatim: «poista yläosan valikko eri
   sivuvaihtoehdoista, jätetän käyttöön tämä raju.» Versiot Syvä ja Kirkas
   sekä valikko on poistettu. Jäljellä on yksi ilme.

   Luokka `nikoy-v-raju` jää, koska nämä säännöt tulevat perussääntöjen
   JÄLKEEN ja voittavat kaskadissa. Sulauttaminen käsin olisi muutos, jossa
   jokin arvo jäisi väärään järjestykseen huomaamatta.
   ========================================================================== */

/* --- Raju: typografia hallitsee, kuva on pienempi ja tekstin alla. --- */
/* 🔴 JÄTTIKOKO PIENENI 18.9.2026. Omistaja pyysi pienennystä kolmessa
   kohdassa erikseen — avaus, manifesti ja lupaus — ja samalla: «Pidä myös eri
   fonttikokojen määrä maltillisena ettei sivulla ole valtavasti eri
   fonttikokoja.» Nämä kolme osiota käyttävät SAMAA jättikokoa, joten kaikki
   kolme pyyntöä toteutuvat yhdellä portaikolla. Uusia kokoja ei tullut yhtään.

   Koko ei kuitenkaan ollut vapaasti valittavissa. Avauksen rivi on nyt «kaikki
   liiketoimintasi tieto», joka on mitattuna 10,025 × fonttikoko. Palsta on
   1240 px, joten rivi vaatii enintään 123 px — vanha 168 px olisi taittanut
   sen ja tuottanut juuri sen viidennen rivin, joka oli tarkoitus poistaa.
   Valittu 124 px jättää 59 px varaa (4,8 %).

   Portaat on koottu tähän yhteen paikkaan. Ennen kaksi pienintä tulivat
   perussäännöistä (osa 3) ja kaksi suurinta täältä; sama koko määriteltiin
   siis kahdessa eri tiedoston kohdassa.

   🔴 MITTARIVIRHE, joka ehti julkaisuun asti. Ensimmäinen kokovalinta nojasi
   kertoimeen 9,359 «kaikki liiketoimintasi tieto» -riville, ja se oli väärä.
   Mittaelementille kopioitiin `letter-spacing` SELAIMEN LASKEMANA PIKSELINÄ
   (-5,88px, joka on -.035em × 168px) mutta font-sizeksi asetettiin 100px.
   Pikseliarvo ei skaalaudu: kirjainväli oli -.0588em eli 68 % liian tiukka,
   ja 28-merkkinen rivi mitattiin .67 kertoimen verran liian kapeaksi. Valittu
   128 px läpäisi laskelman ja taittui ruudulla kahdelle riville — eli tuotti
   juuri sen viidennen rivin, joka oli tarkoitus poistaa.

   Kertoimet on nyt mitattu `letter-spacing: -.035em` -arvolla ja tarkistettu
   kontrollilla: ennuste 128 px:llä vs. ruudulta mitattu leveys osui 0,5 px:n
   sisään kuudella rivillä kuudesta (659/658,9 · 1036/1036 · 1031/1030,8 ·
   892/892 · 820/819,9 · 935/934,5).

   Pisin rivi on «kaikki liiketoiminnastasi», kerroin 9,527. Katto on palsta /
   9,527. Varaa jätetään reilusti, koska kirjasin on järjestelmän oma
   (-apple-system · Segoe UI · Roboto) ja leveys vaihtelee koneittain —
   nollamarginaali taittaisi rivin jollakin muulla koneella kuin tällä.

     porras      palsta   katto   valittu   varaa
     < 735 px      327     34 px   32 px      7 %
     735 px        687     72 px   60 px     17 %
     1069 px      1021    107 px  100 px      7 %
     1441 px      1240    130 px  124 px      5 %

   🔴 KOKO NOSTETTU TAKAISIN 116 → 124 px. Omistaja tarkensi: «tarkoitin vain
   sanojen muutosta, en fonttikoon muutosta.» Koko viedään siis niin lähelle
   vanhaa 168 px:ää kuin rivi sallii.

   Vanhaan 168 px:ään ei kuitenkaan voi palata, eikä syy ole tämän istunnon
   sanamuutoksissa: se ei mahtunut ENNENKÄÄN. Mitattu vanhalta sivulta «Sinun
   liiketoimintasi.» vaati 168 px:n koossa 1353 px, kun palsta on 1240 px —
   rivi taittui kahdelle riville, ja juuri siitä syntyi aiempi keskitysvika,
   jossa taittunut rivi valui vasempaan reunaan. 124 px on suurin koko, joka
   pitää sekä avauksen että manifestin pisimmän rivin yhdellä rivillä. */
body.nikoy-v-raju .nikoy-jatti,
body.nikoy-v-raju .nikoy-mrivi { letter-spacing: -.035em; line-height: .96; font-size: 32px; }
@media (min-width: 735px) {
  body.nikoy-v-raju .nikoy-jatti,
  body.nikoy-v-raju .nikoy-mrivi { font-size: 60px; }
}
@media (min-width: 1069px) {
  body.nikoy-v-raju .nikoy-jatti,
  body.nikoy-v-raju .nikoy-mrivi { font-size: 100px; }
}
@media (min-width: 1441px) {
  body.nikoy-v-raju .nikoy-jatti,
  body.nikoy-v-raju .nikoy-mrivi { font-size: 124px; }
}

/* 🔴 OMISTAJAN OHJE 18.9.2026: «Lisää riviväliä ennen "yhdellä silmäyksellä".»
   Neljäs rivi on lauseen loppu — «kaikki liiketoiminnastasi» kertoo MITÄ ja
   «yhdellä silmäyksellä» kertoo MITEN — ja tauko erottaa ne. Sama .16em kuin
   manifestissa, lupauksessa ja kelauksessa: koko sivulla on yksi riviväliarvo,
   ei neljää eri lukua. */
body.nikoy-v-raju .nikoy-avaus .nikoy-jatti-rivi:nth-child(4) {
  margin-block-start: .16em;
}

/* 🔴 OMISTAJAN OHJE 18.9.2026: «"Tulossa syksyllä 2026." selkeästi alemmas
   ensinäkymässä mutta ei liian alas.» Väli oli 24 px, eli vähemmän kuin
   neljäsosa H1:n rivinvälistä (111 px) — saate luki kuin viides otsikkorivi.

   Arvo on `vh` eikä `em`: sääntö kohdistuu saatteeseen, joka on 17 px, joten
   `em` laskisi siitä eikä otsikosta ja tuottaisi 11 px:n välin. Pystysuunnan
   mitta on tässä ruudun korkeus — osio on `100svh` — joten 13vh pitää välin
   samassa suhteessa ruutuun riippumatta ikkunan koosta. Rajat estävät sen
   kutistumisen matalalla ruudulla ja karkaamisen korkealla.

   Huomaa että osio on pystysuunnassa keskitetty: kun lohko kasvaa 132 px,
   saate laskee vain 66 px ja kaikki muu nousee saman verran. Siksi luku on
   suurempi kuin siirtymä, jonka se saa aikaan. */
body.nikoy-v-raju .nikoy-avaus .nikoy-jatti + .nikoy-saate {
  margin-block-start: clamp(44px, 13vh, 168px);
}

/* 🔴 OMISTAJAN OHJE 18.9.2026: «Lisää riviväliä ennen "Nyt se on".» Väli tulee
   VAIN toisen rivin eteen: «Tietoa on paljon» on oma virkkeensä ja «Nyt se on
   / yhdessä paikassa» on toinen. Tauko on virkkeiden välissä, ei virkkeen
   sisällä.

   🔴 KASVATETTU .16em → .32em 18.9.2026 omistajan ohjeella: «Lisää riviväliä
   ennen "Nyt se on / yhdessä paikassa".» Sama arvo kuin manifestissa, joten
   sivun kahdessa jättilohkossa on yksi ja sama riviväli. (Kelauksen .16em on
   erikseen: se on 64 px:n tekstiä, ja em-arvo laskee siellä omasta
   koostaan.) */
body.nikoy-v-raju .nikoy-lupausosio .nikoy-jatti-rivi:nth-child(2) {
  margin-block-start: .32em;
}
/* 🔴 TASAUS 18.9.2026. Omistaja luetteli osiot, joiden kuuluu olla keskitettyjä:
   avaus, manifesti, aiheiden otsikko, lupaus ja väite. Yhteyslomake ei ollut
   listalla: se on lomake, jossa kentät ovat vasemmassa reunassa, ja keskitetty
   lomake olisi hankalampi täyttää kuin luettava.

   Väiteosio palasi perussääntönsä varaan — `.nikoy-vaiteosio` on jo
   `text-align: center`, joten Rajun oma `start`-rivi vain poistettiin.

   Huomaa että näitä ohjataan KAHDELLA eri mekanismilla, koska osiot on
   rakennettu eri tavoin. `.nikoy-avaus` ja `.nikoy-lupausosio` ovat tavallisia
   lohkoja, joissa riittää `text-align`. `.nikoy-manifesti` on flex-pylväs,
   jossa `text-align` ei tekisi mitään: rivit ovat flex-itemejä, ja niiden
   sijainnin ratkaisee `align-items`. Sama ero on `.nikoy-jatti`-otsikossa,
   mutta se toimii silti `text-align`illa, koska sillä ei ole `align-items`-
   arvoa: rivit venyvät oletuksena täyteen leveyteen ja teksti tasataan niiden
   sisällä. */
body.nikoy-v-raju .nikoy-avaus      { text-align: center; }

/* 🔴 OMISTAJAN OHJE 18.9.2026: «Jätä Niko yhtiöt Oy ensinäkymässä siihen missä
   se on mutta siirrä kaikkea muuta alemmas — ja ilman että se vaikuttaa
   mihinkään alempana sivulla.»

   Nämä kaksi vaatimusta ovat pystysuunnassa keskitetyssä osiossa ristiriidassa.
   `justify-content: center` jakaa vapaan tilan tasan ylös ja alas, joten
   pelkkä väli silmän alle kasvattaisi lohkoa ja NOSTAISI silmää puolella
   lisäyksestä — juuri sen elementin, jonka piti pysyä paikallaan.

   Siksi keskitys puretaan ja yläreuna kiinnitetään: 21,7vh on mitattu luku,
   jonka keskitys antoi silmälle tällä sivulla (260,3 px / 1200 px). Silmä jää
   siis sinne missä se oli, ja kaikki sen jälkeen tuleva voi laskea vapaasti.

   Alempi sivu ei liiku, koska osio on `min-height: 100svh` eikä sisältö
   kasva sen yli: 1200 px:n ruudulla pinoksi tulee 260 + 23 + 84 + 496 + 156
   + 21 + 48 = 1088 px eli 112 px pelivaraa. Alapaddingia pienennettiin
   84 → 48 px juuri tämän varan säilyttämiseksi. */
/* 🔴 NOSTETTU 18.9.2026: «siirrä kaikkia […] hiukan ylemmäs ensinäkymässä.
   siirrä "Niko yhtiöt Oy" hiukan ylemmäs.» Kaksi eri siirtoa, ja ne tehdään
   kahdella eri luvulla, koska silmä on lohkon ensimmäinen elementti: sen
   sijainnin ratkaisee yksin yläpadding, ja kaikki muu liikkuu sekä paddingin
   että silmän alamarginaalin mukana.

     yläpadding   21,7vh → 16vh   (−68 px): koko lohko nousee 68 px
     silmän alle   7vh   →  9vh   (+24 px): H1 ja saate palaavat 24 px alas

   Nettona silmä nousee 68 px ja muu sisältö 44 px, eli molemmat nousevat ja
   silmä enemmän — juuri se, mitä pyydettiin. Pinoksi tulee 1200 px:n ruudulla
   192 + 23 + 108 + 496 + 156 + 21 + 48 = 1044 px, joten osio pysyy tasan
   yhdessä ruudussa eikä mikään alempana sivulla liiku. */
body.nikoy-v-raju .nikoy-avaus {
  justify-content: flex-start;
  padding-block: 16vh 48px;
}
body.nikoy-v-raju .nikoy-avaus .nikoy-silma { margin-block-end: 9vh; }
/* 🔴 KAKSI SÄÄNTÖÄ, EI YHTÄ — mitattu vika 18.9.2026.
   `align-items: center` keskittää flex-itemin eli rivin LAATIKON. Se riittää
   niin kauan kuin rivi mahtuu yhdelle riville. Kun teksti taittuu — «Sinun
   liiketoimintasi.» vaatii 168 px:n koossa 1298 px ja palsta on 1240 px —
   laatikko venyy leveimmän rivinsä mittaiseksi, ja sen SISÄLLÄ rivit tasataan
   `text-align`in mukaan. Sitä ei ollut asetettu, joten taittunut rivi valui
   vasempaan reunaan muiden ollessa keskellä.

   Mittari sanoi «keskellä», koska se mittasi laatikon keskipistettä. Laatikko
   oli keskellä; teksti sen sisällä ei ollut. */
body.nikoy-v-raju .nikoy-manifesti  { align-items: center; text-align: center; }

/* 🔴 MITATTU VIKA 18.9.2026. Omistaja: «Oranssi Nyt opacity nousee täydeksi
   liian ylhäällä näkymässä, jolloin "Sinun liiketoimintasi" on miltei
   häviämässä näkymän yläreunassa.»

   Saapuminen lasketaan kaavalla n = (sisaan − 80 − v·porras) / 250, jossa
   `sisaan` on se matka, jonka elementti on noussut ruudun alalaidasta.
   Portaalla 32 px viimeinen rivi (v = 4) on täysin kirkas vasta kun se on
   tullut 80 + 128 + 250 = 458 px sisään. Rivien väli on kasvanut tässä
   istunnossa 125 → 159 px, joten ensimmäisen ja viimeisen rivin etäisyys on
   nyt 690 px: kun viimeinen kirkastuu, ensimmäinen on 1200 − 458 − 690 =
   51,6 px ruudun yläreunasta eli käytännössä ulkona.

   🔴 KORJATTU KAHDESTI. Ensin porras laskettiin nollaan sillä perusteella,
   että 159 px:n rivinväli porrastaa rivit jo geometrialla. Se ratkaisi
   ajoituksen mutta rikkoi liikkeen: omistaja huomasi heti, että rivit
   «tulevat näkyviin liian vauhdikkaasti» ja että liikkeestä katosi pehmeys.
   Syy on se, että nollaporras jättää rivien saapumiseron pelkän geometrian
   varaan — 159 px vieritystä rivien välillä, kun sitä ennen oli 159 + 32 =
   191 px. Peräkkäisyys tihenee, ja kun liikkeen pituus on silti 250 px,
   viereiset rivit ovat suuremman osan ajasta liikkeessä yhtä aikaa.

   Oikea korjaus ei ollut portaan poistaminen vaan koko saapumisen
   AIKAISTAMINEN. Ne ovat eri asioita: porras säätää rivien välistä rytmiä,
   alkukynnys säätää sitä, milloin lohko ylipäätään alkaa kirkastua. Vika oli
   jälkimmäisessä, ja ensimmäistä säätämällä hoidettiin oire.

   Lopulliset arvot, kolmen omistajan havainnon jälkeen. Jokainen havainto
   osoitti eri säätimeen, ja siksi niitä on kolme eikä yksi:

     «toinen ja kolmas rivi tulee liian pitkällä viiveellä»
        → porras 32 → 10 px: rivien välinen rytmi tiivistyy

     «Faktasta jälkeen Nyt tulee ensimmäistä kertaa näkyviin liian myöhään»
        → alkukynnys 80 → 0 px: Nyt on kauimpana (v = 4) ja sillä on lisäksi
          osion suurin marginaali, joten kynnys viivästytti juuri sitä eniten

     «pehmeys liikkeessä puuttuu, erittäin äkkinäinen liike»
        → matka 250 → 320 px, ja käyrä (ks. osa 6) lineaarisesta smoothstepiin

   Viimeinen rivi on täysin kirkas, kun se on tullut 0 + 4·10 + 320 = 360 px
   sisään; ensimmäinen rivi on silloin 1200 − 360 − 690 = 150 px ruudun
   yläreunasta eli kokonaan näkyvissä. Vaatimus «Nyt on koko opacitylla
   näkyvillä ennen kuin se on liian ylhäällä» täyttyy siis edelleen. */
/* 🔴 KOHDISTUS RUUTUUN 18.9.2026. Omistaja määritteli päätepisteen tarkasti:
   kun «Nyt» on täydessä opacityssa, lohkon ylä- ja alapuolelle jäävän tyhjän
   tilan suhde on 2/5 ylhäällä ja 3/5 alhaalla. Lisäksi: «et muokkaa
   yksittäisten rivien liikettä vaan […] koko osio aloittaa liikkeellä
   esiintulon aiemmin» — siksi tässä muuttuu VAIN alkukynnys, joka on kaikille
   riveille yhteinen siirtymä. Porras (10) ja matka (320px) ovat koskemattomat,
   joten rivien rytmi ja yksittäisen rivin liike ovat samat kuin ennen.

   Miksi vakio ei kelpaa: kynnys oli pikseliluku, mutta vaatimus on suhde
   RUUDUN korkeuteen. Matalammalla ruudulla lohko ehtii nousta korkeammalle
   ennen kuin viimeinen rivi valmistuu — omistaja näki sen omalla näytöllään,
   vaikka mittaus 1200 px:n ruudulla näytti oikealta. Sama vakio antaa siis eri
   lopputuloksen eri näytöillä, ja juuri se oli vika.

   Johto. Merkitään H = ruudun korkeus, K = lohkon korkeus, E = ensimmäisen ja
   viimeisen rivin etäisyys, P = porras, M = matka. Viimeinen rivi on valmis,
   kun se on tullut sisään alkukynnys + 4P + M, joten

     lohko.top = 0,4 · (H − K)          ← omistajan 2/5 : 3/5
     rivi4.top = lohko.top + E
     alkukynnys = H − rivi4.top − 4P − M
                = 0,6H + 0,4K − E − 4P − M

   K ja E ovat molemmat fonttikoon monikertoja, koska rivinvälit on määritelty
   em-arvoina: E = 3 · (0,96 + 0,32)em + (0,96 + 0,768)em = 5,568em ja
   K ≈ 6,57em. Sijoittamalla: alkukynnys = 0,6H − 2,94em − 360px. Kaava pitää
   siis suhteen 2/5 : 3/5 sekä jokaisella ruudun korkeudella että jokaisella
   neljällä fonttikokoportaalla ilman erillisiä arvoja.

   `--alkukynnys` on rekisteröitävä (@property, osa 0), jotta selain laskee
   calc()-lausekkeen pikseleiksi; rekisteröimätön custom property jäisi
   tekstiksi, eikä JS saisi siitä lukua. Jos selain ei tue rekisteröintiä,
   lauseke hylätään ja käytössä on oletus 80px eli entinen käyttäytyminen. */
/* 🔴 OMISTAJAN OHJE 18.9.2026: aiheosion otsikko ja johdatus tulevat «liian
   nopealla feiduksella». Osio käytti sivun yleistä matkaa (20,834vh), joka on
   sama kuin lupausosiolla — ja lupaus on omistajan mukaan «erittäin hyvä, ei
   muutosta». Sama luku ei siis tuota samaa tuntumaa: lupauksen rivit ovat
   lyhyitä jättirivejä, kun taas tämä otsikko on monirivinen tekstimassa, joka
   peittää ison osan ruudusta ja jonka kirkastuminen siksi luetaan nopeampana.
   Siksi matkaa pidennetään VAIN tässä osiossa; lupaus jää koskematta. */
body.nikoy-v-raju .nikoy-aiheosio .nikoy-saapuu { --matka: 30vh; }

body.nikoy-v-raju .nikoy-manifesti .nikoy-mrivi {
  /* Porras ja matka `em`-yksiköissä: ne seuraavat fonttikokoa, joten liike on
     samassa suhteessa tekstiin jokaisella neljällä kokoportaalla. 1441 px:n
     ruudulla (124 px) nämä ovat 9,9 px ja 320 px eli entiset arvot. */
  /* 🔴 PALAUTETTU LUPAUKSEN PROFIILIIN 18.9.2026. Omistaja: «kokonaisuudessaan
     kokemus on kärsinyt» — ja samassa viestissä: lupausosio «on erittäin hyvä,
     ei muutosta».

     Mittaus osoitti syyn. Tätä osiota oli säädetty neljä kertaa peräkkäin, ja
     se oli ajautunut poikkeamaan lupauksesta KAIKISSA kolmessa arvossa
     (matka 434 vs 250, porras 9,9 vs 32, kynnys −120 vs 80) — vaikka teksti
     on samaa 124 px:n kokoa samalla sivulla. Jokainen säätö oli erikseen
     perusteltu, mutta yhdessä ne tekivät liikkeestä toisenlaisen kuin
     sivun muissa osioissa.

     Nyt matka ja porras ovat samat kuin lupauksessa, eli liike on identtinen
     sen kanssa, jonka omistaja hyväksyi. Kohdistus ruutuun hoidetaan PELKÄLLÄ
     alkukynnyksellä — se on ainoa säädin, joka siirtää koko lohkoa muuttamatta
     rivien rytmiä tai häivytyksen kestoa. Arvot em-yksiköissä, jotta ne
     skaalautuvat fonttikokoportaiden mukana: ,258em = 32px ja 2,016em = 250px
     kun fontti on 124 px. */
  --porras: .258em;
  --matka: 2.016em;

  /* Kohdistus: kun viimeinen rivi on valmis, lohkon yläpuolelle jää 2/5 ja
     alapuolelle 3/5 tyhjästä tilasta.

       alkukynnys = 0,6H + 0,4K − E − 4P − M

     Lohkon korkeus K ja rivien etäisyys E ovat fonttikoon monikertoja, koska
     rivinvälit on määritelty em-arvoina. Ne on MITATTU selaimesta, ei arvattu:
     K = 6,528em ja E = 5,568em. Sijoittamalla P = ,08em ja M = 2,58em:

       alkukynnys = 0,6H + 2,6112em − 5,568em − 1,032em − 2,016em
                  = 60vh − 6,0048em

     Kynnys on lievästi negatiivinen (−25 px 1200 px:n ruudulla), eli liike
     alkaa hieman ennen kuin rivi on ruudulla. Se on kaavan seuraus eikä
     virhe: päätepiste on kiinnitetty 2/5 : 3/5 -kohtaan, ja koska liikkeen
     pituus on nyt lupauksen 250 px, aloituksen on osuttava juuri tähän.

     Kaava pitää suhteen 2/5 : 3/5 sekä jokaisella ruudun korkeudella että
     jokaisella fonttikokoportaalla — sama kokemus työpöydällä ja mobiilissa
     ilman erillisiä arvoja kummallekin. */
  --alkukynnys: calc(60vh - 6.0048em);
}

/* 🔴 OMISTAJAN OHJE 18.9.2026: «Lisää myös jonkin verran lisää tilaa ennen
   Sinun liiketoimintasi.» Ensimmäisellä rivillä ei ole edeltävää sisarusta,
   joten riviväli ei ulotu siihen — tila on otettava osion yläpadingista.
   84 → 160 → 260 px («vielä lisää väliä», 18.9.2026). Vain yläreuna kasvaa:
   alareuna pitää manifestin ja aiheiden välin ennallaan, jottei muu sivu
   liiku. */
body.nikoy-v-raju .nikoy-manifestiosio { padding-block-start: 260px; }
/* Rajun rivikorkeus on .96, eli laatikko on matalampi kuin kirjaimet: g:n ja
   p:n alapidennykset ulottuvat laatikon ulkopuolelle. Seuraava teksti tarvitsee
   siksi enemmän tilaa kuin muissa versioissa. */
body.nikoy-v-raju .nikoy-jatti + .nikoy-leipa { margin-block-start: 44px; }
body.nikoy-v-raju .nikoy-leipa + .nikoy-saate { margin-block-start: 20px; }


/* ==========================================================================
   13. KAPEA RUUTU

   Applen mitattu raja on 734 px: siinä heidän juuriluokkansa vaihtuu arvoon
   `no-enhanced` ja dokumentti lyhenee 33 560 → 29 097 px. Kiinnitetty jakso
   vaatii kolme ruutua vieritystä yhden näkymän esittämiseen, ja kapealla
   ruudulla se on enemmän vaiva kuin kokemus.
   ========================================================================== */

@media (max-width: 734px) {
  .nikoy-vaiteosio     { padding-block: 0; }
  .nikoy-kuvatausta    { min-block-size: 62svh; padding-block: 64px; }
  .nikoy-kuvausosio    { padding-block: 56px; }
  .nikoy-manifestiosio { padding-block: 60px; }
  /* Sama +80 % kuin leveällä, mutta kapean ruudun omasta pohjasta: väli oli
     60 + 60 = 120 px, uusi on 216 px, joten yläpadding on 216 − 60 = 156 px. */
  .nikoy-aiheosio      { padding-block: 156px 150px; }
  .nikoy-lupausosio    { padding-block: 68px 0; }

  /* Jakso lakkaa olemasta kelaus ja muuttuu tavalliseksi osioksi. */
  .nikoy-jakso { block-size: auto; padding-block: 80px; --t: 1 !important; }
  .nikoy-liima { position: static; block-size: auto; display: block; }

  .nikoy-kuvalava--kelaus { transform: none; opacity: 1; max-inline-size: 100%; }

  /* Kaikki kolme vaihetekstiä näkyviin allekkain: ne ovat yksi virke. */
  .nikoy-vaiheet { display: block; max-inline-size: none; margin-block-start: 32px; }
  .nikoy-vaihe   { display: inline; opacity: 1 !important; transform: none !important; will-change: auto; }
  .nikoy-vaihe + .nikoy-vaihe::before { content: " "; }

  .nikoy-nuoli { display: none; }
}


/* ==========================================================================
   14. LIIKKEEN VÄHENTÄMINEN

   Kun käyttöjärjestelmä pyytää vähemmän liikettä, kaikki liike loppuu ja
   kaikki sisältö on näkyvissä. Vestibulaarihäiriölle vieritykseen sidottu
   liike on oire, ei tehoste.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .nikoy-saapuu { opacity: 1 !important; transform: none !important; }

  .nikoy-jakso { block-size: auto; --t: 1 !important; }
  .nikoy-liima { position: static; block-size: auto; display: block; padding-block: 80px; }
  .nikoy-liima::before { display: none; }
  .nikoy-kuvalava--kelaus { transform: none; opacity: 1; }
  .nikoy-vaiheet { display: block; max-inline-size: none; margin-block-start: 32px; }
  .nikoy-vaihe   { display: inline; opacity: 1 !important; transform: none !important; will-change: auto; }
  .nikoy-vaihe + .nikoy-vaihe::before { content: " "; }
}


/* ==========================================================================
   16. POLJENTO — vaihtoehtoinen rytmi, `?rytmi=poljento`

   🔴 Omistaja toimitti 18.9.2026 tekstin siinä ryhmittelyssä, jossa se on
   kirjoitettu, ja pyysi uuden version vertailtavaksi. Sanat ovat samat kuin
   julkisella sivulla; ero on ryhmittelyssä ja siinä, mitä ryhmittely tekee
   lukukokemukselle.

   KOKOJEN RYTMI on tämän version koko idea. Ensimmäinen lohko laskee
   48 → 32 → 24 px ja nousee iskussa takaisin 72:een. Isku erottuu siksi, että
   sitä ennen on laskettu — ei siksi, että se on lihavoitu. Saate on 17 px:
   lohko päättyy hiljaisuuteen ennen taukoa.
   ========================================================================== */

/* Kapeampi palsta kuin muualla. Pitkä kappale 1240 px:n levyisenä olisi
   noin 110 merkkiä rivillä; luettava haarukka on 45–75. */
.nikoy-rajaus--luku { max-inline-size: 820px; }

.nikoy-p-alku {
  min-block-size: 100svh;
  display: flex; flex-direction: column; justify-content: center;
  /* 🔴 Mitattu: 96 px:n täytteellä lohko oli 917 px eli 17 px korkeampi kuin
     900 px:n ruutu, ja saate «Tulossa syksyllä 2026.» jäi juuri rajan alle.
     Koko lohko on yksi ajatus, joten sen on mahduttava yhteen näkymään —
     80 px antaa 885 px. */
  padding-block: 80px;
  text-align: center;
}

.nikoy-p-karki {
  font-size: 34px; line-height: 1.12; letter-spacing: -.008em; font-weight: 600;
  text-wrap: balance;
  margin-block-start: 22px;
}
.nikoy-p-toinen {
  font-size: 24px; line-height: 1.25; letter-spacing: .004em; font-weight: 400;
  text-wrap: balance;
  margin-block-start: 34px;
}
.nikoy-p-kolmas {
  font-size: 19px; line-height: 1.42; letter-spacing: .011em; font-weight: 400;
  color: var(--teksti-2);
  text-wrap: balance;
  margin-block-start: 22px;
}

/* Isku. Omistaja lihavoi tämän rivin ainoana koko tekstissä. Koko ja väri
   tekevät saman kuin lihavointi tekee tekstitiedostossa. */
.nikoy-p-isku {
  font-size: 40px; line-height: 1.08; letter-spacing: -.018em; font-weight: 600;
  color: var(--korostus);
  text-wrap: balance;
  margin-block-start: 52px;
}
.nikoy-p-saate { margin-block-start: 40px; }

/* Omistajan `---`-viiva. Tauko, ei koriste. */
.nikoy-p-vali { padding: 0; }
.nikoy-kuvatausta--vaiti { min-block-size: min(58svh, 560px); padding-block: 0; }

.nikoy-p-laajuus { padding-block: 112px 0; text-align: center; }

.nikoy-p-laaja {
  font-size: 24px; line-height: 1.34; letter-spacing: .006em; font-weight: 400;
  text-wrap: pretty;
}
/* Aiheet erottuvat VIRKKEEN SISÄLLÄ. Ne eivät irtoa omiksi korteikseen, koska
   omistajan tekstissä ne ovat luettelo virkkeen lopussa. */
.nikoy-p-aihe { font-weight: 600; color: var(--teksti); }

/* Nämä kaksi riviä ovat omistajan tekstissä peräkkäin ILMAN tyhjää riviä
   välissä, toisin kuin muut kappaleet. Väli on siksi rivinvaihdon kokoinen
   eikä kappaleen. */
.nikoy-p-pari { margin-block-start: 56px; }
.nikoy-p-lupausrivi {
  font-size: 32px; line-height: 1.16; letter-spacing: -.004em; font-weight: 600;
  text-wrap: balance;
}
.nikoy-p-lupausrivi + .nikoy-p-lupausrivi {
  margin-block-start: 8px;
  font-size: 21px; line-height: 1.38; letter-spacing: .011em; font-weight: 400;
  color: var(--teksti-2);
}

.nikoy-p-loppu { padding-block: 104px 88px; text-align: center; }
.nikoy-p-kuvaus { margin-block-end: 72px; }
.nikoy-p-kuvaus .nikoy-leipa + .nikoy-leipa { margin-block-start: 20px; }
.nikoy-p-yhteysotsikko { margin-block-end: 28px; }

/* Ensimmäinen lohko saapuu KELLOLLA, ei vierityksellä — se on jo ruudulla
   eikä sen alle voi vierittää, joten vierityssidonnainen laskenta jäisi
   pysyvästi kesken. Sama jako kuin julkisen sivun avauksessa.

   Viimeinen elementti on paikallaan 0,79 s kohdalla: ensivaikutelma ei saa
   odotuttaa. */
.nikoy-p-alku .nikoy-silma,
.nikoy-p-alku .nikoy-p-karki,
.nikoy-p-alku .nikoy-p-toinen,
.nikoy-p-alku .nikoy-p-kolmas,
.nikoy-p-alku .nikoy-p-isku,
.nikoy-p-alku .nikoy-p-saate {
  animation: nikoy-saapuu .55s var(--kayra-ulos) both;
}
.nikoy-p-alku .nikoy-silma     { animation-delay: .02s; }
.nikoy-p-alku .nikoy-p-karki   { animation-delay: .08s; }
.nikoy-p-alku .nikoy-p-toinen  { animation-delay: .14s; }
.nikoy-p-alku .nikoy-p-kolmas  { animation-delay: .18s; }
.nikoy-p-alku .nikoy-p-isku    { animation-delay: .24s; }
.nikoy-p-alku .nikoy-p-saate   { animation-delay: .28s; }

/* Portaat. Sama periaate kuin muualla: kokonaisluku media queryllä. */
@media (min-width: 735px) {
  .nikoy-p-karki      { font-size: 48px; line-height: 1.08; letter-spacing: -.003em; }
  .nikoy-p-toinen     { font-size: 32px; line-height: 1.13; letter-spacing: .004em; }
  .nikoy-p-kolmas     { font-size: 21px; line-height: 1.38; }
  .nikoy-p-isku       { font-size: 64px; line-height: 1.05; letter-spacing: -.024em; }
  .nikoy-p-laaja      { font-size: 28px; line-height: 1.30; letter-spacing: .007em; }
  .nikoy-p-lupausrivi { font-size: 40px; line-height: 1.10; letter-spacing: .002em; }
  .nikoy-p-lupausrivi + .nikoy-p-lupausrivi { font-size: 21px; }
}
@media (min-width: 1069px) {
  .nikoy-rajaus--luku { max-inline-size: 900px; }
  .nikoy-p-karki      { font-size: 56px; line-height: 1.07; letter-spacing: -.005em; }
  .nikoy-p-isku       { font-size: 72px; line-height: 1.05; letter-spacing: -.026em; }
  .nikoy-p-laaja      { font-size: 32px; line-height: 1.28; letter-spacing: .004em; }
  .nikoy-p-lupausrivi { font-size: 48px; line-height: 1.08; letter-spacing: -.003em; }
  .nikoy-p-lupausrivi + .nikoy-p-lupausrivi { font-size: 24px; }
}

@media (max-width: 734px) {
  .nikoy-p-alku    { padding-block: 72px; min-block-size: 92svh; }
  .nikoy-p-laajuus { padding-block: 72px 0; }
  .nikoy-p-loppu   { padding-block: 72px 64px; }
  .nikoy-p-isku    { margin-block-start: 40px; }
  .nikoy-kuvatausta--vaiti { min-block-size: 42svh; }
}


/* ==========================================================================
   15. TULOSTUS
   ========================================================================== */

@media print {
  .nikoy-nuoli, .nikoy-pisteet { display: none; }
  .nikoy-osio { padding-block: 24px; background: #fff; color: #000; }
  .nikoy-kuva--tausta, .nikoy-kuvatausta::before, .nikoy-kortti::after { display: none; }
  .nikoy-kuvatausta { min-block-size: 0; padding-block: 0; }
  .nikoy-rata { overflow: visible; flex-wrap: wrap; }
  .nikoy-jakso { block-size: auto; }
  .nikoy-liima { position: static; block-size: auto; display: block; }
}
