/* =========================================================
   LAYOUT — kontit, ruudukot, osiorakenteet
   ========================================================= */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow {
  max-width: var(--container-narrow);
}

.container--wide {
  max-width: var(--container-wide);
}

/* ---------- Osio ---------- */

.section {
  position: relative;
  padding-block: var(--section-y);
}

.section--lg {
  padding-block: var(--section-y-lg);
}

.section--flush-top {
  padding-block-start: 0;
}

.section__head {
  max-width: 46rem;
  margin-block-end: clamp(2.5rem, 1.5rem + 3vw, 4.5rem);
}

.section__head--center {
  margin-inline: auto;
  text-align: center;
}

.section__head--split {
  max-width: none;
  display: grid;
  gap: var(--sp-6);
  align-items: end;
}

@media (min-width: 900px) {
  .section__head--split {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    gap: var(--sp-12);
  }
}

.section__title {
  margin-block-start: var(--sp-4);
}

.section__lead {
  margin-block-start: var(--sp-5);
  color: var(--text-muted);
  font-size: var(--fs-lg);
  max-width: 38rem;
}

.section__head--center .section__lead {
  margin-inline: auto;
}

/* ---------- Osion taustagrafiikka ---------- */

/* Hillitty koriste osion laitaan, ei koko taustalle. Vaalealla pohjalla
   täysleveä kuva tekisi ilmeestä levottoman ja veisi tekstin kontrastin.
   Vuorottelee vasen/oikea, jotta sivulle syntyy rytmi.
   Piilotetaan alle 1100 px, jossa tekstille ei jää sivutilaa. */
.section__bg {
  position: absolute;
  inset-block: 0;
  /* Negatiivinen: osion isolation: isolate rajaa pinoamiskontekstin, joten
     tausta jää osion oman taustavärin päälle mutta kaiken sisällön alle. */
  z-index: -1;
  display: none;
  width: 40%;
  max-width: 32rem;
  overflow: hidden;
  pointer-events: none;
  user-select: none;
}

@media (min-width: 1100px) {
  .section__bg {
    display: block;
  }
}

.section__bg--right { inset-inline-end: 0; }
.section__bg--left  { inset-inline-start: 0; }

/* Kuva on CSS-tausta eikä <img>. Syy on kestävyys: jos tyylitiedosto ei
   lataudu, <img> valuisi tekstivirtaan täydellä peitolla ja työntäisi
   sisällön alas. Taustakuvana koriste yksinkertaisesti katoaa.
   Sivutuote: display:none estää latauksen kokonaan kapeilla näytöillä.

   Peittävyys on mitoitettu tekstin mukaan, ei maun mukaan. Sivuston
   vaalein tekstiväri --text-subtle oli #6b6b6b eli valkoisella vain
   5,33:1; 24 % pudotti sen 3,15:1:een. Väri tummennettiin #5a5a5a:ksi
   ja peittävyys laskettiin 10 %:iin — 12 % jätti vain 0,02 marginaalin. */
.section__bg {
  background-image: var(--bg-img);
  background-size: cover;
  /* Parallaksi liikuttaa TAUSTAN SIJAINTIA, ei elementtiä. Elementin
     siirtäminen olisi valunut osion rajojen ulkopuolelle naapuriosion
     tekstin päälle, koska .sectionilla ei ole overflow: hidden.
     background-position pysyy määritelmän mukaan laatikon sisällä,
     joten ylivuotoa ei voi syntyä. JS asettaa --bg-shiftin. */
  background-position: center calc(50% + var(--bg-shift, 0px));
  background-repeat: no-repeat;
  opacity: 0.10;
}

.section__bg--right {
  mask-image: linear-gradient(90deg, transparent 4%, #000 62%);
  -webkit-mask-image: linear-gradient(90deg, transparent 4%, #000 62%);
}

.section__bg--left {
  mask-image: linear-gradient(270deg, transparent 4%, #000 62%);
  -webkit-mask-image: linear-gradient(270deg, transparent 4%, #000 62%);
}

/* Sisältö taustan yläpuolelle.

   ÄLÄ tee tätä nostamalla sisaruksia (`.section > *  { position: relative }`).
   Se ylikirjoittaa jo asemoitujen koriste-elementtien position-arvon: esim.
   .hero__glow on position:absolute, ja relativeksi pakotettuna se palasi
   normaaliin virtaan ja kasvatti .page-headin korkeutta 505 px → 1295 px
   (mitattu /palvelut/). Sen sijaan osio tekee oman pinoamiskontekstin ja
   tausta lasketaan sen pohjalle. Negatiivinen z-index ei tässä karkaa osion
   taakse, koska isolation: isolate rajaa kontekstin — tausta piirtyy osion
   oman taustavärin päälle mutta kaiken sisällön alle. Sisarukset saavat
   pitää oman asemointinsa.

   Ei :has()-valitsinta: jos selain ei tue sitä, osio jäisi ilman
   pinoamiskontekstia ja tausta ankkuroituisi väärään esi-isään. Kaikki
   kolme saavat isolationin ehdoitta — se on turvallista, koska ainoa
   suuren z-indexin elementti (.loader, 9999) on osioiden ulkopuolella. */
.section,
.page-head,
.footer {
  position: relative;
  isolation: isolate;
}

/* ---------- Erotinviiva ---------- */

.hairline {
  height: 1px;
  border: 0;
  background: var(--grad-hairline);
}

/* ---------- Ruudukot ---------- */

.grid {
  display: grid;
  gap: var(--grid-gap);
}

@media (min-width: 640px) {
  .grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 720px) {
  .grid--3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (min-width: 640px) and (max-width: 1023px) {
  .grid--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ---------- Header ---------- */

.header {
  position: fixed;
  inset-inline: 0;
  top: 0;
  z-index: var(--z-header);
  padding-block: var(--sp-4);
  transition: padding var(--dur-slow) var(--ease-out);
}

.header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-6);
  padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-5);
  border: 1px solid transparent;
  border-radius: var(--r-full);
  transition:
    background var(--dur-slow) var(--ease-out),
    border-color var(--dur-slow) var(--ease-out),
    box-shadow var(--dur-slow) var(--ease-out),
    backdrop-filter var(--dur-slow) var(--ease-out);
}

.header.is-stuck .header__inner {
  background: rgba(255, 255, 255, 0.72);
  border-color: var(--border);
  box-shadow: var(--shadow-3);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  backdrop-filter: blur(18px) saturate(1.5);
}

.header__nav {
  display: none;
}

@media (min-width: 960px) {
  .header__nav {
    display: flex;
    align-items: center;
    gap: clamp(1.25rem, 0.5rem + 1.6vw, 2.25rem);
  }
}

.header__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

/* Spesifisyys nostettu kahteen luokkaan, jotta components.css:n
   .btn { display: inline-flex } ei kumoa piilotusta. */
.header__inner .header__cta {
  display: none;
}

@media (min-width: 960px) {
  .header__inner .header__cta {
    display: inline-flex;
  }
}

/* ---------- Mobiilivalikko ---------- */

.nav-toggle {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 46px;
  height: 46px;
  padding: 0 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  background: var(--surface);
}

@media (min-width: 960px) {
  .nav-toggle {
    display: none;
  }
}

.nav-toggle__bar {
  display: block;
  height: 2px;
  width: 100%;
  background: var(--text);
  border-radius: 2px;
  transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-fast) linear;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  display: grid;
  align-content: center;
  padding: var(--sp-16) var(--gutter) var(--sp-10);
  background: rgba(255, 255, 255, 0.97);
  -webkit-backdrop-filter: blur(22px);
  backdrop-filter: blur(22px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-slow) var(--ease-out), visibility var(--dur-slow);
}

.mobile-nav.is-open {
  opacity: 1;
  visibility: visible;
}

.mobile-nav__list {
  display: grid;
  gap: var(--sp-2);
  margin-block-end: var(--sp-8);
}

.mobile-nav__link {
  display: block;
  padding: var(--sp-4) 0;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.2rem + 3vw, 2.75rem);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-tight);
  border-bottom: 1px solid var(--border);
  opacity: 0;
  transform: translateY(14px);
}

.mobile-nav.is-open .mobile-nav__link {
  animation: rise-in var(--dur-slow) var(--ease-out) forwards;
}

.mobile-nav.is-open .mobile-nav__link:nth-child(1) { animation-delay: 60ms; }
.mobile-nav.is-open .mobile-nav__link:nth-child(2) { animation-delay: 110ms; }
.mobile-nav.is-open .mobile-nav__link:nth-child(3) { animation-delay: 160ms; }
.mobile-nav.is-open .mobile-nav__link:nth-child(4) { animation-delay: 210ms; }
.mobile-nav.is-open .mobile-nav__link:nth-child(5) { animation-delay: 260ms; }

body.is-locked {
  overflow: hidden;
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  padding-block: clamp(7rem, 5.5rem + 6vw, 9.5rem) clamp(3.5rem, 2.5rem + 4vw, 5.5rem);
  overflow: hidden;
}

/* Hero mitoitetaan näyttöön: yksi ruudullinen, ei enempää.

   svh eikä vh: mobiiliselaimen osoiterivi muuttaa vh:ta kesken
   vierityksen, jolloin hero hyppisi. svh on pienin tila eli se pysyy
   paikallaan. Selaimille jotka eivät tunne svh:ta jää edellinen
   sääntö (vh) voimaan.

   min-height eikä height: jos teksti ei mahdu (iso fonttikoko,
   kapea näyttö, käännös), hero saa kasvaa eikä leikkaa sisältöä.
   Yläraja 52rem estää heroa venymästä absurdiksi pystynäytöllä. */
.hero--media {
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: min(100svh, 52rem);
}

/* Yläpehmuste jättää tilaa kiinteälle otsikkopalkille. Koska sisältö
   on nyt pystysuunnassa keskitetty, pehmuste ei enää yksin määrää
   sijaintia — se vain estää tekstiä menemästä palkin alle matalilla
   näytöillä. */
.hero--media > .container {
  width: 100%;
}

.hero__glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  pointer-events: none;
  will-change: transform;
}

/* Vaalealla pohjalla hehkut ovat murto-osa siitä mitä tummalla:
   0,5 alfa näyttäisi vaaleanpunaiselta läiskältä. */
.hero__glow--1 {
  inset-block-start: -18%;
  inset-inline-end: -12%;
  width: min(46rem, 90vw);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(215, 38, 56, 0.1), transparent 68%);
  animation: drift 22s var(--ease-in-out) infinite;
}

.hero__glow--2 {
  inset-block-end: -22%;
  inset-inline-start: -14%;
  width: min(34rem, 80vw);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgba(240, 75, 95, 0.07), transparent 66%);
  animation: drift 28s var(--ease-in-out) infinite reverse;
}

/* ---------- Heron taustavideo ---------- */

/* Video peittää koko hero-osion. Teksti on sen PÄÄLLÄ, joten
   peittokerros on pakollinen: materiaali on valokuvamaista ja
   kirkkaus vaihtuu ruudusta toiseen. Peitto on voimakkaampi
   vasemmalla, jossa teksti on, ja kevyempi oikealla, jotta
   videosta jää jotain näkyviin. */
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--neutral-900);
}

.hero__bg video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg,
      rgba(16, 16, 16, 0.92) 0%,
      rgba(16, 16, 16, 0.86) 34%,
      rgba(16, 16, 16, 0.66) 62%,
      rgba(16, 16, 16, 0.48) 100%),
    linear-gradient(180deg,
      rgba(16, 16, 16, 0.5) 0%,
      rgba(16, 16, 16, 0.2) 40%,
      rgba(16, 16, 16, 0.55) 100%);
}

/* Sisältö peiton yläpuolelle */
.hero--media .hero__inner {
  position: relative;
  z-index: var(--z-base);
}

.hero__inner {
  position: relative;
  z-index: var(--z-base);
  max-width: 54rem;
}

@media (min-width: 960px) {
  .hero__inner {
    max-width: 52rem;
  }
}

.hero__title {
  margin-block: var(--sp-6) 0;
  font-size: var(--fs-display);
}

.hero__lead {
  margin-block-start: var(--sp-6);
  max-width: 34rem;
  font-size: var(--fs-lg);
  color: var(--text-muted);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  margin-block-start: var(--sp-10);
}

.hero__assurance {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  margin-block-start: var(--sp-6);
  color: var(--text-subtle);
  font-size: var(--fs-sm);
}

.hero__assurance li {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.hero__assurance li::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--brand-red);
}

/* ---------- Footer ---------- */

.footer {
  /* Hillovaluman kaista footerin yläreunassa. Tämä on koko efektin ehto:
     kun pisaroiden takana ei ole tekstiä, ne saavat olla täyttä
     brändipunaista. Ensimmäinen yritys levitti pisarat koko footerin
     alalle tekstin taakse, jolloin mitattu yläraja oli 15 % peittävyys
     — käytännössä näkymätön. Kaista ratkaisee saman asian rakenteella
     eikä peittävyyttä pienentämällä. */
  --drip-band: clamp(4.5rem, 3rem + 5vw, 8rem);

  position: relative;
  margin-block-start: var(--section-y);
  padding-block-start: var(--drip-band);
  border-top: 1px solid var(--border);
  background: linear-gradient(180deg, transparent, var(--neutral-50));
  overflow: hidden;
}

/* Kangas luodaan JS:llä, joten ilman JS:ää tätä ei ole olemassa eikä
   mikään muutu — footeriin jää vain hieman ylimääräistä ilmaa.

   Korkeus = kaista + .footer__gridin oma yläpehmuste, eli täsmälleen se
   tila jossa ei ole tekstiä. Maski häivyttää pisarat ennen kaistan
   loppua: se on rakenteellinen takuu, ei toive. Vaikka pisara putoaisi
   liian pitkälle, se on jo läpinäkyvä ennen ensimmäistä tekstiriviä.

   z-index -1: sama pinoamiskonteksti kuin .section__bg:llä. DOM-järjestys
   ratkaisee, ja kangas lisätään taustagrafiikan jälkeen, joten pisarat
   piirtyvät sen päälle mutta kaiken sisällön alle. */
.footer__drip {
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: -1;
  /* width: 100% on PAKOLLINEN. <canvas> on korvattu elementti, jolla on
     sisäinen koko (width/height-attribuutit), joten pelkkä inset-inline: 0
     ei veny reunasta reunaan kuten tavallisella lohkolla — kaista jäisi
     kapeaksi liuskaksi vasempaan laitaan. */
  width: 100%;
  height: calc(var(--drip-band) + var(--sp-16));
  opacity: 0.92;
  pointer-events: none;
  user-select: none;
  mask-image: linear-gradient(180deg, #000 0%, #000 50%, transparent 86%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 50%, transparent 86%);
}

@media (prefers-reduced-motion: reduce) {
  .footer__drip { display: none; }
}

.footer__grid {
  display: grid;
  gap: var(--sp-10);
  padding-block: var(--sp-16) var(--sp-12);
}

@media (min-width: 800px) {
  .footer__grid {
    grid-template-columns: minmax(0, 1.6fr) repeat(3, minmax(0, 1fr));
    gap: var(--sp-8);
  }
}

.footer__heading {
  margin-block-end: var(--sp-5);
  font-family: var(--font-body);
  font-size: var(--fs-eyebrow);
  font-weight: var(--fw-bold);
  letter-spacing: var(--ls-widest);
  text-transform: uppercase;
  /* Ei --text-subtle: footerin taustagrafiikan päällä se jäi 4,90:1:een,
     eli 0,4 päähän rajasta. --text-muted antaa 5,21:1. */
  color: var(--text-muted);
}

.footer__list {
  display: grid;
  gap: var(--sp-2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* Nimi erottuu omista yhteystiedoistaan, jottei kenenkään meili tai
   numero mene sekaisin toisen kanssa. Ilman tätä lista olisi pelkkä
   pino linkkejä, joista ei näe kenelle mikä kuuluu. */
.footer__person {
  margin-block-start: var(--sp-4);
  color: var(--text);
  font-weight: var(--fw-semibold);
}

.footer__list > .footer__person:first-child {
  margin-block-start: 0;
}

/* Kosketuskohteen vähimmäiskoko (WCAG 2.2 AA, 2.5.8) */
.footer__list li {
  display: flex;
  align-items: center;
  min-height: 28px;
}

.footer__list a {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding-block: var(--sp-6);
  border-top: 1px solid var(--border);
  font-size: var(--fs-xs);
  /* Sama syy kuin .footer__headingissa: varaa taustagrafiikalle. */
  color: var(--text-muted);
}

.footer__bottom a {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
}

/* Footerin linkit EIVÄT muutu punaisiksi hoveroitaessa, vaikka muualla
   sivustolla muuttuvat. Mitattu syy: --accent-text footerin taustagrafiikan
   päällä on 4,79:1 eli 0,29 päässä rajasta — koko footerin koristeellisin
   osio ei kestä sitä. Tummeneminen + alleviivaus on yhtä selvä tilamerkki
   eikä nojaa pelkkään väriin (WCAG 1.4.1). */
.footer a:hover {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer__wordmark {
  display: block;
  margin-block-start: var(--sp-6);
  font-family: var(--font-display);
  font-size: clamp(3rem, 13vw, 12rem);
  font-weight: var(--fw-bold);
  line-height: 0.82;
  letter-spacing: var(--ls-tighter);
  text-align: center;
  white-space: nowrap;
  color: transparent;
  -webkit-text-stroke: 1px rgba(215, 38, 56, 0.16);
  transform: translateY(24%);
  user-select: none;
  pointer-events: none;
}

/* ---------- Väiteosio (sticky) ---------- */
/* Kaksi väitettä, joista ensimmäinen jää ruudulle kiinni ja toinen
   ottaa sen paikan. Toteutus on puhdasta CSS:ää: kummallakin väitteellä
   on oma korkea "raita", jonka sisällä lause on position: sticky.
   Kun raita loppuu, lause irtoaa ja seuraava tulee tilalle.

   Ilman JS:ää tämä toimii sellaisenaan — silloin näkyy vain kaksi
   peräkkäistä isoa lausetta, mikä on täysin luettava lopputulos.

   Raidan korkeus on 100vh + lauseen korkeus, jotta lause ehtii olla
   ruudulla kokonaisen vierityksen verran ennen kuin se vaihtuu. */
.claim {
  position: relative;
  padding-block: var(--section-y);
}

.claim__slot {
  min-height: 128vh;
}

/* Viimeinen raita saa olla matalampi: sen jälkeen tulee jo seuraava
   osio, eikä lauseen tarvitse odottaa omaa vuoroaan uudestaan. */
.claim__slot:last-child {
  min-height: 96vh;
}

.claim__line {
  position: sticky;
  inset-block-start: 50vh;
  max-width: 22ch;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-h2);
  font-weight: var(--fw-bold);
  line-height: var(--lh-snug);
  letter-spacing: var(--ls-tight);
  text-wrap: balance;
  translate: 0 -50%;
}

/* Toinen väite on käänne, joten se on oikealla ja punaisella. */
.claim__line--kaanne {
  margin-inline-start: auto;
  color: var(--accent-text);
}

@media (min-width: 900px) {
  .claim__line {
    max-width: 26ch;
  }
}

/* Kapealla näytöllä sticky-vaihto ei toimi: lause vie jo lähes koko
   ruudun, joten kiinnittäminen jättäisi vain tyhjää vieritettävää.
   Silloin väitteet ovat kaksi peräkkäistä lausetta. */
@media (max-width: 719px), (prefers-reduced-motion: reduce) {
  .claim__slot,
  .claim__slot:last-child {
    min-height: 0;
  }

  .claim__line {
    position: static;
    translate: none;
    max-width: none;
    margin-block-end: var(--sp-10);
  }

  .claim__line--kaanne {
    margin-block-end: 0;
  }
}
