/* Matkakirja ja unohdettu aarre — sovelluskehys (tumma pähkinäpuu) ja aarrekartta (pergamentti). */

/*
 * hidden-attribuutin pitää voittaa aina. Selaimen oletus on display: none,
 * mutta mikä tahansa myöhempi display-sääntö (flex, grid, block) kumoaa sen,
 * jolloin piilotettu elementti jää näkyviin. Tämä sääntö tekee attribuutista
 * ehdottoman, eikä yksittäisiä [hidden]-korjauksia tarvita.
 */
[hidden] { display: none !important; }

/*
 * PÄIVITYSRUUTU (omistajan havainto 13.8.2026: "ruma välitila").
 *
 * Näkyy vain päivityksen jälkeisen latauksen ajan (index.html:n
 * pikkuskripti + js/main.js). Tasainen pelin tumma pohja, keskellä
 * logo ja yksi rivi tekstiä — ei kehyksiä, ei kortteja, ei mitään
 * puoliksi rakentunutta.
 *
 * Sääntö on tiedoston alussa tarkoituksella: se on ensimmäistä
 * maalausta varten, eikä se saa jäädä myöhempien sääntöjen taakse.
 * Värit kirjoitetaan tähän suoraan eikä muuttujina, koska :root-lohko
 * tulee vasta alempana.
 */
.paivitysruutu {
  position: fixed;
  inset: 0;
  z-index: 9000;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2rem;
  padding: 2rem 1.4rem;
  background: #1d1610;
  color: #f3e6d0;
  text-align: center;
}

.paivitysruutu-logo {
  width: min(19rem, 66vw);
  height: auto;
  opacity: 0.92;
}

.paivitysruutu-teksti {
  margin: 0;
  font-size: 0.98rem;
  letter-spacing: 0.02em;
  color: #d9a13b;
}

/* Pelin oma runko pysyy piilossa, kunnes se on rakennettu: puoliksi
   valmis näkymä ei saa vilkkua latausruudun alta. */
body.paivittyy .app { visibility: hidden; }

/*
 * Häivytys valmiin näkymän päältä (js/main.js paataPaivitysruutu).
 * Kesto on sama luku kuin siellä: LATAUSRUUDUN_HAIPYMA_MS. Peli on jo
 * maalattu ruudun alla, joten häivytyksen läpi paljastuu valmis
 * kartta eikä rakentumaton runko.
 */
.paivitysruutu.latausruutu-haipyy {
  opacity: 0;
  pointer-events: none;
  transition: opacity 280ms ease;
}

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

:root {
  /* Sovelluksen kehys */
  --bg: #1d1610;
  --panel: #2a1f16;
  --panel-2: #35271a;
  --line: #4b3826;
  --ink-light: #f3e6d0;
  --muted: #b39c7d;
  --accent: #d9a13b;
  --accent-dark: #8a6114;
  --danger: #ff9b8a;

  /* Kartta */
  --paper: #efdcb4;
  --paper-dark: #dcc08f;
  --map-ink: #46331f;
  --map-ink-soft: #8a6c46;
  --sea-ink: #6e6350;
  --mark: #b03a2b;

  --radius: 12px;
  --gap: 0.6rem;

  /*
   * LIIKKEEN KÄYRÄT (omistajan linjaus 3.9.2026: *"kaikki kohdat
   * pelissä pyritään animoimaan ja niissä käytetään näitä pehmeitä
   * kiihdytyksiä ja jarrutuksia"*).
   *
   * Kolme käyrää riittää koko pelille: sisään tuleva osa jarruttaa
   * pehmeästi paikalleen, paikkaa vaihtava kiihtyy ja jarruttaa, ja
   * poistuva kiihtyy pois. Uusi animaatio ottaa käyränsä täältä eikä
   * kirjoita omaa cubic-bezieriään — silloin koko peli liikkuu samalla
   * tavalla.
   */
  --liike-sisaan: cubic-bezier(0.22, 0.9, 0.24, 1);
  --liike-pehmea: cubic-bezier(0.45, 0, 0.2, 1);
  --liike-ulos: cubic-bezier(0.4, 0, 1, 1);
  /* iOS:n turva-alueet myös muuttujina: JavaScript ei näe env()-arvoja
   * suoraan, ja kehittäjätilan mittarivi tarvitsee ne. */
  --turva-yla: env(safe-area-inset-top, 0px);
  --turva-ala: env(safe-area-inset-bottom, 0px);
  /* Kartan päällä kelluvat kortit: läpikuultava pergamentti kuten .event-toast. */
  --overlay-card: rgba(46, 33, 20, 0.88);
  --overlay-line: rgba(217, 161, 59, 0.45);

  /* Vanhan matkakirjoituskoneen fontti kaikelle käyttöliittymätekstille.
     Kartan käsin piirretyt nimet pysyvät serif-musteella. */
  --font-type: "American Typewriter", "Courier Prime", "Courier New", Courier, monospace;
  /*
   * LUKUKIRJASIN pitkälle leipätekstille.
   *
   * Kirjoituskone on pelin ääni ja se pysyy otsikoissa, napeissa ja
   * kartalla. Mutta Tutki-sivulla on kolmisen tuhatta merkkiä yhtenäistä
   * tekstiä kategoriaa kohti, ja tasalevyinen kirjasin tekee siitä
   * työlästä: kaikki kirjaimet ovat yhtä leveitä, joten sanoilla ei ole
   * muotoa, josta silmä tunnistaa ne vilkaisulla (omistaja: "vaivalloinen
   * lukea, kun tekstiä on niin paljon").
   *
   * Iowan Old Style on iOS:n oma lukukirjasin ja piirretty juuri tähän:
   * iso x-korkeus, avoimet muodot, tumma piirto. Se on jo pelissä kartan
   * kaupunkinimissä, joten uutta latausta ei tule. Varapino kattaa muut
   * laitteet, ja viimeisenä on aina jokin päätteellinen.
   */
  --font-luku: "Iowan Old Style", Charter, "Palatino Linotype", Palatino,
    Georgia, "Times New Roman", serif;

  /*
   * Isoisän käsiala: yksi kaunokirjoitus koko pelissä.
   *
   * Sama pino oli neljässä eri säännössä (maan nimi, lentokalvon
   * vyöhykkeet ja merkinnät, nyt myös maastonimet). Kaksi eri kaunoa
   * samalla kartalla näyttää virheeltä, ja neljä kopiota on neljä
   * tilaisuutta poiketa — siksi pino on tässä kerran.
   *
   * Snell Roundhand ja Savoye löytyvät Applen laitteilta, Segoe Script
   * Windowsista; cursive on varalla.
   */
  --font-kauno: "Snell Roundhand", "Savoye LET", "Bradley Hand",
    "Segoe Script", "Comic Sans MS", cursive;

  /*
   * ATLAKSEN LADONTA — sama antiikva, jolla lehteen poltetaan nimet.
   *
   * Fokuslehden kuva ladotaan Liberation Serifillä (tools/fokuskartta/
   * piirto.js `teksti`), ja kun peli latoo kartalle SAMAAN kuvaan
   * kuuluvia nimiä, sen on käytettävä samaa kirjasinta — muuten
   * lehden oma ladonta ja pelin nimiöt lukevat eri käsialoina
   * (omistajan palaute v1211). Liberation Serif on metriikaltaan
   * Times New Romanin kaksonen, joten varapino antaa laitteilla,
   * joilla sitä ei ole, saman rytmin ja saman kirjainleveyden.
   */
  --font-atlas: "Liberation Serif", "Times New Roman", Times, serif;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  overscroll-behavior: none;
}

body {
  font-family: var(--font-type);
  background: var(--bg);
  color: var(--ink-light);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

button, .brand, .turn-pill, .fact-card h2 {
  -webkit-user-select: none;
  user-select: none;
}

/* --- sovelluskehys --- */

.app {
  /* Kiinnitetään kehys suoraan ruudun reunoihin: iPadin standalone-
   * tilassa sekä 100dvh että rungon 100 % jäivät todellista ruutua
   * lyhyemmiksi ja alle jäi tumma kaista. Kiinteä asemointi kattaa
   * koko näkymän joka selaimessa. */
  position: fixed;
  inset: 0;
  height: auto;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  /* Kapealla ruudulla sisältö ei saa venyttää asettelua leveämmäksi. */
  overflow: hidden;
  min-width: 0;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom)
    env(safe-area-inset-left);
}

.topbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-width: 0;
  padding: 0.45rem 0.8rem;
  background: linear-gradient(180deg, #3a2a1c, #251b12);
  border-bottom: 1px solid var(--line);
}

/*
 * NIMILOGO ON KUVA (omistajan toimittama tiedosto, 5.8.2026).
 *
 * Ennen tässä oli ladottu teksti: MATKAKIRJA ja sen alla viiva ja
 * UNOHDETTU AARRE, jonka kirjaimet tasattiin yksitellen flexillä, jotta
 * rivit olisivat täsmälleen yhtä leveät. Se oli kiertotie sen ympäri,
 * ettei tämän ympäristön selaimessa ole pelin kirjasimia eikä
 * kirjainmittoihin voinut luottaa. Kuvassa mitat ovat kuvassa.
 *
 * Kuva on läpinäkyvä PNG (assets/logo.png). Alkuperäinen tiedosto oli
 * kirkkaanvihreällä taustalla; vihreä on avainnettu pois ja reunojen
 * sekoitus purettu, jotta kirjainten ympärille ei jää vihreää reunusta.
 * Mitattu lopputuloksesta yläpalkin ruskealla: vihreysjäämä -11, eli
 * yhtään vihertävää pikseliä ei jäänyt.
 */
.brand {
  margin: 0;
  min-width: 0;
  display: block;
  line-height: 0;
}

/*
 * KORKEUS, EI LEVEYS.
 *
 * Logo on ylärivin korkein osa, ja ylärivi on kartasta pois. Korkeus
 * sidotaan siis suoraan, ja leveys seuraa kuvasuhdetta (4,09:1).
 *
 * Luvut ovat entisen tekstilogon mitat, jotta ylärivi ei muuta
 * korkeuttaan: mitattu 36 px työpöydällä (1440), 32 px tabletilla (834)
 * ja 22 px puhelimessa (390). Puhelimen arvo on omassa lohkossaan
 * alempana.
 *
 * vw-yksikkö keskellä eikä pelkkä rem: sama syy kuin ennen, eli kapea
 * ruutu ei saa saada työpöydän kokoista logoa.
 */
.brand-kuva {
  display: block;
  height: clamp(1.73rem, 3.8vw, 2.25rem);
  width: auto;
  max-width: 100%;
}

/*
 * Kukkaro, päivämäärä ja matkalaukku ovat sama nappi (omistajan toive):
 * rahat ja tavarat ovat samassa laukussa. Ulkoasu on yhä pilleri, ei
 * nappi — se ei saa kilpailla kartan kanssa, mutta sen pitää tuntua
 * napautettavalta.
 */
.turn-pill {
  flex: 0 1 auto;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.9rem;
  padding: 0.25rem 0.7rem;
  border-radius: 999px;
  background: var(--panel);
  border: 1px solid var(--line);
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.turn-pill:hover,
.turn-pill:focus-visible {
  border-color: var(--kulta, #eab84e);
}
.turn-pill .laukku-ikoni {
  display: inline-flex;
  color: var(--muted);
}
.turn-pill .laukku-ikoni svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linejoin: round;
}

/*
 * Päiväkirjan päivämäärä. Aika on tarinaa eikä uhkaa, joten mittari on
 * kirjoituskonetekstiä muun pillerin sävyissä — ei hälytysväriä missään
 * vaiheessa, ei myöskään ennätyksen umpeuduttua.
 */
.turn-pill .clock {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.turn-pill .clock::before {
  content: '·';
  margin-right: 0.45rem;
}

/* Ajan eteneminen välähtää kevyesti kullalla, jotta pelaaja huomaa
 * vilkaista päivämäärää. Yksi rauhallinen hengähdys, ei vilkutusta. */
.turn-pill.aika-valahdys .clock {
  animation: aika-valahdys 1.4s ease-out;
}

@keyframes aika-valahdys {
  0% { color: var(--muted); }
  22% { color: var(--accent); text-shadow: 0 0 8px rgba(234, 184, 78, 0.55); }
  100% { color: var(--muted); }
}

@media (prefers-reduced-motion: reduce) {
  .turn-pill.aika-valahdys .clock { animation: none; }
}

/*
 * Päävalikko eli hampurilainen (omistajan toive 4.8.2026, palautettu).
 *
 * v237 nosti säännöt ja uuden pelin suoraan yläriville ja poisti tämän.
 * Ylärivi kävi kuitenkin ahtaaksi: nimilogon ja neljän kuvakkeen välissä
 * päiväpilleri leikkautui kesken sanan puhelimella. Valikossa on tilaa
 * sekä kuvakkeelle että nimelle, toisin kuin ylärivillä.
 */
.valikko-kotelo { position: relative; }

.paavalikko {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.3rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(15, 10, 5, 0.45);
  /*
   * VALIKKO VIERITTYY (omistaja 5.9.2026 iPhone-kaappaus: *"Tee valikosta
   * scrollattava. En pääse noihin alempiin enää puhelimella käsiksi
   * muuten."*). Pelilauta-osio (v1567) kasvatti valikon puhelimen ruutua
   * korkeammaksi, ja Työhuoneen alimmat rivit jäivät ruudun alle. Katto
   * on ruudun korkeus miinus ylärivi ja marginaali (dvh ei sisällä
   * Safarin osoiteriviä); ylivuoto vierittyy valikon sisällä eikä
   * vieritä sivua (overscroll-behavior). Sama sääntö kattaa myös
   * kehittäjävalikon (class="paavalikko kehittaja-valikko").
   */
  max-height: calc(100dvh - 5.6rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

@supports not (height: 100dvh) {
  .paavalikko { max-height: calc(100vh - 6.4rem); }
}

.paavalikko button {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.45rem 0.6rem;
  background: none;
  border: 1px solid transparent;
  border-radius: 8px;
  white-space: nowrap;
}

.paavalikko button:hover { background: rgba(234, 184, 78, 0.12); }

/*
 * ── LITTEÄ VALIKKO: EI ALIVALIKKOJA ──────────────────────────────────
 *
 * Omistaja 5.8.2026: *"hampurilaisesta voisi suoraan avautua kaikki
 * varusteet sekä äänisäädöt nappeina ja ihan alalla olisi säännöt ja
 * uusi peli napit keskitettynä. Varusteet ja äänet voisi olla omien
 * otsikoiden alla. Keskitä kaikki napit ja otsikot."*
 *
 * Varusteet ja Äänet olivat nappeja, jotka avasivat oman paneelinsa
 * valikon päälle. Kaksi napautusta yhden säädön takana on paljon, kun
 * säätöjä on kahdeksan.
 */
/*
 * VÄLJEMPI LADELMA (omistaja 5.8.2026: "liian pienet marginaalit ...
 * varsinkin varusteet otsikon ylä- ja alapuolella pitäisi olla lisää
 * tilaa").
 *
 * Valikko peri pudotusvalikon tiiviit mitat ajalta, jolloin siinä oli
 * neljä tekstiriviä. Nyt siinä on kaksi osastoa ruudukkoineen ja
 * komentorivi, ja osastot tarvitsevat ilmaa erottuakseen toisistaan.
 */
.paavalikko { align-items: stretch; gap: 0.55rem; padding: 0.85rem 0.8rem 0.7rem; }

.valikko-otsikko {
  /* Otsikon yläpuolelle enemmän kuin alapuolelle: väli KUULUU sitä
     seuraavalle osastolle, ja epäsymmetria sitoo otsikon ruudukkoonsa
     eikä edelliseen lohkoon. */
  margin: 0.5rem 0 0.45rem;
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-align: center;
  color: var(--accent);
}

/*
 * Äänipaneeli on nyt valikon sisällä eikä sen päällä: pois
 * absoluuttinen asemointi, oma tausta ja oma reunus. Se oli
 * pudotusvalikon kuori, ja pudotusvalikkoa ei enää ole.
 *
 * (Sama sääntö koski linssivalitsinta, kunnes se muutti
 * matkalaukkuun 18.8.2026 — sen vastine on nyt
 * `.passport-card .linssi-valikko`.)
 */
.paavalikko .kertoja-valikko {
  align-items: center;
  position: static;
  width: auto;
  max-width: none;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

/*
 * ── VALIKON KAKSI ALINTA RIVIÄ TÄYTTÄVÄT LEVEYDEN ────────────────────
 *
 * Omistaja 13.8.2026: *"hampurilaisen ikonit ovat vielä korjaamatta.
 * Niitä piti vähän levittää ja tehdä vähän lisää välistystä, jotta ne
 * täyttävät nätisti keskitetysti koko tilan. Siis ne kaksi alinta
 * nappiriviä. Ylin varusteiden rivi voi jäädä juuri noin."*
 *
 * Äänirivi peri varusteruudukon neljä saraketta, vaikka äänitiloja on
 * kolme: 44 pikselin napit istuivat sarakkeidensa vasemmassa laidassa
 * ja neljäs sarake jäi tyhjäksi oikeaan reunaan — mitattuna vasemmalla
 * 14 px ja oikealla 20 px. Rivi on nyt oma flex-rivinsä kuten
 * alarivikin, ja molemmat käyttävät samaa napinleveyttä ja samaa jakoa
 * (space-between), joten ne täyttävät valikon laidasta laitaan ja
 * asettuvat myös keskenään samaan linjaan.
 *
 * Varusteruudukko jää ennalleen: se on ruudukko, johon tulee rivejä
 * lisää varusteiden myötä, eikä sen jakoa saa sitoa nappien määrään.
 *
 * EI `flex-wrap: wrap`. Valikko on absoluuttisesti asemoitu, joten sen
 * leveys tulee sisällön luontaisesta leveydestä — ja rivittyvän
 * flex-rivin luontainen leveys on yhden napin verran, ei kolmen. Sen
 * kanssa valikko kutistui 82 pikseliin ja napit latautuivat päällekkäin.
 * Nappeja on kolme eikä rivin tarvitse rivittyä.
 */
/*
 * KAKSI KYTKINTÄ ALLEKKAIN (omistajan pelitestipalaute v1119:
 * *"Erittele ÄÄNET-osioon kaksi selkeää omaa päälle/pois-kytkintä:
 * KERTOJA (luennat) ja TAUSTAÄÄNET (ambienssi + efektit)"*).
 *
 * Kolme kuvakeneliötä vierekkäin oli arvoitus: mikä niistä oli päällä
 * ja mitä kukin tarkoitti, selvisi vain kokeilemalla. Nyt rivillä on
 * kuvake, nimi ja tila sanana — ja rivi on koko valikon levyinen, eli
 * sormelle helppo kohde.
 */
.paavalikko .kertoja-valikko {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.paavalikko .kertoja-valikko button {
  flex-direction: row;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  min-height: 44px;
  padding: 0.35rem 0.7rem;
  justify-content: flex-start;
  background: rgba(53, 39, 26, 0.55);
  border: 1.2px solid var(--line);
  border-radius: 8px;
}

.paavalikko .kertoja-valikko button svg { width: 24px; height: 24px; }

.paavalikko .kertoja-valikko .aanikytkin-nimi {
  flex: 1 1 auto;
  text-align: left;
  font-family: var(--font-type);
  font-size: 0.82rem;
  letter-spacing: 0.06em;
}

/* Tila sanana rivin oikeassa laidassa: "päällä" / "pois". */
.paavalikko .kertoja-valikko .aanikytkin-tila {
  flex: 0 0 auto;
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.75;
}

/* Päällä oleva kytkin erottuu kullalla, kuten valittu varuste. */
.paavalikko .kertoja-valikko button.valittu {
  background: var(--panel-2);
  border-color: var(--accent-dark);
  color: var(--accent);
}

/* Pois kytketty rivi on vaimea mutta luettava — ei katoa näkyvistä. */
.paavalikko .kertoja-valikko button:not(.valittu) {
  color: rgba(230, 214, 184, 0.62);
}

.paavalikko .kertoja-valikko button:not(.valittu) svg { opacity: 0.55; }

/* Täppä oli pudotusvalikon rivimerkintä; kytkinrivillä tilan kertoo
   sana ja väri. */
.paavalikko .kertoja-valikko .tappa { display: none; }

/*
 * PELILAUDAN VALINTA (omistaja 5.9.2026: *"pelissä periaatteessa voisi
 * olla lopulta kytkin, millä pelaaja voisi valita haluaako pelata
 * pallonäkymässä vai sillä meidän vanhalla kartalla"*). Rivit ovat
 * äänikytkinten näköiset ja käyttävät niiden sääntöjä (.kertoja-valikko
 * myös lautakotelossa) — sama asetusvalikko, sama riviasu. Omaa tyyliä
 * tarvitsee vain vaihdon vihjerivi, joka kertoo sivun latautuvan.
 */
.lauta-vihje {
  margin: 0.35rem 0 0;
  font-family: var(--font-type);
  font-size: 0.7rem;
  line-height: 1.3;
  text-align: center;
  color: var(--muted);
}

.lauta-vihje[hidden] { display: none; }

/*
 * ── VALIKON KOMENNOT: KAKSI LEVEÄÄ TEKSTINAPPIA ──────────────────────
 *
 * Omistajan päätös 18.8.2026: "uusi peli" ja sen alla "ehdota
 * sisältöä", koko rivin levyisinä ja allekkain. v854:n kapeat
 * kuvakeleveät napit ("uusi", "ehdota") olivat sekä pieni kohde että
 * arvoituksellinen teksti; leveä nappi kertoo mitä se tekee ja on
 * sormelle helppo.
 *
 * Napit SAAVAT korostua: valikossa ei ole enää muuta pelisisältöä,
 * joten nämä kaksi ovat sen ainoat komennot.
 */
.valikko-alarivi {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  align-self: center;
  /* Rivi on koko valikon levyinen, jotta yläpuolen vaakaviiva jatkuu
   * laidasta laitaan (omistaja 13.8.2026). */
  width: 100%;
  margin-top: 0.5rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--line);
}

.paavalikko .valikko-alarivi button {
  /* Koko leveys, sormen mittainen korkeus. Ei kiinteää leveyttä: napin
   * pituus on valikon pituus, ei sanan. */
  width: 100%;
  min-height: 44px;
  padding: 0.55rem 0.9rem;
  justify-content: center;
  background: rgba(53, 39, 26, 0.55);
  border: 1.2px solid var(--line);
  border-radius: 8px;
}

.paavalikko .valikko-alarivi .valikko-tekstinappi {
  /* Korostus: kullan sävyinen teksti ja hieman vahvempi kehys kuin
     äänipainikkeilla — nämä ovat komentoja, ne saavat erottua.
     Kirjasin on valikon oma eikä käsiala: palautenappi peri
     `--font-hand`-käsialan ajalta, jolloin se oli pelkkä huutomerkki
     kartan kulmassa, eikä käsiala kanna kahta sanaa. */
  color: var(--accent);
  border-color: var(--accent-dark);
  font-family: inherit;
  font-size: 1.02rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: 0.04em;
  /* Täysleveä nappi ei skaalaudu osoittimen alla: kasvava laatikko
     työntäisi valikkoa. Korostus tehdään taustalla. */
  transform: none;
}

.paavalikko .valikko-alarivi .valikko-tekstinappi:hover,
.paavalikko .valikko-alarivi .valikko-tekstinappi:focus-visible {
  background: var(--panel-2);
  color: var(--ink-light);
  transform: none;
}

/* Kertojavalikko: nappi näyttää nykyisen tilan kuvakkeen ja avaa alleen
 * pienen paneelin, jossa neljä kuvakeriviä täppineen. */
.kertoja-kotelo { position: relative; }

.kertoja-valikko {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.3rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(15, 10, 5, 0.45);
}

.kertoja-valikko button {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.4rem 0.55rem;
  background: none;
  border: 1px solid transparent;
  border-radius: 8px;
}

.kertoja-valikko button:hover { background: rgba(234, 184, 78, 0.12); }

.kertoja-valikko .tappa {
  width: 1em;
  color: var(--accent);
  font-weight: 700;
  visibility: hidden;
}

.kertoja-valikko button.valittu {
  border-color: rgba(176, 138, 60, 0.55);
}

.kertoja-valikko button.valittu .tappa { visibility: visible; }

/*
 * Laukku herää eloon, kun sinne tulee jotain uutta: passileima,
 * kunniamerkintä tai löydetty aarre. Pieni heilahdus ja lämmin
 * kultahehku — kuin laukku tömähtäisi pöydälle.
 */
.turn-pill.laukku-elo {
  animation: laukku-elo 0.9s cubic-bezier(0.34, 1.4, 0.5, 1);
}

@keyframes laukku-elo {
  0% { transform: none; }
  14% { transform: rotate(-7deg) scale(1.14); }
  32% { transform: rotate(6deg) scale(1.1); box-shadow: 0 0 12px rgba(234, 184, 78, 0.55); }
  52% { transform: rotate(-4deg) scale(1.06); }
  72% { transform: rotate(2.5deg) scale(1.03); }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .turn-pill.laukku-elo { animation: none; }
}

.topbar-actions {
  margin-left: auto;
  display: flex;
  gap: 0.4rem;
  flex: 0 0 auto;
}

/*
 * KEHITTÄJÄN HAMMASRATASVALIKKO (omistajan tilaus 29.8.2026,
 * index.html #kehittaja-valikko-kotelo).
 *
 * Kotelo näkyy vain kehittäjätilassa, joten se ei saa varata ylärivistä
 * tilaa muilta: `hidden` piilottaa sen kokonaan, ja `flex: 0 0 auto`
 * estää sitä venymästä kun se on näkyvissä. Ylärivissä on siis yhä
 * kehittäjänkin silmissä vain YKSI kuvake (omistajan sääntö
 * 27.8.2026) — kytkimet asuvat sen alla.
 *
 * Pudotusvalikko lainaa hampurilaisen tyylin sellaisenaan
 * (index.html: class="paavalikko kehittaja-valikko"), joten kaksi
 * valikkoa vierekkäin näyttää yhdeltä perheeltä eikä sääntöjä
 * kirjoiteta kahteen kertaan. Tässä on vain se, mikä on kehittäjän
 * omaa: rivin kolme saraketta ja tilateksti.
 *
 * Valikko avautuu OIKEASTA laidastaan (`right: 0`, peritty
 * .paavalikosta) eli vasemmalle päin — hammasratas on ylärivin
 * oikeassa reunassa, ja vasemmalle avautuva levy pysyy ruudulla myös
 * kapeimmalla puhelimella. Se on kartan päällä (.paavalikon z-index),
 * mutta laitemittari asuu karttaruudussa omalla z-indexillään 9999,
 * joten valikko ei peitä mitattavaa laatikkoa.
 */
.kehittaja-valikko-kotelo {
  position: relative;
  flex: 0 0 auto;
}

.kehittaja-valikko-kotelo[hidden] { display: none; }

/*
 * VALIKKO LAITEMITTARIN PÄÄLLE, EI SEN ALLE.
 *
 * Mittarin laatikko asuu karttaruudussa omalla z-indexillään 9999
 * (js/karttamittari.js) ja alkaa saman ylänurkan tuntumasta, joten
 * avattu valikko jäisi oletusarvoillaan mittarin alle luettavaksi
 * kelpaamattomana — juuri sen kytkimen alle, jota valikosta ollaan
 * kääntämässä. Suljettuna valikko on pelkkä kuvake ylärivissä, joten
 * mittari näkyy kokonaan aina kun sitä luetaan; avattuna se on
 * hetkellinen levy mittarin päällä, kuten pudotusvalikon kuuluukin.
 */
.kehittaja-valikko { z-index: 10000; }

/*
 * Kolme saraketta: kuvake, nimi ja tila. Nimi vie jäljelle jäävän
 * tilan, joten tilateksti asettuu aina samaan kohtaan oikeaan laitaan
 * eikä rivistä tule portaikkoa.
 */
.kehittaja-valikko .kehittaja-kytkin {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 0.55rem;
  text-align: left;
}

.kehittaja-kytkin-nimi {
  font-size: 0.92rem;
  letter-spacing: 0.02em;
}

/*
 * Tila luetaan yhdellä vilkaisulla: päällä oleva kytkin kultaa sekä
 * nimen että tilatekstin, pois kytketty jää himmeäksi.
 */
.kehittaja-kytkin-tila {
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/*
 * Leveä tilateksti: siirtymämusiikin rivi kertoo kolmen raidan
 * tilanteen kerralla ("jalan \2713  laiva \2013  lento \2013"), eikä
 * versaali harvennuksella mahdu riville. Sama väri ja koko, vain
 * muotoilu kevyempi.
 */
.kehittaja-kytkin-tila.laaja {
  font-size: 0.6rem;
  letter-spacing: 0.01em;
  text-transform: none;
  white-space: nowrap;
}

/*
 * Kehittäjän voimakkuussäädin (omistaja 3.9.2026): nimi vasemmalla,
 * miinus, arvo ja plus oikealla samassa rivissä kuin kytkimet.
 */
.kehittaja-valikko .kehittaja-saadin {
  display: grid;
  grid-template-columns: 1fr auto auto auto;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  text-align: left;
}

.kehittaja-saadin-nappi {
  min-width: 1.8rem;
  padding: 0.1rem 0.4rem;
  font-size: 1rem;
  line-height: 1.2;
}

.kehittaja-saadin-arvo {
  min-width: 2.6rem;
  text-align: center;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--kulta, #eab84e);
  font-variant-numeric: tabular-nums;
}

.kehittaja-valikko .kehittaja-kytkin[aria-pressed='true'] {
  color: var(--kulta, #eab84e);
  border-color: rgba(176, 138, 60, 0.55);
}

.kehittaja-valikko .kehittaja-kytkin[aria-pressed='true'] .kehittaja-kytkin-tila {
  color: var(--kulta, #eab84e);
}

/* Yhden rivin vihje (mittarin uudelleenlataus, generoinnin tulos). */
.kehittaja-valikko-vihje {
  margin: 0.35rem 0 0;
  max-width: 15rem;
  font-size: 0.7rem;
  line-height: 1.3;
  color: var(--muted);
}

.kehittaja-valikko-vihje[hidden] { display: none; }


/*
 * Muutoslokin omat toiminnot: päivitys ja kehittäjätila.
 *
 * Hampurilainen poistettiin (omistajan toive), ja nämä kaksi harvoin
 * tarvittavaa toimintoa siirtyivät versionumeron taakse. Ne ovat lokin
 * alalaidassa omalla rivillään, erotettuna listasta ohuella viivalla:
 * loki on luettavaa, nämä ovat painettavaa.
 */
.muutokset-toiminnot {
  display: flex;
  gap: 0.5rem;
  margin: 0.7rem 0 0.2rem;
  padding-top: 0.6rem;
  border-top: 1px solid rgba(70, 51, 31, 0.22);
}

.muutokset-toiminnot button {
  flex: 1 1 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.42rem 0.5rem;
  font-size: 0.78rem;
  color: #46331f;
  background: none;
  border: 1px solid rgba(70, 51, 31, 0.28);
  border-radius: 3px;
}

.muutokset-toiminnot button:hover:not(:disabled) {
  background: rgba(234, 184, 78, 0.16);
  color: #46331f;
}

.muutokset-toiminnot .viiva-ikoni { width: 1rem; height: 1rem; }


/*
 * Linssivalitsin (docs/linssit-suunnitelma.md luku 5).
 *
 * Sama kotelo + absoluuttinen paneeli kuin kertojavalikossa,
 * jotta se käyttäytyy tutulla tavalla eikä vie ylärivistä tilaa ennen
 * kuin ensimmäinen linssi on löytynyt. Paneeli aukeaa oikeasta
 * reunastaan vasemmalle: kotelo on ylärivin oikeassa laidassa, ja
 * vasemmalle aukeava paneeli mahtuu myös 360 px:n puhelimelle.
 */
.linssi-kotelo { position: relative; }

/* Päällä oleva linssi näkyy napissa kullalla: ylärivistä pitää nähdä
   yhdellä silmäyksellä, katsotaanko karttaa jonkin lasin läpi. */
#linssi-btn.paalla { color: var(--accent); }

.linssi-valikko {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  z-index: 60;
  width: max-content;
  /*
   * Leveysraja mitattu puhelimella: kotelo on ylärivin oikeassa
   * laidassa mutta kahden napin päässä reunasta, joten oikeaan
   * reunaansa kiinnitetty paneeli alkaa noin 7 rem päässä ruudun
   * oikeasta laidasta. Ilman tätä rajaa 336 px:n paneeli valui 390 px:n
   * ruudulla vasemman reunan yli ja nimen ensimmäinen kirjain jäi
   * näkymättömiin (mitattu: paneelin vasen reuna oli -17 px).
   */
  /*
   * PUOLEEN ENTISESTÄ (omistaja 5.8.2026: "kavenna alivalikkonäkymää
   * puoleen nykyisestä"). 21rem -> 10,5rem.
   *
   * Paneeli oli leveä kahdesta syystä, joista toinen oli vika: liuskat
   * eivät mahtuneet yhdelle riville vaan pinoutuivat neljäksi täysleveäksi
   * napiksi, koska päävalikon sääntö `.paavalikko button { width: 100% }`
   * osui myös niihin (korjattu alempana). Mitattu ennen: paneeli 290 px,
   * jokainen liuska 270 px eli koko leveys yhtä kuvaketta kohti.
   *
   * 9rem = 144 px on tasan puolet. Liuskat kiertyvät kahden riveiksi,
   * mikä on niiden oma suunniteltu käytös (ks. .linssi-liuskat) ja myös
   * välttämätöntä: linssejä on tulossa yksitoista, eivätkä ne mahtuisi
   * yhdelle riville millään leveydellä. Kuvaus liuskojen alla kiertyy
   * useammalle riville, ja se on oikea järjestys — kuvake on valinta,
   * teksti on selitys.
   */
  max-width: min(9rem, calc(100vw - 7rem));
  padding: 0.45rem 0.55rem 0.55rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 10px 28px rgba(15, 10, 5, 0.45);
}

/*
 * Liuskarivi on Tutki-ikkunan aiheliuskojen kuvio (.wiki-liuskat):
 * kuvakkeet yhdellä rivillä, valittu liuska samaa pintaa kuin sisältö
 * sen alla. Värit ovat ylärivin tummat eivätkä pergamentin, koska
 * paneeli on osa käyttöliittymää eikä karttaa — muoto kantaa
 * tunnistuksen, ei väri.
 *
 * TÄMÄ ON NYKYÄÄN VAIN SELITEKORTIN ASKELLIUSKOJEN tyyli
 * (.linssi-selite): niissä on tekstiä ja ne ovat yhdellä rivillä, eli
 * juuri se muoto, jota varten liuska keksittiin. Linssivalitsin sai
 * omat neliönsä alempana.
 *
 * Liuskat KIERTYVÄT usealle riville eivätkä vierity vaakaan: vieritys
 * piilottaisi linssejä, ja piilotettu linssi on sama kuin löytymätön.
 */
.linssi-liuskat {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.25rem;
  padding-bottom: 0.5rem;
  border-bottom: 1.5px solid var(--line);
}

.linssi-liuskat button {
  appearance: none;
  flex: 0 0 auto;
  /*
   * Liuska on kuvakkeen levyinen, ei valikon.
   *
   * Valitsin asuu päävalikon sisällä, ja `.paavalikko button` antaa
   * kaikille napeilleen `width: 100%` — se on oikein valikon riveille
   * mutta väärin liuskoille, jotka on tarkoitettu vierekkäin.
   */
  width: auto;
  display: grid;
  place-items: center;
  padding: 0.3rem 0.5rem 0.62rem;
  min-height: 0;
  background: rgba(53, 39, 26, 0.55);
  border: 1.2px solid var(--line);
  border-bottom-color: transparent;
  border-radius: 7px 7px 0 0;
  color: var(--muted);
  cursor: pointer;
  /* Alareunan viiva kulkee liuskan ali; tämä nostaa sen sen päälle. */
  margin-bottom: -0.5rem;
}

.linssi-liuskat button svg { display: block; }

.linssi-liuskat button:hover { background: var(--panel-2); color: var(--ink-light); }

/* Valittu liuska on samaa pintaa kuin paneeli sen alla ja sen alareuna
   on auki — juuri se tekee liuskasta liuskan eikä napista. */
.linssi-liuskat button.paalla {
  background: var(--panel);
  border-color: var(--accent-dark);
  border-bottom-color: var(--panel);
  color: var(--accent);
}

/*
 * ── VALITSIMEN RUUDUKKO: IRRALLISET NELIÖT ───────────────────────────
 *
 * Omistaja: "tee ikoneista irrallisia neliöitä pienellä pyöristyksellä
 * jotka täyttävät tilan tasaisesti."
 *
 * Liuskan muoto kaatui siihen, että paneeli kavennettiin puoleen
 * (v269: 290 -> 144 px). Kahdelle riville kiertynyt liuskarivi ei ole
 * liuskarivi vaan ruudukko, jossa on turhia viivoja: liuskan idea on
 * yksi rivi, jonka alta valittu aukeaa sisältöön.
 *
 * RUUDUKKO EIKÄ FLEX. `1fr`-sarakkeet jakavat leveyden tasan, joten
 * napit ovat keskenään samankokoisia eikä oikeaan laitaan jää vajaata
 * kaistaletta — juuri se on "täyttävät tilan tasaisesti". `auto-fill`
 * ja `minmax` päättävät sarakemäärän leveydestä: nykyisellä 127
 * pikselin sisäleveydellä kaksi, ja jos paneeli joskus levenee,
 * useampi. Linssejä on tulossa yksitoista, joten rivimäärän on
 * saatava kasvaa itsestään.
 *
 * `aspect-ratio: 1` tekee napista neliön riippumatta kuvakkeen koosta.
 */
.linssi-valikko .linssi-liuskat {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
  align-items: stretch;
  gap: 0.35rem;
  padding-bottom: 0.6rem;
}

.linssi-valikko .linssi-liuskat button {
  aspect-ratio: 1;
  padding: 0;
  border-color: var(--line);
  border-radius: 8px;
  margin-bottom: 0;
}

/*
 * ISOMMAT KUVAKKEET (omistaja 5.8.2026: "suurenna niitä kuvakkeita
 * isommaksi, ovat nyt vähän liian vaikeita painaa ja näkyvätkin liian
 * pienellä").
 *
 * Neliö oli jo 59 pikseliä eli reilusti kosketuskohteen minimin yli,
 * mutta kuvake sen sisällä oli 1,2 em ≈ 19 px — kolmasosa ruudusta.
 * Silmä mittaa painettavan kohteen KUVASTA eikä näkymättömästä
 * laatikosta, joten nappi tuntui pieneltä vaikka ei ollut.
 *
 * Koko on PIKSELEINÄ eikä em-yksiköinä. Valikon kirjasinkoko vaihtelee
 * ruudun mukaan, ja em-mitalla kuvake jäi puhelimella 25 pikseliin ja
 * kasvoi työpöydällä 32:een — juuri väärin päin, koska sormella
 * painetaan puhelinta. Neliö on 59 px molemmilla, joten kuvakekin saa
 * olla: 34 px eli runsas puolet ruudusta, sama suhde kuin ylärivin
 * napeissa.
 */
.linssi-valikko .linssi-liuskat button svg {
  width: 34px;
  height: 34px;
}

/* Valittu neliö erottuu kullalla eikä sulautumalla: irrallisessa
   neliössä ei ole alareunaa, jonka voisi avata. */
.linssi-valikko .linssi-liuskat button.paalla {
  background: var(--panel-2);
  border-color: var(--accent-dark);
}

/*
 * NAPAUTETTU MUTTA VIELÄ SYTYTTÄMÄTÖN (omistaja 5.9.2026). Napautus
 * vaihtaa vain selitteen, joten ruutu tarvitsee oman, kevyemmän
 * merkkinsä: haalea reunus kertoo "tästä puhutaan", kun taas päällä
 * olevan linssin täysi kulta kertoo "tämä on kartalla". Kaksi tilaa
 * voivat olla eri ruuduissa yhtä aikaa.
 */
.linssi-valikko .linssi-liuskat button.esikatselu {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent-dark);
}

.linssi-liuskat button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* Valitun linssin nimi ja yhden rivin kuvaus liuskojen alla: kuvake
   yksin jättäisi arvailun varaan. */
.linssi-tiedot { padding-top: 0.6rem; }

.linssi-nimi {
  margin: 0 0 0.2rem;
  font-family: var(--font-type);
  font-size: 0.86rem;
  letter-spacing: 0.04em;
  color: var(--accent);
}

.linssi-lyhyt {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--ink-light);
}

/*
 * Lähde ja lisenssi eivät ole koriste: aineistot ovat CC BY -lisenssin
 * alaisia ja vaativat nimeämisen. Kortti on napin takana, koska koko
 * merkintä osoitteineen on pitkä — lyhyt muoto (tekijä · lisenssi) on
 * näkyvissä koko ajan kartan selitekortissa.
 */
.linssi-lahde-avaa {
  margin-top: 0.5rem;
  padding: 0.15rem 0;
  background: none;
  border: 0;
  color: var(--muted);
  font-family: var(--font-type);
  font-size: 0.74rem;
  text-decoration: underline dotted;
  cursor: pointer;
}

.linssi-lahde-avaa:hover { color: var(--ink-light); }

/*
 * AKTIVOI ON NAPPI, EI SANA (omistaja 6.9.2026: *"Tee aktivoi tekstistä
 * nappi."*).
 *
 * Ruudun napautus vaihtaa selitteen (omistaja 5.9.2026), ja kytkentä
 * tapahtuu selitteen ALLA olevasta napista. Sana kappaleen perässä oli
 * oikea `<button>` jo ennen tätä, mutta se näytti tekstilinkiltä ja oli
 * yhden tekstirivin korkuinen — sormelle liian pieni juuri siinä
 * kohdassa, jossa laukun ainoa varsinainen toiminto on.
 *
 * Ilme on laukun omaa messinkiä: ohut kultareunus, pergamenttitäyte ja
 * sama kapiteeliotsikkolatomus kuin osastojen otsikoissa. Korkeus on
 * 44 px, joka on kosketuskohteen alaraja.
 *
 * Valitsinta on KAKSI, ja se on tarkoituksellista: laukku on dialogi,
 * ja `.dialog button` (0,1,1) maalaisi tähänkin yleisen
 * pergamenttinapin aaltoreunoineen. `.dialog .linssi-aktivoi` (0,2,0)
 * voittaa sen, ja yksinäinen luokka pitää tyylin voimassa myös kartan
 * puolella.
 */
.linssi-aktivoi,
.dialog .linssi-aktivoi {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  min-width: 8.5rem;
  min-height: 44px;
  margin: 0.7rem auto 0.1rem;
  padding: 0.3rem 1.2rem;
  background: linear-gradient(180deg, rgba(255, 249, 232, 0.72), rgba(233, 209, 160, 0.55));
  border: 1px solid rgba(122, 85, 20, 0.65);
  border-radius: 8px;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    0 1px 3px rgba(46, 30, 14, 0.22);
  color: var(--accent);
  font-family: var(--font-type);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background 160ms ease, box-shadow 160ms ease, transform 120ms ease;
}

.linssi-aktivoi:hover:not(:disabled),
.dialog .linssi-aktivoi:hover:not(:disabled) {
  background: linear-gradient(180deg, rgba(255, 252, 242, 0.9), rgba(240, 219, 176, 0.7));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 2px 6px rgba(46, 30, 14, 0.26);
}

.linssi-aktivoi:active:not(:disabled),
.dialog .linssi-aktivoi:active:not(:disabled) { transform: translateY(1px); }

.linssi-aktivoi:focus-visible,
.dialog .linssi-aktivoi:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/*
 * Päällä oleva linssi: nappi sanoo "Ota pois" ja kytkee sen pois — sama
 * nappi, käänteinen suunta (js/ui.js lisaaLinssinAktivointi). Himmeämpi
 * täyte kertoo, ettei tämä ole se nappi, jolla matka jatkuu.
 */
.linssi-aktivoi.pois,
.dialog .linssi-aktivoi.pois {
  background: linear-gradient(180deg, rgba(246, 238, 220, 0.5), rgba(219, 200, 166, 0.4));
  color: rgba(70, 51, 31, 0.85);
}

@media (prefers-reduced-motion: reduce) {
  .linssi-aktivoi,
  .dialog .linssi-aktivoi { transition: none; }
}

/*
 * Selitteen vaihto häivytetään sisään: napautuksesta napautukseen
 * teksti vaihtuu pehmeästi eikä hyppää (js/ui.js
 * havaitseLinssiTietojenVaihto lisää luokan joka piirrolla).
 */
@keyframes linssiSelitteenVaihto {
  from { opacity: 0; transform: translateY(3px); }
  to { opacity: 1; transform: none; }
}

.linssi-tiedot.vaihtui { animation: linssiSelitteenVaihto 220ms ease-out; }

@media (prefers-reduced-motion: reduce) {
  .linssi-tiedot.vaihtui { animation: none; }
}

.linssi-lahde {
  margin-top: 0.35rem;
  padding: 0.45rem 0.55rem;
  background: var(--panel-2);
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 0.74rem;
  line-height: 1.45;
}

.linssi-lahde p { margin: 0 0 0.25rem; }
.linssi-lahde-lisenssi { color: var(--muted); }
.linssi-lahde-linkki { color: var(--accent); }

.stage {
  display: grid;
  min-width: 0;
  grid-template-columns: minmax(0, 1fr) clamp(250px, 26vw, 340px);
  gap: var(--gap);
  padding: var(--gap);
  min-height: 0;
}

.map-pane {
  position: relative;
  min-height: 0;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: #241a12;
  overflow: hidden;
  display: flex;
  /* Myös säiliölle, ei vain SVG:lle: WebKitin touch-action-tuki on
     SVG-elementeillä puutteellinen, ja pelkkä #boardin sääntö jätti
     Safarille raon aloittaa oma sivun zoomaus kartan eleistä (iPadin
     "kartta hyppää" -havainnon toinen puoli). Div-säiliöllä sääntö
     pitää kaikissa moottoreissa. */
  touch-action: none;
}

/*
 * KARTAN SIIRTOKUORI (omistaja 26.8.2026 ilta: *"scrollaus parempi
 * mutta ei taysin sujuva"* — wrapper-siirto).
 *
 * Kuori on paneelin kokoinen kehys SVG:n ympärillä, ja SE liikkuu
 * panoroitaessa ja nipistettäessä — ei SVG-juuri (js/kartta.js
 * asetaPan, paivitaNipistys, ajaKamera). Syy on mitattu: muunnos
 * svg-juuressa likaa laudan asettelun kerran kehyksessä, tavallisen
 * divin muunnos ei koske asetteluun lainkaan.
 *
 * Kuori on itse flex-säiliö, jotta SVG:n oma asemointi säilyy
 * täsmälleen ennallaan: lähikuvassa se on paneelia isompi ja
 * `align-self: flex-start`, aloituskartalla `center` (js/kartta.js
 * sovitaAloitusZoom / sovitaMannerZoom kirjoittavat inline-mitat
 * yhä SVG:hen). Kuori ei leikkaa mitään — leikkaus on .map-panen
 * `overflow: hidden`, ja juuri siksi kuori saa liikkua vapaasti.
 *
 * Origo vasempaan yläkulmaan: nipistyksen muunnoslaskenta
 * (js/kartta.js paivitaNipistys) olettaa sen, ja nyt oletus pitää
 * paikkansa tarkalleen — kuoren kulma ON paneelin kulma.
 */
.kartta-kuori {
  flex: 1 1 auto;
  align-self: stretch;
  min-width: 0;
  min-height: 0;
  width: 100%;
  height: 100%;
  display: flex;
  transform-origin: 0 0;
  touch-action: none;
  /*
   * KARTTAAN ANKKUROIDUT KAPPALEET (#98/#100). Kuoressa asuu SVG:n
   * lisäksi noppa (.die-layer): se on DOM-kappale, jota SVG ei voi
   * piirtää (CSS-3D-kuutio), mutta joka silti makaa kartan päällä.
   * Ankkurointi ei maksa mitään laskentaa — kuoren oma muunnos
   * (js/kartta.js asetaPan, paivitaNipistys) siirtää ja skaalaa
   * lapsensa siinä missä kartankin, joten panoroinnin kehysbudjettiin
   * ei tule yhtään uutta riviä. `position: relative` on tässä juuri
   * sitä varten: absoluuttisesti asemoitu lapsi laskee paikkansa
   * KUOREN kulmasta, ja kuoren kulma on paneelin kulma (ks. yllä).
   */
  position: relative;
}

#board {
  width: 100%;
  height: 100%;
  display: block;
  /* Kartta on staattinen: koko lauta näkyy kerralla ilman zoomausta. */
  touch-action: manipulation;
  /* Nipistys voi alkaa myös kokonäkymästä, ja sen muunnoslaskenta
     (js/kartta.js paivitaNipistys) olettaa origon vasempaan yläkulmaan.
     Oletusorigo (50 % 50 %) veisi eleen ankkurin keskelle ja kartta
     karkaisi sormien alta heti ensimmäisellä liikkeellä. Muunnos
     kirjoitetaan nykyään kuoreen, mutta origo jää tähän varmuuden
     vuoksi: sääntö on halpa eikä saa kadota kuoren mukana. */
  transform-origin: 0 0;
}

/*
 * ============ ULOIN ZOOMI: KOKO LAUTA KERRAN ========================
 *
 * Omistaja 2.9.2026: kartan pitää mahtua vaakaruudulle kokonaan, eikä
 * se saa silloin näkyä kahdesti — sivuille jää mieluummin samaa
 * vaaleaa paperia kuin ylä- ja alapuolelle. Kytkin on
 * js/kartta.js paivitaLaudanKierto, joka kirjoittaa luokan SVG:n
 * juureen heti kun näkymä on lautaa leveämpi.
 *
 *   1. Kierron <use>-kopio pois: lauta piirtyy kerran.
 *   2. Laudan juuriryhmä leikataan arkin levyiseksi. Se on tarpeen
 *      kopion lisäksi siksi, että napautettavat merkit on monistettu
 *      oikeina elementteinä laudan leveyden päähän (js/ui.js
 *      kiertoKohdat) — ilman leikkausta ne kelluisivat paperilla.
 *   3. Laudan ulkopuolinen pergamentti esiin (js/mapart.js
 *      drawPaperUlkopuoli). Se on juuriryhmän ULKOPUOLELLA, joten
 *      leikkaus ei koske siihen.
 */
.paperi-ulkopuoli { display: none; }

#board.lauta-kokonaan .paperi-ulkopuoli { display: block; }
#board.lauta-kokonaan .lauta-kierto { display: none; }
#board.lauta-kokonaan .board-root { clip-path: url(#lauta-rajaus); }

/*
 * Aloituskartan lähikuva puhelimella: kartta on paneelia leveämpi ja sitä
 * selataan sivusuunnassa. Siirto tehdään transformilla, jolloin selain
 * käyttää valmista rasteria eikä piirrä karttaa uudelleen joka kehyksellä.
 * Mitat asettaa js/ui.js sovitaAloitusZoom.
 */
/* Lähikuvassa kartta ei aina peitä paneelia kokonaan (liu'un alussa se
   on vasta kasvamassa). Paneelin oma tumma tausta paistoi tällöin
   reunoilta; sama pergamentin väriliuku kuin kartalla peittää sen. */
/*
 * Sama pergamentti myös AVAUSNÄKYMÄSSÄ ilman zoomia (omistajan havainto
 * 16.8.2026 iPadilla). Maailmankartta on leveä ja säilyttää
 * kuvasuhteensa, joten korkealla ruudulla sen alapuolelle jää paneelia,
 * jota kartta ei peitä — ja juuri siihen tilaan avausteksti kirjoittuu.
 * Ilman tätä teksti oli tummalla pohjalla keskellä tyhjää.
 */
body.aloitus-zoom .map-pane,
body.manner-zoom .map-pane,
body.aloitusnakyma .map-pane {
  background: radial-gradient(circle at 50% 46%, #f6e7c6 0%, #ecd8ae 55%, #cfae79 100%);
}

/* Liu'un ajaksi kartan reunahäivytys pois (omistajan havainto): se
   piirtyi kasvavan kartan ulkopuolelle ja näkyi tummina kaarina.
   Etusivun lähikuvassa se ei enää palaa lainkaan: siellä reunan hoitaa
   kiikari (omistajan päätös). Sama 700 ms kuin kiikarin esiintulossa,
   jolloin efektit sulavat toisikseen eikä kumpikaan pompahda.

   Mantereen lähikuvassa häivytys jää pois joka sivulta (omistajan
   toive). Kokonäkymässä se rajaa laudan kuin vanhan filmin ruudun,
   mutta lähikuvassa kartta jatkuu joka suuntaan panoroitavaksi — silloin
   vaalea reuna ei rajaa mitään, se vain haalistaa sen osan karttaa,
   jota ollaan katsomassa. Kokonäkymässä häivytys palaa itsestään, kun
   luokka poistuu. */

/*
 * Selain ei saa napata eleitä omaan käyttöönsä — ei vaakavetoa eikä
 * nipistystä. Tämä koskee myös kokonäkymää, koska nipistys ALKAA
 * sieltä. iOS:llä tämä ei yksin riitä: siellä sivun oma zoom estetään
 * vasta kosketustapahtumien preventDefaultilla (js/ui.js).
 */
#board { touch-action: none; }

body.aloitus-zoom #board,
body.manner-zoom #board {
  touch-action: none;
  /* Raahaus ei saa maalata kartan tekstejä valituiksi. */
  user-select: none;
  -webkit-user-select: none;
  /* Siirto ja zoomausliuku lasketaan elementin vasemmasta yläkulmasta
     (js/kartta.js asetaPan), joten origo ei saa olla keskellä. */
  transform-origin: 0 0;
}

/*
 * OMA KERROS KUORELLE, EI SVG:LLE (wrapper-siirto 26.8.2026).
 *
 * will-change oli ennen #boardilla, jolloin selain nosti SVG-juuren
 * omalle kerrokselleen — ja juuri siihen juureen kirjoitettiin myös
 * siirto, jonka asettelunlikaus oli jäljelle jäänyt nykimisen syy.
 * Nyt lippu on sillä elementillä, joka oikeasti liikkuu; SVG saa
 * pysyä paikallaan kuoren sisällä.
 */
body.aloitus-zoom .kartta-kuori,
body.manner-zoom .kartta-kuori {
  will-change: transform;
}

/*
 * Lähikuvassa matkakirjan ja toimintojen teksti osuu väkisin kartan
 * päälle. Tekstin alle tulee pehmeä vaalennus (omistajan toive): ei
 * laatikkoa vaan reunoiltaan häivähtävä pergamenttivalo, joka nostaa
 * kirjaimet esiin ilman että kartta katoaa.
 */
body.manner-zoom .fact-card,
body.pallolauta-paalla .fact-card { isolation: isolate; }

/*
 * Toimintonappien alta vaalennus on poistettu (omistajan toive): se
 * haalisti kartan alalaidan, ja siellä juuri on eniten katsottavaa.
 * Napeilla on oma pergamenttilevynsä ja tilarivillä sama vaalea
 * tekstivarjo kuin kartan omissa nimissä, joten kumpikin pysyy
 * luettavana ilman erillistä valoa. (Rivin entinen otsikkoteksti
 * "Valitse matkustustapa." poistettiin 12.8.2026.)
 *
 * Päiväkirjakortti pitää omansa: siinä on pitkä leipäteksti, joka ei
 * mahtuisi luettavaksi pelkän varjon turvin.
 */
/* Sama paperi pallolaudalla (body.pallolauta-paalla, js/pallolauta/lauta.js). */
body.manner-zoom .fact-card::before,
body.pallolauta-paalla .fact-card::before {
  content: '';
  position: absolute;
  /* Reilu ylitys joka suuntaan, jotta häivytys ehtii sulaa karttaan
     eikä jätä suoraa reunaa. */
  inset: -46% -22%;
  z-index: -1;
  pointer-events: none;
  background: radial-gradient(
    ellipse at 50% 50%,
    rgba(247, 238, 214, 0.9) 0 30%,
    rgba(247, 238, 214, 0.62) 46%,
    rgba(247, 238, 214, 0.28) 62%,
    rgba(247, 238, 214, 0) 78%);
}

/*
 * Mantereelle saavuttaessa matkakirja ja toimintonapit odottavat, että
 * zoomaus on ohi (omistajan toive). Näin pelaaja näkee ensin mantereen
 * kokonaan ja vasta sitten kortit. Häivytys on sama kuin kiikarilla,
 * jotta ne tulevat esiin samaan tahtiin.
 */
body[data-mode] .rail { transition: opacity 700ms ease; }

body.manner-odottaa .rail {
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms ease;
}

/* Raahauksen ajaksi kartan sykähdykset vaikenevat (omistajan toive):
   liikkuva kartta on jo tarpeeksi työtä ruudunpäivitykselle.

   TÄMÄ EI OLE VAIN KAUNEUTTA VAAN PANOROINNIN SUJUVUUS (mitattu
   26.8.2026, Chromium + CDP-invalidointijäljitys): SVG-lapsen
   CSS-transform-animaatio EI ole kompositorin työtä, vaan jokainen
   animaatiokehys likaa KOKO laudan asettelun ("Style changed" →
   LayoutInvalidation joka kehyksellä). Likainen asettelu taas pakottaa
   jokaisen siirtokäsittelijän asettelunluvun (clientWidth ym.)
   laskemaan ison laudan asettelun synkronisesti — fokuslaatta-syke
   yksin tuotti 178 pakotettua asettelua 180 kehyksen panoroinnissa,
   vaimennettuna 8. Siksi jokainen laudan SVG:n sisällä jatkuvasti
   sykkivä animaatio on oltava tässä listassa; fokuspisteen vastine
   asuu lajinsa vieressä css/fokusvirta.css:ssä.

   PAUSSI EIKÄ POISTO (26.8.2026). Sääntö oli ennen `animation: none`,
   ja se vaimentaa yhtä hyvin — mutta se myös NOLLAA muunnoksen:
   puoliksi kasvanut kehä kutistuu takaisin lepomittaansa juuri siinä
   silmänräpäyksessä, kun sormi osuu ruutuun, ja hyppää eleen päätyttyä
   uudestaan jakson alkuun. Kaksi ylimääräistä geometrian muutosta
   eleen molemmissa päissä — eli kaksi asettelun mitätöintiä juuri
   niissä hetkissä, joissa nykäys tuntuu — ja päälle näkyvä nytkähdys.
   `animation-play-state: paused` jäädyttää kehän siihen mittaan, jossa
   se oli, ja päästää sen jatkamaan samasta kohdasta.

   Mitattu (Chromium, iPad-ikkuna 834×1112, 2 s lepoa Kreikan
   fokusnäkymässä): vaimentamattomana 120 asettelua ja 120
   tyylinlaskentaa, `animation: none` 1 ja 1, `paused` 1 ja 1 — eli
   vaimennusteho on sama, ja ero on pelkkää voittoa. */
body.kartta-raahaus .target-ring,
body.kartta-raahaus .target-halo,
body.kartta-raahaus .fokuslaatta-syke { animation-play-state: paused; }

/* ELÄVÄ KARTTASISÄLTÖ EI VÄISTY ELEEN AJAKSI (omistaja 1.9.2026 ilta,
   sanatarkasti: *"kaikki elementit pitää pysyä päällä kun karttaa
   liikutetaan tai zoomataan vaikka niitä ei olisi poltettu."*).

   Tässä oli luokkapari `kartta-merkit-haipyy` / `kartta-merkit-piilossa`,
   joka häivytti nimikerroksen ja otti merkkikerrokset `display: none`
   -tyylillä pois maalikierroksesta eleen ajaksi, sekä nimikerroksen
   oma opacity-siirtymä ja sen liikeherkkyyspoikkeus. Koko mekanismi on
   purettu — perustelu, mitatut luvut ennen ja jälkeen sekä se, mitä
   purku maksaa (ruutuavaruudessa ladotun nimikerroksen napsahdus eleen
   lopussa), ovat js/kartta.js asennaPanorointi -metodin ensimmäisessä
   lohkossa.

   MAATUMMENNUS ei väistynyt kummassakaan eleessä jo ennen tätä
   (omistaja 1.9.2026 aamu ja ilta); nyt sama sääntö koskee kaikkea
   muutakin elävää kerrosta. */

/* NYKYISEN MAAN VAHVISTETTU ÄÄRIVIIVA (js/maatummennus.js).

   TUMMENNUS ON POISTETTU (omistaja 2.9.2026: *"Tummennuksen voisi
   ottaa pois myös normaalista pelitilasta. Jätetään pelkkä vahvistettu
   kartan ääriviiva jäljelle."* ja *"kehittäjätilassa ota pois se
   tummennusvalinta ja pidä pelkkä kartan ääriviivojen tummennus aina
   päällä"*). Kerroksessa on enää maan raja viivana; naapurimaiden
   varjopolku, sen sävy ja kehittäjän kytkin on purettu. Alkuperäinen
   tilaus (31.8.2026: *"ympäröivät valtiot voisi tummentaa hieman...
   ja maan ääriviivat piirtää hieman paksummalla"*) elää siis enää
   jälkimmäisessä puoliskossaan.

   KATOAMISTA EI OLE (1.9.2026 ilta): kerros ei väisty eleen ajaksi
   kummassakaan eleessä, joten sillä ei ole eleen jälkeistä paluutakaan.
   Ks. yllä oleva lohko ja js/kartta.js asennaPanorointi.

   FEIDAUS ON SIINÄ HETKESSÄ, JOSSA VIIVA SYNTYY: maa vaihtuu tai
   näkyvyysehto aukeaa, ja js/maatummennus.js `piirra` käynnistää tämän
   animaation uudelleen (`animation: none` -> pakotettu tyylin luku ->
   takaisin). Animaatio on yhä ANIMAATIO EIKÄ SIIRTYMÄ, koska se on
   ainoa, joka voidaan käynnistää alusta ilman lähtöarvoa — siirtymä
   tarvitsisi kaksi kehystä ja rivin ajastuskoodia.

   === FEIDAUS ON PERITTY fill/stroke-opacity, EI RYHMÄN opacity —
       JA SE ON PORTAIKKO ===========================================

   Kaksi valintaa, molemmat mittaustuloksia varjollisella kerroksella
   (tools/savukkeet/savuke-maailmanakyma.mjs, kehittäjän maailmanäkymä,
   Chromium 390x844 dpr3, kuusi pyyhkäisyä + neljä nipistystä, kolme
   ajoa). Luvut jäävät tähän, koska ne perustelevat yhä nykyiset
   valinnat — ja kerros on nyt kevyempi kuin mikään mitattu variantti:

     variantti                        panoroinnin lt   nipistyksen lt
     ei maatummennusta (lähtötaso)     0 / 0 / 287 ms  382 / 403 / 397
     ryhmän `opacity`, portaaton      429 / 702 ms     933 / 1202 ms
     peritty fill-opacity, portaaton    0 / 0 / 0 ms   520 / 435 / 786
     peritty fill-opacity, steps(7)     0 / 0 / 0 ms   388 / 429 / 475

   1. RYHMÄN `opacity` EI KELPAA, ja syy on tämän lohkon alussa:
      peittävyys väliltä 0–1 pakottaa selaimen tekemään ryhmästä oman
      läpinäkyvyystasonsa. `fill-opacity` ja `stroke-opacity` eivät tee
      tasoa lainkaan — ja koska ne PERIYTYVÄT, animaatio voi silti olla
      ryhmässä. Sen on oltavakin: `display` vaihtuu ryhmässä, ja
      animaatio käynnistyy alusta vain siinä elementissä, jonka oma
      display muuttuu (lapsipolkujen omat animaatiot eivät käynnisty
      uudelleen — mitattu, ei arvattu).

   2. PORTAIKKO (steps) leikkaa maalikerrat. Portaaton feidaus maalasi
      varjon parikymmentä kertaa 350 ms:ssä; seitsemän porrasta maalaa
      sen seitsemästi. Ero näkyi luvuissa muttei ruudulla, ja pelkällä
      viivalla ero on entistäkin pienempi — portaikko jää, koska se on
      mitattu halvemmaksi eikä maksa mitään. */
.maatummennus { animation: maatummennus-esiin 350ms steps(7, end); }
@keyframes maatummennus-esiin {
  from { fill-opacity: 0; stroke-opacity: 0; }
  to { fill-opacity: 1; stroke-opacity: 1; }
}
/* Ääriviiva on kartan omaa mustetta ja KARTTAVAKIO: non-scaling-stroke
   pitää sen samana ruutupikselimääränä zoomista riippumatta, kuten
   laattoihin poltettu rantaviiva. Leveys tulee elementiltä, jotta luku
   ja sen perustelu ovat yhdessä paikassa js/maatummennus.js:ssä.

   SÄVY ON HIMMEÄ MUSTE EIKÄ TÄYSI --map-ink, ja alfa on värissä eikä
   `stroke-opacity`-ominaisuudessa. Reunus on 1.9.2026 alkaen kaksi
   ruutupikseliä 60 %:n musteella (*"paksunna maan rajaa myös
   hieman"*), jolloin se lukee korostuksena mutta ei rajapyykkinä —
   leveys ja sen perustelu js/maatummennus.js TUMMENNUS_VIIVA. Omaa
   `stroke-opacity`-arvoa EI saa antaa: se katkaisisi perinnän
   ryhmästä, ja juuri perittyä stroke-opacityä yllä oleva
   portaikkofeidaus animoi (ks. mittaustaulukko). Värin alfa kertautuu
   feidauksen kanssa. */
.maatummennus-viiva {
  fill: none;
  stroke: rgba(70, 51, 31, 0.6);
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

@media (prefers-reduced-motion: reduce) {
  /* Liikeherkkyys: viiva ilmestyy kerralla, ei feidaten. */
  .maatummennus { animation: none; }
}

/* NÄKYMÄN ULKOPUOLISET MERKIT POIS (js/ui.js paivitaMaailmanRajaus —
   koko perustelu ja mittausluvut siellä).

   Eleen ajan piilotus (yllä) kattaa vain ne kerrokset, jotka ovat
   kymmeniä solmuja. Kehittäjän maailmanäkymässä kartalla on lisäksi
   KOKO laudan kaupunkikerros — 602 näkyvää solmua — ja sen kaikki
   ryhmittely maalipaloihin tehdään joka kehyksellä riippumatta siitä,
   osuuko solmu ruudulle. Rajaus jättää kierrokseen vain ne, jotka
   ovat ruudulla tai ruudullisen päässä siitä.

   PIILOTUS ON LUOKKA, EI SUODATIN (sama iOS-sääntö kuin muillakin
   kartan kerroksilla, tests/rules.test.mjs), ja se lasketaan vain
   näkymän asettuessa — ei kehyksessä eikä pointermovessa. */
.fokus-ikkunan-ulkona { display: none; }

/*
 * Vanhan kiikarin vääristymä (omistajan toive): maailmankartan
 * lähikuvassa ruudun reunat sumenevat, saavat vihertävän linssin sävyn
 * ja ohuen värikehän — halvan linssin kromaattinen aberraatio.
 *
 * Kolme kerrosta samasta elementistä:
 *   .kiikari         sumennus + vihreä sävy
 *   .kiikari::before  lämmin (punainen) kehä uloimpana
 *   .kiikari::after   kylmä (syaani) kehä hieman sisempänä
 * Aito linssi taittaa pitkät ja lyhyet aallonpituudet eri kohtaan, ja
 * juuri se näkyy kuvakentän laidalla värillisenä reunuksena.
 *
 * Sumennus alkaa syvemmältä kuin vihreä sävy (omistajan toive:
 * epätarkkuus nykyisellä paikallaan, väri enemmän reunoille). Siksi
 * maski ja taustaväri eivät jaa samoja rajoja.
 *
 * Kerros asuu z-tasolla 2: kartan päällä mutta nopan (3), avaustekstin
 * (3) ja alarivin korttien (4) alla. Se nousee esiin vasta kun zoomaus
 * on valmis (js/ui.js lisää kiikari-paalla), ja katoaa raahauksen
 * ajaksi — sumennus liikkuvan kartan päällä on puhelimelle liikaa.
 */
.kiikari {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 700ms ease, visibility 0s linear 700ms;
}

body.aloitus-zoom.kiikari-paalla .kiikari {
  opacity: 1;
  visibility: visible;
  transition: opacity 700ms ease, visibility 0s;
}

/* Sama tarkkuus kuin esiin nostavassa säännössä, muuten raahaus ei
   voittaisi sitä. */
body.aloitus-zoom.kiikari-paalla.kartta-raahaus .kiikari {
  opacity: 0;
  transition: opacity 110ms ease;
}

.kiikari,
.kiikari::before,
.kiikari::after {
  -webkit-mask-image: radial-gradient(
    ellipse 84% 75% at 50% 50%,
    rgba(0, 0, 0, 0) 42%,
    rgba(0, 0, 0, 1) 74%
  );
  mask-image: radial-gradient(
    ellipse 84% 75% at 50% 50%,
    rgba(0, 0, 0, 0) 42%,
    rgba(0, 0, 0, 1) 74%
  );
}

body.aloitus-zoom .kiikari {
  -webkit-backdrop-filter: blur(7px) saturate(0.8);
  backdrop-filter: blur(7px) saturate(0.8);
  /* Vihreä alkaa vasta 66 %:n kohdalla — kartan päälle sitä tulee
     selvästi vähemmän kuin sumennusta. */
  background: radial-gradient(
    ellipse 84% 75% at 50% 50%,
    rgba(84, 128, 92, 0) 62%,
    rgba(64, 112, 76, 0.36) 78%,
    rgba(26, 60, 38, 0.7) 89%
  );
}

.kiikari::before,
.kiikari::after {
  content: '';
  position: absolute;
  inset: 0;
  /* Multiply, ei screen: kartta on vaalea pergamentti, jolloin
     kirkastava sekoitus vain pesee värin pois. Kertova sekoitus
     päästää läpi sen värin, jonka kehä edustaa, ja vaimentaa muut —
     juuri niin kuin linssin taittovirhe näkyy vaaleaa taustaa
     vasten. */
  mix-blend-mode: multiply;
}

/* Lämmin kehä uloimpana: pitkät aallonpituudet taittuvat vähemmän. */
.kiikari::before {
  background: radial-gradient(
    ellipse 84% 75% at 50% 50%,
    rgba(255, 126, 90, 0) 74%,
    rgba(255, 126, 90, 0.22) 90%,
    rgba(255, 126, 90, 0.22) 100%
  );
}

/* Kylmä kehä sisempänä: lyhyet aallonpituudet taittuvat enemmän. */
.kiikari::after {
  background: radial-gradient(
    ellipse 84% 75% at 50% 50%,
    rgba(120, 200, 255, 0) 60%,
    rgba(120, 200, 255, 0.13) 76%,
    rgba(120, 200, 255, 0) 90%
  );
}

/* Vanhan filmin vaalea vinjetti: kartan reunat haalistuvat kuin
   ikääntyneessä filmiruudussa. Piirretään ruudun päälle, joten se
   myötäilee aina näkyvää aluetta laudan rajauksesta riippumatta.

   Alareunasta vinjetti on poistettu (omistajan toive). Siellä se ei
   näyttänyt filmiltä vaan haalistumalta: alalaidassa on eniten
   kaupunkeja ja nimiä, ja kelluvat napit istuvat juuri sen päällä.

   Poisto tehdään kolmella reunaliu'ulla eikä yhdellä soikiolla. Soikio
   haalisti väistämättä myös alalaidan, ja kun se yritettiin peittää
   mask-imagella, tulos näytti oikealta Chromiumissa mutta alalaita jäi
   silti vaaleaksi iPhonella (omistajan havainto: "vinjetti ei lähtenyt
   pois"). Reunakohtaiset liu'ut eivät piirrä alalaitaan mitään eivätkä
   tarvitse maskia toimiakseen, joten tulos on sama joka selaimessa.
   Kulmat saavat kahden liu'un summan ja pysyvät tummimpina kuten
   ennenkin. */
/* Reunahäivytys on poistettu (omistajan päätös 2.8.2026: "voit ottaa
   vinjetoinnin vaaleampaan pois kaikkialta nyt kun kartta on
   liikuteltava" — ja kaikilla laitteilla).

   Se rajasi lautaa kuin vanhan filmin ruudun silloin, kun kartta oli
   kiinteä kokonäkymä. Nyt karttaa panoroidaan ja zoomataan joka
   laudalla, joten reuna ei rajaa mitään: se vain haalistaa sitä osaa
   karttaa, jota ollaan katsomassa. Aiemmin häivytys sammutettiin
   lähikuvassa omalla luokkasäännöllä; kun kaikki on lähikuvaa, sääntöä
   ei tarvita lainkaan. */
.map-pane::after { content: none; }

/*
 * Zoomipainikkeet kartan oikeassa reunassa (omistajan toive: sama
 * zoomaus joka alustalle, ei pelkkiä sormieleitä).
 *
 * Pystyssä oikeassa reunassa, keskikorkeudella. Alalaita on
 * matkustusnappien ja päiväkirjan käytössä, ylälaidassa on kortti —
 * oikea reuna on ainoa kohta, joka on vapaa kaikissa vaiheissa.
 *
 * Pergamentin väreissä kuten kartan muutkin merkinnät, jotta napit
 * kuuluvat karttaan eivätkä leiju sen päällä käyttöliittymänä.
 */
/*
 * Maiden lehdet -nappi kartan oikeaan ylälaitaan.
 *
 * Sama pyöreä pergamenttinappi kuin zoomissa, mutta oma elementtinsä:
 * zoomiryhmä katoaa kosketuslaitteilta, ja tämän on näyttävä kaikilla.
 * Painettuna se on tumma, jotta kartan tila näkyy napista itsestään.
 */
.maalehti-nappi {
  position: absolute;
  /* Vasempaan reunaan (omistaja 14.8.2026): oikea yläkulma kuuluu
     maapillerille, joka näkyy maaselaimessakin. */
  left: 0.5rem;
  top: 0.6rem;
  z-index: 3;
  width: 2.15rem;
  height: 2.15rem;
  min-width: 40px;
  min-height: 40px;
  display: grid;
  place-items: center;
  /*
   * Pehmuste nollaan (omistajan havainto 13.8.2026: "kuvake sivussa
   * ympyrään nähden"). Nappien yleissääntö antaa 0.5rem/0.8rem
   * pehmusteen, jolloin 20 px:n kuvake ei mahdu 40 px:n ympyrän
   * sisältöalueeseen ja gridin keskitys vääntyy sivuun — pyöreässä
   * kuvakenapissa keskitys hoituu gridillä, ei pehmusteella.
   */
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: rgba(239, 220, 180, 0.9);
  color: var(--map-ink);
  cursor: pointer;
}

/*
 * Inline-svg elää tekstirivillä ja tuo baseline-tyhjän alleen, mikä
 * työnsi kuvaketta ylös vasempaan (omistajan havainto 10.8.2026 ilta:
 * "napin ikoni on oudosti keskitetty") — block antaa gridin keskittää.
 */
.maalehti-nappi svg { display: block; }

.maalehti-nappi[hidden] { display: none; }

.maalehti-nappi:hover { background: rgba(245, 231, 200, 0.95); }

.maalehti-nappi[aria-pressed='true'] {
  background: var(--map-ink);
  color: rgba(245, 231, 200, 0.95);
}

/*
 * KARTAN +/- -PAINIKKEET (.zoomi, .zoomi-nappi) on POISTETTU
 * 27.8.2026 (omistajan tilaus). Kosketuslaitteilta ne oli piilotettu
 * jo ennestään mediaehdolla, koska siellä zoomataan nipistämällä; nyt
 * myös työpöydällä on eleet: trackpadin nipistys zoomaa portaattomasti,
 * hiiren rullan naksu portain ja kahden sormen vieritys panoroi
 * (js/kartta.js, TRACKPADIN ELEET). Napit vain peittivät karttaa.
 */

/*
 * Kartan oma ohjerivi (.board-hint) ja vuorolaatikon tilarivi
 * (.turn-status) on poistettu 13.8.2026 (omistaja: *"kartan päälle ei
 * tule enää mitään ohjetekstiä"*). Molemmat kelluivat kartan päällä.
 * Kehotus tulee kartalta itseltään: valittavat kohteet korostuvat
 * renkailla (.target-ring), ja pitkän hiljaisuuden jälkeen pöllö
 * vinkkaa omassa kuplassaan (.pollo-vihje).
 */

/* --- laudalla lepäävä 3D-noppa --- */

/*
 * Nopan kerros on KARTAN SIIRTOKUORESSA (.kartta-kuori, #98) eikä
 * karttaruudussa: se panoroituu ja nipistyy kartan mukana ilman
 * omaa laskentaa. `inset: 0` on siis kuoren laatikko eli paneelin
 * kokoinen; lähikuvassa noppa voi jäädä sen ulkopuolelle, ja se on
 * oikein — leikkauksen hoitaa .map-panen overflow.
 *
 * --die-skaala on kartan mittakaava suhteessa siihen hetkeen, jolloin
 * noppa heitettiin (js/kartta.js ankkuroiNoppa). Perusmitta on
 * ennallaan; vain kerroin on uusi, joten lähennettäessä noppa kasvaa
 * kartan mukana kuten laudalla makaava kappale kasvaisi.
 */
.die-layer {
  --die-perus: clamp(32px, 5.4vmin, 56px);
  --die-skaala: 1;
  --die-size: calc(var(--die-perus) * var(--die-skaala));
  --half: calc(var(--die-size) / 2);
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 3;
  transition: opacity 0.42s ease;
}

/* Uuteen kaupunkiin saavuttaessa noppa katoaa (js/die.js haivyta). */
.die-layer.noppa-haipyy { opacity: 0; }

.board-die {
  position: absolute;
  left: 0;
  top: 0;
  width: var(--die-size);
  height: var(--die-size);
  perspective: 900px;
}

/*
 * WILL-CHANGE VAIN HEITON AJAKSI (omistajan pelitesti 27.8.2026,
 * iPhone: *"kartat eivät näy taustalla kun pelinappula hyppii"*).
 *
 * MIKÄ MENI RIKKI. #98 siirsi nopan kartan SIIRTOKUOREEN
 * (.kartta-kuori), jotta panorointi kuljettaisi sen ilmaiseksi. Kuoren
 * sisällä on kuitenkin myös koko kartan SVG, ja noppa makaa sen PÄÄLLÄ
 * (z-index: 3). Pysyvä `will-change: transform` pitää nopan omalla
 * kompositorikerroksellaan aina — myös levossa, eli koko sen ajan kun
 * heitetty noppa odottaa laudalla nappulan matkan yli. Kun päällä
 * lepää pysyvä kerros, WebKitin on nostettava sen ALLA oleva sisältö
 * omaan kerrokseensa säilyttääkseen piirtojärjestyksen — ja se sisältö
 * on lähikuvassa moninkertainen ruutuun nähden. iPhonen
 * kerrospuskurikatto tulee vastaan, kerros jää varaamatta ja kartta
 * piirtyy TYHJÄNÄ. Sama iOS:n vika kuin suodattimilla (tests/
 * rules.test.mjs "kartan isot kerrokset eivät käytä suodatinta"), vain
 * eri reittiä: siellä puskurin varaa suodatin, täällä will-change.
 *
 * KORJAUS ON AJOITUS, EI RAKENNE. Vihje on voimassa vain sen sekunnin,
 * jonka noppa oikeasti pyörii ja pomppii (js/die.js lisää ja poistaa
 * .noppa-vierii), ja juuri silloin se on myös hyödyllinen. Levossa
 * makaava noppa on tavallinen elementti, eikä kartan alle jää mitään
 * nostettavaa. Noppa pysyy kuoressa, joten #98:n panorointietu säilyy.
 */
.board-die.noppa-vierii { will-change: transform; }

/*
 * Varjo jää laudan pintaan, kun noppa nousee ilmaan. Tavallinen pehmeä
 * varjo (omistajan valinta): liukuvärjäys on jo itsessään pehmeä, joten
 * blur-suodinta ei tarvita — se maksaisi joka kehyksellä.
 */
.die-shadow {
  position: absolute;
  left: 0;
  top: 0;
  width: calc(var(--die-size) * 1.3);
  height: calc(var(--die-size) * 0.58);
  /* Varjo kurkistaa nopan alareunan alta: muuten kuutio peittää sen
   * kokonaan ja noppa näyttää kelluvan laudan yllä. */
  margin-top: calc(var(--die-size) * 0.32);
  border-radius: 50%;
  background: radial-gradient(ellipse at 46% 42%, rgba(44, 27, 10, 0.8) 0 16%, rgba(44, 27, 10, 0) 74%);
  opacity: 0.44;
  will-change: transform, opacity;
}

.die-cube {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  -webkit-transform-style: preserve-3d;
}

/*
 * Vanha luunoppa, ei kiillotettu muovinen (omistajan huomio): kulunut
 * norsunluun sävy paperirakeella, kynämäinen ääriviiva ja käsin painetut
 * musteiset silmät. Kiiltokerroksen tilalla on tummuva patina.
 */
.die-face {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  padding: 12%;
  gap: 4%;
  /* Maltillinen pyöristys: isompi pyöristys jätti kuution kulmiin raot,
   * joista tausta vilkkui läpi (omistajan havainto). */
  border-radius: 9%;
  /* Vaaleampi luu ja tummempi mustereuna, jotta tahko irtoaa
   * pergamentista eikä sävy paina tummaksi. */
  background-image:
    var(--paper-noise),
    radial-gradient(circle at 36% 30%, #f9f1da 0%, #efe0bd 55%, #ddc9a2 100%);
  background-blend-mode: multiply, normal;
  border: 1.8px solid rgba(46, 32, 17, 0.92);
  box-shadow: inset -2px -3px 6px rgba(108, 76, 34, 0.22);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* Sivutahkot ovat aavistuksen tummempia, jolloin kuutio saa syvyyttä. */
.die-face.face-3, .die-face.face-4 { filter: brightness(0.96); }
.die-face.face-5, .die-face.face-6 { filter: brightness(0.9); }

.die-face .pip {
  align-self: center;
  justify-self: center;
  width: 70%;
  aspect-ratio: 1;
  /* Hieman epäpyöreä ja kallellaan — kuin musteella painettu. */
  border-radius: 52% 48% 50% 55% / 48% 55% 45% 52%;
  background: radial-gradient(circle at 44% 38%, #5a4023 0%, #46331f 58%, #362610 100%);
  transform: rotate(7deg);
}

.die-face span:nth-child(2n) .pip,
.die-face span:nth-child(2n).pip { transform: rotate(-11deg) scale(0.96); }
.die-face span:nth-child(5n).pip { transform: rotate(19deg) scale(1.04); }

/* Valo tulee aina samasta suunnasta: patina ei pyöri nopan mukana. */
.die-gloss {
  position: absolute;
  inset: -6%;
  border-radius: 24%;
  pointer-events: none;
  background:
    radial-gradient(circle at 30% 24%, rgba(252, 244, 222, 0.22), rgba(255, 255, 255, 0) 42%),
    radial-gradient(circle at 76% 84%, rgba(44, 27, 10, 0.2), rgba(0, 0, 0, 0) 56%);
  mix-blend-mode: soft-light;
}

/* --- tapahtumaikkuna kartan päällä --- */

.event-toast {
  position: absolute;
  left: 50%;
  top: 16%;
  transform: translate(-50%, 0);
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.7rem 1.1rem;
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(46, 33, 20, 0.96), rgba(30, 21, 12, 0.96));
  border: 1px solid var(--accent);
  box-shadow: 0 14px 40px rgba(0, 0, 0, 0.45);
  color: var(--ink-light);
  font-size: 1.05rem;
  font-weight: 600;
  pointer-events: none;
  max-width: 80%;
  text-align: left;
  animation: toast-in 0.28s cubic-bezier(0.2, 1.4, 0.5, 1);
}

.event-toast.leaving { animation: toast-out 0.3s ease-in forwards; }
.event-toast .toast-icon { font-size: 1.6rem; line-height: 1; }
.event-toast .toast-sub { display: block; font-size: 0.85rem; font-weight: 400; color: var(--muted); }
.event-toast.treasure { border-color: #eec66b; }
.event-toast.bad { border-color: #d9705f; }
.event-toast.die { font-size: 1.4rem; }
.event-toast.die .toast-icon { font-size: 2.6rem; color: var(--accent); }

@keyframes toast-in {
  from { opacity: 0; transform: translate(-50%, 18px) scale(0.92); }
  to { opacity: 1; transform: translate(-50%, 0) scale(1); }
}

@keyframes toast-out {
  to { opacity: 0; transform: translate(-50%, -14px) scale(0.97); }
}

@media (prefers-reduced-motion: reduce) {
  .event-toast, .event-toast.leaving { animation: none; }
  .pawn-moving { transition: none; }
  .board-die, .die-cube, .die-shadow, .die-layer { transition: none !important; }
}

.rail {
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr);
  gap: var(--gap);
  min-height: 0;
}

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.6rem 0.7rem;
  min-width: 0;
}

/* --- vuorolaatikko ---
 *
 * Laatikossa on enää napit. Tilarivi (.turn-status), sen rivi
 * (.turn-row) ja vanha tekstinoppa (.die) poistuivat 13.8.2026:
 * kortti kelluu kartan päällä, joten jokainen niiden näyttämä sana oli
 * tekstiä kartan päällä. Silmäluku näkyy laudalle jäävässä nopassa
 * (.die-layer). */

.actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.4rem;
}

/* Toiminnot lepäävät, kun animaatio on käynnissä. */
.actions[data-busy] { opacity: 0.45; pointer-events: none; }

/* Matkustustavan ensimmäinen vaihe: napit aina yhdessä rivissä.
 * body[data-mode]-muoto tarvitaan, jotta rivi voittaa kelluvan asettelun
 * auto-fit-ruudukon myös kapealla ruudulla. */
body[data-mode] .actions[data-rivi='yksi'],
.actions[data-rivi='yksi'] {
  grid-template-columns: none;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
}

button {
  font: inherit;
  padding: 0.5rem 0.8rem;
  min-height: 42px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--ink-light);
  cursor: pointer;
  touch-action: manipulation;
}

button:hover:not(:disabled) { background: #43331f; }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
button:disabled { opacity: 0.45; cursor: not-allowed; }

button.primary {
  background: linear-gradient(180deg, #eab84e, #d09024);
  border-color: var(--accent-dark);
  color: #2c1e07;
  font-weight: 700;
}

button.primary:hover:not(:disabled) { background: linear-gradient(180deg, #f3c661, #d9a13b); }
button.ghost { background: transparent; min-height: 36px; padding: 0.35rem 0.7rem; }

.error {
  margin-top: 0.5rem;
  color: var(--danger);
  font-size: 0.85rem;
}

.muted { color: var(--muted); font-size: 0.88rem; }

/* --- pelaajat --- */

/* Moninpelin pelaajakortit poistettiin — matkaajan tiedot ovat passissa. */

/*
 * Ikoninapit: kartalta viedään mahdollisimman vähän tilaa, joten
 * matkustustavan valinta on ikoni ja lyhyt selite. Kapealla napilla selite
 * piiloutuu ja jäljelle jää pelkkä ikoni — title ja aria-label kertovat
 * merkityksen niille, jotka eivät ikonia tunnista.
 */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.5rem 0.7rem;
}

.icon-glyph { font-size: 1.15rem; line-height: 1; }
.icon-label { white-space: nowrap; }

/*
 * PÖLLÖ YLIVIIVATTUNA, PULU PERÄÄN (omistajan tilaus 27.8.2026).
 *
 * Tietokumppanin nimilapuissa lukee vitsi, jonka hahmo tekee itsestään:
 * Livia on Viisaan Pöllön SIJAINEN, joten koko nimi "Viisas Pöllö" on
 * vedetty yli YHDELLÄ pitkällä vedolla ja perässä lukee erillinen sana
 * "Pulu" (omistajan tarkennus 31.8.2026, muoto on aina tämä — ei pelkkä
 * "Pöllö" eikä sanakohtaisia vetoja). Lappu näyttää käsin korjatulta,
 * ei uusiksi
 * ladotulta — siksi viiva on OHUT ja pelin oma sinettivahan punainen
 * (sama sävy kuin ihmenauhan puna, css/fokuskohteet.css --nauha-pinta-1
 * #a1524a), ei huomioväri.
 *
 * VETO ON KÄSIN PIIRRETTY JA VINO (omistajan tarkennukset 27.8.2026).
 * Vaakasuora `text-decoration: line-through` näyttää ladotulta
 * korjaukselta, ja suora palkki kierrettynäkin näyttää viivaimelta.
 * Siksi selaimen oma koristelu on pois päältä (<s> saisi sen
 * oletuksena) ja veto on INLINE-SVG sanan päällä: kaksi kevyesti
 * kaartuvaa polkua, pyöreät päät, sinettivahan punainen ja hieman
 * läpikuultava, niin että kirjaimet erottuvat vedon alta.
 *
 * SUUNTA ON YLÄOIKEALTA ALAS VASEMMALLE ja veto ULOTTUU YLI TEKSTIN
 * KORKEUDEN: polku alkaa kirjainten yläreunan yläpuolelta oikealta ja
 * päättyy alareunan alapuolelle vasemmalle, kuten nopea kynänveto
 * paperilla. Polut ja niiden mitoitus ovat js/ui-apurit.js:ssä
 * (VEDON_POLUT) — täällä ovat vain väri, paikka ja se, miten veto
 * mahtuu riville.
 *
 * YKSI YHTENÄINEN VETO PER LAPPU. viewBox venytetään koko nimen mittaan
 * (preserveAspectRatio="none"), joten sama polku kattaa sanaparin
 * "Viisas Pöllö" yhtenä vetona; viivanleveys pysyy silti vakiona
 * (vector-effect: non-scaling-stroke). Yliviivattu osa on siksi myös
 * `white-space: nowrap`: jos sanapari katkeaisi kahdelle riville,
 * absoluuttinen veto vetäisi vinon viivan molempien rivien yli.
 *
 * EI LEIKKAUDU EIKÄ KASVATA RIVIÄ. SVG on absoluuttinen, joten se ei
 * ole rivilaatikon mitassa mukana — rivinkorkeus ei muutu. Ylitys ylä-
 * ja alapuolelle on pieni (0,12em kumpaankin suuntaan) ja mahtuu
 * nimilappujen rivinkorkeuden sisään, joten kuplien ja kortin ylärivin
 * overflow ei leikkaa vedon päitä. Ylitystä ei kasvateta ilman, että
 * kuplat katsotaan uudelleen laitteella.
 *
 * Yliviivattu sana on himmeämpi ja korvaava sana jää normaaliin
 * väriin, jotta silmä lukee "Pulu" ensin. Himmennys on sanan omassa
 * kuoressa eikä <s>-solmussa: muuten se himmentäisi myös vedon.
 *
 * SÄVYSÄÄTÖ 28.8.2026 (omistaja: *"pöllön yliviivaus saisi olla vähän
 * himmeämmällä ja pöllö sanan taas hieman vahvemmalla"*). Punainen veto
 * oli niin kylläinen, että se peitti sanan alleen — nyt viiva on
 * himmeämpi (alfa 0,82 → 0,55) ja sana vahvempi (himmennys 0,55 →
 * 0,78). Vitsi säilyy: veto näkyy yhä selvästi, mutta "Pöllö" luetaan
 * sen alta ilman että sitä tarvitsee arvata.
 *
 * <s> on aria-hidden (js/ui-apurit.js polloNimilappu): ruudunlukija
 * kuulee vain korvaavan sanan, eikä yliviivattua sotkua lueta koskaan
 * ääneen.
 *
 * Väri on sama sekä pergamentilla että tummalla paneelilla — se on
 * riittävän tumma vaalealle paperille ja riittävän kylläinen tummalle.
 */
.pollo-yliviivattu {
  position: relative;
  display: inline-block;
  vertical-align: baseline;
  text-decoration: none;
  white-space: nowrap;
}

.pollo-yliviivattu-sana { opacity: 0.78; }

/*
 * MITAT KIRJOITETAAN AUKI, EI JÄTETÄ AUTOLLE. SVG on korvattu elementti
 * (replaced element): pelkkä `inset` ilman leveyttä ja korkeutta jättää
 * sen omaan sisäiseen 300×150-kokoonsa tai kutistaa sanan mittaan, eikä
 * ylitystä synny lainkaan. Siksi laatikko lasketaan sanasta:
 * 0,16em kumpaankin sivuun ja 0,12em ylös ja alas.
 */
.pollo-veto {
  position: absolute;
  left: -0.16em;
  top: -0.12em;
  width: calc(100% + 0.32em);
  height: calc(100% + 0.24em);
  overflow: visible;
  pointer-events: none;
  stroke: rgb(161 82 74 / 0.55);
}

/*
 * SUURENNUSLASIN SYKE UUDESSA KAUPUNGISSA.
 *
 * Omistajan toive 11.8.2026: uuteen kaupunkiin saavuttaessa Tutki-napin
 * pitää kertoa itsestään, jotta pelaaja tajuaa painaa sitä. Syke on
 * hillitty ja pergamentin oma oranssi (--accent), ei huomioväri: kartta
 * on mustetta ja paperia, ja kirkas hehku näyttäisi siinä virheeltä.
 *
 * ITERAATIOITA ON KUUSI, EI `infinite`. Kaksi syytä: sykkivä nappi
 * ruudun laidassa käy hermoille, jos pelaaja jää lukemaan lehteä, ja
 * ikuinen animaatio jää päälle myös silloin kun sen sammuttava
 * napautus jää jostain syystä tulematta. Kuusi sykettä on noin
 * yhdeksän sekuntia — sen ehtii huomata, eikä se jää kiusaamaan.
 * Luokka poistetaan silti napin painalluksesta (js/ui.js).
 */
.icon-btn.tutki-syke {
  animation: tutki-syke 1.5s ease-in-out 6;
}

@keyframes tutki-syke {
  0%, 100% {
    box-shadow: 0 0 0 0 rgba(217, 161, 59, 0);
    border-color: var(--line);
  }
  50% {
    box-shadow: 0 0 10px 2px rgba(217, 161, 59, 0.5);
    border-color: var(--accent);
    color: var(--accent);
  }
}

/*
 * Liikkeen välttäjälle pelkkä värivihje: nappi jää oranssireunaiseksi,
 * joten viesti menee perille ilman sykettä.
 */
@media (prefers-reduced-motion: reduce) {
  .icon-btn.tutki-syke {
    animation: none;
    border-color: var(--accent);
    color: var(--accent);
  }
}

/* Viivaikonit piirretään kartan kynällä: pelkkä ääriviiva tekstivärillä,
 * jotta napit istuvat mustepiirrokseen — emoji erottui siitä irrallisena. */
.viiva-ikoni { display: inline-flex; align-items: center; }
.viiva-ikoni svg {
  width: 1.2em;
  height: 1.2em;
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.viiva-ikoni .taytto { fill: currentColor; stroke: none; }

/*
 * Sama viivakynä irrallisena SVG:nä (js/ui.js viivaIkoniSvg).
 *
 * Matkalaukku piirtää varusteiden kuvakkeet linssimoduulien poluista
 * ilman `.viiva-ikoni`-kuorta, eivätkä yllä olevat säännöt siis osuneet
 * niihin: ilman tätä polut piirtyivät SVG:n oletuksella eli mustana
 * täyttönä ja mustina läiskinä. Viivanleveys on suhteutettu isompaan
 * kokoon — 44 pikselin kuvakkeessa 1,7 näyttäisi tussilta.
 */
.viiva-ikoni-kuva {
  display: block;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.viiva-ikoni-kuva .taytto { fill: currentColor; stroke: none; }

/* Tekstinappi viivaikonilla: ikoni ja teksti samalle riville. */
.ikoni-teksti {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
}

/* Alle 520 px napit kutistuvat pelkiksi ikoneiksi. */
@media (max-width: 520px) {
  .icon-label { display: none; }
  .icon-btn { padding: 0.5rem; }
}

/* Vaiheen B napit ovat rivin levyisiä: nimet ovat pitkiä. */
.actions .wide { grid-column: 1 / -1; }

/*
 * Saapumiskortti: kaupungin matkatarina keskellä ruutua. Kortti on kapeampi
 * kuin säännöt, jotta teksti pysyy luettavan mittaisena rivinä.
 */
/*
 * Saapumiskortti on kevyt: ohut yksinkertainen kehys ilman tuplaraamia,
 * ei tekstiä eikä kultalaattaa — vain paikan nimi ja päätös.
 */
.arrival-card { max-width: 380px; border-width: 1.5px; }

/* Saapumiskortin toinen viiva on erityisen hento: kuin kynä olisi
   käynyt reunan kahdesti, kevyemmin jälkimmäisellä kerralla. */
.arrival-card::before {
  inset: -5px;
  border-width: 1px;
  border-color: rgba(70, 51, 31, 0.22);
  transform: rotate(0.4deg);
}

.arrival-card h2 {
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  letter-spacing: 0.06em;
}

/* Tapahtumakortin teksti (luokka jäi tapahtumille, kun saapumiskortti keveni). */
.arrival-text {
  margin: 0.5rem 0 0.9rem;
  font-size: 0.95rem;
  line-height: 1.5;
  min-height: 4.5em; /* teksti naksuu esiin: kortti ei saa hypähdellä */
}

.arrival-ask {
  margin: 0.2rem 0 1rem;
  font-family: var(--font-type);
  font-size: 0.85rem;
  letter-spacing: 0.05em;
  color: var(--accent-ink, inherit);
}

.arrival-card .dialog-actions button {
  background: none;
  border-width: 1px;
}

.arrival-card .dialog-actions button.primary {
  background: none;
  border: 1.5px solid rgba(176, 138, 60, 0.9);
  color: #7a5514;
}

.arrival-card .dialog-actions button.primary:hover:not(:disabled) {
  background: rgba(234, 184, 78, 0.18);
}

/* Paikan lyhyt esittely saapumiskortissa: pari lausetta tiivistelmästä. */
.arrival-intro {
  margin: 0.2rem 0 0.6rem;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--accent-ink, inherit);
}

/* Wikipedian kuva saapumiskortissa; Lue lisää -linkki on esittelyn alla. */
.arrival-kuvakotelo {
  position: relative;
  margin: 0.15rem auto 0.3rem;
  /* Kotelo kutistuu kuvan levyiseksi, jotta laskuri ja selailunuolet
   * pysyvät kuvan päällä myös silloin kun pystykuva ei täytä palstaa. */
  width: fit-content;
  max-width: 100%;
}

/*
 * Kuvat omissa mittasuhteissaan (omistajan toive: "kuvat saisivat näkyä
 * niiden alkuperäisessä mittasuhteessa eikä venytettynä panoraamaksi").
 *
 * Aiemmin tässä oli width:100% + kiinteä max-height + object-fit:cover.
 * Se ei venyttänyt kuvaa vaan rajasi sen — mutta lopputulos oli sama
 * silmälle: pystykuvasta jäi näkyviin leveä kaistale keskeltä, ja se
 * näyttää panoraamalta. Nyt selain skaalaa kuvan mahtumaan molempiin
 * rajoihin suhteet säilyttäen: pystykuva jää kapeaksi ja korkeaksi,
 * vaakakuva leveäksi ja matalaksi. Mitään ei rajata pois.
 */
.arrival-image {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 210px;
  border-radius: 6px;
  border: 1px solid rgba(70, 51, 31, 0.3);
}

/* Kuvalaskuri kulmassa houkuttaa avaamaan gallerian — riittävän
   tumma pilleri erottuakseen vaaleistakin kuvista (omistajan toive). */
.arrival-kuva-laskuri {
  position: absolute;
  right: 0.4rem;
  bottom: 0.35rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: rgba(30, 22, 12, 0.6);
  color: rgba(255, 250, 240, 0.98);
  font-family: var(--font-type);
  font-size: 0.74rem;
  letter-spacing: 0.04em;
  pointer-events: none;
}

/*
 * Hennot selailunuolet: kuvia voi vaihtaa avaamatta isoksi. Koko kuvan
 * vasen ja oikea laita on klikattavaa nuolialuetta; keskeltä kuva aukeaa
 * suurennokseen. Dialogin yleinen nappityyli kumotaan tässä.
 *
 * LAITALIUKUVÄRI POISTETTU KAIKISTA KARUSELLEISTA (omistajan tilaus
 * 17.8.2026 Firenzen lehden etusivun kuvakaappauksesta: *"Ota pois
 * kaikkialta karuselleista"*). Nuolialue on 32 % kuvan leveydestä ja
 * koko kuvan korkuinen, joten liukuväri tummensi kuvan molemmat laidat
 * ylhäältä alas — kansikuva näytti siltä kuin siinä olisi vinjetti.
 * Tämä yksi sääntö palvelee KAIKKIA karuselleja (lehden kansikuva ja
 * nostogalleria: js/ui.js kaariNostoGalleria ja saapumiskuva;
 * nähtävyysjuttujen ja oppaan jaksojen karuselli: js/nahtavyydet.js
 * nahtavyydenKaruselli), joten poisto riittää tehdä kerran.
 *
 * OSUMA-ALUE JA ELE SÄILYVÄT ENNALLAAN: vain maali katosi, ei
 * selattavuus. Nuolimerkki erottuu nyt omalla halollaan — kolme
 * sisäkkäistä tekstivarjoa, jotka hehkuvat tummana tiiviisti glyyfin
 * ympärillä. Vaalealla kuvalla halo antaa vaalealle merkille reunan,
 * tummalla kuvalla merkki itse on vaalea. Halo on glyyfin kokoinen,
 * ei laidan kokoinen — juuri se oli tilauksen ero.
 */
.dialog button.arrival-kuva-nuoli {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 32%;
  height: auto;
  display: flex;
  align-items: center;
  border: 0;
  border-radius: 6px;
  background: transparent;
  box-shadow: none;
  /* Kosketuslaitteen oma napautusvälähdys pois: nuolialue on kolmannes
     kuvasta, joten välähdys näkyisi laajana laattana kuvan päällä. */
  -webkit-tap-highlight-color: transparent;
  color: rgba(255, 250, 240, 0.98);
  text-shadow:
    0 0 2px rgba(20, 14, 6, 0.95),
    0 0 6px rgba(20, 14, 6, 0.8),
    0 1px 3px rgba(20, 14, 6, 0.9);
  font-size: 1.9rem;
  line-height: 1;
  cursor: pointer;
  padding: 0;
  margin: 0;
}

/*
 * TAUSTA ON LÄPINÄKYVÄ MYÖS TILOISSA (omistajan kuvakaappaus 18.8.2026
 * iPadilla, Pariisin lehden kansikuva: kuvan oikea kolmannes vaalean
 * harson peitossa, harson vasen reuna terävä pystyviiva).
 *
 * MITATTU JUURISYY on erottelutarkkuus, ei uusi maali. Dialogin yleinen
 * nappisääntö `.dialog button:hover:not(:disabled)` maalaa taustaksi
 * rgba(255, 255, 255, 0.6), ja sen tarkkuus on (0,3,1) — KORKEAMPI kuin
 * perussäännön `.dialog button.arrival-kuva-nuoli` (0,2,1). Ennen v842
 * nuolella oli omat `…nuoli.seuraava:hover`-säännöt (0,4,1), joiden
 * tumma liukuväri voitti tuon vaalean taustan; kun liukuvärit poistettiin,
 * nuolen hover-tausta putosi dialogin yleissäännölle. Mitattuna
 * iPad-emuloinnissa (834x1112, Pariisin kansikaruselli) napautuksen
 * jälkeen `.arrival-kuva-nuoli.seuraava`:n laskettu backgroundColor oli
 * rgba(255, 255, 255, 0.6), leveys 213/666 px (= 32 %) ja korkeus koko
 * kuvan 430 px — juuri omistajan näkemä harso. iPadilla hover jää
 * napautuksen jälkeen päälle, joten harso oli pysyvä.
 *
 * Korjaus on yksi tarkkuudeltaan riittävä sääntö, joka pitää taustan
 * läpinäkyvänä KAIKISSA tiloissa. `:not(:disabled)` ei ole tässä ehto
 * vaan PAINO: sen kanssa valitsin on (0,4,1) ja voittaa yleissäännön
 * (0,3,1) riippumatta siitä, kummassa kohtaa tiedostoa se on. Ilman
 * sitä tarkkuudet olisivat tasan, ja tiedostossa myöhemmin tuleva
 * yleissääntö voittaisi — se mitattiin ensimmäisessä korjausyrityksessä.
 * Osuma-alue, ele ja glyyfin halo säilyvät ennallaan — vain maali
 * pysyy poissa.
 */
.dialog button.arrival-kuva-nuoli:hover:not(:disabled),
.dialog button.arrival-kuva-nuoli:focus:not(:disabled),
.dialog button.arrival-kuva-nuoli:focus-visible:not(:disabled),
.dialog button.arrival-kuva-nuoli:active:not(:disabled) {
  background: transparent;
}

/* Hiiren alla vain merkki kirkastuu ja sen halo tiivistyy — tausta
   pysyy läpinäkyvänä myös silloin (sama tilaus). */
.dialog button.arrival-kuva-nuoli:hover:not(:disabled) {
  color: #fff;
  text-shadow:
    0 0 2px rgba(20, 14, 6, 1),
    0 0 8px rgba(20, 14, 6, 0.95),
    0 1px 3px rgba(20, 14, 6, 0.95);
}

.dialog button.arrival-kuva-nuoli.edellinen {
  left: 0;
  justify-content: flex-start;
  padding-left: 0.35rem;
}

.dialog button.arrival-kuva-nuoli.seuraava {
  right: 0;
  justify-content: flex-end;
  padding-right: 0.35rem;
}

.arrival-card .wiki-btn { margin: 0 0 0.7rem; }

/*
 * Vanha valokuva muistikirjan kyljessä: pieni vedos valkoisin reunuksin
 * tekstin oikeassa laidassa, ja teksti kiertää sen. Kääre tarvitaan,
 * koska kortti on pystyflex eikä kelluminen toimi suoraan sen lapsissa.
 */
.fact-teksti-rivi {
  /* Kääre rajaa tekstin korkeuden kortin pystyflexissä; itse vieritys
   * tapahtuu tekstissä, jotta valokuva pysyy paikallaan kulmassa.
   * Kääre on itsekin flex-säiliö: prosenttikorkeus ei ratkea flexin
   * laskemaa korkeutta vasten (teksti kasvoi sisällön mittaiseksi ja
   * leikkautui ilman vieritystä), mutta flex-lapsi kutistuu oikein. */
  position: relative;
  min-height: 0;
  flex: 1 1 auto;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Vain teksti vierii — ilman kehyksiä ja ilman näkyvää palkkia, kuin
 * muistikirjan sivu liukuisi sormen alla. Kutistuminen ja vieritys
 * tulevat .fact-textin omista flex-säännöistä. Suora dvh-katto on
 * vyö ja henkselit -varmistus: se ei riipu flexin kutistumisesta
 * missään selaimessa (iPadin Safari päästi tekstin kartan päälle). */
/*
 * EI RIVIKATTOA (omistajan päätös 7.8.2026): "matkakirja voisi avautua
 * jatkossa kokonaan, koska se pienenee kätevästi kokonaan kun karttaa
 * liikuttaa. eli sen välikoon voisi ottaa pois kokonaan."
 *
 * Ennen tässä oli viiden rivin ikkuna (puhelimella kolmen), jonka sai
 * napauttamalla auki. Kolmesta koosta jäi kaksi: koko merkintä ja
 * yhden rivin nimilappu (.pieni), johon kartan liike kutistaa kortin.
 * Kortin oma korkeusraja hoitaa sen, ettei pitkä merkintä peitä
 * karttaa, ja teksti vierii, jos se ei mahdu edes siihen.
 */
.fact-teksti-rivi .fact-text {
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.fact-teksti-rivi .fact-text::-webkit-scrollbar { display: none; }

/*
 * Jatkuu-vihje: kun tekstiä on näkymän alapuolella, viimeinen rivi
 * häipyy hennosti (.jatkuu-luokkaa ohjaa ui.js).
 *
 * NUOLI POISTUI v318:ssa (omistaja: "ota matkakirjasta lopusta nuoli
 * alas pois, se on nyt turha"). Se oli tarpeen niin kauan kuin
 * merkintä näkyi viiden rivin ikkunassa ja loppu piti hakea
 * napauttamalla. Kun kortti aukeaa kokonaan (v317), tekstiä jää
 * näkymän alle vain poikkeuksellisen pitkässä merkinnässä — silloin
 * riittää häivytys, joka kertoo saman asian koristelematta.
 */
.fact-teksti-rivi.jatkuu .fact-text {
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 1.2em), rgba(0, 0, 0, 0.25));
  mask-image: linear-gradient(180deg, #000 calc(100% - 1.2em), rgba(0, 0, 0, 0.25));
}

/* Teksti kiertää kuvan alussa: näkymätön varaus kelluu kuvan kohdalla
 * tekstin sisällä, ja vieritettäessä teksti liukuu paikallaan pysyvän
 * vedoksen alta — kuin kuva makaisi sivun päällä. */
.fact-teksti-rivi:has(.fact-valokuva:not([hidden])) .fact-text::before {
  content: '';
  float: right;
  width: 72px;
  height: 58px;
}

.fact-valokuva {
  position: absolute;
  top: 0.15rem;
  right: 0;
  z-index: 2;
  transition: opacity 0.25s ease;
  width: auto;
  margin: 0;
  padding: 3px 3px 7px;
  background: #f8f3e6;
  border: 0;
  border-radius: 1px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.32);
  transform: rotate(2.5deg);
  cursor: pointer;
}

/* Vieritetty teksti kulkisi kuvan alle — vedos väistyy lukemisen ajaksi. */
.fact-teksti-rivi.vieritetty .fact-valokuva {
  opacity: 0;
  pointer-events: none;
}

.fact-valokuva img {
  display: block;
  width: 54px;
  height: 42px;
  object-fit: cover;
  filter: grayscale(1) sepia(0.12) contrast(1.04);
}

/*
 * Postikorttikatselin: kuva aukeaa hieman vinottain muistikirjan viereen,
 * valkoiset reunukset ja lähderivi kuten vanhassa vedoksessa. Napautus
 * mihin tahansa sulkee.
 */
/* Postikorttipino: kääre asemoi, kortit ovat sisällä. Kun kaupungilla on
 * myös uusi kuva, se pilkottaa vanhan alta ja nousee napautuksesta
 * päälle (omistajan kokeilu). */
/*
 * MATKAKIRJAN PIENOISKUVA PIILOTETTU (omistajan tilaus 23.8.2026:
 * "matkakirjasta piti piilottaa se pienoiskuva"). Piilotettava on
 * matkakirjamerkinnän vieressä oleva pieni valokuvanappi
 * (index.html: #fact-valokuva) — EI postikorttikatselinta.
 *
 * VAROITUS SEURAAVALLE (v1076:n vika): ensimmäinen yritys piilotti
 * .postikortti-luokan, ja silloin YKSIKÄÄN kuva ei auennut enää koko
 * ruudulle missään päin peliä — samaa katselinta käyttävät lehden
 * suurennokset (js/lehti.js), kohdekartan kohteet (js/nahtavyydet.js)
 * ja js/ui.js:n oma suurennos. Älä koske .postikortti-sääntöihin
 * tämän takia.
 *
 * Piilotus on pelkkä näkyvyyskytkin: js/ui.js rakentaa napin yhä,
 * kuvadata on paketeissa ja tiedostot ovat tallessa, joten paluu on
 * tämän yhden säännön poistaminen.
 */
.fact-valokuva { display: none; }

/*
 * Pienoiskuvan kellutusvaraus pois samalla. Ylempänä (.fact-text::before)
 * kelluu näkymätön 72x58 laatikko, joka varaa tekstistä tilan
 * pienoiskuvalle. Kun kuva on piilossa, varaus jäisi voimaan ja teksti
 * kiertäisi tyhjää kolkkaa — omistajan havainto 24.8.2026 ("teksti
 * kiertää näkymätöntä kuvaa"). Nämä kaksi sääntöä kuuluvat yhteen: jos
 * pienoiskuva palautetaan näkyviin, poista molemmat.
 */
.fact-teksti-rivi:has(.fact-valokuva:not([hidden])) .fact-text::before {
  content: none;
}

.postikortti {
  position: fixed;
  z-index: 70;
  /*
   * Puhelimella entinen mitoitus, isolla ruudulla isompi.
   *
   * Omistajan toive 3.8.2026: "nämä kuvat voisi näkyä isompana" —
   * havainto tuli iPadilta. Katto 460 px oli mitoitettu puhelimelle, ja
   * tabletilla kortti jäi ruudun keskelle pieneksi lapuksi vaikka tilaa
   * oli runsaasti.
   *
   * Kasvatus tehdään vain leveille ruuduille (alla @media). Puhelimella
   * korttiin ei mahdu enempää: kuvan lisäksi siinä on kuvateksti, ja
   * pelkkä korkeuden kasvattaminen tekisi vaakakuvasta pystykortin.
   */
  width: min(84vw, 460px);
  animation: postikortti-esiin 0.24s ease-out;
}

.postikortti-kortti {
  position: relative;
  z-index: 2;
  background: #f8f3e6;
  padding: 0.55rem 0.55rem 0.3rem;
  border-radius: 2px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
  /* Reilummin vinoon — pinon kortit kallistuvat ristikkäin
   * (omistajan toive). */
  transform: rotate(-4.5deg);
  transition: transform 0.22s ease, z-index 0s;
}

/* Alempi kortti pilkottaa alareunasta ja kutsuu napauttamaan. Kortti
 * rajataan päällimmäisen kokoiseksi, ettei sen sisältö pursua näkyviin
 * (omistajan havainto), ja kuva täyttää kortin — alta pilkottaa siisti
 * kuvareuna valkoisine kehyksineen. */
.postikortti-kortti.alla {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  transform: rotate(4deg) translate(14px, 30px);
  cursor: pointer;
}

.postikortti-kortti.alla img {
  position: absolute;
  inset: 0.55rem;
  width: calc(100% - 1.1rem);
  height: calc(100% - 1.1rem);
  min-height: 0;
  object-fit: cover;
}

.postikortti-kortti.alla .kuvateksti,
.postikortti-kortti.alla .kuvalahde { visibility: hidden; }

/* Vain häivytys: kehyksen transformia käytetään pystykeskitykseen,
 * joten animaatio ei saa koskea siihen. */
@keyframes postikortti-esiin {
  from { opacity: 0; }
}

.postikortti img {
  display: block;
  width: 100%;
  /* Kiinteä kuvaikkuna: vaaka- ja pystykuvat näkyvät suurin piirtein
   * samankokoisina, ja korkea kuva ei venytä korttia ruutua
   * korkeammaksi (omistajan toive). Kuva rajataan ikkunaan. */
  height: min(48vh, 330px);
  object-fit: cover;
  background: #ded5c2;
  border: 1px solid rgba(0, 0, 0, 0.12);
}

/*
 * Harmaasavy vain aidosti vanhoille vedoksille (omistajan toive).
 *
 * Ennen sääntö koski kaikkia postikortin kuvia, jolloin nykypäivän
 * kuva näytti yhtä vanhalta kuin sadan vuoden takainen — ja koko
 * ennen/nyt-asetelma katosi. Luokan asettaa js/ui.js kuvan oman
 * vuosiluvun perusteella, ei kortin paikan.
 */
.postikortti img.vanha-vedos { filter: grayscale(1) contrast(1.03); }

/*
 * Pinon laskuri: monesko kuva ja montako niitä on.
 *
 * Kahden kuvan pinossa alta pilkottava reuna riitti vihjeeksi, mutta
 * useamman kuvan pinossa pelaaja ei näe montako niitä vielä on.
 * Laskuri on hillitty ja istuu kuvatekstin viereen.
 */
.postikortti-laskuri {
  position: absolute;
  right: 0.7rem;
  bottom: 0.45rem;
  margin: 0;
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: rgba(74, 55, 26, 0.62);
}

.postikortti-kortti.alla .postikortti-laskuri { visibility: hidden; }

/*
 * Leveä ruutu: kortti ja kuva isommiksi. Raja 700 px on sama kuin
 * muuallakin pelissä (mannerzoomin automatiikka), joten "kapea ruutu"
 * tarkoittaa kaikkialla samaa.
 */
@media (min-width: 700px) {
  .postikortti { width: min(88vw, 76vh, 720px); }
  .postikortti img { height: min(52vh, 500px); }
}

/*
 * Työpöytäselain: kuva vielä isommaksi, jos ikkunaa riittää.
 *
 * Omistajan toive: "työpöytäselaimella kuvat voisivat aueta vielä
 * isommiksi jos selaimen ikkuna on vain tarpeeksi iso."
 *
 * Ehtona on sekä leveys ETTÄ korkeus. Pelkkä leveysehto kasvattaisi
 * kuvaa myös matalassa ikkunassa — esimerkiksi kannettavalla, jossa
 * selain on puolikkaana näytön leveydeltä mutta täydessä korkeudessa
 * vain 600 px — ja kortin alareuna jäisi ruudun alle.
 *
 * Nämä tulevat 700px-säännön JÄLKEEN tarkoituksella: kaikilla on sama
 * tarkkuus, joten lähdejärjestys ratkaisee, ja aiemmin kirjoitettuna
 * nämä olisivat jääneet tehottomiksi.
 */
@media (min-width: 1000px) and (min-height: 760px) {
  .postikortti { width: min(84vw, 82vh, 880px); }
  .postikortti img { height: min(60vh, 600px); }
}

@media (min-width: 1500px) and (min-height: 950px) {
  .postikortti { width: min(76vw, 84vh, 1040px); }
  .postikortti img { height: min(64vh, 760px); }
}

.postikortti .kuvateksti {
  /* Alamarginaali 0,15 → 0,25 rem (23.8.2026): lähde on nyt tämän
   * sisällä eikä oma kappaleensa, joten sen 0,1 rem:n alamarginaali
   * siirtyy tänne ja kortin alareuna pysyy ennallaan. */
  margin: 0.35rem 0.1rem 0.25rem;
  font-family: var(--font-type);
  /* Isompi selite (omistajan toive). */
  font-size: 0.86rem;
  line-height: 1.45;
  color: #5a4a33;
}

/* Lähde ja vuosi selitettä pienemmällä ja vaimeammalla. */
.postikortti .kuvalahde {
  margin: 0.15rem 0.1rem 0.1rem;
  font-family: var(--font-type);
  font-size: 0.6rem;
  color: #8a7a60;
}

/* Kulttuurinoston kuva vihjaa suurennoksesta. */
.kulttuuri-kuva-nappi { cursor: zoom-in; }

/*
 * Kulttuurinoston suurennos: sama postikorttivedos, mutta keskellä
 * ruutua ja väreissä — taideteos tai valokuva näytetään sellaisenaan.
 * Katselin elää saapumisikkunan sisällä (modaalin päällä).
 */
/*
 * Suurennus on AINA SUORASSA ja niin isona kuin ruutuun mahtuu
 * (omistajan toive: "Tutkinäkymän kuvat voisivat aina avautua
 * maksimikokoon... aina suorassa").
 *
 * Kierto kuului postikorttipinoon, jossa se on osa asetelmaa. Yksin
 * avatussa suurennuksessa se ei kerro mitään — se vain kallistaa
 * teoksen. Myös ilmestymisliike on poistettu: napautuksen ja kuvan
 * väliin ei jää mitään.
 */
.postikortti.kulttuuri-suurennos {
  /*
   * Keskitys marginaalilla eikä transformilla. Transform tekee
   * elementistä kiinnitettyjen jälkeläisten sijoituskehyksen, jolloin
   * alla oleva koko ruudun pohja olisi rajautunut kortin kokoiseksi.
   */
  inset: 0;
  margin: auto;
  width: min(96vw, 1600px);
  height: fit-content;
  max-height: 100dvh;
  transform: none;
  cursor: zoom-out;
  animation: none;
}

/*
 * Tumma pohja koko ruudun yli. Maksimikokoinen kuva peittää arkin
 * tekstin, ja ilman pohjaa selite jäisi tekstin sekaan lukukelvottomaksi
 * — ja kuvan reuna katosi vaaleaan paperiin. Tämä on luettavuutta, ei
 * tehoste: ei liikettä, ei sumennusta.
 */
.postikortti.kulttuuri-suurennos::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: rgba(14, 9, 4, 0.88);
}

.postikortti.kulttuuri-suurennos img {
  filter: none;
  /* .postikortti img antaa kiinteän kuvaikkunan (min(48vh, 330px)),
   * joka on pinon mitoitus eikä suurennuksen: se on kumottava, tai
   * kuva jäisi 330 pikselin korkuiseksi ruudun koosta riippumatta. */
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 80dvh;
  margin-inline: auto;
  object-fit: contain;
  background: #efe7d4;
}

/* Selite ja lähde jäävät kuvan alle kapeana rivinä, eivät levene
 * kortin täyteen leveyteen isolla ruudulla. 60rem oli iPadin
 * vaakanäytöllä yhä lähes koko ruutu (omistajan havainto 23.8.2026
 * julistesuurennoksesta: "lado alaosan teksti kapeammalle alalle") —
 * 36rem on lukupalsta, joka vastaa pystyjulisteen leveyttä. */
.postikortti.kulttuuri-suurennos .kuvateksti,
.postikortti.kulttuuri-suurennos .kuvalahde {
  max-width: 36rem;
  margin-inline: auto;
  text-align: center;
  /* Vaalea teksti tummalla pohjalla. */
  color: rgba(247, 239, 220, 0.92);
}

.postikortti.kulttuuri-suurennos .kuvalahde { color: rgba(247, 239, 220, 0.62); }

/*
 * Maan tiedot kaupungin rinnalla saapumiskortissa (omistajan toive):
 * ohut jakoviiva ja pieni maaetiketti erottavat sen kaupungin
 * esittelystä samalla hillityllä tyylillä.
 */
/*
 * Kaupunki ja maa vierekkäin (omistajan toive): leveällä ruudulla kortti
 * levenee kahteen palstaan, kapealla palstat putoavat allekkain. Ilman
 * maaosiota (muut laudat) kortti pysyy kapeana yksipalstaisena.
 *
 * KATTO EI KOSKE TUTKI-ARKKIIN (omistajan iPad-havainto 13.8.2026:
 * *"Lehti näkyy vieläkin liian kapeana iPadilla."*). Saapumiskortti
 * avataan nykyään aina arkkina, jonka leveys on oma sääntönsä
 * (.dialog.arkki .dialog-card). Tämä 700 pikselin katto on siitä
 * vanhempi, ja se on kumottu arkissa vain :has()-valitsimen suuremmalla
 * tarkkuudella — hauras tapa, koska se kaatuu heti jos selain ei tue
 * :has():ia. Nyt katto on rajattu suoraan pois arkista, eikä arkin omien
 * mittojen tarvitse enää voittaa mitään.
 */
.dialog:not(.arkki) .arrival-card:has(#arrival-maa:not([hidden])) {
  max-width: min(92vw, 700px);
}

.arrival-palstat {
  display: flex;
  gap: 1.1rem;
  align-items: flex-start;
}

.arrival-palsta {
  flex: 1 1 0;
  min-width: 0;
}

.arrival-maa {
  flex: 1 1 0;
  min-width: 0;
  border-left: 1px dashed rgba(70, 51, 31, 0.35);
  padding-left: 1.1rem;
  margin: 0.1rem 0 0.3rem;
}

/*
 * Kaupungin elämää -lohko: kulttuurinostot ja tutustu ja vastaa -kysymys
 * palstojen alla koko kortin leveydellä.
 */
.arrival-kulttuuri {
  border-top: 1px dashed rgba(70, 51, 31, 0.35);
  margin-top: 0.25rem;
  padding-top: 0.4rem;
}

/*
 * VISA LEHDESSÄ (omistajan ohje 8.8.2026: "pomppaa ja houkuttelee
 * vastaamaan") on ladottu samaan muottiin kuin lehden minitehtävä —
 * ks. "LEHDEN TEHTÄVÄLAATIKKO" tämän tiedoston loppupuolella. Sieltä
 * tulevat kehys, otsake, vastausrivit ja palaute molemmille.
 */

.arrival-kulttuuri > summary {
  cursor: pointer;
  font-family: var(--font-type);
  font-size: 0.88rem;
  letter-spacing: 0.06em;
  color: #7a5514;
  padding: 0.1rem 0 0.35rem;
}

.kulttuuri-nosto { margin-bottom: 0.6rem; }

.kulttuuri-otsikko {
  margin: 0 0 0.15rem;
  font-weight: 700;
  font-size: 0.92rem;
}

.kulttuuri-nosto img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 260px;
  border: 1px solid rgba(70, 51, 31, 0.3);
  border-radius: 6px;
  margin: 0.25rem 0;
}

.kulttuuri-lahde {
  margin: 0.05rem 0 0;
  font-size: 0.7rem;
  font-family: var(--font-type);
  color: rgba(90, 74, 51, 0.85);
}

/* Muusikkonoston linkki Apple Musiciin: pieni nuottipilleri otsikon
   korkeudella oikeassa reunassa (auto-marginaali työntää oikealle). */
.kulttuuri-musiikkilinkki {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  flex-shrink: 0;
  white-space: nowrap;
  margin: 0 0 0 auto;
  padding: 0.18rem 0.55rem;
  border: 1px solid rgba(90, 74, 51, 0.45);
  border-radius: 999px;
  font-family: var(--font-type);
  font-size: 0.7rem;
  color: rgba(64, 51, 34, 0.95);
  text-decoration: none;
  background: rgba(255, 252, 245, 0.6);
}

/* Ilmainen ääninäyte Apple Music -linkin vieressä: sama nappi kuin
   muilla näytteillä, mutta hieman pienempi, koska se jakaa rivin
   otsikon ja Apple Music -pillerin kanssa. Auto-marginaali työntää
   parin oikeaan reunaan silloinkin, kun Apple Music -linkkiä ei ole. */
.kulttuuri-musiikkinayte {
  margin-left: auto;
  padding: 0.22rem 0.6rem;
  font-size: 0.72rem;
}

.kulttuuri-musiikkilinkki + .kulttuuri-musiikkinayte { margin-left: 0.3rem; }

.kulttuuri-musiikkilinkki:hover {
  border-color: rgba(64, 51, 34, 0.75);
  background: rgba(255, 252, 245, 0.95);
}

/*
 * Otsikko ja ääninäytteen nappi samalla rivillä — PUHELIMELLA
 * ALLEKKAIN.
 *
 * Rivi oli `nowrap` ja nappi `flex: 0 0 auto`, joten kumpikaan ei
 * antanut periksi. Mitattu 390 pikselin ruudulla: "Kuuntele
 * musiikkia" -nappi työntyi 44 pikseliä arkin oikean reunan yli ja
 * lehti sai vaakavierityksen. Vika oli kaikissa kansisivuissa, joissa
 * nostolla on ääninäyte (Lontoo ja Madrid), ei yhdessä tekstissä.
 *
 * Rivitys on oikea korjaus eikä kavennus: nappi on painike, ja
 * kutistettuna sen teksti katkeaisi kesken. Omalla rivillään se on
 * yhtä luettava kuin ennenkin.
 */
.kulttuuri-otsikkorivi {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0 0 0.15rem;
}

.kulttuuri-otsikkorivi .kulttuuri-otsikko { margin: 0; }

/*
 * Kuuntele näyte: oikea nappi kaiutinkuvakkeella — tekstilinkiksi
 * puettuna se hukkui Lue lisää -rivien joukkoon (omistajan havainto).
 * Soidessa nappi saa kultapohjan ja näyttää keston ja toistokohdan.
 */
.kulttuuri-kuuntele {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  /* Ei kasva, saa kutistua, ei koskaan emoaan leveämpi — ks.
     .kulttuuri-otsikkorivi yllä. */
  flex: 0 1 auto;
  max-width: 100%;
  padding: 0.32rem 0.7rem;
  background: rgba(255, 250, 238, 0.9);
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 8px;
  color: #46331f;
  font-family: var(--font-type);
  font-size: 0.8rem;
  cursor: pointer;
}

.kulttuuri-kuuntele:hover { background: #fffdf6; }

.kulttuuri-kuuntele.soi {
  background: rgba(234, 184, 78, 0.28);
  border-style: solid;
}

.kulttuuri-kuuntele .aika {
  font-variant-numeric: tabular-nums;
  font-size: 0.72rem;
  color: rgba(70, 51, 31, 0.75);
}

/*
 * Radionapin live-merkki.
 *
 * Punainen on tässä ainoa paikka koko kartalla, jossa sitä käytetään
 * merkkinä eikä piirroksena — juuri siksi se erottuu pergamentilta
 * heti. Merkki kertoo, että toisessa päässä on oikea lähetys, joka
 * soi juuri nyt jossain päin maailmaa.
 *
 * Piste sykkii vain napin soidessa. Levossa sykkivä piste kilpailisi
 * huomiosta kaupungin sisällön kanssa, ja liike kartalla on varattu
 * pelin omille tapahtumille.
 */
.kulttuuri-kuuntele .live {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #a3281c;
}

.kulttuuri-kuuntele .live::before {
  content: '';
  width: 0.42rem;
  height: 0.42rem;
  border-radius: 50%;
  background: #c4321f;
}

.kulttuuri-kuuntele.soi .live::before {
  animation: live-syke 1.6s ease-in-out infinite;
}

@keyframes live-syke {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.25; }
}

/*
 * Aseman nimi voi olla pitkä ("SLBC Tamil National Service"), eikä
 * nappi saa työntää korttia leveämmäksi. Nimi katkeaa kolmeen
 * pisteeseen, mutta merkki, live ja kello pysyvät aina näkyvissä:
 * ne ovat napin toiminta, nimi on sen selite.
 */
.kulttuuri-kuuntele > span:not(.aika):not(.live) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 14rem;
}

.kulttuuri-kuuntele .merkki,
.kulttuuri-kuuntele .aika,
.kulttuuri-kuuntele .live { flex: 0 0 auto; }

@media (prefers-reduced-motion: reduce) {
  .kulttuuri-kuuntele.soi .live::before { animation: none; }
}

/* Kulttuurivisan avausnappi: sama mustekynän nappityyli kuin näytteellä. */

/*
 * Tutki paikka ja Jatka matkaa erilleen sisällöstä: napit hengittävät
 * alempana oman jakoviivansa alla (omistajan toive).
 */
.arrival-card .dialog-actions {
  margin-top: 1.5rem;
  padding-top: 1rem;
  border-top: 1px dashed rgba(70, 51, 31, 0.35);
  /* Etsi kätkö putoaa omalle täysleveälle rivilleen (alla). */
  flex-wrap: wrap;
}

/*
 * Etsi kätkö / Tapaa X kaikkien nappien alle koko leveänä ja
 * matalana (omistajan toive 9.8.2026) — MYÖS lehden viimeisellä
 * sivulla, jossa se aiemmin hukkui alanappirivin jatkoksi
 * (omistaja: "ei näy Etsi kätkö eli tapaa x nappia"). Järjestys
 * käännetään orderilla — DOMissa nappi pysyy ensimmäisenä, jotta
 * Enter valitsee sen yhä. Lehtitilassa order 4 tulee lehden omasta
 * säännöstä ja pitää napin viimeisenä sielläkin.
 */
.arrival-card .dialog-actions #arrival-yes {
  order: 9;
  flex: 1 1 100%;
  min-height: 0;
  padding: 0.45rem 0.8rem;
}

/*
 * Kulttuurivisan palaute: selkeä kehystetty ruutu, jota ei voi ohittaa
 * katseella — oikea vastaus kultareunuksin, väärä mustereunuksin.
 */
.kulttuuri-tulos {
  margin: 0.4rem 0 0;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  border: 1.5px solid rgba(70, 51, 31, 0.55);
  background: rgba(255, 250, 238, 0.85);
  font-size: 0.88rem;
  line-height: 1.45;
  color: #3a2a16;
  animation: fact-in 0.3s ease-out;
}

/* Oikea vastaus vihreälle pohjalle (omistajan toive 5.8.2026) —
 * myös väärin menneen vastauksen palaute KERTOO oikean vastauksen,
 * joten sekin on vihreä: punainen pohja näytti virheilmoitukselta. */
.kulttuuri-tulos.oikein-tulos {
  border-color: rgba(74, 124, 58, 0.75);
  background: rgba(106, 158, 84, 0.18);
}

.kulttuuri-tulos.vaarin-tulos {
  border-color: rgba(74, 124, 58, 0.45);
  background: rgba(106, 158, 84, 0.1);
}

/*
 * Visan vaihtoehdot kevyemmiksi ja väljemmiksi (omistajan palaute
 * 5.8.2026: "raskaan näköisiä ja ahdas"): ohut yhtenäinen viiva
 * pelinappien paksun katkoviivan sijaan, pyöreä kapseli ja
 * enemmän ilmaa nappien välissä ja ympärillä.
 */
.kulttuuri-vaihtoehdot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
  margin: 0.55rem 0 0.5rem;
}

.dialog .kulttuuri-vaihtoehdot button {
  font-size: 0.85rem;
  padding: 0.5rem 1.05rem;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 999px;
  background: rgba(255, 250, 238, 0.6);
  box-shadow: none;
}

.dialog .kulttuuri-vaihtoehdot button:hover {
  border-color: rgba(70, 51, 31, 0.75);
  background: rgba(255, 250, 238, 0.95);
}

/* Kapealla ruudulla palstat allekkain ja jakoviiva takaisin vaakaan. */
@media (max-width: 640px) {
  .arrival-palstat { flex-direction: column; gap: 0; }
  .arrival-palsta, .arrival-maa { flex: 0 0 auto; width: 100%; }
  .arrival-maa {
    border-left: 0;
    border-top: 1px dashed rgba(70, 51, 31, 0.35);
    padding-left: 0;
    padding-top: 0.5rem;
    margin-top: 0.15rem;
  }
}

.arrival-maa-rivi {
  margin: 0 0 0.25rem;
  display: flex;
  align-items: center;
  gap: 0.45rem;
}

.arrival-maa-nimi {
  /* Sama kirjaintyyli kuin kaupungin otsikolla (omistajan toive):
   * kirjan serif-antiikva, ei konekirjoitusta eikä kapiteeleja. */
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: inherit;
}

/*
 * PERUSTIETOLAATIKKO kartan alla (pilottimaat).
 *
 * Omistajan palaute 21.8.2026 Omanin maalehden karttasivulta:
 * "voisivat olla vähän isommalla ja ne voisi muotoilla vielä enemmän
 * pelin tyyliin kaikilla sivuilla, joissa niitä näkyy". Rivit olivat
 * 0,74 rem:n symboliriviä, joita kännykällä sai siristellä, ja
 * mittapalkit näyttivät pyöreine päineen modernilta liukusäätimeltä.
 *
 * Nyt lohko on vanhan almanakan faktalaatikko: kaksoisviiva ylle,
 * harvennettu nimiö, arvot kirjoituskoneella selvästi isompina,
 * pisteviivajohdin arvosta sijoitukseen ja sijoitusluvut omassa
 * sarakkeessaan oikeassa reunassa. Mitat ovat em-yksikköinä, joten
 * ikonit, palkit ja liput kasvavat kirjasimen mukana.
 *
 * Sama lohko piirtyy maalehden karttasivulle (js/lehti.js) ja
 * kaupunkilehden maaosastoon (js/ui.js openArrival) samoihin
 * #arrival-maa-elementteihin, joten tyyli kattaa kummankin.
 */
.maa-tunnusluvut {
  margin: 0.45rem 0 0;
  padding: 0.45rem 0.55rem 0.4rem;
  font-family: var(--font-type);
  font-size: 0.95rem;
  line-height: 1.35;
  color: #4a3c28;
  background: rgba(120, 96, 60, 0.05);
  border-top: 3px double rgba(70, 51, 31, 0.55);
  /*
   * Kapealla yksi sarake, leveällä kaksi. auto-fit katsoo LOHKON
   * leveyttä eikä ruudun: sama sääntö osuu oikein niin puhelimen
   * täysleveään maalehteen kuin kaupunkilehden kapeaan palstaan.
   */
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr));
  gap: 0.1rem 1.5rem;
}

/* Almanakan nimiöt harvennettuna versaalina — laatikko kertoo itse,
 * mitä lukuja ja mitä kieliä siinä on. */
.maa-tunnusluvut::before,
.maa-tervehdykset::before {
  grid-column: 1 / -1;
  flex: 1 0 100%;
  margin-bottom: 0.15rem;
  font-family: var(--font-type);
  font-size: 0.66rem;
  font-style: normal;
  font-weight: 400;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.55);
}

.maa-tunnusluvut::before { content: "Perustiedot"; }
.maa-tervehdykset::before { content: "Hyvää päivää"; }

/*
 * Rivit sulautuvat laatikon ruudukkoon (display: contents), jotta
 * kaikki neljä tunnuslukua asettuvat samaan sarakejakoon. Ennen ne
 * olivat kolme erillistä riviä, joissa sijoitusluvut sahasivat eri
 * kohdissa.
 */
.maa-tunnusrivi { display: contents; }

/* Sijoitus maailmassa ja puhujaosuus: vaimeampi lisätieto, mutta
 * sekin luettavan kokoista. */
.maa-sija {
  color: rgba(70, 51, 31, 0.62);
  font-size: 0.8em;
  letter-spacing: 0.02em;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.maa-tunnus {
  display: flex;
  align-items: center;
  gap: 0.45em;
  min-width: 0;
  padding: 0.1rem 0;
}

/*
 * Arvosarakkeelle vähimmäisleveys, jotta johtimet ja mittapalkit
 * alkavat samalta viivalta kuin taulukossa. min() jättää kapeimmalle
 * palstalle varan kutistua, ettei rivi valu reunan yli.
 */
.maa-tunnus-arvo {
  min-width: min(7.6em, 45%);
  font-weight: 600;
  white-space: nowrap;
}

/*
 * Pisteviivajohdin arvosta sijoitukseen — vanhan hakuteoksen keino.
 * Pisteet ovat taustakuvaa, joten johdin venyy vapaasti rivin
 * mitassa ja pistejako pysyy samana.
 */
.maa-tunnus-johdin {
  flex: 1 1 1.2rem;
  min-width: 0.6rem;
  height: 0.5em;
  margin-top: 0.4em;
  background-image: radial-gradient(circle at center,
    rgba(70, 51, 31, 0.5) 1.1px, transparent 1.4px);
  background-size: 0.45em 0.5em;
  background-repeat: repeat-x;
}

/* Mittapalkki musteella painettuna: suorat kulmat, hiusviivakehys,
 * neljännesasteikko pohjassa ja vinorasteri täytteessä. Väri kertoo
 * tason kuten ennenkin (punainen → keltainen → vihreä), mutta muoto
 * ei enää muistuta liukusäädintä (omistajan palaute 21.8.2026). */
.maa-palkki {
  flex: 0 0 auto;
  display: block;
  width: 3.6em;
  height: 0.66em;
  border: 1px solid rgba(70, 51, 31, 0.6);
  border-radius: 0;
  background-color: rgba(255, 252, 244, 0.5);
  background-image: repeating-linear-gradient(to right,
    rgba(70, 51, 31, 0.16) 0 1px, transparent 1px 25%);
  overflow: hidden;
  margin: 0;
}

.maa-palkki-tayte {
  position: relative;
  display: block;
  height: 100%;
  border-radius: 0;
}

.maa-palkki-tayte::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(45deg,
    rgba(252, 247, 234, 0.42) 0 0.5px, transparent 0.5px 2.5px);
}

.maa-tunnus-ikoni {
  flex: 0 0 auto;
  display: inline-flex;
}

.maa-tunnus-ikoni svg {
  width: 1.2em;
  height: 1.2em;
  display: block;
  fill: none;
  stroke: rgba(70, 51, 31, 0.85);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Nappi puettuna tekstilinkiksi — dialogin nappityyli kumotaan. */
.dialog button.maa-demokratia {
  color: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 0.22em;
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  margin: 0;
  /* Nappien yleinen 42 px minimikorkeus toisi tekstiriviin ison
   * näkymättömän tyhjän ylä- ja alapuolelle. */
  min-height: 0;
  font: inherit;
  font-weight: 600;
  letter-spacing: inherit;
  cursor: pointer;
}

.dialog button.maa-demokratia:hover:not(:disabled) {
  background: none;
  color: var(--accent);
}

/* V-Dem-infoikkuna: kevyt kerros dialogin päällä, pergamenttikortti
 * keskellä. Selitys ensin, linkki kuvaajaan vasta sen alla. */
.vdem-info {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(15, 10, 5, 0.45);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.vdem-kortti {
  position: relative;
  width: min(86vw, 380px);
  padding: 0.9rem 1rem 0.8rem;
  border-radius: 8px;
  background: #f8f3e6;
  color: #3a2a16;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45);
}

.vdem-otsikko {
  margin: 0 0 0.3rem;
  font-size: 1.1rem;
}

.vdem-arvo {
  margin: 0 0 0.5rem;
  font-family: var(--font-type);
  font-size: 0.86rem;
  color: #7a5514;
}

.vdem-selitys {
  margin: 0 0 0.55rem;
  font-size: 0.95rem;
  line-height: 1.45;
}

.vdem-yleis {
  margin: 0 0 0.6rem;
  font-size: 0.8rem;
  line-height: 1.4;
  color: rgba(90, 74, 51, 0.9);
}

.vdem-linkki {
  font-family: var(--font-type);
  font-size: 0.86rem;
  color: #7a5514;
}

.dialog button.vdem-sulje {
  position: absolute;
  top: 0.3rem;
  right: 0.3rem;
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0.3rem;
  margin: 0;
  color: rgba(90, 74, 51, 0.8);
  cursor: pointer;
}

.dialog button.vdem-sulje:hover:not(:disabled) {
  background: none;
  color: #3a2a16;
}

/*
 * Tervehdysrivi on saman faktalaatikon alaosasto: sama pohja ja
 * reunus, hiusviiva erottamassa luvuista ja kaksoisviiva laatikon
 * pohjaksi. Tervehdykset ladotaan lukukirjasimen kursiivilla, jotta
 * vieras kieli erottuu numeroiden kirjoituskoneesta.
 */
.maa-tervehdykset {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 1.35rem;
  /* Hengähdys tervehdysten ja esittelytekstin väliin. */
  margin: 0 0 0.85rem;
  padding: 0.4rem 0.55rem 0.45rem;
  background: rgba(120, 96, 60, 0.05);
  border-top: 1px solid rgba(70, 51, 31, 0.22);
  border-bottom: 3px double rgba(70, 51, 31, 0.55);
  font-size: 0.95rem;
  color: #4a3c28;
}

.tervehdys {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
}

/*
 * Oma kääre tervehdykselle: unicode-bidi eristää oikealta vasemmalle
 * kirjoitetun tekstin (arabia, heprea) omaksi saarekkeekseen, jolloin
 * lippu ja puhujaosuus pysyvät sen jäljessä eivätkä liu'u väärälle
 * puolelle rivin bidi-ladonnassa.
 */
.tervehdys-teksti {
  font-family: var(--font-luku);
  font-style: italic;
  font-size: 1.1em;
  line-height: 1.25;
  unicode-bidi: isolate;
}

.tervehdys img {
  height: 1.05em;
  width: auto;
  display: block;
  align-self: center;
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 1px;
}

.tervehdys-osuus { font-size: 0.78em; }

/* Maan lippu suht pienenä nimen vieressä (omistajan toive). */
.arrival-lippu {
  height: 1.05rem;
  width: auto;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 2px;
  display: inline-block;
}

/*
 * Maan minikartta pelin omasta rajadatasta: muoto, pelin kaupungit ja
 * nykyinen kaupunki korostettuna — sama kynä kuin laudalla.
 */
.arrival-maa-kartta-svg {
  display: block;
  width: 100%;
  max-height: 195px;
  /* Tunnusluvut istuvat heti kartan alle (omistajan toive). */
  margin: 0.1rem auto 0;
}

.minimaa-pohja {
  fill: rgba(138, 108, 70, 0.13);
  stroke: rgba(70, 51, 31, 0.85);
  stroke-width: 1.3px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.minimaa-piste {
  fill: #f6e7c6;
  stroke: rgba(70, 51, 31, 0.9);
  stroke-width: 1.1px;
  vector-effect: non-scaling-stroke;
}

.minimaa-piste.nykyinen { fill: #d94f3d; }

.minimaa-nimi {
  fill: #46331f;
  font-family: var(--font-type);
  letter-spacing: 0.04em;
}

/* Passin matkasaalis: laatta ja sen nimi allekkain. */
.passport-finds {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.find {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
  /* Passi on vaaleaa pergamenttia, joten teksti perii dialogin tumman musteen. */
  color: inherit;
}

.find-text { font-variant-numeric: tabular-nums; }

/* Matkan tiedot passissa: selite vasemmalle, luku oikeaan reunaan. */
.find-value {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

/* Matkan mittarit: kokemuspisteet ja tietoprosentti rahan alla. */

/*
 * MATKALAUKKU: NAHKAA JA MESSINKIÄ, EI KATKOVIIVAA.
 *
 * Omistaja 5.8.2026: *"matkalaukun ääriviivat voisi muuttaa
 * toisenlaisiksi. Eli katkoviiva pois ja tilalle enemmän nahkaisen
 * matkalaukun reunat ja alas kahva."*
 *
 * Kortilla oli jo nahkakehys, mutta sen päällä näkyi `.dialog-card`in
 * yhteinen kynämäinen katkoviiva — kaksi eri materiaalia päällekkäin,
 * ja katkoviiva voitti, koska se on terävin. Se piilotetaan tästä
 * kortista (ks. ::before alempana).
 *
 * Nahka syntyy kolmesta asiasta eikä väristä: paksusta reunuksesta,
 * ompeleesta reunuksen sisäpuolella ja kulmien tummumasta. Ommel on
 * katkoviiva sekin, mutta LYHYIN pistoin ja nahkan sisällä — silloin se
 * lukee ompeleeksi eikä piirretyksi rajaksi.
 *
 * VALITSIN ON `.dialog-card.passport-card` EIKÄ `.passport-card`.
 *
 * v282 kirjoitti tämän lyhyellä valitsimella, ja katkoviiva jäi siitä
 * huolimatta näkyviin: `.dialog-card` asettaa oman kynäviivansa ja on
 * tässä tiedostossa MYÖHEMPÄNÄ (rivi ~4250 vs ~2360). Yhtä vahvat
 * valitsimet ratkaistaan järjestyksellä, joten myöhempi voitti.
 * Mitattu selaimesta: kortin reuna oli yhä `dashed 1px`, vaikka tässä
 * lukee `12px solid`.
 *
 * Kahden luokan valitsin on vahvempi eikä riipu järjestyksestä — sama
 * korjaus kestää senkin, että joku siirtää lohkoja.
 */
.dialog-card.passport-card {
  max-width: 520px;
  position: relative;
  /*
   * Kortti on pystyflex, jotta sen ainoa lapsi (.laukku-sisus) kutistuu
   * kortin mittaan ja vierii sen sisällä (omistaja 6.9.2026: "Laukku
   * pitää olla skrollattava myös"). Ilman tätä sisus kasvaa sisällön
   * mittaiseksi ja leikkautuu kortin `overflow: hidden` -kehykseen.
   */
  display: flex;
  flex-direction: column;
  /*
   * NAHKA ON YLÄPALKIN VÄRINEN JA YLÄREUNA PUUTTUU (omistaja 5.8.2026:
   * "laukun reunat voisi olla samalla värillä kuin yläpalkki ja laukun
   * yläreunan voisi ottaa kokonaan pois, niin että näyttäisi että laukku
   * aukeaa suoraan yläpalkista").
   *
   * Väri on sama tumma ruskea kuin palkin liu'un alapää (#251b12), ei
   * entinen vaalea satulanahka: kun kortti on kiinni palkissa, kahden eri
   * ruskean raja piirtäisi juuri sen viivan, jonka on tarkoitus kadota.
   * Yläreunus ja yläkulmien pyöristys ovat pois samasta syystä — laukku
   * jatkaa palkkia eikä ala siitä.
   */
  border: 12px solid #2b2015;
  border-top: 0;
  border-radius: 0 0 12px 12px;
  /*
   * VÄLJEMMÄT SISENNYKSET (omistaja: "nyt teksti ja tavarat ovat liian
   * kiinni reunassa"). Nahkareunus on materiaalia eikä marginaalia:
   * silmä lukee sisällön alkavan vasta sen sisäpuolelta, joten
   * pehmusteen on oltava reunuksen LISÄKSI eikä sen sijasta.
   *
   * PYSTYPEHMUSTE ON SISUKSELLA (.laukku-sisus), ei kortilla: vierivä
   * teksti saa kulkea nahkareunaan asti sen sijaan että katkeaisi
   * pehmusteen kohdalla ja jättäisi tyhjän kaistan reunukseen.
   */
  padding: 0 1.7rem;
  box-shadow:
    /* Ommel: vaalea katkoviiva nahkan sisäreunassa. */
    inset 0 0 0 2px rgba(226, 196, 150, 0.28),
    inset 0 0 0 3px rgba(46, 30, 14, 0.4),
    inset 0 0 30px rgba(88, 58, 28, 0.16),
    0 14px 34px rgba(20, 12, 4, 0.45);
  overflow: hidden;
}

/* Kynämäinen katkoviiva pois: laukku on nahkaa, ei luonnoslehtiö. */
.dialog-card.passport-card::before { display: none; }

/*
 * Messinkiset kulmavahvikkeet. Neljä kolmiota kortin kulmissa —
 * oikeassa laukussa ne suojaavat juuri sen, mihin kolhut osuvat.
 * Piirretty liukuväreillä eikä kuvina, jotta ne skaalautuvat.
 */
.dialog-card.passport-card::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(135deg, rgba(198, 158, 82, 0.85) 0 14px, transparent 14px) left top / 34px 34px no-repeat,
    linear-gradient(225deg, rgba(198, 158, 82, 0.85) 0 14px, transparent 14px) right top / 34px 34px no-repeat,
    linear-gradient(45deg,  rgba(198, 158, 82, 0.85) 0 14px, transparent 14px) left bottom / 34px 34px no-repeat,
    linear-gradient(315deg, rgba(198, 158, 82, 0.85) 0 14px, transparent 14px) right bottom / 34px 34px no-repeat;
  opacity: 0.55;
}

/*
 * KAHVA ALALAITAAN.
 *
 * Kaksi kiinnikettä ja niiden välissä kaari. Kaari on `border-bottom`
 * -reunus pyöristetyssä laatikossa: se on yksi elementti eikä kolme, ja
 * nahkan paksuus tulee samasta luvusta kuin kehyksellä.
 *
 * Kahva on kortin SISÄLLÄ, koska kortilla on `overflow: hidden`
 * (kulmavahvikkeet vaativat sen). Ulkopuolelle roikkuva kahva
 * leikkautuisi pois.
 */
/*
 * AARNIN LUETTELO vihreän passin tilalla.
 *
 * Rivi eikä ruudukko: luettelo on luettelo, ja nimet ovat eri mittaisia
 * (Suuren Zimbabwen kivilintu, Lapin kulta). Ruudukossa lyhyen nimen
 * ympärille jäisi tyhjää ja pitkä katkeaisi.
 */
.laukku-aarteet {
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
}

.aarre-rivi {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.85rem;
  /* Kateissa oleva aarre on himmeä: luettelo kertoo mitä ETSITÄÄN. */
  opacity: 0.62;
}

.aarre-rivi.loytynyt {
  opacity: 1;
  font-weight: 600;
}

.aarre-merkki {
  width: 1em;
  text-align: center;
  color: var(--accent);
}

.aarre-nimi { flex: 1 1 auto; }

.aarre-tila {
  font-family: var(--font-type);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.8;
}

/* Kateissa-rivi on yhteenveto eikä aarre: ei merkkiä, luku oikeaan
   reunaan kuten matkariveillä. */
.aarre-kateissa { opacity: 0.72; }

.aarre-luku {
  margin-left: auto;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}


/*
 * NIMIKILPI SIIRTYI LAUKUSTA LOGOON (omistaja 5.8.2026: "copyright-linkin
 * voisi poistaa matkalaukusta ja siirtää logoon").
 *
 * Laukun alalaidassa oli messinkilaatan näköinen linkki "Matkakirja ©
 * 2026". Se oli piilossa kahden napautuksen takana ja väärässä
 * paikassa: laukku on pelaajan tavaroita varten, ei pelin tekijöitä.
 * Logo on nyt itse se linkki, ja se on aina näkyvissä.
 *
 * Logo on nappi eikä koriste, joten napin oletusasu on purettava —
 * sama tarve kuin radion merkkivalossa, ja sama ansa: pelin yleinen
 * `button { min-height: 42px }` venyttäisi ylärivin korkeutta.
 */
.brand-nappi {
  display: block;
  padding: 0;
  min-height: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Hillitty vihje siitä, että logo on painettava: kirkastuu hieman.
 * Kultafolio ei saa välkkyä kartan päällä, joten muutos on pieni. */
.brand-nappi:hover .brand-kuva,
.brand-nappi:focus-visible .brand-kuva { filter: brightness(1.12); }

.brand-nappi:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Lähdeikkuna: pitkä luettelo, joka luetaan silmäillen. Kortti on
 * tavallinen paperikortti (.dialog-card hoitaa reunan, taustan ja
 * pystyvierityksen), joten täällä säädetään vain sisältöä. */
.lahteet-card {
  /* Rivit ovat pitkiä nimiä; kapeampi kortti katkoisi ne palasiksi. */
  max-width: 620px;
}

/*
 * OTSIKKONA SAMA LOGO, TUMMALLA POHJALLA.
 *
 * Pelaaja napautti logoa ylärivillä, ja ikkuna avautuu siitä mitä hän
 * napautti — se on koko siirron idea.
 *
 * TUMMA LAATTA EIKÄ PERGAMENTTI (omistaja 5.8.2026: "logo saisi olla
 * tummalla pohjalla ennen tekstiä ja vähän pienemmällä"). Kullattu
 * folio on tehty tummaa vasten: pergamentilla se on kulta kullan päällä
 * ja kirjainten ääriviivat katoavat. Laatta on samaa sävyä kuin ylärivi
 * (linear-gradient #3a2a1c -> #251b12), joten logo näyttää täsmälleen
 * siltä, mistä se avattiin.
 *
 * Laatta on kilpi eikä palkki: se päättyy ennen tekstiä ja pyöristyy
 * kulmistaan, jolloin paperi jatkuu sen ympärillä.
 */
.lahteet-nimikilpi {
  margin: -0.2rem 0 1.1rem;
  padding: 0.85rem 1rem;
  text-align: center;
  background: linear-gradient(180deg, #3a2a1c, #251b12);
  border: 1px solid var(--line);
  border-radius: 10px;
}

/*
 * Pienempi kuin ensimmäisessä yrityksessä: 22rem -> 14rem. Laatta antaa
 * logolle oman tilansa, joten sen ei enää tarvitse olla iso ollakseen
 * otsikko. Ylärivillä logo on 23 px korkea, tässä 55 — yhä yli
 * kaksinkertainen, mikä oli alkuperäinen toive ("avautuu isompana").
 */
.lahteet-logo {
  display: block;
  width: 100%;
  max-width: 14rem;
  height: auto;
  margin: 0 auto;
}

.lahteet-sisus {
  font-size: 0.82rem;
  line-height: 1.5;
}

.lahteet-alaotsikko {
  margin: -0.3rem 0 0.6rem;
  font-style: italic;
  color: rgba(70, 51, 31, 0.7);
}

.lahteet-copyright {
  margin: 0 0 0.5rem;
  font-weight: 600;
}

.lahteet-teksti { margin: 0 0 0.5rem; }

.lahteet-sisus h3.lahteet-otsikko {
  margin: 1.1rem 0 0.4rem;
  font-size: 0.9rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border-top: 1px dashed rgba(70, 51, 31, 0.45);
  padding-top: 0.8rem;
}

.lahteet-sisus h4.lahteet-ryhma {
  margin: 1rem 0 0.15rem;
  font-size: 0.85rem;
  letter-spacing: 0.04em;
}

.lahteet-ryhma-johdanto {
  margin: 0 0 0.45rem;
  font-style: italic;
  color: rgba(70, 51, 31, 0.7);
}

.lahteet-lista {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Yksi lähde = yksi lohko, jossa nimi, tekijä ja lisenssi allekkain.
 * Taulukko olisi luettavampi leveällä ruudulla mutta hajoaisi
 * puhelimessa, jolla peliä pelataan. */
.lahteet-lista li {
  margin: 0 0 0.55rem;
  padding-left: 0.7rem;
  border-left: 2px solid rgba(70, 51, 31, 0.22);
}

.lahteet-nimi,
.lahteet-tekija,
.lahteet-lisenssi,
.lahteet-huom {
  display: block;
}

.lahteet-nimi { font-weight: 600; }

.lahteet-tekija {
  font-size: 0.78rem;
  color: rgba(70, 51, 31, 0.8);
}

.lahteet-lisenssi {
  font-size: 0.78rem;
  color: rgba(70, 51, 31, 0.62);
}

/* Kirjaamaton lisenssi erottuu, jottei tyhjää kohtaa lueta vapaudeksi. */
.lahteet-lisenssi.epaselva {
  color: #8a4a1c;
  font-style: italic;
}

.lahteet-huom {
  font-size: 0.76rem;
  font-style: italic;
  color: rgba(70, 51, 31, 0.7);
}

.lahteet-lopetus {
  margin: 1rem 0 0;
  font-size: 0.78rem;
  color: rgba(70, 51, 31, 0.7);
}

/* Tavarat matkamuistoina: isompi kuva ja selite sen alla, rivit
 * täyttyvät vasemmalta oikealle (omistajan toive). */
/*
 * Ei erillistä taustaa (omistaja 13.8.2026: "tavaroiden tausta liian
 * tumma, ei ehkä tarvitse eriväristä taustaa ollenkaan") — 10.8:n
 * tumma samettitarjotin poistettu, tavarat istuvat suoraan laukun
 * paperilla ja selitteet perivät kortin tekstivärin.
 */
/*
 * KOLME TAVARAA RINNAKKAIN (omistajan tilaus 18.8.2026, kuvakaappaus
 * iPhonen pystyasennosta): kiinteä 108 pikselin ruutu mahtui kapealla
 * puhelimella vain kahdesti, ja kolmas putosi omalle rivilleen —
 * laukku venyi pitkäksi juuri kun siihen tuli uusia rivejä.
 *
 * Ruudukko eikä kiertyvä flex-rivi: `repeat(3, minmax(0, 1fr))` jakaa
 * leveyden aina kolmeen yhtä suureen sarakkeeseen, olipa ruutu 320 tai
 * 520 pikseliä leveä. Silloin tavarat myös latautuvat suoriin
 * pystyriveihin sen sijaan että viimeinen rivi jäisi vajaaksi.
 */
#passport-finds {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.7rem 0.5rem;
  align-items: start;
  justify-items: center;
  padding: 0.4rem 0;
}

#passport-finds .find {
  flex-direction: column;
  gap: 0.25rem;
  /*
   * Ruutu on sarakkeensa levyinen, ei kiinteä. Nimet ovat yhdyssanoja
   * ("Topografialinssi", "Vesistölinssi") eikä sanan sisältä löydy
   * katkaisukohtaa, joten pakotettu tavutus (.find-text) on yhä
   * paikallaan — muuten pitkä nimi valuisi naapurin päälle.
   */
  width: 100%;
  text-align: center;
  /*
   * 0,68 -> 0,58 rem. Sarake kapeni kolmanneksella, kun rinnakkain
   * mahtuu kolme; pisin nimi ("Topografialinssi") on kuusitoista
   * merkkiä ja mahtuu kapeaan sarakkeeseen yhdellä rivillä vasta tällä
   * koolla — mitattu 390 px:n puhelimella, jossa sarake on ~100 px.
   */
  font-size: 0.58rem;
  line-height: 1.25;
}

/* Kuva kutistuu sarakkeen mukana: 44 px:n aarrekuvake on kapealla
   puhelimella leveämpi kuin sen sarake. `height: auto` pitää
   kuvasuhteen, koska korkeus tulee elementin omasta attribuutista. */
#passport-finds .find img { max-width: 100%; height: auto; }

#passport-finds .find-text { overflow-wrap: anywhere; }

.passport-count {
  margin: 0.6rem 0 0.4rem;
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
}

/*
 * ── MATKARIVIN AVATAR JA TIETÄJÄNIMIKE ───────────────────────────────
 *
 * Omistajan tilaus 18.8.2026: tietäjäpisteiden riville nykyisen tason
 * MUOTOKUVA (ennen tässä oli pöllön viivakuvake), nimike aina näkyviin
 * pisteiden yhteydessä, sen alle edistymispalkki ja seuraavan tason
 * raja hienovaraisesti. Rivin perässä i-nappi, joka avaa tasogallerian.
 *
 * Kuva on rivin ensimmäinen solu, ei tekstin sisällä: silloin selitteet
 * alkavat samasta kohdasta riippumatta siitä, onko rivillä kuvaa.
 * Kuvattomien rivien sisennys tulee siitä, että ne alkavat suoraan
 * tekstillä — matkalohkossa on vain yksi kuva, eikä sarake saa varata
 * tilaa tyhjänä muilta.
 */
.find-avatar {
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  object-fit: cover;
  /* Ohut messinkireunus: sama kehys kuin muillakin laukun metalliosilla,
     jotta muotokuva istuu nahkaan eikä leiju sen päällä. */
  border: 1px solid rgba(122, 85, 20, 0.55);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  background: rgba(255, 255, 255, 0.35);
}

/*
 * i-NAPPI on rivin viimeinen solu ja lainaa pikkuselosteen asun
 * (button.seloste-nappi, tiedoston lopussa) — samassa laukussa on jo
 * Aarnin luettelon i-nappi, eivätkä kaksi i-nappia saa näyttää
 * kahdelta eri napilta. Tässä vain rivin oma asemointi.
 */
.tietaja-info { flex: 0 0 auto; }

/*
 * EDISTYMISPALKKI: matka nykyisen tason alusta seuraavaan rajaan.
 * Ohut ja kullanvärinen — mittari, ei hälytin. Nollautuu noustessa,
 * eikä ylimmällä tasolla piirretä lainkaan (js/ui.js renderProgress).
 */
.tietaja-palkki {
  height: 0.28rem;
  margin: 0.25rem 0 0.15rem;
  border-radius: 0.2rem;
  background: rgba(70, 51, 31, 0.16);
  overflow: hidden;
}

.tietaja-palkki-tayte {
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--accent-dark, #8a6114), var(--accent, #d9a13b));
  /* Leveys tulee JS:stä; siirtymä tekee laukun uudelleenavaamisesta
     pehmeän ilman erillistä animaatiota. */
  transition: width 400ms ease;
}

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

/* Seuraava taso on vihje eikä mittari: pienempi, himmeämpi ja
   oikeaan reunaan pisteiden alle. */
.tietaja-seuraava {
  margin: -0.05rem 0 0.2rem;
  text-align: right;
  font-size: 0.68rem;
  font-style: italic;
  color: rgba(70, 51, 31, 0.6);
}

/*
 * ── MATKAN TILASTOT VÄKÄSEN ALLA ─────────────────────────────────────
 *
 * Omistaja 6.9.2026: *"Piilota nuo tiedot väkäsen alle."* Laskurit,
 * Aarnin luettelo, tavarat ja julisteet kokoontuvat yhden avattavan
 * lohkon alle; Sijainti, Kukkaro ja tietäjätaso jäävät näkyviin sen
 * yläpuolelle ja Varusteet nousee heti niiden alle.
 *
 * Otsikkorivi on NAPPI, ja `.dialog button` maalaisi siitä
 * pergamenttilaatikon aaltoreunoineen — siksi valitsimessa on kaksi
 * luokkaa (0,2,0), joka voittaa yleissäännön (0,1,1).
 */
.laukku-lohko { margin: 0.2rem 0 0; }

.passport-card .laukku-lohko-otsikko,
.dialog .laukku-lohko-otsikko {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  /* Sormelle riittävä rivi ilman että otsikko kasvaa muita isommaksi. */
  min-height: 44px;
  padding: 0.1rem 0;
  background: none;
  border: 0;
  border-bottom: 1px solid rgba(122, 85, 20, 0.28);
  border-radius: 0;
  box-shadow: none;
  color: var(--accent);
  text-align: left;
  cursor: pointer;
}

.passport-card .laukku-lohko-otsikko:hover,
.dialog .laukku-lohko-otsikko:hover {
  background: none;
  border-bottom-color: rgba(122, 85, 20, 0.5);
}

.passport-card .laukku-lohko-otsikko:focus-visible,
.dialog .laukku-lohko-otsikko:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Otsikkoteksti on sama pieni kapiteeli kuin muillakin osastoilla;
   napin sisällä marginaalit tulevat napilta. */
.laukku-lohko-otsikko .passport-count { margin: 0; }

/*
 * Väkänen on SVG-viiva eikä emoji: emoji vaihtaisi ilmettä laitteesta
 * toiseen eikä ottaisi laukun messingin väriä. Kiinni ollessaan se
 * osoittaa oikealle (›), auki alas (⌄) — kierto, ei kuvanvaihto,
 * jotta liike on jatkuva.
 */
.laukku-vakanen {
  flex: 0 0 auto;
  width: 1.05rem;
  height: 1.05rem;
  color: rgba(122, 85, 20, 0.85);
  transition: transform 260ms cubic-bezier(0.3, 0.9, 0.4, 1);
}

.laukku-lohko-otsikko[aria-expanded='true'] .laukku-vakanen { transform: rotate(90deg); }

/*
 * Avautuminen animoidaan pehmeästi (omistajan pysyvä linjaus: kaikki
 * liike animoidaan). `max-height` saa oikean lukunsa JS:stä
 * (js/ui.js paivitaTilastolohko) ja palautuu `none`:ksi siirtymän
 * jälkeen, jotta myöhemmin latautuva julistevedos ei jää katkolle.
 *
 * `visibility` pitää kiinni olevan lohkon poissa myös näppäimistöltä
 * ja ruudunlukijalta — pelkkä nollakorkeus jättäisi napit fokusjonoon.
 */
.laukku-lohko-sisus {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  visibility: hidden;
  transition:
    max-height 280ms cubic-bezier(0.3, 0.9, 0.4, 1),
    opacity 200ms ease,
    visibility 0s linear 280ms;
}

.laukku-lohko-sisus.auki {
  opacity: 1;
  visibility: visible;
  transition:
    max-height 280ms cubic-bezier(0.3, 0.9, 0.4, 1),
    opacity 220ms ease 60ms,
    visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .laukku-vakanen,
  .laukku-lohko-sisus,
  .laukku-lohko-sisus.auki { transition: none; }
}

/*
 * ── VARUSTEET MATKALAUKUSSA ──────────────────────────────────────────
 *
 * Valitsin muutti hampurilaisvalikosta laukkuun 18.8.2026. Paneeli oli
 * valikossa pudotusvalikon kuori (absoluuttinen asemointi, oma tumma
 * tausta, varjo); laukussa se on osasto muiden joukossa, joten kuori
 * puretaan ja ruudukko istuu suoraan laukun paperille.
 *
 * KUVANAPIT NELIÖIDEN TILALLE (omistaja 18.8.2026: "Nuo graafisemmat
 * ovat parempia"). Napit ovat samoja pyöreitä varustekuvia kuin
 * Tavarat-ruudukon aarteet, kolme riviin kuten Tavaroissa, ilman
 * nimilappua — nimi ja kuvaus tulevat valittaessa .linssi-tiedot-
 * lohkoon ruudukon alle. Nappi itsessään on pelkkä ympyrä: reunus
 * tulee kuvan omasta kehyksestä (.aarre-ikoni) ja valinta piirretään
 * messinkirenkaana napin ympärille.
 */
.passport-card .linssi-kotelo { position: static; }

.passport-card .linssi-valikko {
  position: static;
  width: auto;
  max-width: none;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

.passport-card .linssi-valikko .linssi-liuskat {
  /* Sama kolmen sarakkeen jako kuin #passport-finds-ruudukossa. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  justify-items: center;
  align-items: center;
  gap: 0.7rem 0.5rem;
  padding: 0.4rem 0 0.7rem;
  /* Laukku on vaaleaa pergamenttia: erotinviiva on mustetta, ei
     tumman paneelin vaaleaa reunaa. */
  border-bottom-color: rgba(70, 51, 31, 0.28);
}

/*
 * Leveä ruutu (omistaja 18.8.2026): "isoisän matkalaukku voisi olla
 * iPadille hieman kapeampi. Ja varusteet voisi latoa neljä per rivi.
 * nyt vähän tyhjäkäyntiä visuaalisesti" — ja tarkennus: "iphonella
 * kolme per rivi on hyvä". Kapea ruutu pitää siis 520 px:n katon ja
 * kolme saraketta; leveällä laukku kapenee ja varusteet tiivistyvät
 * neljään.
 */
@media (min-width: 700px) {
  .dialog-card.passport-card { max-width: 470px; }

  .passport-card .linssi-valikko .linssi-liuskat {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/*
 * Nappi on pyöreä ja kuvansa kokoinen: neliön reunat ja paneelitausta
 * pois, jotta ruudukossa on vain esineitä eikä laatikoita. 64 px on
 * reilusti kosketuskohteen minimin yli ja mahtuu kolmen sarakkeeseen
 * kapeimmallakin puhelimella (sarake on ~100 px 390 px:n ruudulla).
 */
.passport-card .linssi-valikko .linssi-liuskat button {
  aspect-ratio: 1;
  width: 64px;
  max-width: 100%;
  display: grid;
  place-items: center;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 50%;
  color: #46331f;
}

.passport-card .linssi-valikko .linssi-liuskat button img.aarre-ikoni {
  width: 100%;
  height: 100%;
}

.passport-card .linssi-valikko .linssi-liuskat button:hover {
  background: none;
  color: #46331f;
  box-shadow: 0 0 0 2px rgba(122, 85, 20, 0.35);
}

/*
 * "Ei linssiä" ei ole valokuva vaan viivakuvake: se saa oman pyöreän
 * pergamenttikiekkonsa samalla kehysrenkaalla kuin varustekuvat
 * (.aarre-ikoni-varjo), jotta rivi pysyy yhtenäisenä.
 */
.passport-card .linssi-valikko .linssi-liuskat button[data-linssi=''] {
  background: rgba(252, 241, 212, 0.55);
  box-shadow: 0 0 0 1.5px rgba(94, 74, 47, 0.55);
}

.passport-card .linssi-valikko .linssi-liuskat button[data-linssi='']:hover {
  background: rgba(252, 241, 212, 0.9);
  box-shadow: 0 0 0 2px rgba(122, 85, 20, 0.45);
}

/* Valittu varuste saa selvän messinkirenkaan (sama sävymaailma kuin
   aktiivinapeissa): sisempi tumma messinki ja ulompi vaalea hohde. */
.passport-card .linssi-valikko .linssi-liuskat button.paalla {
  background: none;
  color: #46331f;
  box-shadow: 0 0 0 2.5px rgba(122, 85, 20, 0.9), 0 0 0 5.5px rgba(198, 158, 82, 0.35);
}

.passport-card .linssi-valikko .linssi-liuskat button[data-linssi=''].paalla {
  background: rgba(252, 241, 212, 0.9);
}

/*
 * Napautettu varuste, jota ei ole vielä aktivoitu: ohut messinkiviiva
 * ilman messinkirengasta. Ero päällä olevaan (2,5 px + hohde) on
 * tarkoituksella selvä — rengas kuuluu vain kartalla olevalle
 * linssille. Siirtymä pitää valinnan pehmeänä sormen alla.
 */
.passport-card .linssi-valikko .linssi-liuskat button {
  transition: box-shadow 180ms ease;
}

.passport-card .linssi-valikko .linssi-liuskat button.esikatselu:not(.paalla) {
  box-shadow: 0 0 0 1.5px rgba(122, 85, 20, 0.55), 0 0 0 4px rgba(198, 158, 82, 0.18);
}

@media (prefers-reduced-motion: reduce) {
  .passport-card .linssi-valikko .linssi-liuskat button { transition: none; }
}

/* Valitun varusteen nimi ja kuvaus liuskojen alla: keskitetty kuten
   tavaroiden selitteet, ja laukun oma muste. */
.passport-card .linssi-tiedot { padding-top: 0.6rem; text-align: center; }
.passport-card .linssi-nimi { color: #46331f; }
.passport-card .linssi-lyhyt { color: rgba(70, 51, 31, 0.85); }

/* Laukku on pergamenttia: "aktivoi" saa saman tumman kullan kuin muut
   pergamentin tekstilinkit (.wiki-btn), ei paneelin vaaleaa aksenttia. */
.passport-card .linssi-aktivoi { color: #7a5514; }

.passport-card .linssi-aktivoi:hover:not(:disabled),
.passport-card .linssi-aktivoi:focus-visible { color: #9c6f1e; }


/*
 * Leimaruudukko poistettu v282:ssa yhdessä vihreän passin kanssa.
 * `.stamp` jää, koska tapahtumakupla käyttää sitä (.event-toast.stamp).
 */
.stamp {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.55rem 0.5rem;
  /* Dialogi on vaaleaa pergamenttia, joten leiman muste on tummanvihreää. */
  border: 2px solid rgba(58, 102, 48, 0.7);
  border-radius: 6px;
  background: rgba(120, 168, 108, 0.16);
  color: #35602c;
  text-align: center;
  /* Leimasin ei osu koskaan aivan suoraan. */
  transform: rotate(-1.5deg);
}

.stamp-label {
  font-family: var(--font-type);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.stamp-date {
  font-family: var(--font-type);
  font-size: 0.68rem;
  opacity: 0.85;
  font-variant-numeric: tabular-nums;
}

.event-toast.stamp {
  /* Leimakupla on tavallinen tapahtumakupla, ei passin leima. */
  transform: none;
  border-color: rgba(120, 168, 108, 0.55);
  background: var(--overlay-card);
  color: var(--ink-light);
  text-align: left;
}

/* --- tiesitkö että --- */

.fact-card {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-color: #55402a;
  background:
    linear-gradient(180deg, rgba(217, 161, 59, 0.07), rgba(0, 0, 0, 0)) ,
    var(--panel);
}

/*
 * OTSIKKORIVI VARAA TILAN KAIUTTIMELLE (omistajan bugiraportti
 * 28.8.2026 iPhonesta: kuvake istui merkinnän paikkarivin päällä,
 * "762":n kohdalla).
 *
 * Kaiutin on kortin oikeassa yläkulmassa absoluuttisesti aseteltuna
 * (.fact-kuuntele), joten se ei itse varaa tilaa asettelusta. Rivin
 * mitat annetaan siis TÄSSÄ, ja ne on sidottu samaan --kaiutin-koko
 * -mittaan kuin nappi:
 *  - line-height: kuvakkeen korkuinen rivilaatikko, joten nappi mahtuu
 *    kokonaan otsikkorivin kohdalle eikä ylety paikkariville;
 *  - padding-inline-end: kuvakkeen leveys + väli, joten pitkäkään
 *    otsikko ei mene kuvakkeen alle millään ruudunleveydellä.
 * Kirjasinkoko vaihtuu ruudun mukaan (media-lohko), rivimitta ei —
 * kuvake on molemmilla sama.
 */
.fact-card h2 {
  margin: 0 0 0.35rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  line-height: var(--kaiutin-koko);
  padding-inline-end: calc(var(--kaiutin-koko) + 0.4rem);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--accent);
}

.fact-place {
  margin: 0 0 0.25rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/*
 * YHDEN RIVIN LAPUN OMA PAIKKARIVI (omistajan pelitestipalaute v1119:
 * *"kun laatikko pienenee yhdelle riville, rivillä saa näkyä VAIN
 * otsikko ja kaupungin nimi — ei päivämäärää, säätä eikä tekstin
 * alkua"*).
 *
 * Auki kortissa tämä on poissa: siellä paikkarivi on merkinnän oma
 * kohtausrivi (#fact-place). Kutistuessa ne vaihtavat paikkaa —
 * teksti ei siis lyhene leikkaamalla, vaan lapussa on oma lyhyt
 * muotonsa (js/ui.js asetaPaikkarivi).
 */
.fact-place-lyhyt { display: none; }

.fact-text {
  margin: 0;
  overflow-y: auto;
  min-height: 0;
  flex: 1 1 auto;
  font-size: 0.9rem;
  line-height: 1.45;
  color: var(--ink-light);
  -webkit-overflow-scrolling: touch;
}

/* Isoisän aikataulurivi matkakirjamerkinnän perässä: oma pieni
 * konekirjoitusrivinsä, joka ei peitä merkintää. */
.aikataulu-rivi {
  display: block;
  margin-top: 0.45rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  line-height: 1.4;
  color: rgba(90, 74, 51, 0.95);
}

.aikataulu-rivi b { font-weight: 700; }

/* Lähdeviite: pieni ja vaatimaton, mutta aina saatavilla. */
.source-line {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.78rem;
  color: var(--muted);
}

.source-line .source-label {
  margin-right: 0.3rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.68rem;
  opacity: 0.75;
}

.source-line a { color: inherit; text-decoration: underline dotted; }
.source-line a:hover { color: var(--accent); }

/* Pergamenttilaatikossa lähde on mustetta, ei vaaleaa tekstiä. */
.quiz-result .source-line { color: #7a6039; }
.quiz-result .source-line a:hover { color: var(--mark); }

/* Uusi tieto häivähtää esiin, jotta vaihdoksen huomaa. */
.fact-text.fact-in { animation: fact-in 0.45s ease-out both; }

@keyframes fact-in {
  from { opacity: 0; transform: translateY(5px); }
}

/* --- kartta --- */

.paper { fill: url(#paper-grad); }
/* Rakeisuus on nyt valmiiksi piirretty laatta (js/mapart.js grainTile),
   ei elävä suodatin. Sekoitustila saa jäädä: pelkkä multiply ilman
   suodatinta on halpa. */
.grain { opacity: 0.5; mix-blend-mode: multiply; pointer-events: none; }

/*
 * Linssikerros (js/linssit/kerros.js).
 *
 * Kerros on tyhjä ja näkymätön, kunnes linssi sytytetään. Siirtymä on
 * ainoa liike, jonka linssi saa tehdä: mitattu 15 fps vastaan 60 fps,
 * kun kartan päällä on jatkuvasti muuttuva elementti (js/ui.js
 * 7529–7534). Tämä laukeaa kerran vaihdossa ja jää sitten paikalleen.
 *
 * Sisällön värit EIVÄT tule täältä vaan elementeiltä itseltään:
 * rasteroitava linssi on irrallinen SVG eikä peri tätä tiedostoa.
 */
.linssi { pointer-events: none; transition: opacity 0.22s ease-out; }

/*
 * Paperin rakeisuus pois valokuvalinssin päältä.
 *
 * rect.grain on juuriryhmässä kaupunkien jälkeen ja sekoittuu
 * kertolaskulla, joten se jää linssin päälle. Piirretylle linssille se
 * on hyväksi — se sitoo linssin samaan karttaan eikä näytä päälle
 * liimatulta — mutta valokuva (yökartta) himmenisi sen alla ruskeaksi.
 * Malli on sama kuin lennon ajaksi tehty poisto alempana.
 */
body.linssi-valokuva .grain { display: none; }

/*
 * VESISTÖLINSSI: KAUPUNGIT TAKA-ALALLE, VEDEN NIMET ETEEN.
 *
 * Omistaja 5.8.2026: *"kaupunkien tekstit voisi laittaa haaleammalla ja
 * kaupunkien pallot myös, mutta jokien nimet saisi näkyä tummemmalla."*
 *
 * Miksi tämä on CSS eikä linssin oma piirto: kaupungit ja maastonimet
 * ovat linssin YLÄPUOLELLA kartan omassa puussa (js/ui.js — `cities`
 * luodaan linssikerroksen jälkeen, `maastonimet` on suoraan <svg>:n
 * lapsi). Linssi ei siis voi himmentää niitä piirtämällä, ja
 * sopimuksen mukaan se ei saa antaa elementeille luokkia. Sävy on
 * näkymän ominaisuus, ja näkymä merkitään body-luokalla
 * (js/linssit/kerros.js merkitseLuokat).
 *
 * Peittävyys eikä väri: nimessä on paperinvärinen ulkoviiva
 * (paint-order: stroke), ja pelkkä täytön haalistus jättäisi viivan
 * kellumaan ilman tekstiä.
 */
body.linssi-vesistot .cities .city-label,
body.linssi-vesistot .karttanimi-kaupunki,
body.linssi-vesistot .karttamerkki { opacity: 0.34; }
body.linssi-vesistot .cities .city,
body.linssi-vesistot .cities .city-start,
body.linssi-vesistot .cities .city-gate,
body.linssi-vesistot .cities .airport,
body.linssi-vesistot .cities .coast-soft { opacity: 0.38; }
/* Veden nimet täyteen mustepeittoon: ne ovat tämän näkymän asia. */
body.linssi-vesistot .maastonimi-joki .maastonimi-teksti,
body.linssi-vesistot .maastonimi-jarvi .maastonimi-teksti {
  fill: rgba(20, 44, 68, 0.98);
}

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

/*
 * Linssin selitekortti kartan nurkassa (suunnitelman luku 5.2).
 *
 * Kortti nojaa .event-toastin pergamenttiin: läpikuultava tumma pohja
 * ja kultainen reuna, jotta värilaput luetaan sekä meren että
 * mantereen päältä. Se on tavallista DOM:ia kartan päällä eikä SVG:tä,
 * joten kierron <use>-kopio ei monista sitä eivätkä napautukset mene
 * kartan läpi.
 *
 * Nurkan valitsee js/ui.js sijoitaLinssiSelite: aina se, jossa
 * päiväkirja ei ole.
 */
.linssi-selite {
  position: absolute;
  z-index: 4;
  width: min(240px, 52%);
  /* Vyöhykelinssillä voi olla toistakymmentä riviä (topografiassa 12).
     Kortti ei saa kasvaa yli puolen ruudun: kartan pitää jäädä näkyviin
     sen vierestä. Sama dvh-mitta kuin päiväkirjalla — iPadin Safari ei
     soveltanut prosenttirajaa. */
  max-height: 46vh;
  max-height: 46dvh;
  overflow-y: auto;
  padding: 0.5rem 0.65rem;
  background: var(--overlay-card);
  border: 1px solid var(--overlay-line);
  border-radius: 12px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
  color: var(--ink-light);
  font-size: 0.76rem;
  line-height: 1.4;
  animation: card-in 0.32s cubic-bezier(0.2, 1.2, 0.5, 1);
  transition: max-height 260ms ease, padding 260ms ease;
}

.linssi-selite[data-corner='tl'] { top: 0.5rem; left: 0.5rem; }
.linssi-selite[data-corner='tr'] { top: 0.5rem; right: 0.5rem; }
.linssi-selite[data-corner='bl'] { bottom: 0.9rem; left: 0.5rem; }
.linssi-selite[data-corner='br'] { bottom: 0.9rem; right: 0.5rem; }

.linssi-selite h2 {
  margin: 0 0 0.35rem;
  font-family: var(--font-type);
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent);
}

/*
 * Linssin nimi on painike, ei pelkkä otsikko: kutistettuna se on ainoa
 * näkyvä osa selitettä, ja aria-expanded kertoo apuvälineelle kumpi
 * tila on päällä. Ulkonäkö on tarkalleen entinen otsikkorivi — kaikki
 * napin oletukset (pehmuste, kehys, 42 px korkeus) otetaan pois.
 */
.linssi-selite-nappi {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  min-height: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: left;
  cursor: pointer;
}

.linssi-selite-nappi:hover:not(:disabled) { background: none; }

/*
 * --- kutistettu selite (.pieni) --------------------------------------
 *
 * Omistajan toive 4.8.2026: "samoin topografian selitykset — kummankin
 * voisi avata klikkaamalla suuremmaksi." Kutistettuna jäljellä on vain
 * linssin nimi; värilaatikot, askelliuskat ja muut rivit jäävät
 * leikkautuvan reunan alle ja häipyvät ennen sitä.
 *
 * Kortin pehmuste siirtyy kutistettuna nappiin, jolloin koko lappu on
 * yhtä napautuspintaa eikä nappi jää keskelle kehystä.
 */
.linssi-selite.pieni {
  /* Nimirivi (1.4 × 0.76rem) + napin pehmuste + kortin kehys. */
  max-height: calc(1.4 * 0.76rem + 0.8rem + 2px + 1px);
  padding: 0;
  overflow: hidden;
  width: max-content;
  max-width: min(240px, 52%);
}

.linssi-selite.pieni h2 { margin: 0; }

.linssi-selite.pieni .linssi-selite-nappi {
  padding: 0.4rem 0.65rem;
  /* Nimi pysyy yhdellä rivillä myös silloin, kun jonkin tulevan linssin
   * nimi on pitkä: toinen rivi jäisi korkeusrajan alle piiloon. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Siirtymä perusluokassa, jotta se pätee molempiin suuntiin. */
.linssi-selite > *:not(h2) { transition: opacity 160ms ease; }

.linssi-selite.pieni > *:not(h2) {
  opacity: 0;
  pointer-events: none;
}

.linssi-selite-rivit {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.18rem;
}

.linssi-selite-rivit li { display: flex; align-items: center; gap: 0.4rem; }

/* Värilappu on aineiston oma väri, joten sen asettaa js/ui.js. */
.linssi-lappu {
  flex: 0 0 auto;
  width: 0.8rem;
  height: 0.8rem;
  border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, 0.35);
}

.linssi-askel-otsikko {
  margin: 0.5rem 0 0.15rem;
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Askelliuskat ovat samat kuin valitsimessa, vain tekstillä: aikataso
   vaihtuu pelaajan komennolla eikä ajastimella (riski 12). */
.linssi-selite .linssi-liuskat { border-bottom-color: var(--overlay-line); }
.linssi-selite .linssi-liuskat button {
  padding: 0.22rem 0.45rem 0.55rem;
  font-family: var(--font-type);
  font-size: 0.72rem;
}

.linssi-selite-lahde {
  margin: 0.5rem 0 0;
  font-size: 0.68rem;
  line-height: 1.35;
  color: var(--muted);
}

/*
 * Kutistuminen ja avautuminen ovat pehmeitä vain sille, joka haluaa
 * liikettä: liikeherkälle molemmat tapahtuvat kertaheitolla. Tila
 * vaihtuu silti tarkalleen samoin, vain ilman liukua.
 */
@media (prefers-reduced-motion: reduce) {
  .linssi-selite { animation: none; }
  .linssi-selite,
  .linssi-selite > *:not(h2),
  body[data-mode] .fact-card,
  .fact-card > *:not(.fact-place-lyhyt) { transition: none; }
}

.graticule { stroke: #9d8253; stroke-width: 1; opacity: 0.28; fill: none; }

.sea-echo { fill: none; stroke: #b99a68; stroke-linejoin: round; }
.sea-echo-1 { stroke-width: 46; opacity: 0.17; }
.sea-echo-2 { stroke-width: 26; opacity: 0.2; }
.sea-echo-3 { stroke-width: 10; opacity: 0.26; }

.land { fill: url(#land-grad); }
.lake { fill: #ecd9ae; }

/*
 * Maasto: korkeusvyöhykkeet, järvet ja joet.
 *
 * Omistaja: "Vuorien näkyvyys voisi kuitenkin olla hillitty." Siksi
 * vyöhykkeet ovat läpikuultavia eivätkä peittäviä — pergamentin
 * rakeisuus ja maan oma liukuväri näkyvät läpi, ja vuoristo lukee
 * sävynä eikä uutena karttana kartan päällä.
 *
 * Ääriviivaa ei ole. Korkeusvyöhykkeen raja on sopimus eikä rantaviiva,
 * eikä siitä pidä tulla yhtä terävää kuin mantereen reunasta.
 */
/*
 * Reunaviivattomuus sanotaan VYÖHYKKEILLE, ei koko kerrokselle.
 *
 * Tässä luki ennen `.maasto path { stroke: none; }`. Se on kahden
 * osan valitsin (luokka + elementti) ja voittaa siksi jokaisen yhden
 * luokan säännön — myös `.joki`-viivan oman värin. Seuraus: joet
 * piirtyivät kartalle mutta ilman viivaa, eli eivät näkyneet
 * KOSKAAN. Vika ei näkynyt mistään: elementit olivat DOMissa, testit
 * menivät läpi, ja puuttuvaa jokea ei osaa kaivata ennen kuin
 * huomaa, ettei Mississippiä ole.
 *
 * Nyt sama asia sanotaan niille kolmelle luokalle, joita se koskee.
 * Pidempi mutta ei salakavala: uusi viivallinen muoto ei voi enää
 * kadota siksi, että joku muu sääntö sattuu olemaan tarkempi.
 */
.korkeus-keski,
.korkeus-ylos,
.korkeus-huippu,
.iso-jarvi { stroke: none; }
/*
 * VYÖHYKKEET LÄMPENEVÄT YLÖSPÄIN.
 *
 * Omistaja 4.8.2026: "Kartta saisi olla lämpimämmän näköinen
 * kauttaaltaan. Korkeusero lisäys teki kartasta nyt liian harmaan
 * vihertävän peruskorkeudeltaan. Eli peruskorkeuden väri saisi olla
 * sama kuin mikä oli ennen korkeuserojen käyttöönottoa kartan väri ja
 * siitä ylöspäin mentäessä värit tulisivat tummemmiksi ja punaisen
 * ruskeammiksi."
 *
 * Vanhat sävyt olivat oikeansuuntaisia mutta vääränlämpöisiä: #c9a86e
 * ja #a8823f ovat keltavihreän puolella (vihreän osuus suurempi kuin
 * punaisen ja sinisen väli antaisi olettaa), ja haaleana paperin päällä
 * ne veivät koko maan oliivin suuntaan. Nyt sama vaaleusporrastus mutta
 * punaisen ruskean suuntaan käännettynä. Alanko ei saa vyöhykettä
 * lainkaan, joten sen väri on tasan sama kuin ennen korkeuseroja:
 * pelkkä land-grad (mapart.js #e7d2a4 -> #d2b47e).
 */
.korkeus-keski { fill: #c69257; opacity: 0.3; }
.korkeus-ylos { fill: #a2603a; opacity: 0.34; }
/*
 * Lumi on VAALEA SÄVY, ei valkoinen täyttö.
 *
 * Alkuperäinen #f6f1e6 oli sekä vaaleampi että harmaampi kuin paperi,
 * joten se ei näyttänyt lumelta vaan siltä että kartasta puuttuu pala
 * (omistajan havainto: "Himalaja näyttää reiältä kartalla"). Sepia-
 * kartalla ei ole valkoista — vaalein sävy on paperi itse, ja mikä
 * tahansa sitä vaaleampi luetaan aukoksi.
 *
 * Siksi sävy on lämmin ja paperin puolella: se vaalenee ruskeasta
 * ylöspäin mutta pysyy saman perheen värinä. Toinen puoli korjausta on
 * aineistossa: lumiraja nostettiin 4000 metristä 5000 metriin, jolloin
 * Tiibetin ylätasanko jäi ruskeaksi ja vaalea sävy kutistui
 * harjanteeksi. Läiskä näytti reiältä, nauha näyttää vuorelta.
 */
.korkeus-huippu { fill: #f0e3c6; opacity: 0.55; }

/*
 * Varjostus: sama seepia, mutta maasto alkaa näyttää maastolta.
 *
 * Omistaja 4.8.2026: "täysväri siihen linssiin, mutta pidetään seepia
 * normaalissa pelinäkymässä, ja sitä voi HIEMAN kehittää vielä noiden
 * mainitsemieni varjostusten ja muiden avulla."
 *
 * --- miksi tämä ei ole uusi väri ---
 *
 * Varjo ei tuo kartalle mitään uutta sävyä. Se on sama ruskea muste
 * kuin korkeusvyöhykkeillä ja sama lämmin paperinvalkoinen kuin
 * lumella (.korkeus-huippu), vain hyvin haaleana. Kartta ei siis saa
 * uutta ilmettä — nykyiset vyöhykkeet saavat suunnan.
 *
 * --- miksi läpinäkyvyys eikä tummempi väri ---
 *
 * Voimakkuutta säädetään TÄSSÄ eikä varjostuksen liioittelukertoimessa
 * (tools/varjostus.mjs). Syy on että leikkautunut varjo pysyy
 * leikkautuneena, vaikka sen piirtäisi kuinka haaleana: liian suuri
 * kerroin painaa jyrkimmät rinteet nollaan, jolloin muoto muuttuu
 * reiäksi eikä sitä saa enää takaisin millään opacityllä.
 *
 * --- miksi varjo on vahvempi kuin valo ---
 *
 * Seepiakartan vaalein sävy on paperi itse, eikä sitä vaaleampaa ole
 * (sama syy kuin lumella: liian vaalea luetaan reiäksi kartassa).
 * Valolla on siis vain hitunen matkaa, varjolla koko musteen matka.
 * Aineistossa sama epäsymmetria on jo valmiina: varjo leikkautuu
 * nollaan ja valo ykköseen, joten varjon puoli ulottuu kolme kertaa
 * kauemmas tasaisesta.
 *
 * Ääriviivaa ei ole. Varjolla ei ole rajaa maastossakaan.
 */
.varjo-1,
.varjo-2,
.valo-1 { stroke: none; }
/*
 * Luvut on mitattu eikä arvattu. Vertailukuvat samasta Himalajan
 * näkymästä, kun varjostus on kytketty pois ja päälle (900 x 700 px,
 * suurin yksittäisen pikselin muutos 255-asteikolla):
 *
 *     varjo   valo   suurin muutos   keskimäärin
 *      0,09   0,16         22            2,4
 *      0,14   0,24         30            3,6
 *      0,20   0,32         39            4,9
 *      0,28   0,42         47            6,3
 *
 * 0,09 oli kirjaimellisesti liian hienovarainen: ero näkyy mittarissa
 * muttei silmässä, ja näkymätön muutos on turha muutos. 0,28:ssa
 * vuoristot alkavat olla kartan pääasia. 0,20 on se kohta, jossa
 * Andit, Kalliovuoret ja Tiibet erottuvat yleiskuvassa muodoiksi mutta
 * kartta on yhä sama seepiakartta.
 *
 * varjo2 piirtyy varjo1:n PÄÄLLE, joten syvin varjo on 0,36 eikä 0,20.
 */
/*
 * Varjon sävy käännettiin lämpimäksi samasta syystä kuin vyöhykkeiden.
 * #6a5836 on oliivinruskea, ja koska varjo peittää lähes kaiken maan
 * jolla on rinnettä, se vei koko kartan harmaanvihreään. #6b4529 on
 * saman tummuinen mutta punaisen ruskean puolella.
 */
.varjo-1 { fill: #6b4529; opacity: 0.26; }
.varjo-2 { fill: #6b4529; opacity: 0.26; }
.valo-1 { fill: #fff2d4; opacity: 0.4; }

/*
 * Vesi on yhtä sävyä koko kartalla, eikä se sävy ole sininen.
 *
 * Omistaja 4.8.2026: "Järvet ja joet pitää olla meren kanssa saman
 * sävyisiä. Ota sininen pois."
 *
 * Meri ei ole tällä kartalla väri vaan PAPERI: mantereet on sävytetty
 * ja meri jää pohjaksi. Järvi on siis meri maan sisällä, ja oikea
 * täyttö on sama paperi — täsmälleen kuten pienillä järvillä jo on
 * (.lake, rantaviiva-aineistosta). Sininen täyttö teki suurista
 * järvistä kartalle liimatun tarran, koska mikään muu kartalla ei ole
 * sinistä.
 */
.iso-jarvi { fill: #ecd9ae; }
.iso-jarvi-reuna { fill: none; stroke: var(--sea-ink); stroke-width: 1.4; opacity: 0.5; }

/*
 * Pääjoki järven väreissä (omistajan toive 10.8.2026: "samalla
 * tavalla ja värillä kuin järvet"). Uoma on järven paperitäyttö
 * viivana, ja sen alla leveämpi reunaveto järven reunaviivan
 * musteella ja peitolla: näkyviin jää 1,4 yksikön ranta kummallakin
 * puolella — sama kuin .iso-jarvi-reuna. Täyttö ja viiva sanotaan
 * kummallekin luokalle erikseen (ks. reunaviivattomuus-oppi yllä).
 */
.iso-joki {
  fill: none;
  stroke: #ecd9ae;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/*
 * Kapea ja peittävä reuna (omistajan kalibrointipyyntö 10.8.2026:
 * "joet näyttävät menevän pehmeämmin kuin järven reuna"). Järven
 * reunaviiva istuu kahden täytön terävällä rajalla; joen reunaveto
 * taas sulaa maastoon, jos se on leveä ja puoliksi läpinäkyvä.
 * Kapeampi kaistale (0,7/puoli) ja korkeampi peitto piirtyvät
 * samalla terävyydellä kuin järven raja.
 */
.iso-joki-reuna {
  fill: none;
  stroke: var(--sea-ink);
  stroke-width: 3.6;
  opacity: 0.72;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/*
 * Joki vaaleampana kuin meren aallot (omistajan toive 4.8.2026).
 *
 * Sama sävyperhe kuin muullakin vedellä, mutta vaaleampi: joki on
 * kartan hennoin viiva, ja täysi musteen voima teki siitä yhtä
 * painavan kuin rantaviiva. Lähellä joki saa oman uomansa
 * (.lahivesi-uoma), joten tämän ei tarvitse kantaa kuin yleisvaikutelma.
 */
.joki {
  fill: none;
  stroke: #8e836d;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.6;
}
/*
 * Maastonimet: joet, järvet ja vuoristot kaunokirjoituksella.
 *
 * KOLME ASIAA, JOTKA TÄSSÄ ON PAKKO SANOA ÄÄNEEN.
 *
 * 1. SAMA KÄSIALA KUIN MAAN NIMESSÄ. Fontti tulee muuttujasta
 *    --font-kauno, jota myös .country-name ja lentokalvon merkinnät
 *    käyttävät. Kaksi eri kaunoa samalla kartalla näyttää virheeltä.
 *
 * 2. TÄYTTÖ JA VIIVA SANOTAAN ERIKSEEN JOKAISELLE LUOKALLE.
 *    Naapurissa (.maasto) on kirjattu, mitä tapahtui kun
 *    `.maasto path { stroke: none; }` voitti `.joki`-säännön: kaikki
 *    169 jokea olivat näkymättömiä kuukausia, elementit olivat DOMissa
 *    ja testit vihreinä. Nimikerroksessa on <text>, <circle> ja
 *    <textPath> sisäkkäin, joten sama ansa on täällä auki: yhden
 *    ryhmäsäännön sijaan jokainen muoto saa oman.
 *
 * 3. EI SUODATTIMIA EIKÄ VARJOJA. Sama iOS-sääntö kuin muulla
 *    kartalla: suodatettu kerros palaa taustalta tyhjänä.
 *
 * Kerros ei ota napautuksia vastaan — muuten nimi söisi kartan oman
 * napautuszoomauksen. Poikkeus on i-ikoni, joka palauttaa ne itselleen.
 */
/* ---------------------------------------------------------------------------
   PYRAMIDILAUDAN PAIKANNIMET — RUUTUAVARUUDESSA (omistaja 30.8.2026)
   ---------------------------------------------------------------------------
   Kaupunkien, vuorten ja järvien nimiöt ja merkit poistuivat laatoista,
   koska poltettu nimi on laitepikseleissä ja siksi iPadilla kolmasosan
   kokoinen (js/karttanimet.js). Ladonta on siirretty peliin
   sellaisenaan; nämä säännöt vain antavat sille laattojen ulkoasun.

   KOKO EI OLE TÄÄLLÄ. font-size tulee elementiltä laudan yksiköissä
   (koko / skaala), jotta nimi on aina se sama määrä CSS-pikseleitä.
   Tyylitiedostoon kirjattu koko jäätyisi yhteen mittakaavaan.

   HARVENNUS EI OLE TÄÄLLÄ, JA SE ON MITTA EIKÄ MAKU. Pääkaupungin nimi
   ladotaan harvennetuin kapiteelein (aikakauden atlaskonventio,
   js/karttanimet.js PAAKAUPUNGIN_ASU), ja sekä `font-variant` että
   `letter-spacing` tulevat elementiltä — samasta luvusta, jolla ladonta
   mittasi nimen laatikon. Tyylitiedostoon kirjattu harvennus ei voisi
   olla mitasta tietoinen, ja nimet menisivät päällekkäin.

   TÄSSÄ LOHKOSSA OLI `letter-spacing: normal`, JA SE OLI ANSA. Mikä
   tahansa CSS-sääntö voittaa SVG:n esitysmääreen, joten se sammutti
   ladonnan oman harvennuksen kokonaan (mitattu Chromiumilla: kapiteeli
   *"Lontoo"* pysyi 35,19 pikselissä, vaikka määre pyysi 45,3).
   Harvennusta ei siis saa asettaa täällä kummallakaan arvolla — ei
   edes oletuksena.
   --------------------------------------------------------------------------- */
.karttanimet { pointer-events: none; }

/*
 * KOHTEEN NIMI ON NAPAUTETTAVA KOKONAAN (omistaja 1.9.2026 ilta:
 * "Saisiko karttanostoissa myös tekstit kokonaisuudessa
 * klikattaviksi?"). Kerros pysyy muuten mykkänä; vain kohdenimet
 * ottavat tapahtumia, ja napautus avaa kohteen kortin
 * (js/karttanimet.js kerroksen kuuntelija -> js/fokuskohteet.js).
 */
.karttanimet .karttanimi-kohde[data-kohde] {
  pointer-events: auto;
  cursor: pointer;
}
/*
 * MAASTONIMI JA SEN KOLMIO OTTAVAT NAPAUTUKSIA SAMALLA SÄÄNNÖLLÄ
 * (omistaja 2.9.2026: "Dinaariset Alpit mitä ei voi klikata").
 * Nimi on iso maali, kolmiolla on oma läpinäkyvä ympyränsä
 * (js/karttanimet.js MAASTON_OSUMA_R) — maalaamaton muoto ei ottaisi
 * osumia vastaan, joten `fill` on läpinäkyvä eikä `none`.
 */
.karttanimet [data-maasto] {
  pointer-events: auto;
  cursor: pointer;
}
.karttanimet .karttamerkki-osuma {
  fill: transparent;
  stroke: none;
}
/* ---------------------------------------------------------------------------
   ELÄVÄN NIMIKERROKSEN MUSTE ON MITATTU POLTETUSTA LAATASTA
   (omistaja 2.9.2026 ilta)
   ---------------------------------------------------------------------------
   Sanatarkasti: "nuo ei poltetut kaupunkien nimet saisi olla vähän
   haaleammalla sävyllä jotta sopisivat noiden poltettujen tekstien kanssa
   paremmin."

   MIKSI SÄVYT EROSIVAT. Poltettu muste kulkee patinapassien läpi
   (tools/patina.mjs RESEPTIT.nosto → SAVYT: musteen sävytys, haalennus
   0,13 ja sävykäyrä 0,88 x L + 21), elävä kerros ei kulje minkään läpi.
   Sama lähtömuste päätyy siis kahteen eri sävyyn, ja ero näkyy juuri
   siinä näkymässä, jossa molemmat ovat samaan aikaan ruudulla.

   LUKU ON MITATTU EIKÄ ARVATTU. Nostotason laatasta
   (julisteet/pyramidi/2026-09-02e/nostot/z7/93/38.webp) luettuna, neljä
   eri kohtaa ja kunkin 40 tumminta pikseliä:

     Plovdiv (nimiö)          rgb(102, 88, 74)   alfa 234
     Levski (nimiö)           rgb(103, 88, 73)   alfa 230
     Boyanan kirkko (nimiö)   rgb(104, 89, 74)   alfa 235
     Plovdivin symboli        rgb(107, 89, 71)   alfa 237
     Musalan kolmio           rgb( 91, 79, 67)   alfa 205

   Nimiöiden keskiarvo on rgb(103, 88, 73) alfalla 0,92 — ja se on tämän
   muuttujan arvo. Entinen elävä muste oli #4a3421 eli rgb(74, 52, 33)
   TÄYDELLÄ peitolla: tummempi, kylläisempi ja kontrastisempi kuin sama
   nimi laatassa.

   YKSI MUUTTUJA, EI VIITTÄ VAKIOTA. Kaikki tämän kerroksen muste tulee
   samasta luvusta, ja vain PEITTO vaihtelee perheittäin — juuri kuten
   laatassa (symboli 0,93, nimiö 0,92, kolmion veto 0,80). Jos laatan
   patina joskus muuttuu, tässä on yksi paikka, johon uusi mittaus
   kirjoitetaan.
   --------------------------------------------------------------------------- */
:root { --karttamuste: 103, 88, 73; }
.karttanimi {
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  text-rendering: optimizeLegibility;
  fill: rgba(var(--karttamuste), 0.92);
  stroke: none;
  dominant-baseline: middle;
}
/* Järvi kursiivilla ja veden musteella, kuten laatoissakin. */
.karttanimi-jarvi { font-style: italic; fill: rgba(70, 86, 96, 0.85); }
/* Läheltä näkyvä maastonimi (tärkeys 2–3) on kohteen maastonimiön asua:
   kohdenimiön koko tulee ladonnasta (js/karttanimet.js maastonAsu),
   kursiivi täältä. Omistaja 3.9.2026: Dinaariset Alpit ei saa olla
   isompi kuin viereiset Dinara ja Sveti Jure. */
.karttanimi-lahi { font-style: italic; }
/*
   KOHTEEN NIMI ON KAUPUNGIN NIMEN SUKUA, EI OMA KIELENSÄ (omistajan
   päätös 30.8.2026: "sama ladonta kuin paikannimillä"). Sama kirjasin
   tulee jo .karttanimestä ja koko elementiltä.

   MUSTE ON NYT TÄSMÄLLEEN SAMA KUIN KAUPUNGIN NIMELLÄ (2.9.2026), ja se
   on päinvastainen päätös kuin tässä ennen luki ("hitusen kevyempi
   muste, jotta pelin oma sisältö erottuu"). Syy on mittaus: elävän
   noston nimi ja POLTETUN noston nimi ovat samassa kuvassa vierekkäin,
   ja niiden on oltava saman värisiä tai kartalla on kaksi
   mustejärjestelmää (sama vaatimus kuin koolla, savuke-syvazoomi vartio
   10). Kaupungista kohde erottuu koossa (KOKO.kaupunki 12,5-14 vs.
   KOKO.kohde 8,5) ja kirjainlajissa (harvennettu kapiteeli vs. kursiivi)
   — ne kertovat eron ilman että muste tekee siitä kaksi eri karttaa.

   HALO ON POIS TARKOITUKSELLA. Entinen kohdenimiö vedosti nimensä
   taakse pergamenttia, koska se ladottiin merkin kylkeen ottamatta
   naapureista selvää. Ladonta hoitaa nyt saman asian oikein päin:
   nimi asetetaan sinne missä on tilaa, eikä sen tarvitse raivata
   tilaa alleen. */
.karttanimi-kohde { fill: rgba(var(--karttamuste), 0.92); }
/*
   NOSTON VIIVA — merkiltä nimelle. Kartan kevyttä apuviivastoa: ohut,
   haalistunut muste, lyhyet katkot, ei nuolenpäitä. Paksuus ja katkot
   tulevat elementiltä CSS-pikseleinä (js/karttanimet.js NOSTON_VIIVA,
   NOSTON_KATKO), koska ne ovat ruudun mittaa eivätkä kartan. */
.karttanimi-nosto {
  fill: none;
  stroke: rgba(96, 74, 48, 0.42);
  stroke-linecap: round;
}
/*
   MERKIT SAMASTA MUSTEESTA KUIN NIMET (2.9.2026). Nimi ja sen merkki
   ovat sama merkintä kartalla; jos vain nimi haalenisi, piste jäisi
   nimeään tummemmaksi ja kartalla lukisi kaksi eri painovuotta. Peitot
   ovat laatasta mitatut (symboli 0,92, kolmion veto 0,80); renkaan
   0,75 on entinen, koska kaksoisrenkaan kuuluu olla hiuksenohut.
   Poikkeus on järven nimi yllä: se on veden mustetta eikä maan. */
.karttamerkki { pointer-events: none; }
.karttamerkki-piste { fill: rgba(var(--karttamuste), 0.92); stroke: none; }
.karttamerkki-rengas { fill: none; stroke: rgba(var(--karttamuste), 0.75); }
.karttamerkki-vuori { fill: none; stroke: rgba(var(--karttamuste), 0.8); }

.maastonimi { pointer-events: none; }
.maastonimi-teksti {
  font-family: var(--font-kauno);
  font-style: italic;
  letter-spacing: 0.06em;
  fill: rgba(70, 51, 31, 0.72);
  stroke: none;
}
/* Vesistön nimi meren musteella, kuten uoma ja järven reuna itsekin. */
/*
 * Vesien nimet olivat kursiivin ja haalean sävyn takia optisesti
 * pienempiä kuin kaupunkien nimet, vaikka korkeus mitattuna oli sama.
 * Sävy tummennettiin täyteen peittoon; koko nostettiin mapart.js:ssä.
 */
.maastonimi-joki .maastonimi-teksti,
.maastonimi-jarvi .maastonimi-teksti { fill: rgba(92, 80, 60, 0.98); }

.maastonimi-i {
  pointer-events: auto;
  cursor: pointer;
}
.maastonimi-i-keha {
  fill: rgba(239, 220, 180, 0.85);
  stroke: rgba(70, 51, 31, 0.55);
  stroke-width: 1;
  /* Viivan paksuus on laudan yksiköissä ja kutistuisi lähikuvassa
     näkymättömiin. Vektorimitta pitää kehän aina yhtä ohuena. */
  vector-effect: non-scaling-stroke;
}
.maastonimi-i-kirjain {
  font-family: var(--font-type);
  font-weight: 700;
  fill: rgba(70, 51, 31, 0.8);
  stroke: none;
}
.maastonimi-i:hover .maastonimi-i-keha { fill: var(--accent); }

/*
 * FOKUSMOODI: muun maailman maastonimet harson taakse (js/ui.js
 * himmennaMaastonimet).
 *
 * Nimikerros on juuriryhmän ulkopuolella eikä sumuverho yllä siihen,
 * joten himmennys tehdään tässä. Nimi ei katoa kokonaan: kartta on
 * isoisän atlas, ja Alppien nimi saa kummitella sumun takana kuten
 * mantereiden ääriviivatkin. Nykyisen maan nimet jäävät ennalleen.
 *
 * i-nappi katoaa sen sijaan kokonaan: himmeän nimen vieressä se
 * houkuttelisi napauttamaan aluetta, jonne peli ei vielä anna mennä.
 */
.maastonimi-harson-alla .maastonimi-teksti { fill: rgba(70, 51, 31, 0.2); }
.maastonimi-harson-alla .maastonimi-i { display: none; }



/*
 * LÄHIKUVAN VESI.
 *
 * Yleisnäkymässä kartalla ei ole sinistä: meri on paperia ja joki
 * ohut mustejuova (ks. .joki ja .iso-jarvi). Se sääntö pätee yhä.
 * Tämä kerros on eri asia — se herää vasta kun karttaa katsoo
 * läheltä, ja silloin vesi saa uoman, syvyyden ja värin.
 *
 * Sininen on vaimeaa ja harmaan puolella: kirkas sininen riitelisi
 * pergamentin kanssa ja näyttäisi toisesta ohjelmasta lainatulta.
 * Kaikki peittävyydet ovat matalia, jotta paperin rakeisuus näkyy
 * läpi myös veden alta.
 */
.lahivesi { pointer-events: none; }

/* Meren pohja: mitä syvempi, sitä tummempi. Sisäkkäiset vyöhykkeet. */
/*
 * VESI ON MUSTETTA JA PAPERIA, EI SINISTÄ.
 *
 * Omistajan linjaus 4.8.2026: "jätä sininen väri pois kaikista
 * vesielementeistä". Sävyt ovat nyt samasta sepiaperheestä kuin kartan
 * muu muste (--sea-ink #6e6350) — vesi erottuu vaaleudella ja
 * tummuudella, ei värillä. Sama linjaus kuin v222:ssa järvillä ja
 * joilla; tämä vie sen loppuun myös syvyysvyöhykkeissä, lähivedessä ja
 * vesistönimissä.
 *
 * MERISYVYYS ON HILLITTY, KOSKA SE VUOTAA RANNAN YLI.
 *
 * Vyöhykkeet on rajattu piirrettyyn rantaviivaan (js/ui.js
 * `meri-rajaus`), ja rajaus toimii — mutta se ei riitä. Aineisto on
 * karkeampaa kuin rannikko, ja rajauksen reunalle jää muutaman pikselin
 * levyinen kaistale, joka lähikuvassa lukeutuu maaksi. Omistaja on
 * raportoinut siitä neljästi.
 *
 * MITATTU lähimmällä zoomilla, maan keskiväri sisämaan pisteistä:
 *
 *   kaikki näkyvissä      191,167,125
 *   rajaus pois           190,171,135
 *   joet ja järvet pois   192,167,125   ← joet EIVÄT ole syy
 *   merisyvyys pois       193,162,111   ← sama kuin kaukaa katsottuna
 *
 * Eli rajaus poistaa vuodosta noin 40 %, ja loput tulee siitä, ettei
 * kahden eri tarkkuuden rajaa saa osumaan yhteen pikselilleen. Ainoa
 * keino, joka ei riipu aineistojen yhteensopivuudesta, on tehdä
 * vyöhykkeistä niin hennot, ettei ylivuoto erotu. Syvänteet saavat jäädä
 * hieman vahvemmiksi: ne ovat kaukana rannasta.
 */
.merisyvyys { stroke: none; }
.merisyvyys-200 { fill: #c3b598; opacity: 0.07; }
.merisyvyys-2000 { fill: #b0a186; opacity: 0.08; }
.merisyvyys-4000 { fill: #9c8d74; opacity: 0.09; }
.merisyvyys-6000 { fill: #877a63; opacity: 0.11; }

/* Järvi: vesi ja matala reunus. */
.lahivesi-jarvi { fill: #c6b795; opacity: 0.38; stroke: none; }
.lahivesi-jarvi-matala {
  fill: none;
  stroke: #a89a7c;
  stroke-width: 26;
  opacity: 0.30;
}

/*
 * Joen kolme vetoa. Järjestys on tärkeä: ranta alimmaisena, uoma
 * päälle, valo viimeisenä. Viivan päät ja kulmat pyöreiksi, tai
 * nauha katkeaa mutkissa neliömäisiin nokkiin.
 */
.lahivesi-ranta,
.lahivesi-uoma,
.lahivesi-valo {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.lahivesi-ranta { stroke: #7d7057; opacity: 0.34; }
.lahivesi-uoma { stroke: #ab9a78; opacity: 0.55; }
/*
 * Valojuova selvästi vaimeampi. Kirkas vaalea nauha lämpimän
 * pergamentin päällä LUETAAN viileäksi, vaikka sen sävy on lämmin
 * (mitattu elävästä puusta: rgb(231,220,192)) — omistaja raportoi
 * joesta sinisenä vielä senkin jälkeen, kun sinistä ei enää ollut.
 * Sama ilmiö kuin maan ja meren rajalla: silmä vertaa, ei mittaa.
 */
.lahivesi-valo { stroke: #d9c9a4; opacity: 0.28; }


/*
 * Radiotilan sulkunappi ruudun oikeaan yläkulmaan.
 *
 * Yläpalkin PÄÄLLE eikä sen sisään: radiotilassa peli on tauolla, ja
 * sulku kuuluu radiolle. Se ilmestyy ja katoaa soittimen mukana, joten
 * yläpalkin oma asettelu ei saa muuttua sen takia.
 */
/*
 * RADIOTILA: ruudulla vain kartta ja soitin.
 *
 * Omistaja 4.8.2026: "Piilota Matkakirja ja alanapit radion ollessa
 * käytössä." Radiotilassa peli on tauolla — matkustustavan valinta ja
 * matkakirjan kortti eivät koske mihinkään, mitä radiossa voi tehdä, ja
 * soittimen yläpuolella ne vain kilpailevat sen kanssa.
 *
 * visibility eikä display: kortti ja napit säilyttävät mittansa, joten
 * kartan asettelu ei hyppää radion syttyessä eikä sammuessa.
 */
body.radio-tila .fact-card,
body.radio-tila .actions {
  visibility: hidden;
  pointer-events: none;
}

.radio-sulje {
  position: fixed;
  top: max(10px, env(safe-area-inset-top));
  right: max(10px, env(safe-area-inset-right));
  z-index: 61;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid #6b5233;
  border-radius: 50%;
  background: #2a1c10;
  color: #e8d9b8;
  cursor: pointer;
  box-shadow: 0 2px 8px rgb(0 0 0 / 45%);
}
.radio-sulje:hover { background: #3a2716; }
.radio-sulje:active { transform: translateY(1px); }

.coast { fill: none; stroke: var(--map-ink); stroke-width: 3.2; stroke-linejoin: round; }
.coast-soft { fill: none; stroke: var(--map-ink); stroke-width: 0.85; opacity: 0.45; }
/* Maiden rajat: hyvin hento katkoviiva vanhan kartan tapaan. */
.border {
  fill: none;
  stroke: var(--map-ink);
  stroke-width: 0.9;
  stroke-dasharray: 5 4;
  stroke-linejoin: round;
  opacity: 0.22;
}
/*
 * MAAN KOROSTUS ON KOKONAAN PURETTU — EI SÄÄNTÖÄ, KOSKA EI KERROSTA.
 *
 * SÄVYTYS (.country-tint) POISTETTIIN 30.8.2026 ILLALLA. Omistajan
 * havainto iPadilta: *"Valittu maa maalautuu nyt ohuen harmaalla
 * värillä. Poista väritys."* Sävy oli jätetty samana päivänä
 * ääriviivaa purettaessa sillä perusteella, että moite koski viivaa —
 * omistaja näki sävyn laitteella ja päätti toisin. Poistettu koodina
 * (js/ui.js drawCountryBorders ja drawBoard) eikä piilotettu täältä,
 * joten luokkaa ei enää ole olemassa.
 *
 * PUNAINEN ÄÄRIVIIVA (.country-korostus) POISTETTIIN 30.8.2026.
 * Omistajan pelitestipalaute v1095: *"punainen maan ääriviiva on
 * epätarkka → OTETAAN POIS"*. Viiva piirrettiin laudan karkeasta
 * 50m-rannikosta, kun laattaan poltettu ranta on tarkkaa 10m-
 * aineistoa — viiva osui eri kohtaan kuin ranta, jonka se muka rajaa.
 * Piilotus oli ennen body.fokuspohjassa, ja kun luokan asettaja katosi
 * lehtipurussa, viiva palasi ruudulle. Nyt sitä ei enää piirretä
 * (js/ui.js drawCountryBorders).
 */

/* ===========================================================================
   FOKUSMOODI KARTALLA (omistajan linjaus 24.8.2026, js/ui.js
   paivitaFokusKerros / paivitaFokusSumu)
   ---------------------------------------------------------------------------
   Kaksi sääntöä, ei enempää:

   1. KÄYMÄTTÖMÄN MAAN DATA KATOAA. Laatta, rantarengas, porttikehä,
      lentokoneen merkki ja kaupungin nimi saavat luokan .fokus-piilossa.
      `display: none` eikä opacity: piilossa oleva laatta ei saa jäädä
      napautettavaksi eikä maksaa piirtoa panoroinnissa.

   2. KÄYMÄTÖN MAAILMA HIMMENEE. Harso on pergamentin omaa vaaleaa,
      ei harmaata eikä mustaa: kartta on paperia, ja paperin päälle
      laskeutuu sumu eikä varjo. Läpikuultavuus on mitoitettu niin, että
      mantereiden ääriviivat erottuvat yhä — pelaajan pitää nähdä, että
      maailmaa on olemassa, muttei mitä siellä on.

   MAAPOHJAN AITO EPÄTERÄVYYS EI OLE TÄSSÄ. Kartan raskas osa on
   bittikartaksi rasteroitua taidetta (js/mapart.js pilkoTaide), eikä
   siitä voi sumentaa yhtä maata naapurin pysyessä tarkkana. Verhon
   reuna pehmenee maskin omassa suodattimessa; oikea maakohtainen
   topografian tarkentuminen tulee esirenderöityjen karttojen kanssa.
   =========================================================================== */

.fokus-piilossa { display: none; }

/* ---------------------------------------------------------------------------
   ALOITUSKARTAN MUUT KAUPUNGIT POIS (omistajan pelitestipalaute v1119:
   *"piilota toistaiseksi KAIKKI muut kaupungit paitsi Ateena … nimet,
   ympyrät, konesymbolit; Lontoo lähtöpisteenä saa jäädä"* — js/ui.js
   paivitaAloituskaupungit, ETUSIVUN_NAKYVAT)

   Lähtöpisteen valinnassa valittavia kohteita on tasan yksi, mutta
   kartalla oli neljätoista kaupunkia laattoineen ja lentokonemerkkeineen
   — ne lupasivat matkoja, joita ei ole vielä olemassa.

   `display: none` samasta syystä kuin .fokus-piilossa yllä: piilossa
   oleva laatta ei saa jäädä napautettavaksi eikä maksaa piirtoa.
   Piilotus koskee VAIN aloitusvaihetta; katselutilassa (?lauta=) lauta
   näkyy täytenä maailmankarttana kuten ennenkin.
   ------------------------------------------------------------------------- */
.aloitus-piilossa { display: none; }

/* ---------------------------------------------------------------------------
   MATKAREITIT ATLAKSEN PÄÄLLE (omistajan pelitestipalaute v1119, kohta 16:
   *"matkustamisen askellus on kadonnut … reittipisteet ja nappula piirtyvät
   atlas-kerroksen päälle"* — js/ui.js paivitaMatkareitit)

   Laudan oma reittiverkko asuu bittikartassa, joka on fokusnäkymässä
   atlaslehtien alla piilossa. Nappula askelsi siis tyhjän paperin yli.
   Nämä ovat sama reitti kerrottuna atlaksen kielellä: hento musteviiva ja
   pienet askelpisteet, joissa nappula pysähtyy.

   Viivan paksuus ja katkoviivan jakso tulevat js:stä, koska ne mitataan
   RUUDUN pikseleinä eivätkä laudan yksiköinä.
   ------------------------------------------------------------------------- */
.matkareitti {
  fill: none;
  stroke: #4a3a24;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.42;
}

/* Merireitti erottuu maareitistä sinertävällä musteella, kuten laudallakin. */
.matkareitti-meri { stroke: #3d5570; }

/*
 * LENTOKAARI (omistaja 1.9.2026: *"Poistetaan lentoreitit kokonaan
 * näkyvistä. Piirretään ne näkyviin reaaliajassa vasta sitten jos
 * pelaaja päättää mennä lentokoneella."*)
 *
 * Muste on sama poltettu sinooperi, jolla lentoreitit olivat
 * laatoissa (rgba(150,54,40)), jotta merkin merkitys ei vaihdu — vain
 * sen elinikä. Hitusen näkyvämpi kuin laiva- ja maareitti, koska se
 * on vastaus pelaajan juuri tekemään valintaan.
 */
.matkareitti-lento {
  stroke: #963628;
  opacity: 0.6;
}

.matkareitti-piste {
  fill: rgba(250, 243, 226, 0.9);
  stroke: #4a3a24;
  stroke-width: 1;
  opacity: 0.7;
  vector-effect: non-scaling-stroke;
}

/* ---------------------------------------------------------------------------
   KEHITTÄJÄN "pisteet"-KERROS ON POISTETTU (omistajan tilaus 27.8.2026)
   ---------------------------------------------------------------------------
   Punainen kaupunki- ja reittiverkko piirtyi 25.–27.8.2026 fokuskartan
   päälle, jotta omistaja näki mihin voi hypätä. Tilalla on ylärivin
   maailmanappi: siinä näkyvät laudan omat kaupunkilaatat (js/ui.js
   maailmanakyma), ja reitit jäävät nimenomaan pois — ne olivat
   omistajan mukaan se osa, jota ei haluta nähdä.
   ------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   PELIMERKKIEN PIILOTUS (.fokus-lehden-alla) POISTETTIIN 30.8.2026
   ---------------------------------------------------------------------------
   Sääntö piilotti laudan pyöreät pelimerkit — kaupungin laatan,
   käännetyn aarrekiekon, pelinappulan ja kohderenkaan — fokuslehden
   alueelta (omistajan pelitestipalaute v1097: *"Ota pallot pois"*).
   Perustelu oli lehti: OPAAKKI atlaksen sivu yhden maan päällä, jonka
   päällä laudan grafiikka näytti toisesta pelistä lainatulta.

   Pyramidissa "lehti" on koko maailma, joten sama sääntö piilottaisi
   pelimerkit kaikkialta. Luokkaa ei enää kirjoiteta kenellekään
   (js/ui.js paivitaFokusPallot).
   ------------------------------------------------------------------------- */




/*
 * LAATTA ON FOKUSNÄKYMÄN TUTKI-NAPPI (omistajan pelitestitilaus
 * 24.8.2026): alarivillä on vain Liiku, ja tutkiminen alkaa nykyisen
 * kaupungin laatan napautuksesta. Laatta piirtyy lehden päällä pienenä
 * (js/ui.js paivitaFokusLaatta), joten napautusalue on erillinen
 * näkymätön ympyrä — sama ratkaisu ja sama syy kuin kohderenkaiden
 * .target-hit-alueella. Osoitin kertoo hiirellä, että tästä pääsee
 * eteenpäin; kosketuksella alue vain on riittävän iso.
 */
.fokuslaatta-osuma {
  fill: transparent;
  cursor: pointer;
}

/* ===========================================================================
   LAATTA SYKKII KEVYESTI (omistajan pelitestitilaus 25.8.2026)
   ---------------------------------------------------------------------------
   *"Ateenan laatta sykkii kevyesti houkutellen klikkaamaan."* Laatta on
   fokusnäkymän ainoa nappi kartalla (Tutki muutti sen sisään), eikä
   pelaaja arvaa sitä pelkästä pienestä pallurasta.

   KEHÄ ON ERILLINEN, EI LAATAN OMA SKAALAUS. Laatan transform-määre on
   pelin kirjoittama (heilunta + kiinteä ruutukoko, js/ui.js
   asetaLaatanKoko), ja CSS:n transform voittaa määreen — sykkivä laatta
   menettäisi siis sekä heiluntansa että paikkansa. Kehä on siksi oma
   ympyränsä laatan ympärillä (js/ui.js paivitaFokusLaatta).

   SAMAT KOLME SÄÄNTÖÄ KUIN VIHREÄLLÄ KOHTAAMISPISTEELLÄ
   (js/fokuspiste.js, css/fokusvirta.css):

     1. EI SUODATTIMIA. Suodatettu kerros palaa iOS:n taustalta tyhjänä
        (tests/rules.test.mjs), joten sumeaa hehkua ei ole — pelkkä
        läpikuultava ääriviiva.
     2. MITTAKAAVA, EI `r`. SVG:n geometriamääreiden CSS-animointi ei ole
        kaikissa selaimissa tuettua; `transform: scale()` on, ja koska
        ympyrän keskipiste on ankkurin origossa, oletusarvoinen
        transform-origin osuu samaan pisteeseen.
     3. VAIN opacity JA transform. Kompositori hoitaa molemmat ilman
        uudelleenmaalausta, eikä kartan rasterointi joudu töihin.

   HILLITTY EIKÄ HUOMIOPIIPPARI (omistajan sanamuoto): jakso on hidas,
   kasvu muutaman pikselin luokkaa ja väri pergamentin oma okra
   (--accent) läpikuultavana — sama väri, jolla peli muutenkin kuiskaa
   (.icon-btn.tutki-syke).
   =========================================================================== */
.fokuslaatta-syke {
  fill: none;
  stroke: var(--accent, #d9a13b);
  stroke-width: 1.4;
  opacity: 0.42;
  /* Kehä on koriste: napautukset kuuluvat .fokuslaatta-osumalle. */
  pointer-events: none;
  animation: fokuslaatta-syke 2600ms ease-in-out infinite;
}

@keyframes fokuslaatta-syke {
  0%, 100% { transform: scale(1); opacity: 0.42; }
  50% { transform: scale(1.22); opacity: 0.12; }
}

/* Liikkeen välttäjälle pelkkä kehä ilman sykettä — merkki säilyy,
   liike jää pois (sama sääntö kuin muillakin pelin sykkeillä). */
@media (prefers-reduced-motion: reduce) {
  .fokuslaatta-syke { animation: none; opacity: 0.38; }
}

/*
 * PÖLLÖ OSOITTAA LAATTAA. Kun laatta ilmestyy aarrevaiheessa lehden
 * päälle, se saa kevyen huomioeleen: kaksi rauhallista sykähdystä ja
 * sitten hiljaisuus. Vain `opacity` liikkuu — ei suodattimia (iOS) eikä
 * geometriaa, jotta kartan rasterointi ei joudu töihin.
 */
@keyframes fokus-laatta-esiin {
  0% { opacity: 0; }
  25% { opacity: 1; }
  50% { opacity: 0.45; }
  100% { opacity: 1; }
}

.fokus-laatta-esiin {
  animation: fokus-laatta-esiin 1400ms ease-in-out 1;
}

@media (prefers-reduced-motion: reduce) {
  .fokus-laatta-esiin { animation: none; }
}

.fokus-sumu-harso {
  fill: rgba(238, 225, 196, 0.62);
  stroke: none;
}

/*
 * VERHO FOKUSKUVAN YMPÄRILLÄ (omistajan pelitesti 24.8.2026, v1101:
 * *"fokustilassa näkyy vanha pelilauta fokuskuvan ulkopuolella"*).
 *
 * Kun kartalla on maan fokuskuva, kuvan ULKOPUOLI on taustaa eikä
 * pelilautaa: paksut rantaviivat, ruskeat väripinnat ja katkoviivareitit
 * asuvat laudan bittikartassa (js/mapart.js pilkoTaide), eikä valmiista
 * rasterista voi piilottaa yhtä kerrosta. Verho on ainoa keino, joka
 * niihin yltää — ja siksi se on täällä paksumpi kuin käymättömän maan
 * tavallinen harso: laudan piirroksesta jää enää aavistus, joka kertoo
 * että maailmaa on olemassa.
 *
 * Sama pergamentin vaalea, ei harmaata: kartta on paperia, ja paperin
 * päälle laskeutuu sumu eikä varjo. Peittävyys on värissä eikä
 * opacityssa, jottei kerros saa omaa läpinäkyvyystasoaan (ja sen
 * mukana omaa piirtopuskuriaan) — sama iOS-varovaisuus kuin
 * suodattimien välttämisessä.
 */
.fokus-sumu-harso.fokus-sumu-kuva {
  fill: rgba(240, 228, 200, 0.93);
}


/* ---------------------------------------------------------------------------
   KAUPUNKIEN NIMET OVAT LAATOISSA (30.8.2026)
   ---------------------------------------------------------------------------
   Täällä oli kaksi sääntöä, jotka kutistivat elävän .city-labelin
   fokusnäkymässä. Pyramidilaudalla elävää nimilappua ei enää ladota
   lainkaan: kaikkien 261 kaupungin nimet on poltettu laattoihin omalla
   typografiallaan ja omalla törmäyksenvältelyllään (js/ui.js
   drawBoard, docs/moduulit/laattapyramidi.md luku 6c). Katselutilan
   manterelaudoilla .city-label on ennallaan laudan omassa koossaan.

   VALINTATILAN KOHDENIMET (.target-nimi, js/ui.js drawTargets) jäävät:
   ne ovat pelitilaa — mihin juuri nyt voi matkustaa — eivät paikannimiä.
   --------------------------------------------------------------------------- */


/*
 * Maan nimi + lippu kiinteänä kylttinä kartan kehyksellä (Fable
 * maxin speksi 10.8.2026; omistajan tarkennukset samana iltana:
 * aina oikeassa reunassa, aina näkyvillä, EI i-merkkiä, ja mitat
 * samat kuin matkakirjan supistetulla chipillä leveyttä lukuun
 * ottamatta — sama kirjasinkoko, tausta, kulma ja varjo). Koko
 * kyltti on nappi, joka avaa nykyisen maan lehden; osuma-alue
 * laajennetaan ::after-pseudolla. Kirjanappia väistetään
 * sivusuunnassa ja yläoikean päiväkirjakorttia alaspäin.
 */
.maa-pilleri {
  position: absolute;
  /* Sama etäisyys reunasta kuin matkakirjan lapulla (data-corner-säännöt:
   * 0.4rem) ja ilman pystytäytettä sama rivinkorkeus kuin lapun
   * supistetulla rivillä — omistajan huomio 12.8.2026: kyltit istuivat
   * eri korkeuksilla ja maakyltti oli paksumpi. */
  top: 0.4rem;
  right: 0.4rem;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0 0.5em;
  border: 0;
  border-radius: 6px;
  background: rgba(244, 231, 202, 0.86);
  box-shadow: 0 1px 4px rgba(62, 42, 22, 0.18);
  color: rgba(70, 51, 31, 0.92);
  font-family: var(--font-type);
  font-size: 0.8rem;
  line-height: 1.5;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
}

.maa-pilleri::after {
  content: '';
  position: absolute;
  inset: -8px;
}

.maa-pilleri:hover,
.maa-pilleri:focus-visible { background: rgba(245, 231, 200, 0.97); }

/* Kirjanappi muutti vasempaan reunaan (14.8.2026), joten pillerin ei
   tarvitse enää väistää sitä sivusuunnassa. */


.maa-pilleri[hidden] { display: none; }

.maa-pilleri-lippu {
  height: 0.95em;
  width: auto;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 2px;
}

.maa-pilleri-lippu[hidden] { display: none; }

/* Vertailu- ja radiotila omistavat kartan itse — pilleri pois tieltä
 * samoin kuin päiväkirjakortti ja toimintonapit. MAASELAIMESSA pilleri
 * sen sijaan NÄKYY (omistaja 14.8.2026: "oikealla saisi näkyä sama
 * maakyltti kuin normaalitilassa") — se näyttää valitun maan nimen ja
 * lipun, ja kyltistä aukeaa maan lehti. */
body.vertailu-tila .maa-pilleri,
body.radio-tila .maa-pilleri { display: none; }

.wave { fill: none; stroke: var(--sea-ink); stroke-width: 2; opacity: 0.45; stroke-linecap: round; }

.route { stroke: #6d5333; stroke-width: 2.2; opacity: 0.42; fill: none; }
.route-sea { stroke: var(--sea-ink); stroke-width: 2.2; stroke-dasharray: 11 9; opacity: 0.75; }
.air-route {
  fill: none;
  stroke: var(--mark);
  stroke-width: 2.4;
  stroke-dasharray: 3 13;
  stroke-linecap: round;
  opacity: 0.42;
}

/*
 * ETUSIVUN ALKUANIMAATIO (js/ui.js piirraAlkuReitit).
 *
 * Kaksi valopistettä kiertää aloituskarttaa: isoisän maailmanympärysmatka
 * himmeän punaisena ja kauppareitti Intiasta Lontooseen siniharmaana.
 * Kumpikin jättää perässään haipuvan katkoviivajäljen.
 *
 * VÄRIT OVAT SEEPIAN SISÄLTÄ. Kirkas punainen ja sininen repisivät
 * kartan ilmeen rikki; nämä kaksi ovat samaa sammunutta sävyä kuin
 * kartan omat merkinnät, vain sen verran erillään toisistaan että ne
 * erottaa toisikseen.
 *
 * TÄSSÄ EI ASETETA YHTÄKÄÄN ANIMOITUA OMINAISUUTTA. Liike on SMILiä
 * (12.8.2026, ks. piirraAlkuReitit), ja tyylitiedoston sääntö jyrää
 * SMIL-arvon: jos peittävyys, säde, viivanleveys tai katkoviiva
 * asetettaisiin täällä, animaatio jäisi paikalleen. Ne tulevat
 * elementtien omina määreinä js/ui.js:stä. Väri ja viivan pää eivät
 * ole animoituja, joten ne saavat olla tyylinä.
 *
 * KERROS NÄKYY VAIN AVAUSNÄKYMÄSSÄ. Varsinaisen irrotuksen tekee
 * js/ui.js render(): pelin alkaessa kerros otetaan kokonaan pois
 * puusta, jottei sen animaatioita jää käymään näkymättömissä. Nämä
 * säännöt ovat varmistus kahteen väliin, joissa kerros on vielä
 * puussa mutta ei saa näkyä.
 *
 * PIILOTUS ON visibility, EI display. Kerros syntyy drawBoardissa
 * ennen kuin bodyyn tulee data-mode="start", eli se on hetken
 * piilossa — ja display: none -tilassa syntyneen elementin
 * SMIL-animaatioiden käynnistyminen on juuri sitä WebKitin
 * käyttäytymistä, jota tässä korjauksessa vältetään. visibility
 * piilottaa mutta jättää elementin asetteluun ja aikajanalle.
 */
.alkureitit { visibility: hidden; }
body[data-mode="start"] .alkureitit { visibility: visible; }
body.aloitus-zoom .alkureitit { visibility: hidden; }

.alkureitti-osa { fill: none; stroke-linecap: round; }
.alkureitti-piste { stroke: none; }

.alkureitti-isoisa .alkureitti-osa { stroke: #a4442b; }
.alkureitti-isoisa .alkureitti-piste { fill: #a4442b; }
.alkureitti-kauppa .alkureitti-osa { stroke: #4a6883; }
.alkureitti-kauppa .alkureitti-piste { fill: #4a6883; }

/*
 * POHJAVIIVA: koko reitti hentona yhtenäisenä viivana, aina näkyvissä.
 *
 * Omistaja ei nähnyt animaatiosta jälkeäkään yhdelläkään laitteellaan
 * (12.8.2026), ja liikkeen vähennys piilotti ennen koko kerroksen.
 * Kumpikin päättyi tyhjään karttaan. Pohjaviiva on niin himmeä, että se
 * lukee kartan omana merkintänä — mutta sen ansiosta reitit ovat
 * etusivulla olemassa silloinkin, kun liike ei jostain syystä käy.
 *
 * MITTA ON PIKSELEISSÄ, EI YKSIKÖISSÄ. Laudan yksikkö on 390 pikselin
 * puhelimella noin 0,33 pikseliä, joten 2,6 yksikön viiva olisi ollut
 * alle pikselin — juuri se virhe, joka teki edellisestäkin yrityksestä
 * näkymättömän. Kuusi yksikköä on puhelimella noin kaksi pikseliä.
 * Mitattu ero taustaan (Chromium, 390 px): 1544 pikseliä muuttuu,
 * suurin sävyero 58/255, kun liikkeen vähennys on päällä.
 */
.alkureitti-viiva { stroke-width: 6; opacity: 0.17; }
/*
 * Laivojen pohjaviivat ovat himmeämpiä kuin isoisän (omistaja
 * 12.8.2026: punainen on päähahmo). Sinisiä reittejä on neljä yhden
 * sijaan, joten sama 0,17 olisi kuormittanut kartan neljästä kohtaa
 * kerralla. Liikkuvien osien vastaava kerroin on js/ui.js:n
 * LAJIN_KIRKKAUS — täällä se on käsin, koska pohjaviivaa ei animoida.
 */
.alkureitti-kauppa .alkureitti-viiva { opacity: 0.11; }

/*
 * JÄLKI: SUORAT PÄÄT, EI PYÖREÄT.
 *
 * Jälki kasvaa niin, että seuraava katkoviivan pätkä venyy nollasta
 * täyteen mittaansa (js/ui.js). Pyöreällä päällä nollan mittainen pätkä
 * piirtyy SVG:ssä pisteenä, joten koko piirtämätön osa reittiä olisi
 * näkynyt pistejonona ensimmäisestä ruudusta asti — juuri se, mitä
 * kasvavalla jäljellä yritetään välttää.
 */
.alkureitti-jalki { stroke-linecap: butt; }

@media (prefers-reduced-motion: reduce) {
  /*
   * Liikkeen vähennys: reitit näkyvät staattisina, liikkuvat osat
   * eivät lainkaan. Jos asetus oli päällä jo latautuessa, liikkuvia
   * osia ei ole edes rakennettu (piirraAlkuReitit) — tämä sääntö on
   * sitä varten, että asetus vaihtuu kesken istunnon.
   */
  .alkureitti-viiva { stroke-width: 7; opacity: 0.42; }
  .alkureitti-jalki, .alkureitti-piste { display: none; }
}

.step { fill: #e8d7b0; stroke: #8a7048; stroke-width: 1.2; opacity: 0.7; }
/* Meriaskelmat samaan sepiaan kuin muu vesi: ei sinistä (v252). */
.step-sea { fill: #eee3c8; stroke: #8a7a5f; opacity: 0.65; }

.fare { fill: var(--sea-ink); font-size: 15px; font-weight: 700; letter-spacing: 0.02em; }

/*
 * Kirjoituskonetekstin kirjoittamaton osa: näkymätön mutta vie tilansa,
 * jolloin rivitys on lopullinen jo ensimmäisestä sanasta lähtien.
 */
.pending { visibility: hidden; }

/*
 * AVAUS ON KAKSI LOHKOA (omistajan tilaus 26.8.2026, ilta).
 *
 * *"Aloitussivulla saisi olla maailmankartta pienemmällä ja asettelu
 * niin että maailmankartan päällä olisi 'Maailman ympäri...' -otsikko
 * ja sen alapuolella olisi tyhjää vaaleaa karttapohjaa ja sen päälle
 * tulisi muut tekstit."*
 *
 *   .intro-kartta  ylälohko: pienennetty maailmankartta ja sen päällä
 *                  julisteotsikko (kartta kevyesti sumennettuna,
 *                  .intro-verho, jotta otsikko erottuu).
 *   .intro-arkki   alalohko: peittävä tyhjä pergamentti, jonka päällä
 *                  paikkarivi, avausteksti ja Mistä aloitan? -nappi.
 *
 * Ylälohkon korkeus EI ole arvattu prosentti: js/ui.js placeIntro
 * mittaa, mihin pienennetty lauta loppuu, ja kirjoittaa rajan
 * --intro-kartta-korkeus-muuttujaan. Kartan pienentää js/kartta.js
 * INTRO_SPACE (pergamenttia jatketaan laudan alle). Prosentti tässä on
 * vain varasija ennen ensimmäistä mittausta.
 *
 * PALLOLAUDALLA VARASIJA ON LOPULLINEN (aalto 1D): etusivun pallo
 * (js/etusivupallo.js) täyttää lohkon, eikä tasokarttaa alusteta
 * lainkaan — placeIntro ei siis mittaa mitään. Mitattu ero vanhaan on
 * pieni (mitattu lauta antoi 42 %, varasija on 44 %), joten sommitelma
 * pysyy entisenä.
 */
.intro {
  position: absolute;
  inset: 0;
  /* Avausteksti häipyy pehmeästi, kun kartalle siirrytään. */
  transition: opacity 0.9s ease;
  display: flex;
  flex-direction: column;
  text-align: center;
  pointer-events: none; /* kartta jää napautettavaksi tekstin takaa */
  z-index: 3;
}

/* Ylälohko: pienennetty kartta ja sen päällä julisteotsikko. */
.intro-kartta {
  position: relative;
  flex: 0 0 var(--intro-kartta-korkeus, 44%);
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/*
 * SUMUVERHO KARTAN PÄÄLLE. Oma HTML-kerroksensa nimenomaan siksi, ettei
 * kartan SVG:hen tule suodatinta: iOS:n webapp-tila palauttaa suodatetun
 * SVG-kerroksen tyhjänä taustalta palattaessa (sama vika on korjattu
 * tässä repossa jo useasti — ks. tests/sw.test.mjs).
 *
 * Verho ilmestyy vasta Aloita seikkailu -napin jälkeen (.intro-aloitettu):
 * portin takana etusivulla on terävä kartta ja portin oma tummennus.
 *
 * Verho kattaa KOKO PANEELIN (omistaja 26.8.2026 ilta: *"Blurri
 * loppuu kesken"*): kartan pergamentti hiusviivoineen jatkuu laudan
 * alla (js/kartta.js INTRO_SPACE), joten pelkän ylälohkon kokoinen
 * verho piirsi sumennuksen rajan terävänä saumana alalohkon
 * yläreunaan. Elementti on .intro-paneelin ensimmäinen lapsi, joten
 * lohkot piirtyvät sen päälle ilman z-index-kikkoja.
 */
.intro-verho {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.9s ease;
  /* Kevyt sumennus + hennon pergamentin sävyinen huntu, joka nostaa
     tekstin luettavaksi kartan kuvioinnin päältä. */
  background: rgba(239, 220, 180, 0.3);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

.intro.intro-aloitettu .intro-verho { opacity: 1; }

/*
 * FALLBACK ilman backdrop-filteriä (vanhat WebKitit): sumennusta ei saa,
 * joten luettavuus tehdään tummemmalla hunnulla. Ilman tätä teksti jäisi
 * terävän kartan päälle sellaisenaan.
 */
@supports not ((backdrop-filter: blur(3px)) or (-webkit-backdrop-filter: blur(3px))) {
  .intro-verho { background: rgba(239, 220, 180, 0.62); }
}

/*
 * ALALOHKO: TYHJÄ KARTTAPINTA.
 *
 * EI OMAA TAUSTAA (omistajan oikaisu 26.8.2026: *"alaosa ei vaadi
 * mitään erillistä vaaleampaa aluetta — kartan pohjaa vain voisi
 * jatkaa alaspäin, eli tavallaan tyhjää karttapintaa"*). Kartan oma
 * pergamentti jatkuu laudan alla (js/kartta.js INTRO_SPACE), joten
 * teksti lepää suoraan sillä; luettavuuden hoitaa koko paneelin
 * kattava .intro-verho. Aiempi peittävä liukuväri teki alalohkosta
 * erottuvan vaaleamman arkin ja sauman kartan alalaitaan.
 */
.intro-arkki {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Arkki nousee sumuverhon kanssa samaan tahtiin vasta Aloita
     seikkailu -napin jälkeen: portin takana lauta on iso ja keskellä,
     eikä sen päälle lasketa paperia. */
  opacity: 0;
  transition: opacity 0.9s ease;
}

.intro.intro-aloitettu .intro-arkki { opacity: 1; }

/*
 * Itse palsta. Kirjasinkoon asettaa js/ui.js fitIntro TÄHÄN elementtiin,
 * ja lapset on mitoitettu em-yksiköissä — niin nappi ja kansikuva
 * kutistuvat tekstin mukana, kun ruutu on matala.
 */
.intro-palsta {
  position: relative;
  width: min(560px, 86%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Kokoa säätää js/ui.js fitIntro arkin korkeuden mukaan
     (INTRO_FONT_MAX/MIN). LÄHTÖARVO ON SAMA LUKU KUIN INTRO_FONT_MAX
     (1,14rem): entinen 0,96rem ei ollut mittauksen lähtökoko, joten
     palsta — ja sen em-mittainen nappi ja työpöytäkuva — hyppäsi
     kokoa siinä hetkessä, jona fitIntro ensi kerran ajettiin
     (omistaja 5.9.2026 klo 00.20). Kapealla ruudulla fitIntro kutistaa
     tästä alaspäin, mutta se tapahtuu jo portin takana. */
  font-size: 1.14rem;
  pointer-events: none;
}

/*
 * JULISTEOTSIKKO: teoksen nimi ladottuna, ei kuvana.
 *
 * Kaanonmuutos 25.8.2026 ("ISOISÄ PIIRTÄJÄNÄ"): isoisän matkakirja on
 * nimetön kulunut muistikirja, joten nimi ei voi olla sen kannessa.
 * Nyt se on juliste vuodelta 1873: lukukirjasin versaalina, reilu
 * kirjainväli, kaksi riviä ja hiusviivakoristeet. Mitat ovat em-
 * yksiköissä, joten otsikko kutistuu kokonaisuutena, kun js/ui.js
 * fitIntro sovittaa sen ylälohkoon (26.8.2026 alkaen otsikko on
 * kartan päällä oma lohkonsa, ei enää tekstipalstan ensimmäinen rivi).
 */
.intro-juliste {
  position: relative; /* sumuverhon päälle */
  width: min(560px, 86%);
  margin: 0;
  /*
   * LÄHTÖARVO = INTRO_FONT_MAX × JULISTEEN_KERROIN (1,14 × 1,5 =
   * 1,71rem), siis täsmälleen se koko, jolla js/ui.js fitIntro
   * aloittaa mittauksensa. Entinen 1,44rem oli eri luku, ja otsikko
   * kasvoi 19 % ja nousi 27 px juuri kirjoituskoneen alkaessa —
   * omistajan havainto 5.9.2026 klo 00.20, sanatarkasti: *"etusivun
   * otsikko hyppää alussa eri kokoon kun kirjoituskone teksti
   * alkaa"*. Vartija: tests/lento-ajoitus.test.mjs.
   */
  font-size: 1.71rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55em;
  font-family: var(--font-luku);
  font-weight: 700;
  color: var(--map-ink);
  text-transform: uppercase;
  text-shadow: 0 1px 0 rgba(247, 237, 216, 0.9), 0 0 6px rgba(247, 237, 216, 0.75);
}

/* Kirjainväli levittää rivin oikealle: sama verran takaisin, jotta
   keskitys osuu (viimeisen kirjaimen jälkeinen väli ei näy). */
.juliste-rivi { display: block; line-height: 1.15; }
/* Pelin nimi on julisteen pääotsikko (omistaja 26.8.2026); Vernen
   teosnimi latoutuu sen alle kahtena tasakokoisena alaotsikkorivinä. */
.juliste-nimi { font-size: 1.72em; letter-spacing: 0.24em; text-indent: 0.24em; }
.juliste-yla { font-size: 0.92em; letter-spacing: 0.22em; text-indent: 0.22em; margin-top: 0.35em; }
.juliste-ala { font-size: 0.78em; letter-spacing: 0.24em; text-indent: 0.24em; }
/* Jatko-osan merkintä: viktoriaanisen julisteen tapaan alaotsikko
   PUNAISELLA musteella (sama suku kuin reittiviivan/merkkien
   --mark), lihavoituna — koko pysyy pääotsikkoa pienempänä, väri
   tekee korostuksen (omistaja 26.8.2026). */
.juliste-osa {
  margin-top: 0.45em;
  font-size: 0.6em;
  font-weight: 700;
  letter-spacing: 0.42em;
  text-indent: 0.42em;
  color: #9c3a26;
}

/*
 * JULISTE RAKENTUU PALA PALALTA NAPIN JÄLKEEN (omistajan tilaus
 * 6.9.2026 aamu, sanatarkasti: *"ota taustalta pois pelin otsikko …
 * Kun nappia painetaan niin sitten tulee pienellä viiveellä yläviiva ja
 * otsikko sitten pienen hetken päästä osa 2 teksti. se saisi tulla
 * animoidusti niin että kirjainkoko ja kirkkaus välähtää isompana ja
 * feidautuu nykyiseen, kuin pieni salaman isku. sitten tulisi alaviiva
 * otsikkoon ja pienen hetken päästä alkaisi konekirjoitusteksti."*).
 *
 * `.avaus-kesken` on julisteessa aloitusportista siihen asti, kunnes
 * peli lähtee liikkeelle: se piilottaa KAIKEN, ja js/ui.js
 * (naytaAvausjuliste) paljastaa palat yksi kerrallaan luokalla
 * `.avaus-nakyy`. Ajat ovat js/ui.js:n AVAUS_*-vakioita, kestot tulevat
 * tänne muuttujina (--viivan-piirto, --salaman-kesto, --salaman-kerroin),
 * jotta luvut ovat olemassa vain yhdessä paikassa.
 *
 * PIILOTUS ON PEITTÄVYYTTÄ JA TRANSFORMIA, ei displayta eikä
 * kirjasinkokoa: julisteen mitat ja rivijako pysyvät koko ajan samoina,
 * joten fitIntron mitoitus ei liiku eikä mikään hyppää (vartijat:
 * tests/lento-ajoitus.test.mjs, savuke E11f).
 */
.intro-juliste.avaus-kesken .juliste-rivi,
.intro-juliste.avaus-kesken .juliste-viiva { opacity: 0; }
.intro-juliste.avaus-kesken .juliste-viiva > span { transform: scaleX(0); }

/*
 * VIIVA PIIRTYY KESKELTÄ ULOS: hiusviivat kasvavat merkin (◈) molemmin
 * puolin skaalaamalla, merkki itse feidaa mukana. Leveys muuttuu
 * transformilla, joten rivi ei elä asettelussa.
 */
.juliste-viiva > span:first-child { transform-origin: right center; }
.juliste-viiva > span:last-child { transform-origin: left center; }

.intro-juliste.avaus-kesken .juliste-viiva.avaus-nakyy {
  opacity: 1;
  transition: opacity var(--viivan-piirto, 520ms) ease-out;
}

.intro-juliste.avaus-kesken .juliste-viiva.avaus-nakyy > span {
  transform: scaleX(1);
  transition: transform var(--viivan-piirto, 520ms) cubic-bezier(0.22, 0.68, 0.28, 1);
}

/*
 * SALAMAN LÄHTÖASENTO: rivi maalataan kerran täydellä peittävyydellä,
 * SALAMAN_KERROIN-kokoisena ja kirkkaana (kirkkaus + vaalea hehku).
 * Siirtymä on tässä pois päältä, jotta lähtöasento ehtii kehykseen
 * ennen kuin js/ui.js vaihtaa luokan lopulliseen.
 */
.intro-juliste.avaus-kesken .juliste-rivi.avaus-salama {
  opacity: 1;
  transform: scale(var(--salaman-kerroin, 1.25));
  filter: brightness(1.5) drop-shadow(0 0 0.5em rgba(255, 247, 222, 0.95));
  transition: none;
}

/* …ja tästä se feidaa nykyiseen kokoon, väriin ja hehkuun. */
.intro-juliste.avaus-kesken .juliste-rivi.avaus-nakyy {
  opacity: 1;
  transform: scale(1);
  filter: brightness(1) drop-shadow(0 0 0 rgba(255, 247, 222, 0));
  transition: opacity var(--salaman-kesto, 600ms) ease-out,
    transform var(--salaman-kesto, 600ms) cubic-bezier(0.16, 0.84, 0.3, 1),
    filter var(--salaman-kesto, 600ms) ease-out;
}

@media (prefers-reduced-motion: reduce) {
  /*
   * SAMA JÄRJESTYS, PELKÄT HÄIVYTYKSET (Raamattu, arkkikirjasto:
   * *"prefers-reduced-motion kunnioitetaan (pelkkä häivytys)"*): ei
   * skaalausta eikä salamaa. js/ui.js jättää salamaluokan ottamatta,
   * ja tämä on sen varmistus myös silloin, jos luokka ehtii elementille.
   */
  .intro-juliste.avaus-kesken .juliste-rivi.avaus-salama,
  .intro-juliste.avaus-kesken .juliste-rivi.avaus-nakyy {
    transform: none;
    filter: none;
    transition: opacity var(--salaman-kesto, 600ms) ease-out;
  }
  .intro-juliste.avaus-kesken .juliste-viiva.avaus-nakyy > span {
    transform: scaleX(1);
    transition: none;
  }
}

/*
 * Hiusviivakoriste: kaksi eripaksuista viivaa ja keskellä pelin oma
 * merkki ◈. Viiva on kahtena kappaleena merkin molemmin puolin, koska
 * yhtenäisen viivan katkaisu vaatisi merkin taakse umpinaisen laatan —
 * ja sen alta pitää näkyä kartta.
 */
.juliste-viiva {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  width: min(100%, 17em);
  font-size: 0.62em;
  letter-spacing: 0;
  color: rgba(70, 51, 31, 0.7);
}

.juliste-viiva > span {
  flex: 1;
  height: 4px;
  border-top: 1px solid rgba(70, 51, 31, 0.55);
  border-bottom: 1px solid rgba(70, 51, 31, 0.26);
}

.intro-text {
  margin: 0;
  color: var(--map-ink);
  font-size: 1em;
  line-height: 1.6;
  white-space: pre-line; /* omistajan teksti on kahtena kappaleena */
  text-shadow: 0 1px 0 rgba(247, 237, 216, 0.9), 0 0 6px rgba(247, 237, 216, 0.75);
}

/*
 * Paikkarivi avaustekstin ensimmäisenä rivinä — kohtausmerkintä, ei
 * repliikki. Kertoja ei lue sitä (ks. index.html), joten se ei myöskään
 * näytä samalta kuin luettu teksti: pienempi, harvempi ja himmeämpi,
 * kuin käsikirjoituksen kohtausotsikko. Koko on em, jotta se seuraa
 * fitIntron säätämää kirjasinkokoa.
 */
.intro-paikka {
  display: block;
  margin-bottom: 0.9em;
  font-size: 0.86em;
  letter-spacing: 0.14em;
  color: var(--map-ink-soft);
  opacity: 0.9;
}

/*
 * MISTÄ ALOITAN? — kertojan viimeinen kysymys 1873-nappina (omistajan
 * tilaus 26.8.2026, ilta). Kehys, harvennettu versaali ja sama
 * huomiokieli kuin maataulun plussassa — mutta EI SYKETTÄ: nappi seisoo
 * tyhjällä arkilla eikä kilpaile mistään huomiosta.
 *
 * Erillinen ALOITA MATKA -nappi poistettiin samalla: kysymys ja vastaus
 * peräkkäin oli yksi kehotus liikaa.
 *
 * Ilmestyy vasta kun avausteksti on kirjoittunut loppuun, mutta varaa
 * paikkansa jo ennen sitä (peittävyys eikä display), jottei palsta
 * hyppää napin ilmestyessä.
 */
.intro-valinta {
  margin: 1.4em auto 0;
  padding: 0.55em 1.5em;
  border: 1.5px solid rgba(70, 51, 31, 0.75);
  border-radius: 2px;
  background: rgba(247, 237, 216, 0.55);
  min-height: 44px;
  max-width: 100%;
  font-family: inherit;
  font-size: 0.92em;
  line-height: 1.3;
  font-weight: 700;
  color: var(--map-ink);
  text-transform: uppercase;
  letter-spacing: 0.28em;
  text-indent: 0.28em;
  cursor: pointer;
  pointer-events: auto; /* palsta on läpinapautettava, tämä ei */
  transition: opacity 0.8s ease, background-color 0.25s ease,
    border-color 0.25s ease, transform 0.25s ease;
}

.intro-valinta:hover,
.intro-valinta:focus-visible {
  border-color: var(--map-ink);
  background: rgba(247, 237, 216, 0.85);
  transform: translateY(-1px);
}

/* Nappi odottaa kirjoituksen loppuun näkymättömänä mutta paikallaan. */
.intro-valinta.intro-valinta-piilossa {
  opacity: 0;
  pointer-events: none;
}

/*
 * ISOISÄN TYÖPÖYTÄ tekstin alla: revennyt matkakirja ja sen alta
 * pilkottava irrallinen luonnoslehti. Läpinäkyvät PNG:t suoraan
 * blurratun kartan päälle — ei kehystä, ei laatikkoa, ei varjoa,
 * kuvat tuovat omansa. Leveys on em-yksiköissä, joten sommitelma
 * pienenee tekstin mukana matalalla ruudulla (fitIntro).
 */
.intro-tyopoyta {
  position: relative;
  width: min(100%, 26em);
  margin-top: 1.5em;
  /* Irtolehti kellii laatikon ulkopuolelle: mitään ei leikata. */
  overflow: visible;
}

.intro-kansi {
  position: relative;
  z-index: 1; /* kirja irtolehden päälle */
  display: block;
  width: 100%;
  height: auto;
  /* Kuvasuhde tiedetään ennen latausta, joten palstan korkeus on
     mitattavissa heti eikä kuva hyppää paikalleen jälkikäteen. */
  aspect-ratio: 3 / 2;
  object-fit: contain;
  pointer-events: none;
}

/*
 * Irtolehti kirjan alta vasemmalta, pari astetta vinossa — sommitelma
 * on työpöytä eikä tuotekuva. Absoluuttinen, jotta se ei kasvata
 * palstan korkeutta (fitIntro mittaa sen).
 */
.intro-irtolehti {
  position: absolute;
  z-index: 0;
  left: -13%;
  bottom: -5%;
  width: 47%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: contain;
  transform: rotate(-8deg);
  pointer-events: none;
}

/*
 * Isoisän valokuva oli työpöydällä v1509–v1510; omistaja jätti sen pois
 * etusivulta 3.9.2026. Kortti elää lentokohtauksessa (.lento-valokuva).
 *
 * Kortti irti valkoisesta taustasta (omistaja 3.9.2026): clip-path
 * leikkaa JPG:n valkoiset reunat pois ja skaala täyttää elementin
 * kortilla. Muuttujat tulevat js/isoisan-valokuvat.js rajausTyyli.
 */
.isoisa-rajattu {
  clip-path: inset(
    calc(var(--ry0, 0) * 100%)
    calc((1 - var(--rx1, 1)) * 100%)
    calc((1 - var(--ry1, 1)) * 100%)
    calc(var(--rx0, 0) * 100%)
  );
}
.lento-valokuva .isoisa-rajattu { transform: scale(var(--rskaala, 1)); }

/*
 * ETUSIVUN ESIRENDERÖITY PALLO (js/etusivupallo.js, pallolauta vaihe 5a).
 *
 * Omistaja 5.9.2026: *"siihen kannattaa varmaan renderöidä oma spesifi
 * zoomattu pallo joka pyörii hitaasti lontoosta kohti aasiaa, mutta on
 * jo renderöity blurrattuna, jotta efekti ei vie etusivulla tehoja."*
 *
 * KERROS ON KOKO AVAUSPANEELIN KOKOINEN (omistaja 5.9.2026 klo 21.30:
 * *"pallo saisi pyöriä koko etusivun alalla"*). Se on .intro-paneelin
 * ENSIMMÄINEN lapsi, siis sumuverhon (.intro-verho) ja molempien
 * lohkojen takana; aiemmin kerros asui pelkässä ylälohkossa
 * (.intro-kartta), jolloin työpöydällä alalohko jäi tyhjäksi
 * pergamentiksi. Video on jo sumennettu poltossa, joten tässä ei ole
 * yhtään suodatinta (iOS-sääntö) eikä yhtään jatkuvaa CSS-animaatiota —
 * kone ja viiva liikkuvat js/etusivupallo.js:n laskemina attribuutteina.
 *
 * VIDEO JA SVG RAJAUTUVAT SAMOIN: object-fit: cover ≡ SVG:n
 * preserveAspectRatio="xMidYMid slice" (js/etusivupallo.js
 * SOVITUS_TAPA ja SVG_SOVITUS antavat molemmille saman muunnoksen),
 * joten koneen ruutupiste osuu videon pikseliin myös silloin, kun
 * paneeli on paljon leveämpi tai korkeampi kuin neliömäinen video.
 */
.etusivupallo {
  position: absolute;
  inset: 0;
  /* Pohjimmainen kerros paneelissa: isoisän pino (z-index 2) on tämän
     päällä ja teksti (z-index 3) niiden molempien päällä. */
  z-index: 0;
  overflow: hidden;
  background-color: var(--paper);
  opacity: 0;
  /* Ilmestyminen on ainoa peittävyysanimaatio; kierroksen sauman
     häivytys koskee vain viivaa ja konetta (js/etusivupallo.js
     HAIVYTYS_S) — video looppaa saumattomasti, koska kierros on 360°. */
  transition: opacity 900ms ease;
  pointer-events: none;
}

.etusivupallo.nakyy { opacity: 1; }

.etusivupallo-video,
.etusivupallo-juliste {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* Muutos vaatii saman muutoksen js/etusivupallo.js:n SOVITUS_TAPAan:
     SVG rajautuu sen mukaan (tests/etusivupallo.test.mjs vartioi). */
  object-fit: cover;
}

/*
 * JULISTE NÄKYY HETI, VIDEO VAIHTUU SEN TILALLE PEHMEÄSTI (omistaja
 * 5.9.2026 ilta: *"pallo lähtee heti pyörimään"*). Kumpikin kerros on
 * aluksi läpinäkyvä ja saa `nakyy`-luokan omalla hetkellään: juliste
 * kun kuva on purettu, video kun se on ladattu ja soi. Näin etusivu ei
 * ole sekuntiakaan tyhjä pergamentti eikä video napsahda paikalleen
 * (js/etusivupallo.js KERROKSEN_ILMESTYS_MS on sama luku).
 */
.etusivupallo-juliste,
.etusivupallo-video {
  opacity: 0;
  transition: opacity 900ms ease;
}

.etusivupallo-juliste.nakyy,
.etusivupallo-video.nakyy { opacity: 1; }

.etusivupallo-reitti {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Paksu punainen viiva (omistaja sanatarkasti). Leveys on videon
   pikseleitä, joten se kutistuu kerroksen mukana. */
.etusivupallo-viiva {
  fill: none;
  stroke: #c2452f;
  stroke-width: 11;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.92;
}

.etusivupallo-koneen-runko {
  fill: #2e2114;
  stroke: #2e2114;
  stroke-width: 1.4;
  stroke-linejoin: round;
}

/* Kone katoaa pehmeästi pallon taakse eikä sammu kesken kaiken. */
.etusivupallo-kone { transition: opacity 260ms ease; }

/*
 * ISOISÄN KUVAT JÄTETTIIN POIS ETUSIVULTA (omistajan päätös 6.9.2026
 * klo 01.20, sanatarkasti: *"Jätä isoisän kuvat pois etusivulta"*).
 * Tässä olivat kuvapinon tyylit (`.etusivupallo-pino`,
 * `.etusivupallo-kuva`, kuvateksti ja `--pino-harsokorjaus`); ne on
 * poistettu kokonaan, koska js/etusivupallo.js ei enää luo pinon
 * DOMia — jäljelle jäänyt tyyli olisi kuollutta koodia. Palautus on
 * revert versiohistoriasta. Avauspaneelin kerrokset ovat nyt:
 *
 *   0  .etusivupallo   video, punainen viiva ja kone
 *   1  .intro-verho    pergamenttihuntu
 *   3  .intro-kartta ja .intro-arkki (otsikko, teksti, napit)
 *
 * Pakka js/packs/etusivun-isoisakuvat.js jää tallelle: kuvat odottavat
 * uutta käyttöpaikkaansa (albumi, lentokohtaus).
 */

/*
 * SUMUVERHO KEVENEE PALLON PÄÄLLÄ. Video on jo sumennettu, joten
 * backdrop-filter maksaisi joka kehyksellä turhaan — sen tilalle pelkkä
 * huntu (omistajan ehto: efekti ei saa viedä etusivulla tehoja).
 *
 * HUNTU ON TUMMENNUS EIKÄ PERGAMENTTIA (omistajan tilaus 6.9.2026 aamu,
 * sanatarkasti: *"maailmankartta-animaatio saisi olla vähän tummempi,
 * kuin on ihan aloitusruudussa, ehkä siitä asteen vaaleampi mutta ei
 * niin vaalea kuin nyt"*). Ennen tässä oli vaalea pergamenttihuntu
 * (rgba(239, 220, 180, 0.38)), joka pesi pallon kalpeaksi heti napin
 * painalluksesta.
 *
 * Sama kaava ja sama väri kuin aloitusportilla (.start-gate), yhtä
 * astetta vaaleampana — portti 0,28 keskellä ja 0,6 reunoilla, avaus
 * 0,18 ja 0,44. Luvut ovat nimettyinä muuttujina, jotta portin ja
 * avauksen suhde on luettavissa yhdestä paikasta.
 *
 * Tekstin luettavuus EI ole tämän varassa: palstalla ja otsikolla on
 * omat pergamenttiharsonsa (::before, alla).
 */
.intro.intro-pallolla .intro-verho {
  /* Verho jää pallon ja tekstilohkojen väliin (z-index 1). */
  z-index: 1;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  --avauksen-tummennus: 0.18;
  --avauksen-tummennus-reuna: 0.44;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(36, 26, 18, var(--avauksen-tummennus)) 40%,
    rgba(36, 26, 18, var(--avauksen-tummennus-reuna)) 100%);
}

/*
 * PERGAMENTTIHARSO VAIN TEKSTIN KOHDALLE (5.9.2026 ilta). Kun pallo
 * täyttää koko paneelin, avausteksti ei enää lepää tyhjällä
 * pergamentilla vaan pallon pinnalla — meren sini vei mustepunaisen
 * tekstin kontrastin. Harso on PAIKALLINEN liukuväri palstan ja
 * julisteotsikon takana, ei koko kerroksen päällä: pallo jää näkyviin
 * kaikkialle muualle. EI suodattimia (iOS-sääntö).
 *
 * HARSO ON OMA KERROKSENSA (::before) EIKÄ ELEMENTIN TAUSTA, koska
 * taustan reunan pehmentäminen vaatisi paddingia — ja padding
 * kasvattaisi otsikko- ja tekstilohkoa. Pseudo levittyy laatikon
 * ulkopuolelle muuttamatta asettelua. `z-index: 0` tekee palstasta
 * oman pinon, jotta −1 jää palstan sisään eikä valu pallokerroksen
 * taakse (.intro on z-index: 3 ja siis oma pinonsa).
 */
/*
 * TEKSTILOHKOT VERHON JA PALLON PÄÄLLE (z-index 3); palsta ja
 * julisteotsikko pysyvät omina pinoinaan (z-index 0), jotta niiden
 * pergamenttiharso (::before, z-index −1) jää lohkon sisään eikä valu
 * pallokerroksen taakse.
 */
.intro.intro-pallolla .intro-kartta,
.intro.intro-pallolla .intro-arkki { z-index: 3; }

.intro.intro-pallolla .intro-palsta,
.intro.intro-pallolla .intro-juliste { z-index: 0; }

/*
 * HARSON KAAVA ON YKSI, SÄÄTIMIÄ KOLME (omistajan tilaus 5.9.2026 klo
 * 00.25, sanatarkasti: *"konekirjoituksen tekstin takana oleva
 * vaalennus pienemmälle teholle sekä isommalle alueella mutta niin että
 * häivytys peittää elementin neliöt rajat. ylemmässä myös häivytyksen
 * rajat pois näkyvistä (pohjalaatta vähän isompi ja häivytys
 * pidemmälle matkalle)"*).
 *
 *   --harson-peitto    koko harson voimakkuus (pseudon peittävyys):
 *                      keskellä juuri tämä, reunoilla nolla.
 *   --harson-haivytys  mistä kohtaa sädettä häivytys alkaa. Ennen
 *                      tätä on tasainen lava, sen jälkeen seitsemän
 *                      pysäkin liuku nollaan asti — pitkä matka, jolla
 *                      silmä ei erota yhtään rajaa.
 *   --harson-sade      liukuvärin ellipsin säde laatan mitoista.
 *                      LIUVUN ON SAMMUTTAVA ENNEN LAATAN REUNAA:
 *                      säteellä 56 % reuna (50 % laatasta) osuu jo
 *                      89 %:iin sädettä, jolloin harso on siellä
 *                      käytännössä nolla (≈ 0,03) — juuri tämä
 *                      piilottaa "elementin neliöt rajat". Vanha 74 %
 *                      leikkasi harson kohdassa, jossa peittävyyttä
 *                      oli vielä 0,27, ja suorakulmio näkyi. Sitä
 *                      pienempi säde taas kutistaisi harson alaa —
 *                      laatan ala kasvatetaan insetillä, ei säteellä.
 *
 * Ala on em-mittainen ja siis tekstin kokoinen: kun fitIntro kutistaa
 * kirjasinta, harso kutistuu mukana eikä irtoa tekstistään.
 */
.intro.intro-pallolla .intro-palsta::before,
.intro.intro-pallolla .intro-juliste::before {
  content: '';
  position: absolute;
  z-index: -1;
  pointer-events: none;
  --harson-sade: 56%;
  opacity: var(--harson-peitto);
  background: radial-gradient(ellipse var(--harson-sade) var(--harson-sade) at 50% 50%,
    rgba(243, 228, 196, 1) 0%,
    rgba(243, 228, 196, 0.97) var(--harson-haivytys),
    rgba(243, 228, 196, 0.86) calc(var(--harson-haivytys) + 10%),
    rgba(243, 228, 196, 0.66) calc(var(--harson-haivytys) + 19%),
    rgba(243, 228, 196, 0.42) calc(var(--harson-haivytys) + 28%),
    rgba(243, 228, 196, 0.2) calc(var(--harson-haivytys) + 37%),
    rgba(243, 228, 196, 0.06) calc(var(--harson-haivytys) + 47%),
    rgba(243, 228, 196, 0) 100%);
}

/*
 * KONEKIRJOITUKSEN HARSO: PIENEMPI TEHO, ISOMPI ALA (omistaja 5.9.2026
 * klo 00.25). Peitto 0,94 → 0,62 ja laatta liki kaksinkertainen
 * (-1,2em/-1,6em → -2,6em/-5em), joten teksti lepää yhä pergamentilla
 * mutta pallo näkyy sen läpi eikä harsosta erotu reunaa.
 */
.intro.intro-pallolla .intro-palsta::before {
  inset: -2.6em -5em;
  --harson-peitto: 0.62;
  --harson-haivytys: 42%;
}

/*
 * JULISTEOTSIKON HARSO: POHJALAATTA ISOMPI JA HÄIVYTYS PIDEMMÄLLE
 * (omistaja 5.9.2026 klo 00.25; kuvakaappauksessa 2000 px leveällä
 * ruudulla soikion reuna erottui selvästi otsikon ympäriltä). Laatta
 * -0,5em/-1,4em → -1,8em/-3,6em ja lava loppuu jo 36 %:n kohdalla,
 * joten liuku kestää lähes kaksi kolmasosaa säteestä.
 */
.intro.intro-pallolla .intro-juliste::before {
  inset: -1.8em -3.6em;
  --harson-peitto: 0.8;
  --harson-haivytys: 36%;
}

/*
 * HARSO ON PIILOSSA PORTIN TAKANA JA SYTTYY YLÄVIIVAN KANSSA (omistajan
 * tilaus 6.9.2026 aamu: *"ota taustalta pois pelin otsikko"*). Ilman
 * tätä aloitusportille jäisi vaalea soikio tyhjän otsikon paikalle:
 * julisteen rivit ovat piilossa (.avaus-kesken), mutta harso on
 * julisteen oma ::before eikä katoa niiden mukana. Luokan lisää
 * js/ui.js naytaAvausjuliste ensimmäisessä vaiheessa.
 */
.intro.intro-pallolla .intro-juliste.avaus-kesken::before {
  opacity: 0;
  transition: opacity var(--viivan-piirto, 520ms) ease-out;
}

.intro.intro-pallolla .intro-juliste.avaus-kesken.avaus-harso::before {
  opacity: var(--harson-peitto);
}

/*
 * SAMA ODOTUS TEKSTIPALSTAN HARSOLLE: se syttyy vasta, kun
 * kirjoituskone alkaa (js/ui.js naytaAvausjuliste viimeinen vaihe).
 * Muuten pallon päällä olisi koko avauksen ajan tyhjä vaalea soikio
 * odottamassa tekstiään — se erottuu selvästi nyt, kun taustapallo on
 * tummennettu (omistaja 6.9.2026 aamu).
 */
.intro.intro-pallolla .intro-palsta.avaus-kesken::before {
  opacity: 0;
  transition: opacity var(--salaman-kesto, 600ms) ease-out;
}

.intro.intro-pallolla .intro-palsta.avaus-kesken.avaus-harso::before {
  opacity: var(--harson-peitto);
}

@media (prefers-reduced-motion: reduce) {
  /* Kerros on paikallaan heti (Raamattu, sääntö 4). */
  .etusivupallo { transition: none; }
}

.intro.intro-fade { opacity: 0; }
/*
 * HÄIVYTETTY AVAUSTEKSTI EI OTA NAPAUTUKSIA (aalto 3A, karttapallo.md
 * luku 10.3). Tasokartalla teksti työntyy ruudun alle (.intro-pois),
 * mutta pallolla lähtövalinta avautuu pelkällä häivytyksellä — ja
 * näkymätön "Valitse aloituskaupunki" (.intro-valinta on
 * pointer-events: auto) veisi silloin pallon pyörityksen ja Ateenan
 * napautuksen itselleen. Sama sääntö kelpaa kummallekin laudalle:
 * häivytetty teksti on poissa myös sormelta.
 */
.intro.intro-fade,
.intro.intro-fade * { pointer-events: none; }

/*
 * ALOITUSSIIRTYMÄN TYHJÄ PERGAMENTTIARKKI (js/ui.js naytaAloitusverho).
 *
 * Pelkkä pergamentti ja sen rakeisuus — ei suodattimia, ei sisältöä.
 * Arkki nousee kohdekaupungin napautuksesta, raskas laudanvaihto ja
 * kameran asettuminen tapahtuvat sen takana, ja arkki häipyy vasta
 * valmiiseen lentonäkymään. Peittävyys on ainoa animoitava ominaisuus,
 * joten siirtymä pysyy kompositorissa eikä jää pääsäikeen jumin alle.
 *
 * z-index 50: lentokalvon (7), aloitusportin (6) ja kelluvan
 * pöllönapin (45) yläpuolella, mutta dialogien (60+) alapuolella —
 * arkin on peitettävä KOKO näkymä, myös kartan päällä kelluvat napit.
 */
.aloitusverho {
  position: absolute;
  inset: 0;
  z-index: 50;
  opacity: 0;
  pointer-events: none;
  background-color: var(--paper);
  background-image: var(--paper-noise);
  transition: opacity var(--verho-kesto, 420ms) ease;
}

/* Näkyvä arkki nielee myös napautukset: siirtymän aikana ei valita. */
.aloitusverho.verho-nakyy {
  opacity: 1;
  pointer-events: auto;
}

/*
 * SAAPUMISEN VÄLIKORTTI (omistajan tilaus 26.8.2026): sama tyhjä
 * pergamenttiarkki kuin aloitussiirtymässä, mutta sen keskellä on
 * konekirjoituksella ilmestyvä rivi — kohdekaupunki ja päivälaskuri.
 * Kortti on lennon ja kartan välissä: se on ainoa hetki, jolloin
 * pelaaja lukee mihin hän saapui ja monesko päivä on menossa.
 */
.saapumiskortti {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

.saapumiskortti-teksti {
  margin: 0;
  max-width: min(30rem, calc(100% - 2rem));
  color: var(--map-ink, #46331f);
  font-family: var(--font-type);
  font-size: clamp(1.05rem, 4.4vw, 1.6rem);
  letter-spacing: 0.13em;
  line-height: 1.5;
  text-align: center;
  opacity: 1;
  transition: opacity 320ms ease;
}

/* Teksti häviää ennen karttaa: paperi jää hetkeksi tyhjäksi. */
.saapumiskortti-teksti.poistuu { opacity: 0; }

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

/*
 * Kelluva pöllönappi elää kartan kerrosten ulkopuolella, joten arkin
 * z-index ei yllä sen yli (mitattu: nappi jäi näkyviin tyhjälle
 * arkille). Se väistyy siis omalla säännöllään ja palaa arkin mukana.
 */
body.aloitusverho-paalla .pollo-nappi {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/*
 * PÖLLÖ VÄISTYY LENNON AJAKSI (omistajan pelitestipalaute v1119:
 * *"pöllönappi piiloon lennon ajaksi"*).
 *
 * Lentonäkymä on kohtaus eikä pelitilanne: kartalla on vain reitti,
 * kone ja nuoren herran repliikki. Kelluva pöllönappi jäi kohtauksen
 * päälle oikeaan alanurkkaan — samasta syystä kuin arkin sääntö yllä,
 * eli nappi elää kartan kerrosten ulkopuolella eikä kalvon z-index
 * yllä sen yli. Paneeli suljetaan samalla: auki jäänyt keskustelu
 * peittäisi puolet lennosta.
 *
 * Sama häivytys kuin arkilla, ja nappi palaa itsestään perillä, kun
 * body.flight-active / body.kartalento poistuvat (js/ui.js).
 */
body.flight-active .pollo-nappi,
body.kartalento .pollo-nappi,
body.flight-active .pollo-paneeli,
body.kartalento .pollo-paneeli {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

/*
 * LAUTAA EI MAALATA TÄYSIN PEITTÄVÄN ARKIN ALLA (omistajan pelitesti
 * 25.8.2026: avauslennossa *"menee monta sekuntia, kun pelissä ei
 * tapahdu mitään"*).
 *
 * Arkin takana rakennetaan uusi maailmankartta: 7000 vektorielementtiä,
 * joista tehdään bittikartta (js/ui.js rasteroiTaide). Selain maalasi
 * kuitenkin koko ajan myös itse lautaa — lähikuvassa mitattuna 1,6
 * sekuntia kehykseltä — ja juuri se maalaus vei sen ajan, jolla
 * bittikartan olisi pitänyt valmistua. Arkin alla maalaukselle ei ole
 * katsojaa, joten se jätetään tekemättä.
 *
 * VISIBILITY EIKÄ DISPLAY. Asettelu on jätettävä voimaan: kamera lukee
 * mittansa elävästä puusta (getScreenCTM, getBoundingClientRect) ja
 * rasterointi lukee lasketut tyylit (mapart.js tyylitSisaan). display:
 * none nollaisi molemmat, ja kartasta tulisi tyhjä.
 *
 * Luokka on ERI kuin aloitusverho-paalla ja tulee vasta kun arkki on
 * mitatusti läpinäkymätön: samalla hetkellä asetettuna lauta katoaisi
 * puoliksi läpinäkyvän arkin alta ja ruudulla välähtäisi tyhjää
 * (v1105:n korjaama vika).
 */
body.lauta-arkin-alla #board { visibility: hidden; }

/*
 * Zoomatessa avausteksti työntyy alas pois näkyvistä samaa tahtia kuin
 * kartta suurenee (omistajan toive). Matka, kesto ja pehmennys tulevat
 * js/ui.js:n tyonnaAvausteksti-metodista, joka mittaa kartan alareunan
 * todellisen siirtymän — niin teksti liikkuu kartan kanssa koko matkan
 * eikä vain lähtee ja saavu samaan aikaan. Oletukset ovat varalta.
 *
 * Häivytys loppuu ennen liikettä, jotta teksti on jo poissa silmistä
 * kun se painuu ruudun alle; pelkkä häivytys jätti sen paikalleen
 * haamuksi kartan päälle.
 */
.intro.intro-pois {
  opacity: 0;
  /* Palsta on nykyään koko paneelin levyinen (ei enää translateX(-50%)),
     joten työntö on pelkkä pystysiirto. */
  transform: translateY(var(--intro-tyonto, 85%));
  will-change: transform, opacity;
  transition:
    transform var(--intro-kesto, 1.2s)
      var(--intro-pehmennys, cubic-bezier(0.25, 0.6, 0.2, 1)),
    opacity calc(var(--intro-kesto, 1.2s) * 0.7) ease-in;
}

/*
 * Lento piirretään läpikuultavana kalvona kartan päälle: karttaa ei
 * zoomata (raskasta ja suurennettuna rumaa), vaan kohtaus on oma
 * yksinkertainen piirroksensa, jonka läpi maailmankartta kuultaa.
 */
.flight-overlay {
  position: absolute;
  inset: 0;
  /* Kalvon on oltava kelluvan alarivin (z-index 4) yläpuolella, muuten
   * rivin näkymättömät napit jäävät kalvon päälle nappaamaan napautuksia. */
  z-index: 7;
  /*
   * Kartta sumenee kalvon alla, jotta lentoreitti ja teksti erottuvat
   * (omistajan toive). Ilman sumennusta kaupunkien nimet kilpailevat
   * kortin kanssa ja silmä hakeutuu niihin.
   *
   * Sumennus maksaa mitatusti noin 5 fps lennon aikana (20 -> 15).
   * Kokeilin myös staattista blur-suodinta itse kartalle backdropin
   * sijaan: se maksoi saman verran, joten yksinkertaisempi jää.
   */
  background: rgba(243, 231, 205, 0.62);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  /*
   * KARTTA, TEKSTI JA NAPPI YHTENÄ PINONA (omistajan tilaus 12.8.2026).
   *
   * Ennen kartta keskitettiin kalvoon ja repliikki kellui erikseen
   * kalvon alalaidassa. Leveällä ruudulla ne osuivat päällekkäin:
   * tekstilaatikko peitti lentoreitin loppupään ja kohdekaupungin
   * nimen. Pystypino ratkaisee sen ilman yhtään mittaa — kartta
   * asettuu ylös, teksti tulee sen alle eikä päälle.
   *
   * Pino keskitetään pystysuunnassa mutta painotetaan ylöspäin
   * alareunan täytteellä: silmä lukee kartan ensin, ja Astu
   * mantereelle -nappi jää mukavalle peukalokorkeudelle puhelimessa.
   */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(0.5rem, 2.5vh, 1.6rem) 0
    max(calc(env(safe-area-inset-bottom, 0px) + 3.5rem), 12vh);
  animation: flight-overlay-in 0.35s ease;
}

/*
 * Paperin rakeisuus pois lennon ajaksi. Se on mix-blend-mode-kerros koko
 * ruudun kokoisena, ja jokainen koneen liike pakotti sen sekoittumaan
 * uudelleen: mitattuna 12 -> 15 fps. Kalvon alla rakeisuus ei näy,
 * koska päällä on läpikuultava pergamentti ja sumennus.
 */
body.flight-active .grain { display: none; }

@keyframes flight-overlay-in { from { opacity: 0; } }

/*
 * Karttalehti pinon ylimpänä. flex-shrink: 0 on tässä välttämätön:
 * ilman sitä pystypinossa oleva SVG kutistuisi tekstin tieltä ja
 * lentoreitti litistyisi sitä mukaa kuin repliikki pitenee.
 */
.flight-scene {
  width: min(96%, 1100px);
  max-height: 62%;
  flex: 0 0 auto;
}

.flight-scene .flight-trail { stroke-width: 4.4; }

.flight-dot { fill: #2e2114; }

.flight-name {
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 42px;
  letter-spacing: 0.08em;
  fill: #3a2a16;
}

/* Käsin piirretyt vyöhykeviivat (kääntöpiirit) katkoviivalla. */
.flight-zone {
  fill: none;
  stroke: rgba(70, 51, 31, 0.3);
  stroke-width: 1.6;
  stroke-dasharray: 10 8;
}

/*
 * Isoisän käsiala: kursiivinen kaunokirjoitus, jota ei ole tarkoituskaan
 * pystyä lukemaan kuin osittain — kuin vanhan kartan reunamerkinnät.
 * Fonttipino on --font-kauno, ks. :root.
 */
.flight-zone-name {
  font-family: var(--font-kauno);
  font-style: italic;
  font-size: 21px;
  letter-spacing: 0.1em;
  fill: rgba(70, 51, 31, 0.3);
}

/* Isoisän himmeät merkinnät ja piirrokset kalvon laidoilla. */
.flight-note-text {
  font-family: var(--font-kauno);
  font-style: italic;
  font-size: 24px;
  letter-spacing: 0.02em;
  fill: rgba(70, 51, 31, 0.28);
}

.flight-doodle {
  stroke: rgba(70, 51, 31, 0.3);
  stroke-width: 1.6;
}

.flight-doodle-fill { fill: rgba(70, 51, 31, 0.28); }

/* Lentokohtaus häipyy pois pehmeästi. */
.flight-overlay.flight-leaving {
  opacity: 0;
  transition: opacity 0.28s ease;
}

/*
 * SUMENNUS SEURAA TODELLISTA TILAA, EI SITÄ ETTÄ JOKU MUISTAA SIIVOTA.
 *
 * Kalvo on ainoa koko kartan peittävä sumennus pelissä, ja se elää
 * DOM-elementtinä: jos lennon animaatioketju katkeaa (poikkeus, kesken
 * jäänyt odotus), elementti jää paikalleen ja kartta näyttää
 * kauttaaltaan sumealta ilman että mitään on auki. Tämä sääntö tekee
 * siitä mahdotonta — kalvo näkyy vain silloin kun lento on merkitty
 * käynnissä olevaksi (body.flight-active) tai kun se on juuri
 * häipymässä (.flight-leaving, jonka js/ui.js lisää samassa
 * synkronisessa lohkossa, jossa se poistaa lipun).
 */
body:not(.flight-active) .flight-overlay:not(.flight-leaving) { display: none; }

/* Repliikin kelluva alaosa kalvon pystypinossa.
 *
 * VIRRASSA EIKÄ KELLUEN (omistajan tilaus 12.8.2026): alaosa on
 * kalvon pystypinon toinen jäsen kartan alla, joten teksti ei voi
 * osua lentoreitin päälle.
 *
 * ASTU MANTEREELLE -NAPPI ON POISSA (omistajan tilaus 26.8.2026):
 * lento jatkaa itsestään, ja alaosaan jää vain repliikki. Pino ei
 * siltikään liiku kirjoituksen aikana, koska rivi varaa koko
 * korkeutensa heti (js/ui.js typeText piirtää kirjoittamattoman osan
 * näkymättömänä).
 *
 * VÄLI KARTAN JA REPLIIKIN VÄLIIN (omistajan tilaus 12.8.2026: teksti
 * saa olla vähän alempana). Repliikki oli kiinni lentoreitin
 * alareunassa, ja kone lensi käytännössä tekstin niskaan. Väli on noin
 * kaksinkertainen entiseen. Mitattuna 51 px (390 px) ja 48 px
 * (900 px), kun se oli ennen 21 px ja 20 px.
 *
 * Yläraja on rem-mitta eikä vh, jottei matala vaakanäyttö työntäisi
 * riviä ruudun ulkopuolelle. */
.flight-alaosa {
  margin-top: clamp(1.4rem, 6vh, 3.2rem);
  width: min(680px, calc(100% - 1.6rem));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  z-index: 5;
}

/*
 * Ohita lento -nuoli: pieni kärki oikeassa alanurkassa, joka syttyy
 * muutaman sekunnin kuluttua.
 *
 * Omistajan vaatimus oli "aika huomaamaton", ja se on tässä
 * suunnittelun ehto: nuoli on samalla ruudulla kuin lennon repliikki,
 * jonka lukemiseen lennon kestoa juuri pidennettiin. Siksi ei väriä,
 * ei kehystä eikä liikettä — pelkkä musteen sävyinen kärki, joka
 * häivähtää esiin kahdessa sekunnissa ja kirkastuu vasta osoittimen
 * alla.
 */
.flight-eteen {
  position: absolute;
  right: max(1.1rem, env(safe-area-inset-right, 0px));
  /* Versionumero asuu leveällä ruudulla samassa nurkassa; nuoli nousee
     sen yli, jottei kärki osu numeron päälle. */
  bottom: max(2.9rem, calc(env(safe-area-inset-bottom, 0px) + 2.6rem));
  width: 2.6rem;
  height: 2.6rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink, #46331f);
  opacity: 0;
  pointer-events: none;
  transition: opacity 2s ease;
  cursor: pointer;
  z-index: 3;
}

.flight-eteen.nakyy {
  opacity: 0.3;
  pointer-events: auto;
}

.flight-eteen.nakyy:hover,
.flight-eteen.nakyy:focus-visible {
  opacity: 0.72;
}

.flight-eteen svg {
  width: 100%;
  height: 100%;
  display: block;
}

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

/*
 * ASTU MANTEREELLE -NAPPI ON POISTETTU (omistajan tilaus 26.8.2026:
 * *"ota siitä pois astu mantereelle -nappi. Muuten tulee liikaa
 * nappeja heti alkuun."*). Lento jatkaa laskeuduttuaan itsestään ja
 * napautus vie perille heti, joten kalvolla ei ole enää yhtään nappia
 * — ohitusnuolta lukuun ottamatta. Napin messinkitylli asui tässä.
 */

/* Aloita seikkailu -portti: kartta himmeänä taustalla, nappi keskellä.
 * Napautus avaa selaimen äänilukon, joten intro-puhe ja ambienssi
 * pääsevät soimaan heti. */
.start-gate {
  position: absolute;
  inset: 0;
  z-index: 6;
  /*
   * PORTIN TUMMENNUS on reunakuultoa tasaisen sijaan (arkkikirjaston
   * panos-aste): keskusta jää valoisammaksi ja reunat kehystävät.
   * Luvut ovat nimettyinä muuttujina, koska avauksen taustapallo saa
   * saman kaavan yhtä astetta vaaleampana (.intro.intro-pallolla
   * .intro-verho: 0,18 ja 0,44) — omistajan tilaus 6.9.2026 aamu.
   *
   * Soikio on nyt ruudun keskellä (ennen 42 %, jolloin valoisin kohta
   * osui julisteotsikkoon): portin takana ei enää ole otsikkoa, vaan
   * pelkkä pallo ja keskellä nappi.
   */
  --portin-tummennus: 0.28;
  --portin-tummennus-reuna: 0.6;
  background: radial-gradient(ellipse at 50% 50%,
    rgba(36, 26, 18, var(--portin-tummennus)) 40%,
    rgba(36, 26, 18, var(--portin-tummennus-reuna)) 100%);
  /* Kartta sumenee napin takana (omistaja 26.8.2026:
     "Aloitusvalikossa tekstin ja kartan voi sumentaa") — portti on
     oma pintansa, tarkka sisältö palaa vasta napautuksesta. */
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  animation: flight-overlay-in 0.35s ease;
  padding: 1rem;
}

/*
 * NAPPI IHAN KESKELLE RUUTUA (omistajan tilaus 6.9.2026 aamu,
 * sanatarkasti: *"keskitä aloita seikkailu nappi ihan keskelle
 * ruutua"*). Ennen ryhmä oli 62 %:n korkeudella julisteotsikon
 * alapuolella; nyt otsikkoa ei ole portin takana lainkaan, joten
 * ryhmä keskitetään sekä pysty- että vaakasuunnassa — sama sommitelma
 * työpöydällä ja puhelimessa. Ääniviihje kelluu napin yläpuolella
 * eikä siirrä sitä.
 */
.start-gate-keskus {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Ääniviihje napin yläpuolella: peli on tehty kuunneltavaksi, ja selain
   sallii äänet vasta ensimmäisestä napautuksesta. */
.start-aanet {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 0.8rem);
  transform: translateX(-50%);
  white-space: nowrap;
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  font-family: var(--font-type);
  font-size: 0.98rem;
  letter-spacing: 0.03em;
  color: #e8d6ac;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}

.start-aanet .viiva-ikoni svg { width: 1.25em; height: 1.25em; }

.start-btn {
  font-size: 1.15rem;
  padding: 0.9rem 2rem;
  letter-spacing: 0.04em;
}

/*
 * Alareunan linkki pelin periaatteisiin. Irti virrasta, jotta se ei
 * työnnä Aloita seikkailu -nappia ylös: nappi kuuluu ruudun keskelle
 * (omistajan havainto).
 */
/* Alareunassa on jo kaksi asukasta: versionumero vasemmalla ja
   palautehuutomerkki oikealla. Linkki nostetaan niiden yläpuolelle ja
   sen sivuille jätetään tilaa, ettei rivi ahtaudu (omistajan havainto). */
.start-gate-alaosa {
  position: absolute;
  left: 3.2rem;
  right: 3.2rem;
  bottom: max(2.6rem, calc(env(safe-area-inset-bottom, 0px) + 2.4rem));
  text-align: center;
}

.start-linkki {
  background: none;
  border: 0;
  padding: 0.5rem 0.7rem;
  min-height: 0;
  font-family: var(--font-type);
  font-size: 0.86rem;
  line-height: 1.4;
  color: #d8c091;
  text-decoration: underline;
  text-underline-offset: 4px;
  text-decoration-color: rgba(216, 192, 145, 0.45);
  cursor: pointer;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}

.start-linkki:hover { color: #f2e2bb; }

/* Periaateikkuna: sama pergamentti kuin muissa lapuissa, mutta pitkä
   teksti saa vierittyä. */
.periaate-lappu .dialog-card {
  max-height: 82vh;
  max-height: 82dvh;
  overflow-y: auto;
}

.periaate-otsikko {
  margin: 0 0 0.6rem;
  font-family: var(--font-type);
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  color: #7a5514;
}

.periaate-valiotsikko {
  margin: 1rem 0 0.25rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: #8a6a2c;
}

.periaate-teksti {
  margin: 0;
  color: var(--map-ink);
  font-size: 0.94rem;
  line-height: 1.55;
}

.periaate-teksti.kärki { font-size: 1rem; }

.periaate-linkit {
  margin: 1.2rem 0 0;
  text-align: center;
}

.periaate-linkki {
  color: #7a5514;
  font-family: var(--font-type);
  font-size: 0.9rem;
  text-underline-offset: 4px;
}

/* Palautelohko: kenttä ja nappi erottuvat tekstistä ohuella viivalla. */
.periaate-palaute {
  margin-top: 1.3rem;
  padding-top: 0.9rem;
  border-top: 1px dashed rgba(122, 85, 20, 0.35);
}

.periaate-palaute .periaate-valiotsikko { margin-top: 0; }

.periaate-kentta {
  width: 100%;
  margin-top: 0.6rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid rgba(122, 85, 20, 0.45);
  border-radius: 8px;
  background: rgba(255, 252, 240, 0.7);
  color: var(--map-ink);
  font-family: var(--font-type);
  font-size: 0.9rem;
  line-height: 1.5;
  resize: vertical;
}

.periaate-kentta:focus {
  outline: 2px solid rgba(176, 138, 60, 0.7);
  outline-offset: 1px;
}

.periaate-laheta {
  margin-top: 0.6rem;
  width: 100%;
}

.periaate-huomio {
  margin: 0.5rem 0 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: #6d5a3c;
}

/*
 * LUKIJOIDEN EHDOTUKSET (js/ehdotukset.js): palautelomakkeen perässä
 * oma taitettava osio, jotta palautteen lähettäminen pysyy yhtä
 * yksinkertaisena kuin ennen. Kentät perivät .periaate-kentta-tyylin;
 * tässä on vain osion kehys, rastirivit ja piilokenttä.
 */
.periaate-ehdotus {
  margin-top: 1.1rem;
  padding-top: 0.8rem;
  border-top: 1px dashed rgba(122, 85, 20, 0.35);
}

.periaate-ehdotus > summary {
  cursor: pointer;
  margin: 0;
}

/*
 * Pro-osion rastirivi (omistaja 18.8.2026): vivun tilalla checkbox
 * "Haluan hakea pro-sisällöntuottajaksi" ja pieni i, joka avaa
 * minipopup-selitteen. Rasti perii periaate-rastin kirjasimen; i on
 * sama seloste-nappi kuin laukussa.
 */
.pro-rasti-rivi {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.pro-rasti-nimio {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  cursor: pointer;
  font-family: var(--font-type);
  font-size: 0.82rem;
  color: #6d5a3c;
}

.periaate-nimio {
  display: block;
  margin-top: 0.7rem;
  font-family: var(--font-type);
  font-size: 0.82rem;
  color: #6d5a3c;
}

.periaate-rasti {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  margin-top: 0.6rem;
  font-family: var(--font-type);
  font-size: 0.82rem;
  line-height: 1.45;
  color: #6d5a3c;
}

.periaate-rasti input { margin-top: 0.15rem; }

/* Hunajapurkki: robotille näkyvä, ihmiselle ei. */
.periaate-hunaja {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.periaate-oikeudet {
  margin: 1.2rem 0 0;
  text-align: center;
  font-family: var(--font-type);
  font-size: 0.82rem;
  color: #6d5a3c;
}

.periaate-otsikko:focus { outline: none; }

.periaate-sulje {
  margin-top: 1rem;
  width: 100%;
}

/* Lennon ajaksi alareunan kortit ja napit väistyvät: kalvon alla näkyy
 * vain kohteen kartta. Teksti ja lukuääni jatkuvat piilossa. */
body.flight-active .turn-card,
body.flight-active .fact-card {
  opacity: 0;
  pointer-events: none;
}


/*
 * Puhelin: palsta leveämmäksi, rivit tiheämmiksi ja kansikuva
 * pienemmäksi. Omistajan ohje 25.8.2026: iPhonella tila saa olla ahdas
 * muttei rikki — teksti on tärkein, kuva joustaa.
 */
@media (max-width: 700px) {
  .intro-palsta { width: 92%; }
  .intro-juliste { margin-bottom: 1em; gap: 0.45em; }
  .juliste-nimi { font-size: 1.42em; letter-spacing: 0.18em; text-indent: 0.18em; }
  .juliste-yla { font-size: min(0.86em, 4.4vw); letter-spacing: 0.14em; text-indent: 0.14em; }
  /* "kahdeksassakymmenessä" on 21 merkkiä yhtä sanaa: kapealla
     ruudulla koko sidotaan ruudun leveyteen ja välistys tiivistyy,
     jottei rivi leikkaudu reunoista (omistajan kaappaus 26.8.2026,
     iPhone). */
  .juliste-ala { font-size: min(0.8em, 4vw); letter-spacing: 0.1em; text-indent: 0.1em; }
  .intro-text { line-height: 1.5; }
  .intro-valinta { margin-top: 1.1em; line-height: 1.4; }
  .intro-tyopoyta { width: min(100%, 19em); margin-top: 1.1em; }
  /* Kapealla ruudulla irtolehdelle ei ole tilaa: se valuisi palstan
     ulkopuolelle ruudun laitaan (omistajan lupa piilottaa). */
  .intro-irtolehti { display: none; }
}

/*
 * Matala ruutu (vaakapuhelin): kansikuva pois — palstaan mahtuu vain
 * teksti ja klikattava lause, ja juuri ne kaksi ovat välttämättömiä.
 */
@media (max-height: 520px) {
  .intro-tyopoyta { display: none; }
}

/* Pallonpuoliskokartan kehykset ja asteverkko. */
.hemi-ring {
  fill: none;
  stroke: var(--map-ink);
  stroke-width: 2.2;
  opacity: 0.75;
}

.hemi-ring.outer { stroke-width: 1.4; opacity: 0.55; }
.hemi-tick { stroke: var(--map-ink); stroke-width: 1; opacity: 0.45; }

.graticule-line {
  fill: none;
  stroke: var(--map-ink-soft);
  stroke-width: 0.8;
  opacity: 0.32;
}

.graticule-line.strong { stroke-width: 1.4; opacity: 0.45; }

.city { fill: #f3e5c4; stroke: #6b5230; stroke-width: 1.7; }
.city-start { fill: #eec66b; stroke: #6d4d12; stroke-width: 2.4; }

/* ------------------------------------------------------------------
 * KEHITTÄJÄKARTAN VÄRILAATTAKOODIT ON POISTETTU (omistajan tilaus
 * 26.8.2026: *"Poista pelistä muuten kaikki värilaattakoodit, jotka
 * olivat aiemmin"*). Tässä olivat lehden valmiusasteikko
 * (.city-valmis/.city-tuore/.city-lahes/.city-kesken) ja herokuvien
 * viiteankkurointi (.city-viite-taysi/.city-viite-osa). Sama tieto on
 * yhä Tilastot-taulussa (js/tyohuone-tilastot.js); kartalla laatta on
 * nyt joka tilassa laudan oma pergamentti.
 * ------------------------------------------------------------------ */

/*
 * AVATTU LAATTA VAIHTAA VÄRIÄ (omistajan linjaus 28.8.2026 ilta,
 * kuvakaappaus Sofiasta: *"Pitäisi olla vain nappi ja laatta"* — kumoaa
 * 26.8.2026 aarremerkkilinjan).
 *
 * ENNEN TÄSSÄ OLI PIILOTUS (.aarre-laatan-alla): kaupungin laatta
 * katosi ja tilalle piirtyi aarremerkki, pergamenttikiekko ja
 * kaiverrettu kuvake. Nappulan alla kiekon tumma kehä luki tyhjänä
 * renkaana ja kuvake pilkotti sen takaa — juuri se pino, jonka
 * omistaja näki.
 *
 * NYT: laatta on entisellään ja LÖYTÖ ON PELKKÄ SÄVY. Pergamentin
 * (#f3e5c4) tilalle lämmin kullansävy, sama kieli kuin lähtökaupungin
 * kullatulla laatalla (#eec66b) mutta astetta kypsempi pronssi, jotta
 * löytö ei sekaannu lähtöpaikkaan. Kehä tummenee saman verran kuin
 * muissakin kullatuissa merkeissä (#6d4d12).
 *
 * Väri on luokka eikä suodatin (sama iOS-sääntö kuin kartan muillakin
 * kerroksilla) ja koskee vain laatan omaa ellipsiä: rantarengas,
 * porttikehä ja lentokentän merkki kertovat kaupungista, eivät
 * löydöstä.
 */
.city.aarre-loydetty { fill: #c98a37; stroke: #6d4d12; }
.city-start.aarre-loydetty { fill: #c98a37; stroke: #6d4d12; }

/*
 * LAATTA JÄÄ NAPPULAN ALLE NÄKYVIIN (omistajan tilaus 28.8.2026:
 * *"sen alta saisi näkyä kaupungin laatta (nyt ei näy ollenkaan). eli
 * nappula saa olla pienempi"*).
 *
 * MITÄ TÄSSÄ OLI ENNEN: koko laatta — ellipsi, rantarengas, porttikehä,
 * lentokonemerkki ja sykekehä — piilotettiin nappulan kohdalta
 * (27.8.2026, iPad-kaappaus Sofian fokuslaudalta: *"nappulan alla näkyy
 * monta päällekkäistä kerrosta"*). Se oli oikea korjaus SILLOISELLE
 * nappulalle: hahmo oli 13,2 yksikköä leveä ja laatta 23,2, joten
 * laatasta jäi näkyviin vain ohut sirppi hahmon molemmin puolin — pino
 * eikä kerros.
 *
 * MIKSI SE EI OLE ENÄÄ OIKEA KORJAUS: nappula on nyt 10 x 18,1
 * yksikköä (js/ui.js NAPPULAN_POLKU) ja sen varjo laatan sisällä
 * (varjonR 5,7). Laatan reuna kiertää hahmon joka suunnasta, jolloin
 * kaksi merkkiä samassa pisteessä ei ole kaksi merkkiä vaan yksi:
 * NAPPULA SEISOO LAATALLA. Piilotus tekisi kaupungista sen ainoan
 * paikan kartalla, jolla ei ole laattaa — juuri sitä omistaja katsoi.
 *
 * KAKSI OSAA JÄÄ YHÄ POIS, ja molemmat samasta syystä kuin ennen:
 *   .airport      lentokoneen merkki on laatan KESKELLÄ, täsmälleen
 *                 nappulan takana. Siitä näkyisi vain siivenkärjet
 *                 hahmon molemmin puolin.
 *   .fokuslaatta-syke  houkutteleva, jatkuvasti sykkivä kehä. Se
 *                 kutsuu napauttamaan tyhjää laattaa; nappulan alla
 *                 pelaaja on jo siinä kaupungissa.
 *
 * VAIN NAPPULAN KOHDALTA. Luokka kirjoitetaan geometrisen ehdon
 * mukaan (nappulaKaupungissa), joten muiden kaupunkien merkit ovat
 * ennallaan — samoin oma laatta silloin, kun nappuloita on samassa
 * kaupungissa useampi ja ne on levitetty kehälle laatan viereen.
 */
.airport.nappulan-alla,
.fokuslaatta-syke.nappulan-alla { display: none; }
.airport { font-size: 10px; fill: #8d3a2c; }

/* Porttikaupunki: katkoviivakehä kertoo, että täältä lähtee lento toiselle laudalle. */
.city-gate {
  fill: none;
  stroke: #8d3a2c;
  stroke-width: 1.1;
  stroke-dasharray: 7 6;
  stroke-linecap: round;
  opacity: 0.4;
}

.city-label {
  fill: var(--map-ink);
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.04em;
  paint-order: stroke;
  stroke: rgba(239, 220, 180, 0.9);
  stroke-width: 4px;
  stroke-linejoin: round;
}

.city-label.start-label { font-size: 21px; letter-spacing: 0.1em; text-transform: uppercase; }

/*
 * YLEISKUVASSA EI KAUPUNKIEN NIMIÄ (omistajan tilaus 29.8.2026:
 * *"älä näytä kaupunkien nimiä tällä zoom tasolla"*).
 *
 * Luokka tulee kerrokseen näkymän leveydestä (js/ui.js
 * paivitaKaupunkinimienNakyvyys): kun ruudulla on yli 90 pituusastetta,
 * nimiä on päällekkäin satoja eikä yksikään ole luettavissa.
 * Lähtökaupungit (.start-label) jäävät — niitä on kourallinen ja juuri
 * niitä yleiskuvasta etsitään.
 *
 * `display: none` eikä `visibility`/`opacity`: piilotetun tekstin pitää
 * jäädä pois myös maalauksesta, ei vain näkyvistä (sama iOS-sääntö kuin
 * kartan muillakin kerroksilla, tests/rules.test.mjs).
 */
.cities.kaupunkinimet-piilossa .city-label:not(.start-label) { display: none; }

/* Kaupunkilaudalla nimet ovat astetta pienempiä: mittakaava on kortteleissa. */
#board[data-style='city'] .city-label { font-size: 16px; }
#board[data-style='city'] .city-label.start-label { font-size: 18px; }

/* --- laattojen kuvakkeet --- */

.token-disc { fill: #f7ecd2; stroke: var(--map-ink); stroke-width: 2.5; }

.icon-star { fill: #e8b23c; stroke: #6d4d12; stroke-width: 1.6; stroke-linejoin: round; }

.icon-hat { fill: #34291d; }
.icon-mask { fill: #6b5a45; }
.icon-eye { fill: #f7ecd2; }

.icon-empty { fill: none; stroke: #8a765a; stroke-width: 2; stroke-dasharray: 4 4; }
.icon-empty-line { stroke: #8a765a; stroke-width: 2; stroke-linecap: round; }

/* Taikalasi: läpikuultava lasi, tumma kehys ja varsi. Väri on sama kuin
   laattatyypin oma sävy js/tokens.js:ssä. */
.icon-linssi-lasi { fill: rgba(127, 179, 200, 0.5); stroke: #3b2a13; stroke-width: 1.7; }
.icon-linssi-varsi { fill: none; stroke: #3b2a13; stroke-width: 3.4; stroke-linecap: round; }
.icon-linssi-kajo { fill: none; stroke: rgba(255, 255, 255, 0.8); stroke-width: 1.4; stroke-linecap: round; }

/* Aarrekuvakkeiden varasolu: kolikkopino ja kätköarkku. Aarteella on
   useimmiten oma kuvansa, joten nämä näkyvät vain maissa, joiden omaa
   aarreparia ei ole vielä kirjoitettu (js/packs/paikallisaarteet.js). */
.icon-aarre { fill: #c89a3c; stroke: #3b2a13; stroke-width: 1.5; stroke-linejoin: round; }
.icon-aarre-viivat { fill: none; stroke: #3b2a13; stroke-width: 1.4; stroke-linecap: round; }

.token-icon { display: inline-block; vertical-align: -0.22em; }
/* Tarinallinen aarrekuva pikkuikonina: pyöreä rajaus ja kevyt
 * pergamenttireunus, jotta kuva istuu samaan riviin piirrosikonien
 * kanssa (vanhat jalokivi-ikonit poistuivat 10.8.2026). */
.aarre-ikoni {
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 0 0 1.5px rgba(94, 74, 47, 0.55);
  background: #1a1611;
}

.map-title {
  fill: var(--map-ink);
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  letter-spacing: 0.3em;
  opacity: 0.55;
}

/* Tunnusluvut samalla musteella kuin kartan otsikko (omistajan toive). */
.map-legend {
  fill: var(--map-ink);
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 16px;
  font-style: italic;
  opacity: 0.55;
}

/* Tunnuslukujen viivasymbolit: sama muste kuin otsikossa. */
.map-tunnus-ikoni {
  fill: none;
  stroke: var(--map-ink);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.55;
}

.compass { fill: none; stroke: var(--map-ink); stroke-width: 2; opacity: 0.65; }
.compass-fill { fill: var(--map-ink); opacity: 0.6; }
.compass-letter {
  fill: var(--map-ink);
  font-family: "Iowan Old Style", Georgia, serif;
  font-size: 22px;
  opacity: 0.7;
}

.doodle { fill: none; stroke: var(--map-ink); stroke-width: 2.2; opacity: 0.45; stroke-linecap: round; }
.terrain-mark { fill: none; stroke: var(--map-ink); stroke-width: 2; opacity: 0.3; stroke-linecap: round; }
.terrain-fill { fill: var(--map-ink); opacity: 0.26; }
.doodle-fill { fill: var(--map-ink); opacity: 0.45; }

.target { cursor: pointer; }
.target-hit { fill: transparent; }

/*
 * Lähtöpisteen valinnassa rengas on joka kaupungin päällä yhtä aikaa, joten
 * pyörivä katkoviiva tekisi koko kartasta levottoman. Nämä renkaat vain
 * merkitsevät vaihtoehdon; siirtovaiheen punaiset renkaat ovat kehotus
 * toimia ja saavat siksi jäädä eläviksi.
 */
.target-ring.pick {
  fill: none;
  stroke: #b08a3c;
  stroke-width: 2;
  /*
   * Ei hehkusuodatinta lähtöpisteen valinnassa: siellä rengas piirretään
   * joka kaupungille, eli Afrikassa lähes neljäkymmentä suodatinpintaa
   * yhtä aikaa. Kullanruskea rengas erottuu pergamentilta ilmankin.
   */
  filter: none;
  /* Hento sykähdys kertoo, mihin voi napauttaa. Vain peittoa —
     ei suodinta eikä muotoa, jotta selain ei laske viivoja uusiksi. */
  animation: kohde-syke 2.6s ease-in-out infinite;
}

/*
 * Valittavien kohteiden sykähdys (omistajan toive: "hienoisesti
 * sykkisivät"). Pelkkä peiton vaihtelu on kevein tapa: viivan geometria
 * ja väri pysyvät samoina, joten selain ei piirrä rengasta uusiksi.
 * Raahauksen aikana sykähdys sammuu (ks. body.kartta-raahaus).
 */
@keyframes kohde-syke {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}

.target:hover .target-ring.pick { fill: rgba(176, 138, 60, 0.18); }
.target-ring.pick.picked { stroke: #e8b23c; stroke-width: 3; }
.target-ring.picked { stroke: #e8b23c; }

/*
 * Siirtorenkaat: nopanheiton jälkeen valittavat kohteet. Kullanruskea
 * katkoviiva hukkui pergamenttiin (omistajan havainto 18.8.2026:
 * "valittava siirtymäruutu ei erotu tarpeeksi"), joten kehotus toimia
 * palasi punamerkille: vaalea kultalevy pohjaksi ja punamullanvärinen
 * katkoviivarengas päälle — sama pari, jolla vanhat atlakset merkitsivät
 * reitin ja rajan. Kohteita on kerralla korkeintaan kourallinen, joten
 * vahva merkki ei tee karttaa levottomaksi niin kuin vanha joka
 * suunnan punarengas teki.
 */
.target-ring {
  fill: rgba(246, 210, 122, 0.68);
  stroke: var(--mark);
  stroke-width: 4;
  stroke-dasharray: 8 5;
  transform-box: fill-box;
  transform-origin: center;
  /* Vaalea hehku irrottaa renkaan maastosta ilman animaatiota. */
  filter: drop-shadow(0 0 4px rgba(255, 248, 230, 0.95));
}

/* Suunta, jolla ei ole kaupunkia nopan päässä: pienempi mutta samaa
   punamerkkiä — kaikki valittavat löytyvät yhdellä silmäyksellä. */
.target-ring.far {
  fill: rgba(246, 210, 122, 0.5);
  stroke-width: 2.8;
  stroke-dasharray: 4 4;
  opacity: 0.95;
}

.target:hover .target-ring { fill: rgba(238, 196, 105, 0.8); }
.target:hover .target-ring.far { fill: rgba(238, 196, 105, 0.65); opacity: 1; }

/*
 * Hengittävä kultahalo siirtorenkaan alla (--accent): rengas laajenee
 * pehmeästi ja palaa, himmenemättä koskaan pois — kohde erottuu joka
 * hetki, myös liikkeen ääriasennoissa, sekä vaalealta mereltä että
 * tummalta maalta. Pelkkä muunnos ja peitto — ei suodinta, joten
 * selain ei laske viivoja uusiksi. Raahauksen aikana halo pysähtyy
 * (ks. body.kartta-raahaus).
 */
.target-halo {
  fill: none;
  stroke: var(--accent);
  stroke-width: 5;
  transform-box: fill-box;
  transform-origin: center;
  pointer-events: none;
  transform: scale(1.14);
  opacity: 0.85;
  animation: kohde-halo 2.4s ease-in-out infinite;
}

@keyframes kohde-halo {
  0%, 100% { transform: scale(1.14); opacity: 0.85; }
  50% { transform: scale(1.42); opacity: 0.4; }
}

/* Liikeherkkyys: halo ei hengitä, vaan jää leveäksi kultakehäksi
   renkaan ympärille — vahva staattinen korostus säilyy. */
@media (prefers-reduced-motion: reduce) {
  .target-halo {
    animation: none;
    transform: scale(1.25);
    opacity: 0.7;
  }
}

/* Lentokohde kartalla: rengas ja pieni kone kaupungin yllä. */
.target-ring.lento {
  fill: rgba(120, 148, 196, 0.16);
  stroke: #4a5f86;
  stroke-dasharray: 8 5;
  /* Sama hento sykähdys kuin lähtöpisteissä: lentokohteet erottuvat
     muusta kartasta ilman että mikään liikkuu. */
  animation: kohde-syke 2.6s ease-in-out infinite;
}

.target:hover .target-ring.lento { fill: rgba(120, 148, 196, 0.3); }

.lento-kohde-merkki {
  font-size: 26px;
  fill: #4a5f86;
  paint-order: stroke;
  stroke: rgba(247, 237, 216, 0.9);
  stroke-width: 4px;
}
.target-cost { fill: var(--mark); font-size: 17px; font-weight: 700; }

/* ---------------------------------------------------------------------------
   KOHDEMERKKI FOKUSNÄKYMÄSSÄ — PUNAMERKKI RUUDUN MITASSA (js/ui.js
   drawTargets, fokusKohdeMerkki)
   ---------------------------------------------------------------------------
   Omistajan pelitestitilaus 26.8.2026 (iPad-kuvakaappaus Liiku-tilasta):
   *"kohderenkaat pisteiksi Ateenan tavalla kaikissa tilanteissa"*.
   Silloin tästä tuli PIENI VAALEA PALLURA, ja mitta oli oikea mutta
   merkki liian hiljainen.

   OMISTAJAN OIKAISU 2.9.2026, sanatarkasti:
   *"nopanheitossa valittavat pisteet täytyy näkyä selvemmin"*.
   Kaappaus Kreikan laudalta (heitto 3 Ateenasta): valittavat kohteet
   olivat pieniä valkoisia ympyröitä reittien varrella ja Sofian
   suunnassa, ja ne hukkuivat karttaan käytännössä kokonaan. Koska
   fokusnäkymä on nykyään pelin NORMAALINÄKYMÄ, tämä oli pelin heikoin
   merkki juuri siinä hetkessä, jossa pelaajan pitää tehdä valinta.

   RATKAISU: SAMA KIELI KUIN LAUDALLA, ERI MITTAKAAVA. Merkki puhuu nyt
   täsmälleen samaa kieltä kuin yllä oleva .target-ring/.target-halo-pari
   (omistajan hyväksymä 18.8.2026): vaalea kultalevy pohjaksi,
   punamullan katkoviivarengas päälle ja hengittävä kultahalo alle.
   Ainoa ero laudan merkkiin on KOKO — se mitataan ruudulta eikä
   laudalta, joten atlaslehden päälle ei tule 60 pikselin kehää vaan
   24 pikselin (askelpiste 15 px, kuten .target-ring.far laudalla).
   Kohteita on kerralla korkeintaan kourallinen, joten vahva merkki ei
   tee lehdestä levotonta.

   KOKO TULEE JS:STÄ, EI TÄSTÄ. Säde ja nimen kirjasinkoko lasketaan
   zoomista (paivitaFokusKohdeMitat), koska ne ovat ruudun mittoja
   laudan yksiköissä. Täällä on vain väri, viivan paksuus ja liike.

   VIIVA ON RUUDUN MITASSA (vector-effect: non-scaling-stroke): merkin
   säde elää kartan mittakaavassa, mutta katkoviiva pysyy yhtä paksuna
   ja yhtä tiheänä joka zoomilla — muuten kaukaa katsottuna renkaasta
   tulisi umpinainen ja lähellä kolme paksua viivanpätkää.

   EI SUODATTIMIA. Sama iOS-sääntö kuin muullakin kartalla: laudan
   renkaan drop-shadow jää tästä pois, ja irrotuksen maastosta hoitaa
   halo — pelkkä muunnos ja peitto, ei omaa piirtopuskuria.
   --------------------------------------------------------------------------- */

.target-piste {
  /* Kultalevy pohjaksi ja punamullan katkoviiva päälle — sama pari kuin
     laudan .target-ring, samoilla väreillä. */
  fill: rgba(246, 210, 122, 0.72);
  stroke: var(--mark);
  stroke-width: 3;
  stroke-dasharray: 6 4;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}

/* Askelpiste ilman kaupunkia: pienempi mutta samaa punamerkkiä — kaikki
   valittavat löytyvät yhdellä silmäyksellä (vrt. .target-ring.far). */
.target-piste.far {
  fill: rgba(246, 210, 122, 0.55);
  stroke-width: 2.2;
  stroke-dasharray: 4 3;
}

.target:hover .target-piste { fill: rgba(238, 196, 105, 0.9); }
.target:hover .target-piste.far { fill: rgba(238, 196, 105, 0.75); }

/*
 * Fokusnäkymän halo. Liike, väri ja pysähtyminen raahauksessa tulevat
 * yllä olevasta .target-halo-säännöstä; täällä on vain viivan paksuus
 * ruudun mitassa, koska laudan 5 laudanyksikköä olisi 24 pikselin
 * merkin päällä paksumpi kuin merkki itse.
 */
.target-halo.fokus {
  stroke-width: 3.4;
  vector-effect: non-scaling-stroke;
}

.target-halo.fokus.far { stroke-width: 2.4; }

/*
 * KOHTEEN NIMI. Se on kohdekerroksessa eikä kaupunkikerroksessa, joten
 * se näkyy myös silloin kun kaupungin oma datakerros on fokusmoodissa
 * piilotettu (.fokus-piilossa) — juuri se oli omistajan toive: *"myös
 * fokuslehden ulkopuolella oleville (Sofia ym.)"*.
 *
 * ISOMPI KUIN LAATTAAN POLTETTU KAUPUNGINNIMI,
 * koska valinta on kehotus toimia ja lehden nimet ovat taustaa. Ero
 * pidetään pienenä: nimi on merkintä kartalla, ei otsikko.
 */
.target-nimi {
  fill: var(--map-ink);
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-weight: 600;
  letter-spacing: 0.03em;
  paint-order: stroke;
  stroke: rgba(247, 237, 216, 0.92);
  stroke-width: 3px;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
}

@keyframes target-spin {
  to { transform: rotate(360deg); }
}

/*
 * PELINAPPULA. Väriläiskän (.pawn-ring + .pawn-dot + .pawn-gloss)
 * tilalle tuli tilauksessa #100 tinaherra — pieni tinasotilasmainen
 * herra Fogg, silinteri ja keppi — ja sen tilalle 27.8.2026
 * lautapelinappula (.pawn-nappula alla), koska tinaherra luki kartalla
 * raskaana tummana läiskänä. Tyyli valitaan js/ui.js:n NAPPULA_TYYLI
 * -vakiosta; webp-kuva on yhä repossa paluuta varten.
 *
 * VARJO PIIRRETÄÄN AINA KOODILLA (.pawn-shadow) — vain silloin se voi
 * irrota hypyn laella ja kertoa korkeuden (js/ui.js hyppaaAskel).
 *
 * VARJO ON HAALEAMPI KUIN ENNEN (0,32 -> 0,22). Kun kaupungin laatta
 * tuli takaisin nappulan alle (28.8.2026, ks. .nappulan-alla), varjo ei
 * enää makaa pergamentilla vaan laatan omalla vaalealla pinnalla, jossa
 * entinen tummuus luki toisena laattana laatan sisällä.
 */
.pawn-shadow { fill: rgba(58, 38, 16, 0.22); }
.pawn-kuva {
  /* Kuva on nappulan ainoa pinta: se ei saa napata napautuksia
     kaupungilta, joka on sen alla. */
  pointer-events: none;
}

/*
 * PUINEN LAUTAPELINAPPULA (omistajan tilaus 27.8.2026: tinaherra oli
 * *"liian raskas visuaalisesti"* — ja 28.8.2026: *"pelinappulasta voisi
 * tehdä puun värisen ja matalamman"*). Muoto piirretään koodilla
 * (js/ui.js NAPPULAN_POLKU), joten koko ulkonäkö on näissä
 * ominaisuuksissa:
 *
 *   fill     sorvattua vaaleaa pyökkiä: liuku ylhäältä alas (js/ui.js
 *            puuliuku, #d9b47c -> #c49a63 -> #a87e4c). Ensimmäinen
 *            versio oli lämmin valkoinen #fbf7ef, mutta seepiakartan
 *            päällä se oli laudan vaalein asia ja luki paperinpalana.
 *            Puun sävy on samasta paletista kuin kartta ja selvästi
 *            tummempi kuin kaupungin laatta (#f3e5c4), jonka päällä
 *            nappula seisoo. VARAVÄRI ensin omalla rivillään: jos
 *            määrittelyä ei jostain syystä ole, hahmo on litteä eikä
 *            näkymätön.
 *   stroke   sama tumma ruskea kuin laudan muissa ääriviivoissa —
 *            ohut, koska paksu reunus tekisi nappulasta taas painavan.
 *   vector-effect  ääriviiva pysyy saman levyisenä zoomista riippumatta.
 *            Ilman tätä laudan mittakaava paksuntaisi viivan
 *            fokusnäkymässä tussiksi ja ohentaisi sen yleiskuvassa
 *            olemattomiin.
 */
.pawn-nappula {
  fill: #c49a63;
  fill: url(#nappula-puu) #c49a63;
  stroke: #2b1f12;
  stroke-width: 1.1;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}
/* Nappulan oma ◈ poistui kartalta 28.8.2026 illalla (js/ui.js pawnShape:
   kaupungin kohdalla on vain laatta ja nappula). Tyyli jää tähän, koska
   merkin piirto voi palata: mitta on hahmon mukainen (20 -> 13 px, kun
   siluetti madaltui 25,9:stä 18,1:een). */
.pawn-star { fill: #b8860b; font-size: 13px; }

/*
 * VUORON AINOA RENGAS (omistajan pelitesti 27.8.2026). Nappulan alla oli
 * kaksi kehää: tämä tumma ja sen päällä pelaajan värinen sykähdys
 * (.pawn-pulse), joka laajeni puolitoistakertaiseksi ja himmeni.
 * Fokuslaudalla se luki punertavana hehkuna hahmon jalkojen ympärillä —
 * yhtenä kerroksena liikaa siinä pinossa, jonka omistaja näki. Sykähdys
 * poistettiin kokonaan (js/ui.js pawnShape); jäljelle jäi tämä yksi
 * hillitty kehä, ja samalla katosi kartan SVG:n sisältä jatkuva
 * animaatio, joka pudotti ruudunpäivityksen mitatusti 60 fps:stä 15:een.
 */
.pawn-active-ring {
  fill: none;
  stroke: #2b1f12;
  /* Ohuempi kuin ennen: rengas on nyt hahmon jalkojen alla oleva
     kehä, ei nappulan ääriviiva, eikä se saa kilpailla hahmon kanssa —
     eikä kaupungin laatan oman reunan kanssa, jonka sisään se
     28.8.2026 alkaen mahtuu (js/ui.js renkaanR). */
  stroke-width: 1.4;
  opacity: 0.68;
}

/*
 * Isojen animaatioiden ajaksi kartan päällä ei saa olla mitään jatkuvaa:
 * yksikin sykkivä elementti suodatetun kartan päällä pudottaa
 * ruudunpäivityksen 15 fps:ään. js/ui.js lisää tämän luokan nopanheiton,
 * lentoanimaation ja nappulan siirron ajaksi.
 *
 * SÄÄNTÖ SEURASI ENNEN NAPPULAN SYKÄHDYSTÄ (.pawn-pulse). Se poistettiin
 * 27.8.2026 (yksi vuororengas kahden sijaan, ks. .pawn-active-ring), ja
 * laudan SVG:n sisällä jatkuvasti sykkiviä animaatioita on enää yksi:
 * nykyisen kaupungin laatan houkutuskehä. Vaimennus siirtyi siihen —
 * PAUSSINA EIKÄ POISTONA, samasta syystä kuin raahauksessa
 * (body.kartta-raahaus yllä): `animation: none` nollaisi muunnoksen ja
 * puoliksi kasvanut kehä nytkähtäisi lepomittaansa juuri animaation
 * alkaessa.
 */
.animaatio-kaynnissa .fokuslaatta-syke { animation-play-state: paused; }

/*
 * LIIKKUVA NAPPULA EI SIIRRY ENÄÄ CSS-SIIRTYMÄLLÄ (#100). Hyppy on
 * paraabeli, ja sen paikka lasketaan joka kehyksellä (js/ui.js
 * hyppaaAskel): siirtymä pyöristäisi kaaren pehmeäksi liu'uksi ja söisi
 * juuri sen 3D-vaikutelman, jota varten kaari on. Luokka jäi
 * merkitsemään liikkuvaa nappulaa — siihen tarttuu vain sääntö, joka
 * kieltää muut siirtymät.
 */
.pawn-moving { transition: none; }
.pawn-hahmo, .pawn-varjo { transition: none; }

/* --- dialogit: pergamenttikortit karttatyylillä --- */

:root {
  --paper-noise: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/><feColorMatrix values='0 0 0 0 0.42  0 0 0 0 0.33  0 0 0 0 0.19  0 0 0 0.2 0'/></filter><rect width='140' height='140' filter='url(%23n)'/></svg>");
  /* Epäsäännöllinen kulmapyöristys tekee reunasta käsin piirretyn oloisen. */
  --sketch-radius: 110px 16px 96px 18px / 18px 96px 16px 110px;
  --sketch-radius-alt: 20px 104px 16px 100px / 100px 18px 108px 16px;
}

.dialog {
  border: none;
  padding: 0;
  background: transparent;
  color: var(--map-ink);
  max-width: 620px;
  width: calc(100% - 2rem);
  max-height: 92dvh;
  overflow: visible;
}

.dialog::backdrop {
  background: rgba(14, 9, 4, 0.72);
}

/*
 * LAUKKU AUKEAA PILLERIN ALLE (omistajan toive 5.8.2026).
 *
 * <dialog> keskittää itsensä ruudulle, eikä sitä voi asemoida CSS:llä
 * sen napin suhteen joka sen avasi: nappi on ylärivissä ja dialogi on
 * selaimen ylimmässä kerroksessa, eivätkä ne ole sukua toisilleen.
 * Paikan laskee siis js/ui.js (asemoiLaukku) ja kirjoittaa sen
 * inline-tyyliin; tämän luokan tehtävä on vain purkaa keskitys, jotta
 * laskettu paikka pääsee voimaan.
 *
 * Korkeus rajataan ruudun alalaitaan asti: pilleri on ylhäällä, joten
 * täysi 92dvh valuisi ruudun ali.
 */
.dialog.pillerin-alla {
  margin: 0;
  max-height: calc(100dvh - 5.5rem);
}

/*
 * KORKEUSKATTO EI PITÄNYT 6.9.2026 ASTI (omistaja: "Laukku
 * pitää olla skrollattava myös" — linssin selite jäi ruudun alareunan
 * alle).
 *
 * Ylläoleva `max-height` koski VAIN dialogia, ja dialogilla on
 * `overflow: visible`. Kortti sen sisällä sai korkeutensa omasta
 * `.dialog-card { max-height: 92dvh }` -säännöstään, joka on tässä
 * asetelmassa aina isompi kuin dialogin katto — joten kortti kasvoi
 * dialogin ohi ja valui ruudun ali. Mitattu 390×844: kortti 776 px,
 * dialogin katto 72dvh = 608 px.
 *
 * Flexbox korjaa juuri tämän: kun dialogi on pystysuuntainen
 * flex-säiliö, sen `max-height` kutistaa lapsen (`flex-shrink: 1`)
 * kattoon asti, ja kortin sisus saa vieritettävän jäännöksen.
 * `[open]`-ehto on pakollinen — ilman sitä tekijän `display: flex`
 * voittaisi selaimen `dialog:not([open]) { display: none }` -säännön
 * ja suljettu laukku jäisi ruudulle näkyviin.
 */
.dialog.pillerin-alla[open] {
  display: flex;
  flex-direction: column;
}

.dialog.pillerin-alla > .dialog-card.passport-card {
  /* 92dvh pois: katon antaa dialogi, ei kortti (kortti on jo pystyflex,
     ks. .dialog-card.passport-card ylempänä). */
  max-height: none;
  min-height: 0;
  flex: 0 1 auto;
}

/*
 * VIERIVÄ SISUS. Kortti on kehys (overflow: hidden messinkikulmien
 * takia), joten vieritys kuuluu tälle lapselle. `touch-action: pan-y`
 * ja `overscroll-behavior: contain` ovat samat kuin muissa vierivissä
 * korteissa: sormi vierittää pystyyn eikä ele karkaa kartalle.
 */
.laukku-sisus {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
  touch-action: pan-y;
  -webkit-overflow-scrolling: touch;
  padding: 1.4rem 0 1.6rem;
}

/*
 * Kapean ruudun laukkusäännöt asuvat lehtiarkin kapea-lohkossa
 * (@media max-width: 699px alempana) — rules.test.mjs:n
 * ankkurivartija lukee tiedoston ENSIMMÄISEN kapea-lohkon ja olettaa
 * sen olevan arkin, joten uutta lohkoa ei perusteta tätä ennen.
 */

/*
 * LAUKKU EI TUMMENNA KARTTAA (omistaja 5.8.2026: "älä tummenna taustaa
 * ollenkaan").
 *
 * Muut ikkunat ovat lukemista varten, ja niiden himmennys sulkee kartan
 * pois häiritsemästä. Laukku on eri asia: se aukeaa oman nappinsa alle
 * kuin vetolaatikko, ja pelaaja katsoo yhä karttaa sen vierestä.
 * Himmennetty tausta tekisi siitä modaalin, joka se ei ole.
 *
 * Tunnistevalitsin, koska `.dialog::backdrop` on tässä tiedostossa
 * myöhempänä — ks. sama ansa nahkakehyksessä ylempänä.
 */
#passport-dialog::backdrop { background: transparent; }

/* Modaalin oma fokusrengas ei kuulu paperikortin ympärille. */
.dialog:focus,
.dialog:focus-visible,
.dialog-card:focus,
.dialog-card:focus-visible {
  outline: none;
}

/* Paperikortti dialogin sisällä */
.dialog > form,
.dialog > .paper-card,
.dialog.paper > * {
  position: relative;
}

.dialog {
  --card-bg: radial-gradient(circle at 42% 34%, #f6e7c6 0%, #ecd8ae 58%, #d9be8d 100%);
}

.dialog-card {
  position: relative;
  background-image: var(--paper-noise), var(--card-bg);
  background-blend-mode: multiply, normal;
  /* Ohut yhtenäinen viiva: voimakkaat katkoviivat poistuivat koko
   * pelistä sanomalehtityylin myötä (omistajan toive 5.8.2026). */
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: var(--sketch-radius);
  padding: 1.15rem 1.3rem;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5);
  max-height: 92dvh;
  overflow-y: auto;
  /* Vieritys vain pystysuuntaan: sivuttaisvieritys ei saa herätä koskaan. */
  overflow-x: hidden;
  overscroll-behavior: contain;
  touch-action: pan-y;
  overflow-wrap: break-word;
  animation: card-in 0.32s cubic-bezier(0.2, 1.2, 0.5, 1);
}

/* Toinen, hieman kiertynyt reunaviiva vahvistaa käsin piirretyn vaikutelman. */
.dialog-card::before {
  content: "";
  position: absolute;
  inset: -6px;
  border: 1px dashed rgba(70, 51, 31, 0.32);
  border-radius: var(--sketch-radius-alt);
  transform: rotate(-0.45deg);
  pointer-events: none;
}

@keyframes card-in {
  from { opacity: 0; transform: translateY(16px) rotate(-1.2deg) scale(0.97); }
  to { opacity: 1; transform: none; }
}

.dialog h2 {
  margin: 0 0 0.6rem;
  font-family: var(--font-type);
  font-size: 1.35rem;
  letter-spacing: 0.06em;
  color: var(--map-ink);
}

.dialog p, .dialog label, .dialog .muted { color: #5a4326; }
.dialog .muted { color: #7a6039; }

.dialog menu {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.5rem;
  margin: 1rem 0 0;
  padding: 0;
}


.dialog button {
  background: rgba(255, 255, 255, 0.35);
  border: 1px solid rgba(70, 51, 31, 0.55);
  border-radius: 90px 12px 84px 14px / 14px 84px 12px 90px;
  color: var(--map-ink);
  font-family: var(--font-type);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.dialog button:hover:not(:disabled) { background: rgba(255, 255, 255, 0.6); }

.dialog button.primary {
  background: linear-gradient(180deg, #e9c169, #d3a03c);
  border-style: solid;
  border-color: #7a5a12;
  color: #33240a;
}

.dialog button.primary:hover:not(:disabled) { background: linear-gradient(180deg, #f2d183, #dcae4c); }

.row { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.8rem; }
.rules-text p { margin: 0 0 0.7rem; line-height: 1.45; }

/* --- tietovisa --- */

.quiz-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.7rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid rgba(70, 51, 31, 0.35);
}

.quiz-badge {
  border: 1px solid rgba(70, 51, 31, 0.55);
  border-radius: 999px;
  color: var(--map-ink);
  font-family: var(--font-type);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.2rem 0.7rem;
  transform: rotate(-1.5deg);
}

.quiz-city { color: #7a6039; font-size: 0.9rem; font-style: italic; }

.quiz-question {
  margin: 0 0 1rem;
  font-family: var(--font-type);
  font-size: clamp(1.1rem, 2.3vw, 1.35rem);
  line-height: 1.35;
  color: var(--map-ink);
  text-wrap: balance;
  animation: ink-in 0.4s ease-out both;
}

@keyframes ink-in {
  from { opacity: 0; filter: blur(2px); transform: translateY(6px); }
  to { opacity: 1; filter: none; transform: none; }
}

.quiz-options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
}

.quiz-option {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-align: left;
  padding: 0.7rem 0.9rem;
  min-height: 58px;
  border: 1px solid rgba(70, 51, 31, 0.55) !important;
  border-radius: 86px 14px 92px 12px / 12px 92px 14px 86px !important;
  background: rgba(255, 252, 243, 0.5) !important;
  color: var(--map-ink) !important;
  font-family: var(--font-type) !important;
  font-weight: 500;
  transition: background 0.15s ease, transform 0.15s ease;
  animation: option-in 0.3s ease-out both;
  animation-delay: calc(var(--i, 0) * 70ms);
}

.quiz-option:nth-child(even) { transform: rotate(0.4deg); }
.quiz-option:nth-child(odd) { transform: rotate(-0.4deg); }

@keyframes option-in {
  from { opacity: 0; transform: translateY(10px) rotate(-1deg); }
}

.quiz-option:hover:not(:disabled) { background: rgba(255, 255, 255, 0.85) !important; }
.quiz-option:disabled { opacity: 1; cursor: default; }

.quiz-option .letter {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 1.9em;
  height: 1.9em;
  border: 2px solid var(--map-ink);
  border-radius: 50%;
  font-family: var(--font-type);
  font-weight: 700;
  color: var(--map-ink);
}

.quiz-option .text { flex: 1 1 auto; }

.quiz-option.correct {
  background: rgba(94, 158, 106, 0.32) !important;
  border-color: #2f6b3f !important;
  border-style: solid !important;
  animation: stamp 0.4s cubic-bezier(0.2, 1.6, 0.4, 1);
}

.quiz-option.correct .letter { border-color: #2f6b3f; color: #21532f; }

.quiz-option.wrong {
  background: rgba(176, 58, 43, 0.22) !important;
  border-color: var(--mark) !important;
  text-decoration: line-through;
  text-decoration-color: rgba(176, 58, 43, 0.8);
  text-decoration-thickness: 2px;
}

.quiz-option.hidden-option { opacity: 0.25; text-decoration: line-through; }

@keyframes stamp {
  0% { transform: scale(1.06) rotate(-1.5deg); }
  60% { transform: scale(0.98) rotate(0.6deg); }
  100% { transform: scale(1) rotate(0deg); }
}

.quiz-result {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin: 1rem 0 0;
  padding: 0.7rem 0.9rem;
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 80px 14px 86px 12px / 12px 86px 14px 80px;
  background: rgba(255, 255, 255, 0.42);
  /* Selite hieman isommalla, jotta sen lukee vaivatta (omistajan toive). */
  font-size: 1.02rem;
  line-height: 1.45;
  color: var(--map-ink);
  animation: ink-in 0.35s ease-out both;
}

.quiz-result.right { border-color: #2f6b3f; }
.quiz-result.wrong { border-color: var(--mark); }
.quiz-result .muted { color: #6f5836; display: block; margin-top: 0.15rem; }

.lifeline {
  border: 1px solid rgba(70, 51, 31, 0.5) !important;
  border-radius: 60px 12px 66px 10px / 10px 66px 12px 60px !important;
  background: rgba(255, 252, 243, 0.42) !important;
  color: var(--map-ink) !important;
  font-size: 0.85rem;
}

.lifeline:disabled { opacity: 0.4; }
#quiz-hint { margin-right: auto; }

/* --- tiimalasi: 45 sekunnin vastausaika --- */

.quiz-head-text { display: flex; align-items: center; gap: 0.6rem; min-width: 0; flex: 1 1 auto; }

.quiz-timer {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  flex: 0 0 auto;
  animation: hg-arrive 0.5s ease-out both;
}


@keyframes hg-arrive {
  from { opacity: 0; transform: translateY(-6px) rotate(-8deg); }
}

.hourglass {
  width: 34px;
  height: 52px;
  overflow: visible;
  transform: rotate(-1.5deg);
  transform-origin: 50% 50%;
}

.hourglass.turning { animation: hg-turn 0.7s cubic-bezier(0.35, 0.05, 0.25, 1); }

@keyframes hg-turn {
  from { transform: rotate(178.5deg); }
  to { transform: rotate(-1.5deg); }
}

.hg-wood { filter: url(#hg-rough); }

.hg-wood rect {
  fill: #8a6534;
  stroke: var(--map-ink);
  stroke-width: 1.1;
  stroke-linejoin: round;
}

.hg-glass {
  fill: rgba(255, 255, 255, 0.16);
  stroke: var(--map-ink);
  stroke-width: 1.2;
  stroke-linejoin: round;
  filter: url(#hg-rough);
}

.hg-sand { fill: #c08a3e; opacity: 0.92; }
.hg-stream { fill: #b07f38; opacity: 0.75; animation: hg-pour 0.5s steps(2, end) infinite; }

@keyframes hg-pour {
  0%, 100% { opacity: 0.72; transform: translateX(0); }
  50% { opacity: 0.5; transform: translateX(0.25px); }
}

.hg-shine {
  fill: none;
  stroke: rgba(255, 255, 255, 0.5);
  stroke-width: 1.4;
  stroke-linecap: round;
}

.quiz-seconds {
  font-family: var(--font-type);
  font-size: 0.98rem;
  font-weight: 700;
  color: #7a6039;
  min-width: 1.6em;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.quiz-timer.urgent .hg-sand { fill: #a83c2c; }
.quiz-timer.urgent .hg-stream { fill: #a83c2c; }
.quiz-timer.urgent .quiz-seconds { color: var(--mark); }
.quiz-timer.urgent .hourglass { animation: hg-shake 1s ease-in-out infinite; }

@keyframes hg-shake {
  0%, 100% { transform: rotate(-1.5deg); }
  45% { transform: rotate(1.5deg); }
}

.quiz-hint-text {
  display: flex;
  gap: 0.5rem;
  margin: -0.5rem 0 0.9rem;
  padding: 0.55rem 0.8rem;
  border: 1px solid rgba(120, 90, 40, 0.5);
  border-radius: 70px 12px 74px 10px / 10px 74px 12px 70px;
  background: rgba(240, 220, 170, 0.35);
  font-size: 0.92rem;
  font-style: italic;
  line-height: 1.35;
  color: #6b5227;
  animation: ink-in 0.45s ease-out both;
}

.quiz-hint-text::before { content: "✎"; font-style: normal; opacity: 0.7; }

/* --- aarteen paljastus: generoitu kuva nousee mustasta --- */

/* Tausta on lähes musta, jotta aarrekuvan oma musta pohja sulautuu
 * saumatta eikä mitään reunaa näy (omistajan palaute 9.8.2026).
 * Sama pohja kaikille paljastuksille — kääntyvää seepialaattaa ei
 * enää ole (omistajan linjaus 18.8.2026). */
.reveal-overlay {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  gap: 1rem;
  /*
   * MUSTA POHJA (omistajan pelitestipalaute v1119: *"paljastussivun
   * TAUSTA MUSTAKSI — kuvassa on valmiiksi tumma vinjetti, mustalla
   * pohjalla siitä tulee saumaton; tekstit vaaleiksi mustaa vasten"*).
   *
   * Aarrekuva on maalattu mustalle ja häivytetty säteittäisellä
   * maskilla (.reveal-aarrekuva) — vaalealla harsolla (v894) sen
   * reuna erottui tummana halona, koska maskin läpi paistoi pergamentti.
   * Musta pohja on sama väri kuin kuvan oma, ja sauma katoaa kokonaan.
   *
   * Sumennus jää tunnelmaksi: se pehmentää alla olevan pelinäkymän,
   * mikä näkyy vielä lähes mustan pohjan lävitse.
   */
  /*
   * KESKUSTA MUSTA, REUNAT KUULTAVAT (omistaja 26.8.2026 ilta:
   * "Tausta voisi ehkä hieman kuultaa läpi ainakin jostain kohtaa").
   * Aarrekuva on maalattu mustalle, joten sen kohdalla pohjan on
   * pysyttävä täytenä — muuten kuvan reuna erottuisi halona (sama
   * oppi kuin v894:n vaalean harson kanssa). Säteittäinen liukuväri
   * pitää keskustan umpimustana ja päästää sumennetun pelinäkymän
   * hohtamaan laidoilta: pimeys ei ole seinä vaan hetki kartan päällä.
   */
  background: radial-gradient(
    ellipse 80% 70% at 50% 42%,
    #0b0805 0%,
    #0b0805 48%,
    rgba(11, 8, 5, 0.74) 100%
  );
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  z-index: 20;
  animation: fade-in 0.25s ease-out;
}

/*
 * Tekstit pergamentin sävyisinä mustaa vasten (sama v1119:n tilaus).
 * Sävyt ovat pelin oman paperin vaaleimmat: otsikko lähes valkoinen
 * pergamentti, leipä hitusen vaimeampi.
 */
.reveal-overlay .reveal-caption strong { color: #f4e7ca; }

.reveal-overlay .reveal-caption span,
.reveal-overlay .reveal-caption .reveal-huudahdus { color: #d9c9a4; }

.reveal-overlay .reveal-caption .reveal-isoisa { color: #cbb992; }

.reveal-overlay.leaving { animation: fade-out 0.3s ease-in forwards; }

/* Kulman sulkuruksi poistui 26.8.2026 (omistaja: "Yläkulman ruksi on
 * turha") — Jatka matkaa ja napautus kortille riittävät. */

/*
 * JATKA MATKAA — 1873-NAPPI (omistajan pelitestipalaute v1119:
 * *"sivu pysyy näkyvissä kunnes käyttäjä toimii: lisää selkeä nappi
 * 'JATKA MATKAA' (1873-nappityyli kuten ALOITA MATKA oli)"*).
 *
 * Sama kehystetty versaali kuin etusivun napissa (.intro-valinta),
 * mutta mustalle pohjalle käännettynä: lämmin kultakehys, kullalle
 * vivahtava tumma täyttö ja pergamentinvaalea versaali. Nappi jää
 * KEHYSNAPIKSI — täytetty kulta on varattu päätehtävälle
 * (kohtaamisnappi, ks. `.dialog.lehti … button.primary`), ja Jatka
 * matkaa on kortin poistumistie.
 *
 * Nappi ilmestyy vasta kun kortin tekstit ovat paikallaan (luokka
 * .nakyy), jottei se kilpaile kuvan nousun kanssa.
 *
 * VALITSIMISSA ON MUKANA `.reveal-overlay button`, koska paljastuskortti
 * elää quiz-dialogin sisällä (ui.js: `this.quizDialog.appendChild(overlay)`)
 * ja dialogien yleissääntö `.dialog button` (0,1,1) voittaa pelkän
 * `.reveal-jatka`-luokan (0,1,0). Ilman tätä nappi peri dialogin
 * pergamenttilaatikon: valkoinen 35 %:n täyttö, tumma mustekirjasin ja
 * aaltoreunat — mustaa vasten HAALEA HARMAA LAATIKKO, jonka teksti
 * hukkui (omistajan palaute 27.8.2026: *"jatka matkaa nappi on oudon
 * värinen"*). Sama kaava kuin `.dialog button.lukija-nappi`-lohkossa.
 */
.reveal-jatka,
.reveal-overlay button.reveal-jatka {
  margin-top: 0.6rem;
  padding: 0.68rem 2.2rem;
  min-height: 48px;
  border: 1px solid rgba(228, 196, 128, 0.62);
  border-radius: 3px;
  background: rgba(214, 168, 62, 0.16);
  color: #f4e3b6;
  font-family: var(--font-type);
  font-weight: 600;
  font-size: 0.92rem;
  text-transform: uppercase;
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  /* Ohut musteenmusta reunus pitää versaalin terävänä myös kuvan
     lämpimien laitojen päällä; kultainen kajo irrottaa napin
     mustasta ilman että siitä tulee laatikko. */
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.65);
  box-shadow:
    inset 0 1px 0 rgba(255, 238, 196, 0.13),
    0 0 22px rgba(214, 168, 62, 0.12);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  opacity: 0;
  transition: opacity 0.4s ease-out, background-color 0.2s ease,
    border-color 0.2s ease, transform 0.2s ease;
}

/* `.nakyy` kantaa saman `.reveal-overlay button` -parin kuin perussääntö:
   muuten perussäännön `opacity: 0` (0,2,1) jäisi voimaan tämän yli
   (0,2,0) ja nappi pysyisi näkymättömänä. */
.reveal-jatka.nakyy,
.reveal-overlay button.reveal-jatka.nakyy { opacity: 1; }

/*
 * Kosketus lämmittää kehyksen. Valitsimissa on `:not(:disabled)`, jotta
 * ne voittavat dialogin `.dialog button:hover:not(:disabled)` -säännön
 * tarkkuudessa eivätkä vain lähdejärjestyksessä.
 */
.reveal-jatka:hover,
.reveal-jatka:focus-visible,
.reveal-overlay button.reveal-jatka:hover:not(:disabled),
.reveal-overlay button.reveal-jatka:focus-visible {
  border-color: rgba(248, 228, 176, 0.92);
  background: rgba(214, 168, 62, 0.3);
  transform: translateY(-1px);
}

.reveal-jatka:active,
.reveal-overlay button.reveal-jatka:active:not(:disabled) {
  background: rgba(214, 168, 62, 0.4);
  transform: translateY(0);
}

/* Liikeherkälle pelaajalle nappi vain kirkastuu, ei nouse. */
@media (prefers-reduced-motion: reduce) {
  .reveal-jatka:hover,
  .reveal-jatka:focus-visible,
  .reveal-overlay button.reveal-jatka:hover:not(:disabled),
  .reveal-overlay button.reveal-jatka:focus-visible { transform: none; }
}

@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }

/* Kortti on yhtenä pinona: kuva ja sen alla tekstit. Pitkä esittely
 * (esim. Viisas Pöllö) voi ylittää matalan näytön — silloin pino saa
 * vierittyä sisällään sen sijaan, että viimeinen rivi jäisi reunan
 * taakse. Mahtuvaa korttia tämä ei muuta mitenkään. */
.reveal-scene {
  display: grid;
  justify-items: center;
  gap: 1.5rem;
  max-height: 100%;
  overflow-y: auto;
  padding-inline: 1rem;
  scrollbar-width: none;
}

.reveal-scene::-webkit-scrollbar { display: none; }

.reveal-caption {
  display: grid;
  justify-items: center;
  gap: 0.2rem;
  text-align: center;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.35s ease-out, transform 0.35s ease-out;
}

.reveal-caption.shown { opacity: 1; transform: none; }

/* Nuoren herran huudahdus paljastuksen kärjessä: käsialamainen,
 * lämmin ja hieman isompi kuin arvorivi — spontaani repliikki, ei
 * otsikko. */
.reveal-caption .reveal-huudahdus {
  font-style: italic;
  font-size: 1.08rem;
  color: #4a3009;
  /* Vaalea hohde poistettu 18.8.2026: mustaa korttia vasten se
     irrotti tekstin taustasta, mutta v894:n vaalealla harsolla se
     vaalensi juuri kirjaimen rajapikselit ja teki reunoista sumeat. */
}

/* AI-piirretty aarre nousee mustasta kortin keskelle ilman kehyksiä
 * (omistajan palaute 9.8.2026). Säteittäinen maski häivyttää kuvan
 * reunat, joten esine leijuu pimeässä — tekstit asettuvat ympärille.
 * object-fit: contain näyttää esineen kokonaan leikkaamatta. */
.reveal-aarrekuva {
  /* Neliö: kuvat ovat 1:1, ja maskin on osuttava kuvan reunoihin —
   * leveämmässä laatikossa kuvan pystyreunat jäisivät maskin
   * kirkkaalle alueelle näkyviin. */
  width: min(76vw, 22rem, 52vh);
  aspect-ratio: 1;
  object-fit: contain;
  -webkit-mask-image: radial-gradient(ellipse 70% 70% at center, #000 50%, transparent 74%);
  mask-image: radial-gradient(ellipse 70% 70% at center, #000 50%, transparent 74%);
  opacity: 0;
  transform: scale(0.86);
  transition: opacity 0.9s ease-out, transform 0.9s ease-out;
}

.reveal-aarrekuva.shown { opacity: 1; transform: none; }

/*
 * FAKTA ON OPPIMISTEKSTI (omistajan leiskapäätös 28.8.2026): lyhyt
 * tosi fakta aarteesta kortin alaosassa. Tummassa mallissa vaalea,
 * vaaleissa malleissa musteen sävy (alempana).
 */
.reveal-caption .reveal-fakta {
  font-style: italic;
  font-size: 0.98rem;
  line-height: 1.5;
  max-width: 27rem;
  margin-top: 0.5rem;
  color: #cbb992;
}

/* --- pääaarteen luettelotekstit tummassa mallissa (28.8.2026 ilta) --
 *
 * Omistajan tilaus: *"laita kaikki tekstit mukaan tuohon aarteen
 * esikatseluun"*. Kun pääaarre siirtyi diplomista tummaan malliin,
 * Aarnin luettelon otsake, manner, arvorivi ja LÖYDETTY-leima jäivät
 * pois. Ne palaavat tähän TUMMAN MALLIN OMANA ulkoasuna: kullansävyistä
 * versaalia suoraan mustan päälle. EI pergamenttiarkkia, EI
 * kaiverruskehystä ja EI vaalenevaa pohjaa — kuvan tumma tausta jatkuu
 * saumatta overlayn mustaan, mikä oli koko siirron syy.
 *
 * Diplomin `.reveal-otsake`, `.reveal-alaotsake` ja `.reveal-alanauha`
 * on ladottu absoluuttisesti kehyskuvan kartussiin ja nauhaan, joten
 * tumma malli ei voi käyttää niitä: sillä on omat luokkansa, jotka ovat
 * scene-gridin tavallisia rivejä.
 */

/* Nimiö ja jalka tuovat kortille viisi riviä kolmen sijaan; scenen
 * 1.5 rem:n väli venyttäisi pinon matalalla näytöllä vieritykseen.
 * Merkkiluokan antaa rakennaPaljastus. */
.reveal-scene.luettelo { gap: 1.05rem; }

.reveal-tunnus {
  display: grid;
  justify-items: center;
  gap: 0.3rem;
  text-align: center;
  /* Nimiö nousee kuvan mukana: tummassa mallissa pohja === scene, joten
     sama `.shown` kantaa molemmat. */
  opacity: 0;
  transform: translateY(-8px);
  transition: opacity 0.9s ease-out, transform 0.9s ease-out;
}

.reveal-scene.shown .reveal-tunnus { opacity: 1; transform: none; }

.reveal-tunnus-otsake {
  font-family: var(--font-type);
  font-weight: 700;
  font-size: clamp(0.74rem, 2.6vmin, 0.94rem);
  letter-spacing: 0.26em;
  /* Versaalin viimeinen välike työntäisi rivin vasemmalle ilman tätä. */
  text-indent: 0.26em;
  text-transform: uppercase;
  color: #e8c98a;
}

/* Ohut kultaviiva otsakkeen alle — sama ele kuin diplomin
 * jakoviivalla, mutta piirrettynä kirjaimeen eikä arkille. */
.reveal-tunnus-otsake::after {
  content: '';
  display: block;
  width: 3.6rem;
  height: 1px;
  margin: 0.36rem auto 0;
  background: linear-gradient(
    90deg,
    rgba(232, 201, 138, 0) 0%,
    rgba(232, 201, 138, 0.72) 50%,
    rgba(232, 201, 138, 0) 100%
  );
}

.reveal-tunnus-alaotsake {
  font-family: var(--font-type);
  font-size: clamp(0.6rem, 2.2vmin, 0.78rem);
  letter-spacing: 0.2em;
  text-indent: 0.2em;
  color: #bda87e;
}

/*
 * JALKA: arvorivi ja leima tekstien alle. Jalka on caption-lohkon
 * sisarus, joten yleinen sisarvalitsin tuo sen esiin samalla kahvalla
 * kuin tekstit — JS ei tarvitse omaa luokkaa. Leima jää silti pimeään
 * jalan sisällä, kunnes playTokenReveal lyö sen.
 */
.reveal-loyto {
  display: grid;
  justify-items: center;
  gap: 0.55rem;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.35s ease-out, transform 0.35s ease-out;
}

.reveal-caption.shown ~ .reveal-loyto { opacity: 1; transform: none; }

.reveal-arvo {
  font-family: var(--font-type);
  font-size: clamp(0.84rem, 2.8vmin, 1.02rem);
  letter-spacing: 0.16em;
  text-indent: 0.16em;
  text-transform: uppercase;
  color: #e0be7c;
}

/*
 * LÖYDETTY-LEIMA MUSTALLA POHJALLA: sama kumileima kuin diplomilla
 * (epätasainen painauma maskissa, sama lyöntianimaatio), mutta gridin
 * rivinä eikä arkin kulmassa — ja punainen nostettuna kirkkaammaksi,
 * koska diplomin musteenpunainen katoaisi mustaan.
 */
.reveal-leima.tumma {
  position: static;
  color: #e2664c;
  border-color: #b8412e;
  font-size: clamp(0.8rem, 2.9vmin, 1.06rem);
  /* Kevyt hehku irrottaa leiman mustasta ilman että siitä tulee
     laatikko — sama kaava kuin Jatka matkaa -napin kultakajossa. */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
  box-shadow: 0 0 20px rgba(184, 65, 46, 0.16);
}

/* --- vaaleat paljastusmallit (leiskapäätökset 28.8.2026) ------------
 *
 * Diplomin tausta: pelin näkymä kuultaa purppuraan taitettuna
 * tummennoksen läpi (leiskan brightness/hue-rotate siirtyi
 * backdrop-filteriin — overlayn takana on aito pelinäkymä, ei
 * kuvakaappaus). Säteittäinen liukuväri painaa laidat pimeään.
 *
 * PAIKALLISAARRE SAI OMAN TAUSTAN 3.9.2026 (omistaja Hymettoksen
 * hunajan kortista: *"tämä kaipaa vielä säätöä. taustan voisi
 * levittää koko ruudun alueella ja poistaa vinjetit"*): koko ruutu on
 * tasaista pergamenttia, ei purppuraa laitaa eikä valokeilaa, ja
 * kuva sulautuu siihen ilman maskia (ks. .reveal-pergamentti ja
 * .reveal-overlay.paikallis .reveal-aarrekuva).
 */
.reveal-overlay.diplomi {
  background: radial-gradient(
    ellipse 85% 70% at 50% 42%,
    rgba(80, 46, 116, 0.3) 0%,
    rgba(43, 22, 66, 0.6) 60%,
    rgba(18, 9, 30, 0.88) 100%
  );
  -webkit-backdrop-filter: blur(3px) brightness(0.38) saturate(0.6) hue-rotate(-24deg);
  backdrop-filter: blur(3px) brightness(0.38) saturate(0.6) hue-rotate(-24deg);
}

/*
 * PAIKALLISAARTEEN PERGAMENTTI KOKO RUUDULLE (omistaja 3.9.2026, ks.
 * yllä): overlay itse on pergamenttia laidasta laitaan — sama sävy
 * kuin aarrekuvien oma pohja, aavistuksen tummempana, jotta kuvan
 * pohja katoaa darken-sulautuksessa (alla). Ei backdrop-suodatinta:
 * pohja on peittävä, eikä sumennettu pelinäkymä näy sen läpi.
 */
.reveal-overlay.paikallis {
  background-color: #e6d8ae;
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
}

/*
 * Paikallisaarteen sisältö: EI paperiarkkia, EI kehystä, EI
 * valokeilaa (aiempi säteittäinen liukuväri poistettiin 3.9.2026:
 * "poistaa vinjetit") — pelkkä keskitetty ladonta pergamentin päällä.
 * Kokonaisuus nousee esiin yhtenä kappaleena kuten ennenkin.
 */
.reveal-pergamentti {
  padding: clamp(2rem, 6vmin, 4rem) clamp(2.4rem, 9vmin, 5.6rem)
    clamp(1.6rem, 5vmin, 3.5rem);
  text-align: center;
  background: none;
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 0.9s ease-out, transform 0.9s ease-out;
}

.reveal-pergamentti.shown { opacity: 1; transform: none; }

/* Kuva sulautuu pergamenttiin ILMAN VINJETTIÄ (omistaja 3.9.2026:
 * "poistaa vinjetit"): darken ottaa kanavittain tummemman, joten kuvan
 * oma vaalea pohja — vaaleampi kuin overlayn pergamentti — katoaa ja
 * vain esine jää (multiply olisi tummentanut kuvan pohjan neliöksi).
 * Osalla kuvista pohja on kuitenkin TEKSTUROITUA pergamenttia (esim.
 * FIN tervatynnyri), joka on paikoin overlayta tummempaa ja piirtäisi
 * neliön reunan. Siksi kuvan reunat höyhennetään kapealla SUORAKAIDE-
 * maskilla: vain uloin 9 % häipyy, keskusta on koskematon — se ei ole
 * valokeila eikä halo vaan pelkkä sauman pehmennys. */
.reveal-overlay.paikallis .reveal-aarrekuva {
  mix-blend-mode: darken;
  width: min(78vw, 24rem, 46vh);
  -webkit-mask-image:
    linear-gradient(to right, transparent, #000 9%, #000 91%, transparent),
    linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent, #000 9%, #000 91%, transparent),
    linear-gradient(to bottom, transparent, #000 9%, #000 91%, transparent);
  mask-composite: intersect;
}

/* JATKA MATKAA vaaleilla malleilla: mustan mallin kultakajo on
 * pergamentilla lähes näkymätön (vaalea teksti vaalealla), joten nappi
 * on tässä tumma musteella ja kultaisella tekstillä — sama nappi kuin
 * omistajan hyväksymässä kortissa, nyt luettavana koko ruudun
 * pergamentilla (3.9.2026). */
.reveal-overlay.paikallis button.reveal-jatka,
.reveal-overlay.diplomi.kirkas button.reveal-jatka {
  background: #3b2a12;
  border-color: rgba(228, 196, 128, 0.7);
  color: #f4e3b6;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  box-shadow: 0 2px 10px rgba(40, 26, 8, 0.28);
}
.reveal-overlay.paikallis button.reveal-jatka:hover:not(:disabled),
.reveal-overlay.paikallis button.reveal-jatka:focus-visible,
.reveal-overlay.diplomi.kirkas button.reveal-jatka:hover:not(:disabled),
.reveal-overlay.diplomi.kirkas button.reveal-jatka:focus-visible {
  background: #4a3617;
}

/* Tekstit musteella pergamenttia vasten — vaaleat overlay-värit
 * kumotaan samalla tarkkuudella kuin ne asetettiin. */
.reveal-overlay.paikallis .reveal-caption strong,
.reveal-overlay.diplomi .reveal-caption strong { color: #2f2008; }

.reveal-overlay.paikallis .reveal-caption span,
.reveal-overlay.paikallis .reveal-caption .reveal-huudahdus,
.reveal-overlay.diplomi .reveal-caption span,
.reveal-overlay.diplomi .reveal-caption .reveal-huudahdus { color: #574430; }

.reveal-overlay.paikallis .reveal-caption .reveal-isoisa,
.reveal-overlay.paikallis .reveal-caption .reveal-fakta,
.reveal-overlay.diplomi .reveal-caption .reveal-isoisa,
.reveal-overlay.diplomi .reveal-caption .reveal-fakta { color: #443520; }

/*
 * AARNIN LUETTELON DIPLOMI (vain pääaarteet — kaanoni: luettelossa
 * ovat vain ne). Paperiarkki kaiverruskehyksineen; kehyskuvan oma
 * yläkartussi kantaa otsakkeen ja alanauha arvon, joten niiden
 * paikat on sidottu kehyksen mittasuhteisiin (kuva 2:3).
 */
.reveal-plansi {
  position: relative;
  width: min(94vw, 30rem, 60vh);
  aspect-ratio: 2 / 3;
  display: grid;
  align-content: center;
  justify-items: center;
  row-gap: 0.55rem;
  /* Kehyskuvan kartussi (ylä ~13 %) ja nauha (ala ~10 %) jäävät
   * padding-alueelle — leipäsisältö keskittyy niiden väliin. */
  padding: 19% 13% 13%;
  text-align: center;
  color: #3a2d1c;
  background: radial-gradient(ellipse 120% 90% at 50% 30%, #f4ecd8 0%, #ece0c4 55%, #decfae 100%);
  border-radius: 3px;
  transform: rotate(-0.4deg) scale(0.92);
  box-shadow:
    0 0 70px 10px rgba(210, 170, 240, 0.1),
    0 24px 60px rgba(0, 0, 0, 0.65);
  opacity: 0;
  transition: opacity 0.9s ease-out, transform 0.9s ease-out;
}

.reveal-plansi.shown { opacity: 1; transform: rotate(-0.4deg); }

/* Generoitu kaiverruskehys koko arkin päälle; multiply upottaa sen
 * valkoisen pohjan paperiin. */
.reveal-kehys {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  mix-blend-mode: multiply;
  opacity: 0.9;
  pointer-events: none;
}

/* Otsake kehyksen yläkartussiin, arvo alanauhaan — prosentit
 * seuraavat kehyskuvan piirrosta. */
.reveal-otsake {
  position: absolute;
  top: 6.6%;
  left: 30%;
  right: 30%;
  font-weight: 700;
  font-size: clamp(0.5rem, 1.9vmin, 0.6rem);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.reveal-alaotsake {
  position: absolute;
  top: 13.2%;
  left: 12%;
  right: 12%;
  font-family: var(--font-type);
  font-size: clamp(0.58rem, 2.2vmin, 0.74rem);
  letter-spacing: 0.18em;
  color: #5d4b31;
}

.reveal-alanauha {
  position: absolute;
  bottom: 5.8%;
  left: 30%;
  right: 30%;
  font-family: var(--font-type);
  font-size: clamp(0.52rem, 2vmin, 0.62rem);
  letter-spacing: 0.08em;
  color: #4c3c25;
}

.reveal-jakoviiva {
  position: absolute;
  top: 16.6%;
  left: 29%;
  right: 29%;
  margin: 0;
  border: 0;
  border-top: 1px solid rgba(58, 45, 28, 0.55);
}

/* Pääaarteen kuva on maalattu mustalle pohjalle, joten diplomilla se
 * on kehystetty laatta — multiply tai maski tekisi siitä mustan
 * läiskän paperilla. Vaihtuu upotukseen, kun vaaleapohjaiset
 * pääaarrekuvat on generoitu. */
.reveal-overlay.diplomi .reveal-aarrekuva {
  width: min(62%, 34vh);
  border-radius: 4px;
  -webkit-mask-image: none;
  mask-image: none;
  /* Kermanvärinen paspis ja ohut musteviiva: mustapohjainen kuva
   * istuu paperille kehystettynä laattana kuin kiinnitetty
   * valokuvalevy. */
  border: 0.45rem solid #f6efdd;
  outline: 1px solid rgba(58, 45, 28, 0.45);
  box-shadow: 0 6px 22px rgba(58, 45, 28, 0.4);
}

.reveal-overlay.diplomi .reveal-caption { gap: 0.35rem; }

.reveal-overlay.diplomi .reveal-caption .reveal-fakta,
.reveal-overlay.diplomi .reveal-caption .reveal-isoisa {
  font-size: clamp(0.78rem, 2.6vmin, 0.95rem);
  max-width: 100%;
}

/*
 * LÖYDETTY-LEIMA: punainen kumileima päiväyksineen lyödään diplomiin
 * vasta hetken luvun jälkeen (playTokenReveal). Epätasainen painauma
 * on maskissa; lyönti tulee isosta pienempään pehmeällä rekyylillä.
 */
.reveal-leima {
  position: absolute;
  bottom: 13.5%;
  right: 7%;
  transform: rotate(-14deg);
  color: #a02c22;
  border: 3px solid #a02c22;
  border-radius: 6px;
  padding: 0.3rem 0.9rem 0.25rem;
  font-family: var(--font-type);
  font-weight: 700;
  font-size: clamp(0.9rem, 3.4vmin, 1.3rem);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  opacity: 0;
  -webkit-mask-image: radial-gradient(ellipse 130% 120% at 45% 50%, #000 62%, rgba(0, 0, 0, 0.7) 82%, rgba(0, 0, 0, 0.45) 100%);
  mask-image: radial-gradient(ellipse 130% 120% at 45% 50%, #000 62%, rgba(0, 0, 0, 0.7) 82%, rgba(0, 0, 0, 0.45) 100%);
}

.reveal-leima small {
  display: block;
  font-size: 0.55em;
  letter-spacing: 0.3em;
  text-align: center;
  margin-top: 1px;
}

.reveal-leima.lyoty { animation: leima-lyonti 0.4s ease-in forwards; }

@keyframes leima-lyonti {
  from { opacity: 0; transform: rotate(-14deg) scale(2.2); }
  62% { opacity: 0.9; transform: rotate(-14deg) scale(0.94); }
  to { opacity: 0.82; transform: rotate(-14deg) scale(1); }
}

@media (prefers-reduced-motion: reduce) {
  .reveal-leima.lyoty { animation: none; opacity: 0.82; }
}

/*
 * TUMMA → VAALEA SIIRTYMÄ (omistajan pohjapäätös 28.8.2026): leiman
 * jälkeen overlay saa luokan .kirkas ja valokerros häivyttää
 * purppurapimeyden vaaleaan pergamenttiin — sama lopputila kuin
 * leiskassa aarreleiska-vaalea2.html. Kerros on scenen alla, joten
 * diplomi ja nappi jäävät päälle.
 */
.reveal-valo {
  position: absolute;
  inset: 0;
  background: radial-gradient(ellipse 110% 80% at 50% 40%, #f3ead4 0%, #e9dcbc 55%, #d9c69c 100%);
  opacity: 0;
  transition: opacity 1.2s ease-in-out;
  pointer-events: none;
}

.reveal-overlay.kirkas .reveal-valo { opacity: 1; }

/* Vaalealla lopputilalla plansin purppurahehku vaihtuu paperivarjoon
 * ja Jatka matkaa -napin kultakajo pysyy luettavana. */
.reveal-overlay.kirkas .reveal-plansi {
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.6) inset,
    0 18px 44px rgba(74, 55, 28, 0.35),
    0 4px 12px rgba(74, 55, 28, 0.25);
  transition: opacity 0.9s ease-out, transform 0.9s ease-out,
    box-shadow 1.2s ease-in-out;
}

.reveal-scene { position: relative; }

.reveal-caption strong {
  font-family: var(--font-type);
  font-size: clamp(1.4rem, 4.5vmin, 2rem);
  letter-spacing: 0.05em;
  color: #2f2008;
}

.reveal-caption span {
  color: #3a2915;
  font-size: 0.98rem;
}

.quiz-verdict {
  font-family: var(--font-type);
  font-size: clamp(1.3rem, 3.4vw, 1.7rem);
  letter-spacing: 0.04em;
}
.gem-count { font-size: 0.78rem; color: var(--muted); }

/*
 * KÄTKÖ SULKEUTUI (omistajan pelitestipalaute v1119): toteava rivi
 * tuomion alla, kun kohtaamisen toinen yritys meni väärin ja kaupungin
 * aarre lukittui pysyvästi (js/visa.js, js/game.js lukitseAarre).
 * Vaimea muste — tämä ei ole moite eikä hälytys, vaan tieto.
 */
.quiz-lukko {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.88rem;
  line-height: 1.4;
  color: rgba(90, 67, 38, 0.85);
}

/* --- kapea / pystyasento: tiiviimmät napit ja tekstit --- */

@media (max-width: 900px), (orientation: portrait) {
  .actions button { font-size: 0.92rem; padding: 0.5rem 0.55rem; }
  .fact-text { font-size: 0.84rem; }
}

/* --- kartta täyttää ruudun, paneelit kelluvat sen päällä --- */
/*
 * Kartta on aina pääasia — myös aloitusnäkymässä, jossa kohde valitaan
 * kartalta: .stage on yksi sarake ja .rail asettuu kartan päälle kelluviksi
 * pergamenttikorteiksi. Kartta ei kutistu, joten fitViewBox saa käyttöönsä
 * koko alan. Aiemmin aloitusnäkymä oli kahdessa palstassa, mutta siinä
 * vaiheessa paneelissa on vain ohjerivi ja matkaajan tiedot: leveällä
 * näytöllä sivupalkki jäi lähes tyhjäksi ja söi kartalta satoja pikseleitä.
 *
 * body[data-mode] kertoo yhä vaiheen (start / play) muuta käyttöä varten.
 */

body[data-mode] .stage {
  grid-template-columns: minmax(0, 1fr);
  position: relative;
}

body[data-mode] .rail {
  position: absolute;
  inset: var(--gap);
  display: block;
  pointer-events: none; /* kartta jää raahattavaksi korttien välistä */
  z-index: 4;
}

body[data-mode] .rail > * { pointer-events: auto; }

/* Lennon aikana koko alarivi on poissa pelistä: näkymättömät napit eivät
 * saa ottaa napautuksia kalvon alla. Tämä voittaa yllä olevan auto-säännön
 * tarkkuudellaan riippumatta sääntöjen järjestyksestä. */
body[data-mode].flight-active .rail,
body[data-mode].flight-active .rail > * { pointer-events: none; }

/* Kehys ja pyöristys näkyvät joka reunalla myös asennetussa
 * sovelluksessa (omistajan valinta).
 *
 * Alakehys oli aiemmin turva-alueen eli kotipalkin korkuinen, jotta
 * kotipalkki lepäisi tummalla kehyksellä. Se söi iPhonella kartalta
 * kymmeniä pisteitä: pergamentti loppui selvästi ennen ruudun alareunaa
 * (omistajan havainto ja kuvakaappauksesta mitattuna). Nyt alakehys on
 * sama kapea rako kuin sivuilla, ja kartta jatkuu kotipalkin alle —
 * pergamentilla ei ole siellä mitään napautettavaa, ja kelluvat kortit
 * pysyvät turva-alueen yläpuolella omilla säännöillään (.rail alla).
 * Versionumero ei enää asu kulmassa vaan valikon pohjarivillä. */
body[data-mode] .app { padding-bottom: 0; }
body[data-mode] .stage { padding-bottom: var(--gap); }

/*
 * Kelluvat kortit varasivat alalaidasta turva-alueen verran tilaa
 * kotipalkille. Kehittäjätilan mittarivi paljasti, ettei sitä tarvita:
 * asennetussa sovelluksessa selain sai käyttöönsä 812 pistettä, vaikka
 * ruutu on 874 — kotipalkin kaista jää kokonaan sovelluksen alueen
 * ulkopuolelle. Varaus oli siis saman tilan laskemista kahdesti, ja se
 * söi napeilta 27 pistettä.
 *
 * Kiinteä rako riittää myös siellä, missä kotipalkki oikeasti yltää
 * näkymän päälle: se on ohut läpikuultava viiva, ja napit jäävät sen
 * yläpuolelle.
 */
body[data-mode] .rail { bottom: calc(var(--gap) * 2); }

/*
 * Alarivi: päiväkirja vasemmalla, toiminnot sen oikealla puolella. Rivi
 * katkeaa, kun kortit eivät mahdu rinnakkain — silloin päiväkirja nousee
 * omalle rivilleen nappien yläpuolelle eikä peitä niitä. Ilman tätä
 * kortit menivät päällekkäin kaikilla alle ~1240 px:n leveyksillä,
 * esimerkiksi tabletilla pystyasennossa.
 */
/*
 * KESKITYS ILMAN TRANSFORMIA (juurisyy omistajan havaintoon 13.8.2026:
 * "pöllöikkuna on hassusti vasemmassa reunassa").
 *
 * Tässä luki `left: 50%; transform: translateX(-50%)`. Transform tekee
 * elementistä containing blockin kaikille sen sisällä oleville
 * `position: fixed` -jälkeläisille — ja pöllöpaneeli asuu DOMissa juuri
 * tämän kortin sisällä (.turn-card > #actions > .toimintorivi >
 * .pollo-paikka). Paneelin `right: 0.7rem` mitattiin siis 356 px
 * levyisestä kortista eikä ruudusta, ja siirretystä laatikosta: paneeli
 * ajautui kuusi pikseliä ruudun vasemman reunan ULKOPUOLELLE ja oikealle
 * jäi 28 px rako. Sama vika vääristi paneelin ala- ja yläreunan.
 *
 * `left: 0; right: 0; margin-inline: auto` keskittää saman kortin
 * pikselilleen samaan kohtaan ilman transformia, joten fixed-jälkeläiset
 * ankkuroituvat jälleen ruutuun. Korjaus tehdään täällä eikä paneelissa:
 * ansa koskisi mitä tahansa, mitä alanappiriviin vielä lisätään.
 */
body[data-mode] .turn-card {
  position: absolute;
  left: 0;
  right: 0;
  margin-inline: auto;
  /* Ilman taustalaatikkoa napit osuivat kiinni kartan kehykseen. */
  bottom: 0.9rem;
  width: min(560px, calc(100% - 1.2rem));
}

/*
 * MATKUSTA-NAPPI IRTI ALAREUNASTA (omistajan pelitestipalaute v1119:
 * *"hieman ylemmäs nykyisestä"*). Fokusnäkymässä alarivillä on vain
 * tämä nappi, ja se istui kiinni kartuutsin ja mittajanan rivissä
 * ruudun alalaidassa — iPadilla se osui kotipalkin tuntumaan. Nosto
 * koskee vain yhden napin riviä; kahden napin rivi on entisellään.
 */
.toimintorivi.rivi-yksi { margin-bottom: 1.7rem; }

body[data-mode] .actions {
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
}

/*
 * Päiväkirja kelluu sillä kartan nurkalla, jossa on eniten merta; nurkan
 * valitsee js/ui.js placeFactCard ja kertoo sen data-corner-määreellä.
 * Alanurkat jäävät valitsematta, jos toimintokortti ei mahdu viereen.
 */
body[data-mode] .fact-card {
  position: absolute;
  width: min(340px, 46%);
  /* Korkeusraja ruutuyksiköissä: iPadin Safari ei soveltanut
   * prosenttirajaa (kortti kasvoi koko tekstin mittaiseksi kartan
   * päälle), dvh lasketaan aina ruudusta. Prosentti jää varalle
   * vanhoille selaimille.
   *
   * Katto on 74 dvh, koska kortti on nyt aina auki (v317): kolme
   * neljäsosaa ruudusta riittää lähes joka merkinnälle, ja kartasta
   * jää silti neljännes näkyviin — sen napautus kutistaa kortin
   * yhdelle riville. Sama luku oli ennen napautuksella avatun kortin
   * katto. */
  max-height: 74vh;
  max-height: 74dvh;
  /* Kortti ei vieritä itseään — vain teksti vierii (.fact-text). */
  overflow: hidden;
  transition: max-height 260ms ease;
}

/*
 * .laajennettu-luokka poistui v317:ssä: kortilla ei ole enää
 * välikokoa, joten se on aina niin auki kuin sen oma katto sallii
 * (ks. body[data-mode] .fact-card). Kortti kasvaa siitä reunasta,
 * johon se on kiinnitetty — ylänurkassa alaspäin, alanurkassa
 * ylöspäin.
 */

/*
 * --- yhden rivin päiväkirja (.pieni) ---------------------------------
 *
 * Omistajan toive 4.8.2026: linssin päällä ja karttaa vieritettäessä
 * matkakirja kutistuu yhden rivin korkuiseksi ja avautuu napauttamalla.
 *
 * Näkyväksi riviksi valittiin kaupungin nimi eikä merkinnän ensimmäinen
 * rivi: nimi on aina yksi rivi ja aina valmis, kun taas merkintä syntyy
 * kirjoituskoneella kirjain kerrallaan ja sen alku olisi lapussa milloin
 * mitäkin. Rivi nostetaan pystyflexin ensimmäiseksi (order), jolloin
 * kaikki muu jää leikkautuvan alareunan alle EIKÄ katoa asettelusta —
 * juuri siksi kutistuminen liukuu eikä nytkähdä.
 *
 * Korkeus on rivimitta (rivinkorkeus × kirjasinkoko + kortin pehmuste),
 * ei pikselivakio: kortin teksti on eri kokoista puhelimella ja
 * työpöydällä, ja kirjasin voi pudota varapinoon.
 */
.fact-card {
  /* .fact-place-rivin koko; puhelinversio alempana media-lohkossa. */
  --pieni-rivi: 0.8rem;
}

body[data-mode] .fact-card.pieni {
  /* 0.4rem = body[data-mode]-kortin pysty pehmuste (0.2rem + 0.2rem). */
  max-height: calc(1.5 * var(--pieni-rivi) + 0.4rem + 1px);
  overflow: hidden;
  /*
   * OTSIKKO JÄÄ NÄKYVIIN, JA SILLÄ ON TAUSTA.
   *
   * Ensimmäinen versio jätti riville pelkän kaupungin nimen ilman
   * taustaa, ja omistaja huomautti siitä heti: "Ainut, mikä näkyy, on
   * kaupungin nimi täysin irrallaan." Nimi yksin kartan päällä ei kerro
   * olevansa matkakirjasta — se näyttää yhdeltä kartan paikannimeltä
   * lisää, ja juuri sen erottuminen oli koko lapun tarkoitus.
   *
   * Rivi on siis kaksisarakkeinen ruudukko: otsikko ja sen perässä
   * kaupungin nimi. Kaikki muu jää toiselle riville, jonka korkeusraja
   * leikkaa pois — sisältö pysyy asettelussa, joten kutistuminen liukuu
   * yhä eikä nytkähdä.
   */
  display: grid;
  /*
   * MOLEMMAT SARAKKEET SISÄLTÖNSÄ LEVYISIÄ.
   *
   * Tässä luki `auto minmax(0, 1fr)`, ja `1fr` söi kaiken vapaan tilan:
   * palkki venyi kaistan levyiseksi, vaikka `width: max-content` oli
   * asetettu — max-content laskee raidat, ja 1fr-raita ilmoittaa
   * haluavansa kaiken. Omistaja: "korjaa matkakirjan liian pitkä palkki."
   */
  grid-template-columns: auto auto;
  justify-content: start;
  align-items: baseline;
  column-gap: 0.45em;
  /*
   * Laatikko on nyt täsmälleen sen levyinen, mitä siinä näkyy, joten se
   * saa myös ottaa napautukset vastaan. Aiemmin laatikko oli kaistan
   * levyinen ja läpinäkyvä, ja siksi se joutui päästämään napautukset
   * lävitseen — nyt sellaista tyhjää ei ole.
   */
  width: max-content;
  max-width: 100%;
  pointer-events: auto;
  cursor: pointer;
  /* Pergamenttikaistale otsikon alle: sama sävy kuin kortin paperi. */
  background: rgba(244, 231, 202, 0.86);
  border-radius: 6px;
  padding-inline: 0.5em;
  box-shadow: 0 1px 4px rgba(62, 42, 22, 0.18);
}

/* Otsikko yhden rivin mitassa: h2:n oma koko veisi lapulta kaksi riviä. */
body[data-mode] .fact-card.pieni > #fact-voice {
  grid-row: 1;
  grid-column: 1;
  order: -2;
  opacity: 1;
  margin: 0;
  /* Kaiuttimen tilanvaraus on auki olevan kortin otsikkorivin asia
   * (.fact-card h2). Lapussa kaiutin on häivytetty pois, ja varaus
   * jättäisi kaupungin nimen eteen tyhjän kaistaleen pergamenttia. */
  padding-inline-end: 0;
  font-size: var(--pieni-rivi);
  line-height: 1.5;
  white-space: nowrap;
  pointer-events: auto;
}

/* Kaikki muu kuin rivi itse jää leikkautuvalle toiselle riville. */
body[data-mode] .fact-card.pieni > *:not(#fact-voice):not(.fact-place-lyhyt) {
  grid-row: 2;
  /*
   * PIILOSSA OLEVA TEKSTI EI SAA MÄÄRÄTÄ PALKIN LEVEYTTÄ.
   *
   * `width: max-content` ei riittänyt, ja syy oli mitattavissa: leikattu
   * merkintä on yhä ruudukossa (rivillä 2), ja sen leveys 339 px venytti
   * ensimmäisen sarakkeen samaan mittaan — palkista tuli koko kaistan
   * levyinen, vaikka näkyvissä oli kaksi sanaa. Ruudukko mitoittaa
   * sarakkeen KAIKEN sisältönsä mukaan, myös sen, mikä on häivytetty
   * näkymättömiin.
   *
   * Nollaleveys ja `overflow: hidden` vievät niiden osuuden mitoituksesta
   * kokonaan (silloin myös `min-width: auto` ratkeaa nollaan). Ne pysyvät
   * silti asettelussa, joten kutistuminen liukuu yhä.
   */
  grid-column: 1 / -1;
  width: 0;
  min-width: 0;
  overflow: hidden;
}

.fact-card.pieni .fact-place-lyhyt {
  /* Perussääntö piilottaa rivin; lapussa se on koko sisältö. */
  display: block;
  /* Sama mitta kuin lapun otsikolla, jotta rivi on yhtä korkea kuin
     kortin korkeusraja olettaa (--pieni-rivi). */
  font-size: var(--pieni-rivi);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  order: -1;
  margin: 0;
  line-height: 1.5;
  /*
   * Rivi ei kutistu, muut kutistuvat.
   *
   * Kortti on pystyflex, ja korkeusraja tekee siitä ylitäyden: ilman
   * tätä selain kutistaa KAIKKIA lapsia suhteessa, myös nimiriviä, ja
   * lappu jää tyhjäksi (mitattu: rivin korkeudeksi jäi 0,1 px).
   * Nimirivi pitää oman mittansa ja leikkaus osuu vain siihen, mikä on
   * jo häivytetty näkymättömiin.
   */
  flex: 0 0 auto;
  /* Rivi vain oman mittansa levyinen — ks. pointer-events yllä. */
  width: max-content;
  max-width: 100%;
  pointer-events: auto;
  cursor: pointer;
  /* Yksi rivi myös pitkällä nimellä: ennemmin kolme pistettä kuin
   * kahdelle riville karkaava lappu. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/*
 * Mantereen lähikuvassa päiväkirjan alla on pehmeä pergamenttivalo
 * (body.manner-zoom .fact-card::before). Yhden rivin lapun alla se
 * kutistuu kirkkaaksi vaaleaksi palkiksi kartan poikki — valo on
 * mitoitettu monirivisen leipätekstin alle, ei yhdelle sanalle. Lapun
 * ajaksi se sammuu: kaupungin nimi jää saman vaalean tekstivarjon
 * varaan kuin kartan omat paikannimet, ja juuri se varjo on tehty
 * pitämään yksittäisen nimen luettavana kartan päällä.
 */
body.manner-zoom .fact-card::before,
body.pallolauta-paalla .fact-card::before { transition: opacity 200ms ease; }
body.manner-zoom .fact-card.pieni::before,
body.pallolauta-paalla .fact-card.pieni::before { opacity: 0; }

/*
 * Muut osat häipyvät ennen kuin reuna ehtii leikata ne: kaiutinnappi ja
 * pikkukuva ovat kortin omilla paikoillaan ylhäällä, ja pelkkä leikkaus
 * jättäisi ne roikkumaan puoliksi rivin päälle. Häipymä on kortin omaa
 * kutistumista nopeampi, joten ne ovat poissa ennen kuin lappu on
 * valmis. Siirtymä on perusluokassa, jotta se pätee molempiin suuntiin.
 */
.fact-card > *:not(.fact-place-lyhyt) { transition: opacity 160ms ease; }

.fact-card.pieni > *:not(.fact-place-lyhyt),
.fact-card.pieni .fact-valokuva {
  opacity: 0;
  /* Napautus osuu kutistuneena aina lappuun itseensä, ei sen alle
   * jääneisiin nappeihin. */
  pointer-events: none;
}

/* Kohdistusrengas piirtyy näkyvän rivin ympäri eikä kortin näkymättömän
 * laatikon: rengas kaistan levyisenä yhden sanan ympärillä ei kertoisi
 * mihin näppäimistö osoittaa. */
.fact-card.pieni:focus-visible { outline: none; }

.fact-card.pieni:focus-visible .fact-place-lyhyt {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/*
 * Kartan päällä ei ole laatikoita: päiväkirja ja toiminnot kirjoitetaan
 * suoraan pergamentille kartan omalla musteella. Vaalea tekstivarjo pitää
 * kirjaimet luettavina myös ruudukkoviivojen ja rannikon päällä — sama
 * keino kuin kartan kaupunkinimissä.
 *
 * Kelluva taitto on nyt ainoa taitto: sama pergamenttityyli kaikilla
 * ruuduilla, myös puhelimella.
 */
body[data-mode] .turn-card,
body[data-mode] .fact-card {
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0.2rem 0.35rem;
  color: var(--map-ink);
  text-shadow: 0 1px 0 rgba(247, 237, 216, 0.9), 0 0 6px rgba(247, 237, 216, 0.75);
}

/*
 * Kortin pehmuste myös mittana: kaiutin ripustetaan otsikkoriville
 * juuri tämän verran kortin reunasta (.fact-card .fact-kuuntele),
 * joten luku ei saa asua kahdessa paikassa eri arvoina. Perusarvo on
 * .card-luokan oma pehmuste; kelluvalla kartalla se on pienempi.
 */
.fact-card { --kortti-pehmuste-y: 0.6rem; --kortti-pehmuste-x: 0.7rem; }

body[data-mode] .fact-card {
  --kortti-pehmuste-y: 0.2rem;
  --kortti-pehmuste-x: 0.35rem;
}

body[data-mode] .fact-card h2 {
  color: #7a5514; /* tumma kulta erottuu pergamentilta, kirkas ei */
}

body[data-mode] .fact-place,
body[data-mode] .fact-place-lyhyt {
  color: var(--map-ink-soft);
}

body[data-mode] .fact-text,
body[data-mode] .fact-text .source-line {
  color: var(--map-ink);
}

body[data-mode] .error { color: #9c2f20; }

/*
 * Vähäeleiset napit: ei täyttöä eikä varjoja, vain ohut mustekehys —
 * kuin kartalle piirretyt merkinnät. Vaalea tekstivarjo pitää tekstin
 * luettavana ruudukkoviivojen päällä, kuten muissakin karttateksteissä.
 */
body[data-mode] .actions button {
  /* Kevyt pergamenttilevy pitää napin luettavana myös kaupunkinimien ja
   * rantaviivan päällä (omistajan havainto lentovalinnasta) — pelkkä
   * mustekehys hukkui karttaan. */
  background: rgba(250, 243, 226, 0.72);
  border: 1px solid rgba(122, 85, 20, 0.35);
  color: var(--map-ink);
  text-shadow: 0 1px 0 rgba(247, 237, 216, 0.9);
  backdrop-filter: none;
  box-shadow: none;
}

body[data-mode] .actions button:hover:not(:disabled) {
  background: rgba(255, 248, 232, 0.85);
}

/*
 * Yleinen opacity 0.45 tekee napista pergamentin päällä lähes
 * näkymättömän, joten estetty nappi pitää kehyksensä ja vain teksti
 * vaimenee.
 */
body[data-mode] .actions button:disabled {
  opacity: 1;
  background: none;
  border-color: rgba(122, 85, 20, 0.22);
  color: rgba(58, 42, 22, 0.45);
  text-shadow: none;
}

/*
 * Ensisijainen valinta erottuu tummalla kullalla, ei kultalaatalla —
 * mutta se tarvitsee saman pergamenttilevyn kuin muutkin napit.
 *
 * Aiemmin tässä luki `background: none`, jolloin kartta näkyi napin
 * läpi ja teksti hukkui kaupunkinimiin ja rantaviivaan. Omistajan
 * havainto: "Tutki nappi näkyy huonosti." Levy on hitusen lämpimämpi ja
 * peittävämpi kuin tavallisilla napeilla, joten nappi erottuu kahdesti:
 * kullanvärisestä kehyksestä ja tekstistä sekä hieman kirkkaammasta
 * pohjasta.
 */
body[data-mode] .actions button.primary {
  background: rgba(252, 241, 212, 0.88);
  border-color: rgba(176, 138, 60, 0.85);
  color: #7a5514;
  font-weight: 700;
}

body[data-mode] .actions button.primary:hover:not(:disabled) {
  background: rgba(234, 184, 78, 0.18);
}

/*
 * ── IPHONEN KAARET JA KOTIPALKKI (omistajan havainto 12.8.2026) ──
 *
 * Pelitilassa `.app` luopuu alareunan turva-alueesta tarkoituksella
 * (body[data-mode] .app { padding-bottom: 0 }): pergamentin pitää
 * jatkua kotipalkin alle, tai kartta loppuisi selvästi ennen ruudun
 * reunaa. Kelluvat napit eivät kuitenkaan saa jäädä sinne — iPhonella
 * monitoiminappi, Tutki ja pöllö jäivät osittain kotipalkin ja näytön
 * pyöristetyn kulman alle.
 *
 * Nosto tehdään turva-alueen verran, ja kartan alakulmien pyöristys
 * loivenee samalla niin, että se myötäilee näytön kaarta eikä leikkaa
 * nappien reunoja. Sääntö on rajattu kapeisiin ruutuihin, joten iPad
 * ja työpöytä pysyvät ennallaan — ja koska env():n oletusarvo on 0 px,
 * tavallisessa selaimessa (esim. 390 px Chromium) ulkoasu on
 * pikselilleen entinen.
 *
 * index.html:n viewport-metassa on jo viewport-fit=cover, ilman jota
 * env() palauttaisi iPhonella nollan.
 */
@media (max-width: 640px) {
  body[data-mode] .turn-card {
    bottom: calc(0.9rem + env(safe-area-inset-bottom, 0px));
  }

  body[data-mode] .fact-card[data-corner='bl'],
  body[data-mode] .fact-card[data-corner='br'] {
    bottom: calc(0.9rem + env(safe-area-inset-bottom, 0px));
  }

  .linssi-selite[data-corner='bl'],
  .linssi-selite[data-corner='br'] {
    bottom: calc(0.9rem + env(safe-area-inset-bottom, 0px));
  }

  /* Loivempi kaari alakulmiin: pidempi matka, sama muoto kuin näytön
     omassa reunassa. */
  body[data-mode] .map-pane {
    border-bottom-left-radius: calc(var(--radius) + 1.2rem);
    border-bottom-right-radius: calc(var(--radius) + 1.2rem);
  }
}

body[data-mode] .fact-card[data-corner='tl'] { top: 0.4rem; left: 0.4rem; }
body[data-mode] .fact-card[data-corner='tr'] { top: 0.4rem; right: 0.4rem; }
body[data-mode] .fact-card[data-corner='bl'] { bottom: 0.9rem; left: 0.4rem; }
body[data-mode] .fact-card[data-corner='br'] { bottom: 0.9rem; right: 0.4rem; }

/* --- puhelin: kaikki mahtuu ruudulle ilman vieritystä --- */

@media (max-width: 560px) {
  :root { --gap: 0.45rem; }

  .actions button {
    font-size: 0.82rem;
    padding: 0.4rem 0.4rem;
    min-height: 44px;
    line-height: 1.15;
  }

  /* Matkustustavan napit ovat puhelimella pelkkiä kuvakkeita, mutta ne
   * venyivät silti ruudun levyisiksi ja peittivät kartalta kaistan,
   * jota ne eivät tarvitse (omistajan toive). Nyt ne ovat kuvakkeen
   * kokoisia ja keskellä. Korkeus pysyy 44 pikselissä, jotta sormi osuu.
   *
   * Rajaus koskee vain yhden rivin matkustusvalintaa: leveämmät napit
   * (esim. Takaisin) tarvitsevat tekstitilansa. */
  body[data-mode] .actions[data-rivi='yksi'] {
    grid-auto-columns: minmax(0, 3.6rem);
    justify-content: center;
    gap: 0.5rem;
  }

  /* Omistaja pienensi näitä kahdesti: kuvake tarvitsee vain oman
   * tilansa. Korkeus 40 pikseliä on alle Applen 44 pisteen suosituksen,
   * mutta napit ovat erillään toisistaan eikä vieressä ole mitään
   * muuta napautettavaa, joten ohi osuminen ei tee vahinkoa. */
  body[data-mode] .actions[data-rivi='yksi'] button {
    min-height: 40px;
    padding: 0.3rem;
  }

  /*
   * ALANAPPIRIVI EI VIE KOKO LEVEYTTÄ PUHELIMELLA.
   *
   * Omistajan havainto 13.8.2026 iPhonella: kolme nappia
   * (Matkustustavat | Pöllö | Tutki) venyivät lähes ruudun levyisiksi
   * ja näyttivät raskailta — kuvake keskellä ja tyhjää molemmin puolin.
   * Kavennus tehdään RIVILLE eikä yksittäisille napeille, koska
   * matkanappien liuku on rivin lapsi (inset: 0): jos vain peruspaikat
   * kapenisivat, liuku jäisi leveäksi eikä osuisi enää niiden päälle.
   *
   * 15rem jättää kullekin napille noin 70 pikseliä — reilusti sormen
   * mitta, mutta rivi hengittää kartan päällä. iPadille ja työpöydälle
   * tämä ei yllä: media-ehto rajaa sen puhelimiin.
   */
  .toimintorivi {
    width: min(100%, 15rem);
    margin-inline: auto;
  }

  /* Kelluva päiväkirja levenee kaistaleeksi kartan ylle: 46 % leveydestä
   * olisi puhelimella liian kapea luettavaksi. */
  body[data-mode] .fact-card {
    width: min(340px, calc(100% - 0.8rem));
    /* Ei omaa korkeusrajaa: puhelimella pätee sama 74 dvh:n katto kuin
     * muillakin (v317). Ennen tässä oli 22 dvh:n ikkuna ja tekstissä
     * kolmen rivin katto — ne olivat välikoko, joka poistui. */
  }
  /* Teksti oli hetken isompaa (v148), mutta omistaja palautti sen:
   * isolla fontilla kortti peitti kartasta liian ison kaistan. Koko
   * merkinnän saa auki napauttamalla, joten pieni ikkuna riittää. */
  .fact-card h2 { font-size: 0.68rem; margin-bottom: 0.2rem; }
  .fact-place { font-size: 0.7rem; margin-bottom: 0.15rem; }
  /* Yhden rivin lapun korkeus seuraa samaa pienennystä. */
  .fact-card { --pieni-rivi: 0.7rem; }
  .fact-text { font-size: 0.78rem; line-height: 1.35; }

  /*
   * Kapea ruutu (puhelin): yläpalkin kaikki napit ovat pelkkiä kuvakkeita
   * ja pelin nimi kutistuu yhteen kirjaimeen. Näin kukkaro ja päiväkirjan
   * päivämäärä mahtuvat samalle riville — aiemmin ne katkesivat
   * kolmella pisteellä (omistajan havainto iPhonella).
   */
  .topbar { padding: 0.3rem 0.45rem; gap: 0.35rem; }
  /*
   * Nimilogo puhelimessa pienempänä. Koko sidotaan ruudun leveyteen
   * (vw) eikä pelkkiin pikseleihin: kapeimmalla puhelimella ylärivillä
   * on logon lisäksi kukkaro ja hampurilainen, ja ne on mitoitettu
   * samaan riviin.
   *
   * 5,7vw on entisen tekstilogon mitta: 390 pikselin ruudulla se on
   * 22 px, eli tarkalleen se korkeus, joka logolla oli ennen.
   */
  .brand { flex: 0 1 auto; }
  .brand-kuva { height: min(1.47rem, 5.7vw); }
  .turn-pill { font-size: 0.78rem; padding: 0.2rem 0.5rem; gap: 0.3rem; }
  .topbar-actions { gap: 0.15rem; }
  /*
   * Kosketuskohteet isommiksi puhelimessa.
   *
   * Napit olivat mitattuna 30 x 32 pikseliä. Hampurilaisen poisto toi
   * ylariville kaksi nappia lisää, ja pieni kohde on sitä hankalampi
   * mitä useampi niitä on vierekkäin. Tilaa vapautui, kun pelin nimi
   * kutistui 121:stä 91 pikseliin.
   */
  .topbar-actions button {
    font-size: 0.78rem;
    padding: 0.42rem 0.5rem;
    min-height: 40px;
    min-width: 40px;
  }

  .event-toast { font-size: 0.92rem; padding: 0.55rem 0.8rem; top: 10%; }
  .event-toast .toast-icon { font-size: 1.3rem; }

  .quiz-options { grid-template-columns: minmax(0, 1fr); gap: 0.4rem; }
  .quiz-option { min-height: 48px; padding: 0.5rem 0.7rem; font-size: 0.92rem; }
  .quiz-question { font-size: 1rem; margin-bottom: 0.7rem; }
  .dialog-card { padding: 0.8rem 0.85rem; }
  .dialog { width: calc(100% - 1rem); }
  .reveal-caption strong { font-size: 1.25rem; }
}


@media (pointer: coarse) {
  button { min-height: 46px; }
  .quiz-option { min-height: 62px; font-size: 1.02rem; }
}

@media (prefers-reduced-motion: reduce) {
  .target-ring { animation: none; }
}

/* Maailmankartta */

/*
 * Katselutila (?lauta=): työhuoneen Maanosat-välilehden karttaikkuna.
 * Uusi peli on piilossa, ettei se tyhjentäisi oikean pelin tallennusta.
 */
body.katselu #newgame-btn { display: none; }

/*
 * "Lue lisää": Wikipedian tiivistelmä paikasta. Ei kehystä eikä taustaa —
 * pelkkä tekstilinkki pergamentilla, kuten omistaja päätti. Tumma kulta
 * erottuu pergamentilta; kapean näytön tumma kortti saa oman värin alla.
 */
.wiki-btn {
  margin-top: 0.4rem;
  font-size: 0.78rem;
  padding: 0.1rem 0;
  min-height: 0;
  align-self: flex-start;
  background: none;
  border: 0;
  box-shadow: none;
  color: #7a5514;
  letter-spacing: 0.05em;
  /* Sama kevennys kuin kartan selitteillä: pisteviiva ohuemmaksi ja
   * haaleammaksi, väli tekstiin isommaksi. Väri on erikseen, koska
   * ilman sitä pisteet perivät linkin oman ruskean täydellä
   * voimakkuudella. */
  text-decoration: underline dotted;
  text-decoration-color: rgba(122, 85, 20, 0.45);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.wiki-btn:hover:not(:disabled) {
  background: none;
  color: #9c6f1e;
}

/*
 * Menovinkkien ulkoinen linkki. Sama tekstilinkin ulkoasu kuin
 * "Lue lisää", mutta nuoli kertoo että tästä poistutaan pelistä
 * uuteen välilehteen — pelaajan ei pidä yllättyä.
 */
.nosto-linkki {
  display: block;
  width: fit-content;
  max-width: 100%;
  text-decoration: underline;
  text-decoration-style: dotted;
  /* Sama kevennys kuin muillakin sisältölinkeillä (8.8.2026).
   * Sävy on sama kuin Lue lisää -napilla, jonka ulkoasua tämä muutenkin
   * seuraa; ensimmäinen rivi on varasävy vanhoille selaimille, ja
   * color-mix ottaa vallan siellä missä se tunnetaan, jolloin viiva
   * seuraa linkin omaa väriä myös sen muuttuessa. */
  text-decoration-color: rgba(122, 85, 20, 0.45);
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.nosto-linkki::after { content: ' ↗'; text-decoration: none; }

/* Dialogin sisälläkin Lue lisää on pelkkä tekstilinkki, ei nappi. */
.dialog .wiki-btn,
.dialog .wiki-btn:hover:not(:disabled) {
  background: none;
  border: 0;
  border-radius: 0;
}

/*
 * Havainnon kuvaikoni: pieni kehystetty maisema tekstin alla. Pelkkä
 * ikoni tekstilinkin sijaan — kuva puhuu puolestaan.
 */
/* Päiväkirjan ensimmäinen lause nousee esiin; loput luetaan silmillä. */
.fact-text .fact-lead { font-weight: 700; }

/* Kaiutin ankkuroituu korttiin myös silloin, kun kortti on staattinen. */
.fact-card { position: relative; }

/*
 * ── VALIKON POHJARIVI: versionumero ja palaute ───────────────────
 *
 * Molemmat olivat ennen kiinteinä kartan alakulmissa (position: fixed).
 * Omistajan päätös 12.8.2026 siirsi ne hampurilaisvalikon alimmalle
 * riville: pelinäkymään ei jää kumpaakaan, ja valikko on se paikka,
 * josta pelin ympärykset etsitään. Versionumero vasemmalle, palaute
 * oikealle — sama peilikuva kuin kulmissa, nyt yhdellä rivillä.
 */
.valikko-pohjarivi {
  display: flex;
  align-items: center;
  /* Versionumero yksin oikealla, eikä väliin jää vaakaviivaa —
   * kuvakerivi sen yllä on jo oma päätepisteensä (13.8.2026). */
  justify-content: flex-end;
  gap: 0.8rem;
  width: 100%;
  margin-top: 0.1rem;
}

/* Pohjarivin napit mittaavat itsensä: `.paavalikko button` venyttäisi
   ne täyteen leveyteen ja rivi hajoaisi kahdeksi. */
.paavalikko .valikko-pohjarivi button { width: auto; }

.versio-kulma {
  min-height: 0;
  padding: 0.25rem 0.3rem;
  background: none;
  border: 0;
  font: inherit;
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  /* Valikko on tumma paneeli, ei kartan pergamentti — muste vaihtuu
     vaimeaan vaaleaan, jotta numero pysyy luettavana. */
  color: var(--muted);
  cursor: pointer;
}

/*
 * Pieni tekstinkorkuinen päivitysnappi versionumeron vasemmalla
 * puolella (omistaja 13.8.2026: "versionumeron vasemmalle laitaan
 * voisi tehdä pienen päivitysnapin, tekstin korkuisen"). Sama
 * kirjasinkoko kuin numerolla ja ohut reunus, jotta se lukee napiksi
 * muttei kilpaile valikon isompien painikkeiden kanssa.
 */
.versio-paivitys {
  min-height: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.3em;
  padding: 0.15rem 0.45rem;
  background: none;
  border: 1px solid rgba(230, 214, 178, 0.3);
  border-radius: 6px;
  font: inherit;
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--muted);
  cursor: pointer;
}

.versio-paivitys .viiva-ikoni { display: inline-flex; }
/*
 * Kuvake hieman tekstiä suuremmaksi (omistajan päätös 18.8.2026).
 * Nappi on pelkkä kuvake, ja tekstinkorkuisena (1 em ≈ 11 px) se oli
 * pienin kohde koko valikossa. 1,45 em ≈ 16 px kasvattaa kuvan mutta
 * jättää napin yhä pohjarivin mittaiseksi — se ei saa kilpailla
 * valikon komentonappien kanssa.
 */
.versio-paivitys .viiva-ikoni svg { width: 1.45em; height: 1.45em; }

/* Haun aikana kuvake pyörii — pelkän kuvakkeen napissa ei ole
   tekstiriviä, joka kertoisi "Päivitetään…". */
.versio-paivitys.paivittaa .viiva-ikoni svg {
  animation: versio-paivitys-kierto 900ms linear infinite;
}

@keyframes versio-paivitys-kierto {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  .versio-paivitys.paivittaa .viiva-ikoni svg { animation: none; }
}

.paavalikko .versio-paivitys:hover:not(:disabled),
.paavalikko .versio-paivitys:focus-visible {
  background: none;
  color: var(--ink-light);
  border-color: var(--accent);
}

/*
 * Tuore päivitys korostuu (omistajan toive 9.8.2026): numero on
 * ensimmäisen puolen minuutin ajan selvästi isompi ja tummempi,
 * sitten se kutistuu tavalliseksi pehmeällä siirtymällä.
 */
.versio-kulma { transition: font-size 0.6s ease, color 0.6s ease; }

.versio-kulma.tuore {
  /* Koko ei enää kasva (omistaja 13.8.2026: "versionumero pienellä") —
   * julkaisuja tulee niin tiheään, että isompi koko näytti pysyvältä.
   * Tuoreus näkyy pelkkänä kullan välähdyksenä. */
  color: var(--accent);
  font-weight: 700;
}

.paavalikko .versio-kulma:hover:not(:disabled),
.paavalikko .versio-kulma:focus-visible {
  background: none;
  color: var(--ink-light);
}

/* Päivitysloki: lyhyt lista siitä, mitä kussakin versiossa muuttui.
   Kortti on kapea ja teksti pientä — lokia luetaan kartan päältä,
   ei erillisenä sivuna. */
.muutokset-dialog {
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 4px;
  background: rgba(252, 241, 212, 0.97);
  color: #46331f;
  padding: 1rem 1.1rem 0.8rem;
  width: min(86vw, 340px);
  max-height: 70vh;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35);
}
.muutokset-dialog::backdrop { background: rgba(20, 14, 8, 0.45); }
.muutokset-otsikko {
  margin: 0 0 0.6rem;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.muutokset-lista {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 52vh;
  overflow-y: auto;
  font-size: 0.78rem;
  line-height: 1.45;
}
.muutokset-lista li {
  display: flex;
  gap: 0.55rem;
  padding: 0.16rem 0;
}
/* Versionumero omassa sarakkeessaan: rivit alkavat samasta kohdasta,
   jolloin listaa voi silmäillä pelkän tekstin perusteella. */
.muutokset-lista .muutos-versio {
  flex: 0 0 2.2rem;
  color: rgba(70, 51, 31, 0.55);
  font-variant-numeric: tabular-nums;
}
.muutokset-sulje {
  margin-top: 0.7rem;
  width: 100%;
  padding: 0.4rem;
  font: inherit;
  font-size: 0.8rem;
  color: #46331f;
  background: rgba(252, 241, 212, 0.88);
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 3px;
  cursor: pointer;
}

/*
 * Palautehuutomerkki valikon pohjarivin oikeassa reunassa (omistajan
 * päätös 12.8.2026; ennen kiinteänä kartan oikeassa alakulmassa):
 * pieni ja hillitty, mutta aina saatavilla. Pelaaja voi kertoa
 * virheestä juuri siinä kohdassa peliä, jossa se osui silmään —
 * pelitilanne luetaan vasta lomaketta avattaessa (js/ui.js
 * palauteTilanne), joten siirto valikkoon ei muuta viestin sisältöä.
 */
.palaute-kulma {
  width: 1.6rem;
  height: 1.6rem;
  min-height: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--panel-2);
  color: var(--muted);
  font-family: var(--font-hand, inherit);
  font-size: 0.9rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

.paavalikko .palaute-kulma:hover,
.paavalikko .palaute-kulma:focus-visible {
  background: rgba(234, 184, 78, 0.18);
  color: var(--ink-light);
  transform: scale(1.08);
}

/* Palauteikkuna: sama pergamentti-ilme kuin periaateikkunassa, mutta
 * pienempi — yksi selitys, yksi kenttä ja lähetys. */
/* Kortti on dialogia (620 px) kapeampi — ilman automarginaalia se
 * istui dialogin vasemmassa reunassa ja koko lappu näytti olevan
 * sivussa (omistajan havainto 18.8.2026: "Pop-up-ikkunan voisi
 * keskittää"). */
.palaute-lappu .periaate-kortti { max-width: 30rem; margin-inline: auto; }

.palaute-tilanne {
  margin: 0 0 0.6rem;
  font-size: 0.78rem;
  color: rgba(70, 51, 31, 0.7);
  font-style: italic;
}

/* Kaiutin kortin oikeassa yläkulmassa: hillitty viivapiirros samaan
 * tapaan kuin kuvakuvake — jatkaa merkinnän luentaa.
 *
 * KAIUTIN ON OTSIKKORIVILLÄ, EI TEKSTIN PÄÄLLÄ (omistajan bugiraportti
 * 28.8.2026 iPhonesta). Kaksi asiaa piti korjata:
 *
 *  1. `button.ghost` (min-height: 36px, padding: 0.35rem 0.7rem) on
 *     tarkempi valitsin kuin pelkkä `.fact-kuuntele`, joten tämän
 *     lohkon `min-height: 0` ja `padding: 0.15rem` EIVÄT päteneet.
 *     Napin laatikko oli 40 × 36 px, ja 18 pikselin kuvake keskittyi
 *     siihen — eli kaksi riviä alemmas kuin oli tarkoitus, keskelle
 *     merkinnän paikkariviä. Valitsin on nyt `.fact-card
 *     .fact-kuuntele`, joka voittaa `button.ghost`in.
 *  2. Ankkuri seuraa kortin OMAA pehmustetta (--kortti-pehmuste-*),
 *     jolloin kuvake osuu otsikkorivin kohdalle eikä sen ylä- tai
 *     alapuolelle, vaikka pehmuste vaihtuisi.
 *
 * Otsikkorivi varaa kuvakkeelle sekä korkeuden että leveyden
 * (.fact-card h2), joten leipä- ja paikkarivi jäävät aina kuvakkeen
 * alapuolelle — ruudunleveydestä riippumatta.
 *
 * Kosketusala pidetään sormen kokoisena läpinäkyvällä ::before-alalla:
 * näkyvä kuvake on rivin korkuinen, mutta osuma-ala on entisen napin
 * mittainen. (Vinoviiva mykistetystä tilasta on ::after, ks. alempana.)
 */
.fact-card { --kaiutin-koko: 1.2rem; }

.fact-card .fact-kuuntele {
  position: absolute;
  top: var(--kortti-pehmuste-y);
  right: var(--kortti-pehmuste-x);
  width: var(--kaiutin-koko);
  height: var(--kaiutin-koko);
  padding: 0;
  min-height: 0;
  display: grid;
  place-items: center;
  background: none;
  border: 0;
  box-shadow: none;
  color: #7a5514;
  line-height: 0;
  cursor: pointer;
}

.fact-card .fact-kuuntele svg { width: 1.1rem; height: 1.1rem; }

/* Sormen kokoinen osuma-ala ilman että kuvake kasvaa. */
.fact-card .fact-kuuntele::before {
  content: '';
  position: absolute;
  inset: -0.55rem;
}

.fact-kuuntele:hover:not(:disabled) { background: none; color: #9c6f1e; }

.fact-image-btn {
  align-self: flex-start;
  margin-top: 0.35rem;
  padding: 0.15rem;
  min-height: 0;
  background: none;
  border: 0;
  box-shadow: none;
  color: #7a5514;
  line-height: 0;
  cursor: pointer;
}

.fact-image-btn:hover:not(:disabled) {
  background: none;
  color: #9c6f1e;
}

/*
 * KAIUTIN ON LUENNAN KYTKIN (omistajan tilaus 25.8.2026): erillinen
 * LUENTA-liukukytkin poistui, ja pois kytketty tila piirretaan
 * kaiuttimen paalle vinoviivana. Viiva on ::after-palkki currentColorilla
 * — ei suodattimia, ei kuvatiedostoa — ja kulkee kuvakkeen ylitse
 * kulmasta kulmaan, jotta tila nakyy yhdella silmayksella.
 */
.fact-kuuntele { overflow: visible; }

.fact-kuuntele.mykistetty { color: rgba(122, 85, 20, 0.62); }

.fact-kuuntele.mykistetty::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1.5em;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
  transform: translate(-50%, -50%) rotate(-45deg);
  pointer-events: none;
}

/* Pulman piirroksen selite: hiljainen rivi luonnoksen alla. */
.quiz-selite {
  margin: -0.2rem 0 0.5rem;
  font-size: 0.8rem;
  line-height: 1.45;
  font-style: italic;
  opacity: 0.75;
}

/* Valokuvakysymyksen vedos: kuin arkistokuva paksulla reunuksella. */
.quiz-photo {
  display: block;
  width: 100%;
  max-height: 220px;
  object-fit: cover;
  margin: 0.2rem 0 0.6rem;
  border: 4px solid #f7efdc;
  outline: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 3px;
  box-shadow: 0 2px 8px rgba(60, 42, 22, 0.25);
  cursor: zoom-in;
}

/*
 * Lue lisää -artikkeli sanomalehtityyliin (omistajan toive
 * 5.8.2026): sama vaalea painopaperi ja suora leikattu reuna kuin
 * Tutki-arkilla — vanha ruskea kortti katkoviivoineen jäi eri
 * aikakaudelle. Tausta EI tummene; kartta sumenee kevyesti
 * (sama huntu kuin uutis- ja sääpopupeissa).
 */
.wiki-card {
  max-width: 620px;
  background-image: var(--paper-noise);
  background-color: #f5f0e2;
  background-blend-mode: multiply;
  border-color: transparent;
  border-radius: 0;
  box-shadow: 0 0 60px rgba(0, 0, 0, 0.5);
}

/* Toinen kiertynyt katkoviiva ei kuulu painopaperiin. */
.wiki-card::before { display: none; }

#wiki-dialog::backdrop {
  background: rgba(26, 18, 8, 0.08);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

/*
 * Kirjanmerkkiliuskat Tutki-ikkunan yläreunaan.
 *
 * Omistajan toive: "kategoria valitsemessa voisi olla joku kiva pieni
 * vanhanaikainen visu. eli vain yksi kategoria näkyisi auki
 * kerrallaan."
 *
 * Malli on vanhan osoite- tai tilikirjan rekisteriliuska: pieni
 * kieleke, jonka yläkulmat ovat pyöristetyt ja joka istuu kiinni
 * sisällön yläreunaan. Piirretty samalla mustekynällä kuin kartta —
 * ei täyttövärejä, vain ääriviiva ja pergamentti.
 *
 * Liuskat KIERTYVÄT usealle riville (flex-wrap) eivätkä vierity
 * vaakasuunnassa. Vieritys piilottaisi osan vaihtoehdoista, ja
 * omistajan linjaus on "vain juuri halutut tiedot näkyvissä
 * kerrallaan" — ei "vain osa vaihtoehdoista löydettävissä".
 * Yhdeksän liuskaa mahtuu puhelimella kolmelle riville.
 */
.wiki-liuskat {
  display: flex;
  flex-wrap: wrap;
  /* Liuskat riippuvat yhteisestä alalinjasta kuten oikeassa
   * rekisterikirjassa. Ilman tätä eripituiset nimet asettuvat eri
   * korkeuksille ja rivi näyttää huolimattomalta. */
  align-items: flex-end;
  gap: 0.25rem;
  margin: 0 0 0.9rem;
  padding-bottom: 0.55rem;
  border-bottom: 1.5px solid rgba(70, 51, 31, 0.55);
}

.wiki-liuskat button {
  appearance: none;
  flex: 0 0 auto;
  padding: 0.26rem 0.52rem 0.3rem;
  min-height: 0;
  background: rgba(255, 250, 238, 0.55);
  border: 1.2px solid rgba(70, 51, 31, 0.45);
  /* Yläkulmat pyöreät, alakulmat terävät: liuska nousee sisällöstä. */
  border-bottom-color: transparent;
  border-radius: 7px 7px 0 0;
  color: rgba(70, 51, 31, 0.78);
  font-family: var(--font-type);
  font-size: 0.74rem;
  letter-spacing: 0.01em;
  cursor: pointer;
  /* Alareunan viiva kulkee liuskan ali; tämä nostaa sen sen päälle. */
  margin-bottom: -0.55rem;
  padding-bottom: 0.62rem;
}

.wiki-liuskat button:hover { background: #fffdf6; }

/*
 * Valittu liuska on pergamentin värinen ja sen alareuna on auki —
 * se on sama paperi kuin sisältö alla. Juuri se tekee liuskasta
 * liuskan eikä napin.
 */
.wiki-liuskat button.paalla {
  background: var(--card-bg, #f6e7c6);
  border-color: rgba(70, 51, 31, 0.75);
  /* --card-bg on liukuväri eikä kelpaa reunaväriksi — selain hylkäisi
   * koko rivin ja alareuna jäisi tummaksi. Kiinteä paperinsävy vastaa
   * tarttuvan aiherivin alaosaa, johon liuska kiinnittyy. */
  border-bottom-color: #eedcb6;
  color: #46331f;
  font-weight: 700;
}

.wiki-liuskat button:focus-visible {
  outline: 2px solid #46331f;
  outline-offset: 1px;
}

/*
 * Kategorian johdanto = lehden ingressi: yksi kappale siitä, mitä täältä
 * löytyy. Leipätekstiä isompi ja lukukirjasimella, jotta se erottuu
 * aloitukseksi eikä vain ensimmäiseksi kappaleeksi.
 */
.wiki-kategoria .johdanto {
  margin: 0 0 1.1rem;
  font-family: var(--font-luku);
  font-style: italic;
  color: rgba(70, 51, 31, 0.9);
  font-size: 1.02rem;
  line-height: 1.5;
}

/*
 * LEIPÄTEKSTI LUKUKIRJASIMELLA, ks. --font-luku.
 *
 * Rivinkorkeus 1,62 ja rivin mitta enintään 68 merkkiä: kumpikin on
 * typografian vanha nyrkkisääntö pitkälle tekstille, eikä kumpaakaan ole
 * arvattu — liian tiheä tai liian pitkä rivi eksyttää silmän rivinvaihdossa.
 */
.wiki-nosto .teksti {
  font-family: var(--font-luku);
  font-size: 1.02rem;
  line-height: 1.62;
  max-width: 68ch;
  margin: 0 0 0.7rem;
  color: rgba(58, 42, 26, 0.95);
}

.wiki-nosto .teksti:last-of-type { margin-bottom: 0.5rem; }

/* Lihavoitu aloitus — lehden keino tarttua lukijaan ("poldaus"). */
.wiki-nosto .leipa-aloitus {
  font-weight: 700;
  color: rgba(52, 37, 22, 1);
}

/*
 * ANFANGI aukeaman ensimmäiseen kappaleeseen, kerran sivua kohti.
 * Kirjain nostetaan kolmen rivin korkuiseksi float-tekniikalla, joka
 * toimii kaikissa selaimissa — ::first-letter + initial-letter on
 * kauniimpi mutta tukee vaihtelee.
 */
.wiki-nosto .teksti.anfangi::first-letter {
  float: left;
  font-family: var(--font-type);
  font-size: 3.1em;
  line-height: 0.82;
  font-weight: 700;
  padding: 0.06em 0.12em 0 0;
  color: rgba(70, 51, 31, 0.9);
}

/*
 * SITAATTINOSTON TYYLIT (.wiki-sitaatti) POISTETTU 23.8.2026.
 * Omistajan päätös: aihesivujen jutut ovat niin lyhyitä, että
 * nostettu virke toisti itsensä heti parin rivin päässä. Nosto ei
 * synny enää lainkaan (js/maalehti.js), joten säännöt olisivat
 * jääneet kuolleiksi.
 */

/* Yksi nosto: kuva, otsikko, teksti, selite, lähde. */
/*
 * ============================================================
 * MENOVINKKIEN LISTAMALLI (omistajan päätös 8.8.2026)
 * ============================================================
 *
 * Hakemisto, ei esseekokoelma: pieni kuva, nimi linkkinä ja lause
 * tai kaksi. Rivejä on kymmeniä, joten jokainen pikseli kertautuu —
 * siksi kuva on kiinteän kokoinen ruutu eikä juokseva kuva, ja rivit
 * erottaa toisistaan ohut viiva eikä väli.
 */
.vinkki-ryhma {
  /* Otsikkoteksti vasemmalle, reaktionappi (js/reaktiot.js) rivin
     päähän: baseline pitää tekstin viivan paikallaan, vaikka nappi on
     korkeampi kuin versaalirivi. */
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 1.5rem 0 0.5rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.85);
  border-bottom: 1px solid rgba(70, 51, 31, 0.35);
  padding-bottom: 0.25rem;
}

.vinkkilista { margin: 0; padding: 0; list-style: none; }

.vinkki {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  padding: 0.6rem 0;
  border-bottom: 1px dotted rgba(70, 51, 31, 0.22);
}

.vinkki:last-child { border-bottom: 0; }

/*
 * Kiinteä ruutu, ei juokseva kuva: pysty- ja vaakakuvat vuorottelevat
 * listalla, ja ilman kiinteää mittaa nimet hyppisivät rivi riviltä eri
 * kohtaan. object-fit leikkaa keskeltä, mikä on pikkukuvassa
 * parempi kuin tyhjät palkit.
 */
.vinkki-kuva {
  flex: 0 0 auto;
  width: 84px;
  height: 84px;
  object-fit: cover;
  border: 1px solid rgba(70, 51, 31, 0.3);
  background: rgba(70, 51, 31, 0.06);
}

.vinkki-teksti { min-width: 0; }

.vinkki-nimi {
  display: inline-block;
  font-family: var(--font-type);
  font-size: 0.86rem;
  line-height: 1.25;
  color: #7a5514;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

.vinkki-nimi:hover { color: #9c6f1e; }
.vinkki-nimi::after { content: ' ↗'; text-decoration: none; }

/*
 * Selitys lukukirjasimella, ei kirjoituskoneella. Kirjoituskone on
 * pelin oletus ja oikea lyhyissä riveissä (kuvatekstit, otsikot),
 * mutta hakemistossa selityksiä on parikymmentä peräkkäin — ja
 * pitkä monospace-teksti hidastaa lukemista juuri siellä, missä
 * lukijan on tarkoitus silmäillä.
 */
.vinkki-selitys {
  margin: 0.2rem 0 0;
  font-family: var(--font-luku);
  font-size: 0.95rem;
  line-height: 1.45;
}

.vinkki-lahde {
  margin: 0.2rem 0 0;
  font-family: var(--font-type);
  font-size: 0.66rem;
  color: rgba(70, 51, 31, 0.6);
}

/* Kuvaton rivi ei jätä ruudun kokoista aukkoa vasempaan reunaan. */
.vinkki.kuvaton .vinkki-teksti { padding-left: 0; }

@media (max-width: 420px) {
  .vinkki-kuva { width: 64px; height: 64px; }
  .vinkki-selitys { font-size: 0.88rem; }
}

.wiki-nosto {
  margin: 0 0 1.4rem;
  padding-bottom: 1.1rem;
  border-bottom: 1px dashed rgba(70, 51, 31, 0.28);
}

.wiki-nosto:last-child { border-bottom: 0; padding-bottom: 0; margin-bottom: 0.2rem; }

.wiki-nosto h3 {
  margin: 0 0 0.45rem;
  font-family: var(--font-type);
  font-size: 0.98rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* Nosto on oma taittolohkonsa. */
.wiki-nosto { display: flow-root; }

.wiki-nosto img {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 280px;
  /* Erilevyiset kuvat keskitetään palstalle — vasemmassa laidassa
   * kapea kuva jätti oikealle ison tyhjän kaistan. */
  margin: 0 auto 0.5rem;
  border: 3px solid #f7efdc;
  outline: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 2px;
  cursor: zoom-in;
}

/*
 * Leipätekstin koko, rivinkorkeus ja marginaali ovat YHDESSÄ paikassa
 * ylempänä (ks. "LEIPÄTEKSTI LUKUKIRJASIMELLA"). Tässä oli niistä toinen
 * kopio, ja koska se on tiedostossa myöhempänä, se voitti: lukukirjasin
 * tuli voimaan mutta koko ja rivinkorkeus jäivät vanhoiksi (0,9 rem /
 * 1,5). Puolittain voimaan tullut muutos on pahin laji, koska se
 * näyttää tehdyltä.
 */

/*
 * KUVATEKSTIN (.selite) TYYLIT POISTETTU 23.8.2026. Aihesivujen
 * kainalokuvista jäi jäljelle kuva ja lähderivi (omistajan päätös:
 * "ota ennemmin Kuvatekstit pois ja laita leipäteksti kiertämään
 * kuvaa"), eikä yksikään piirto tee enää .selite-kappaletta noston
 * sisään (js/maalehti.js). Selite elää datassa: alt-teksti ja
 * suurennoksen kuvateksti. Luokka pysyy lukijan ohituslistalla
 * (js/lukija.js) muiden näkymien varalta.
 */

/*
 * Kuvan ja sen lähderivin yhteinen kehys: kutistuu kuvan mittoihin ja
 * keskittyy palstalle. Krediitti EI SAA ylittää kuvan reunaa — kehys
 * on aina täsmälleen kuvan levyinen (100 %, kainalossa 36 % / 27 %).
 */
/*
 * Kuvat palstansa täyteen leveyteen KAPEALLA RUUDULLA (omistajan
 * toive 5.8.2026 + 6.8.2026 "levitä iphonella pystykuvat koko
 * leveyteen"): korkeuskatot jättivät kuvan kellumaan kapeana
 * keskelle. Leveys määrää koon ja korkeus seuraa kuvasuhdetta;
 * puhelimella pystykuva saa olla korkea, se on lehden kuva eikä
 * pikkukuvake.
 *
 * Tämä on nyt puhelimen sääntö. Leveällä ruudulla kuva kutistuu
 * kainaloon ja teksti juoksee sen vierellä — ks. "KAINALOKUVA"
 * alempana (omistajan palaute 21.8.2026).
 *
 * ALAMARGINAALI 0,85 → 0,7 rem (23.8.2026): kuvateksti on poissa, ja
 * kehyksen alla on enää kuuden pisteen krediittirivi. Väli mitattiin
 * kuvan alle jäävän ilman mukaan, ei kadonneen kuvatekstin.
 */
.wiki-nosto .kuvakehys {
  width: 100%;
  margin: 0 auto 0.7rem;
}

/* Kuva omalle rivilleen lohkona, jotta lähderivi alkaa sen alta eikä
 * asetu kuvan viereen. */
.wiki-nosto .kuvakehys img,
.wiki-nosto .kuvakehys .nosto-galleria {
  display: block;
  width: 100%;
  max-height: none;
}

/*
 * LÄHDERIVI YKSIN KUVAN ALLA (23.8.2026). Kuvateksti oli sen pari
 * inline-virrassa; nyt paria ei ole, joten rivi palaa omaksi pieneksi
 * lohkokseen kuvan alle. Se kääriytyy kehyksen leveyteen eli kuvan
 * reunaan asti, ja jos krediitti on pitkä, se rivittyy kuvan alla
 * eikä ulotu leipätekstin puolelle.
 */
.wiki-nosto .kuvakehys .lahde {
  display: block;
  margin: 0.25rem 0 0;
}

/* Lähdemaininta on lisenssiehto, ei koriste: se näkyy aina. */
.wiki-nosto .lahde {
  margin: 0 0 0.85rem;
  font-size: 0.66rem;
  line-height: 1.3;
  color: rgba(70, 51, 31, 0.68);
}

/*
 * LEHTIJUTUN TAITTO LEVEÄLLÄ RUUDULLA (omistajan toive 5.8.2026:
 * "teksti kahteen palstaan leveissä kohdissa" — ja "muihinkin
 * alisivuihin sama").
 *
 * KUVATON nosto: leipäteksti KAHDELLA PALSTALLA, ohut välipalstaviiva
 * keskellä — kuin sanomalehden juttu. Palstalohko on lyhyt
 * (leipäteksti on 440–660 merkkiä), joten molemmat palstat näkyvät
 * ruudulla yhtä aikaa eikä lukija joudu vierittämään edestakaisin.
 * Kapea ruutu (alle 700 px) pysyy yhtenä palstana.
 *
 * KUVALLINEN nosto: kainalokuva, ks. seuraava lohko.
 */
@media (min-width: 700px) {
  .wiki-nosto img { max-height: 520px; }
  .wiki-liuskat button { font-size: 0.8rem; }

  .wiki-nosto .leipa {
    columns: 2;
    column-gap: 2.2rem;
    column-rule: 1px solid rgba(70, 51, 31, 0.25);
  }

  /* 68 ch:n katto on yhden palstan mitta — palstoissa leveyden
   * määrää palsta itse. */
  .wiki-nosto .leipa .teksti { max-width: none; }

  /*
   * ── KAINALOKUVA (omistajan palaute 21.8.2026) ──
   *
   * "ruokakuvat kannattaisi pienentää pienemmiksi ja laittaa
   * leipäteksti juoksemaan sen vierelle. Sivun alin kuva ja sen
   * toinen vaihtoehto on pysty joka levittäytyy aivan liian
   * korkeaksi. nämäkin kuvat voisi ehkä mielummin olla kainalokuvia
   * niin että teksti juoksee sivussa."
   *
   * Kuva kutistuu 42 prosenttiin palstasta, kelluu oikeaan laitaan
   * ja leipäteksti juoksee sen vierellä. Kuvateksti ja lähderivi
   * ovat kuvan alla KAINALON SISÄSSÄ (ne ovat kehyksen lapsia),
   * joten ne eivät irtoa kuvastaan.
   *
   * AINA OIKEALLE, ei joka toinen eri puolelle. Kolme syytä:
   * anfangi kelluu vasemmalla, ja vasen kainalo työntäisi sivun
   * aloituskirjaimen keskelle palstaa; leipätekstin vasen reuna
   * pysyy samassa linjassa otsikoiden kanssa, jolloin silmä löytää
   * rivin alun joka kerta samasta kohdasta; ja vuorottelu on
   * aukeaman keino — yhdessä alle 900 pikselin arkissa se näyttää
   * levottomalta, ei lehtimäiseltä.
   *
   * Kellunta oli käytössä kerran ennenkin (v220–v299) ja kaatui
   * kolmeen vikaan. Ne on nyt korjattu nimeltä:
   *   1. romahtava prosenttileveys → 42 % vasta ≥ 700 px, jolloin
   *      tekstikaistaa jää vähintään ~330 px eli reilut 40 merkkiä;
   *   2. sanan levyinen tekstisuikale → sama asia toisin päin: alle
   *      700 px:n ruudulla kellutusta ei ole lainkaan;
   *   3. venyvät pystykuvat → oma leveys ja korkeuskatto alla.
   *
   * Luokan .kainalo antaa piirto (js/maalehti.js) jokaiselle
   * kuvalliselle nostolle, myös selattavalle gallerialle: Ateenan
   * evzoni-galleria oli juuri se lohko, jonka pystykuvista omistaja
   * huomautti. Nuolet ovat kuvan päällä kolmanneksen levyisinä
   * osuma-alueina, joten ne kutistuvat kuvan mukana.
   */
  /*
   * LEVEYS 42 → 36 % (23.8.2026, sama omistajan päätös kuin
   * kuvatekstin poisto: "niin tyhjä tila katoaa samalla").
   *
   * Kuvateksti oli vain puolet tyhjästä tilasta. Toinen puoli on
   * kelluva kuva itse: 42 prosentissa vaakakuva oli 890 pikselin
   * arkissa noin 375 px leveä ja 315 px korkea, kun sen vierelle
   * jäävä tekstikaista latoi jutun 190 pikseliin — lohkon vasempaan
   * alanurkkaan jäi tyhjä kaista, jota mikään ei täyttänyt.
   * Kaventaminen pienentää kuvaa ja LEVENTÄÄ tekstikaistaa yhtä
   * aikaa, joten ero kutistuu molemmista päistä. Tekstikaista on
   * 36 prosentissa yhä noin 545 px eli reilut 60 merkkiä, siis
   * luettava rivi eikä suikale.
   */
  .wiki-nosto.kainalo .kuvakehys {
    float: right;
    width: 36%;
    margin: 0.2rem 0 0.7rem 1.6rem;
  }

  /*
   * Kelluvan kuvan vieressä teksti on YHDESSÄ palstassa: kaista on
   * jo puolikas, eikä puolikasta jaeta enää kahtia. `columns: auto`
   * eikä `columns: 1` — yhden palstan multicol-laatikko on yhä
   * multicol-laatikko, se muodostaa oman muotoilukontekstinsa eikä
   * kierrä kellujaa lainkaan, vaan latoisi tekstin kapeaksi
   * suikaleeksi kuvan viereen koko lohkon matkalta.
   */
  .wiki-nosto.kainalo .leipa {
    columns: auto;
    column-rule: none;
  }

  /*
   * PYSTYKUVALLE OMA MITTA. Sama 42 % antaisi 2:3-kuvalle noin 500
   * pikselin korkeuden — juuri sitä omistaja moitti. 30 prosentissa
   * 2:3-kuva on noin 400 px ja 3:4-kuva noin 355 px, eli katon alla
   * ilman että katto ehtii vaikuttaa. Se on tarkoitus: kun katto ei
   * pure, kuva täyttää kehyksensä eikä kuvatekstin alle jää kuvaa
   * leveämpää reunusta.
   *
   * Katto 420 px on varmistus poikkeuksellisen kapealle kuvalle
   * (1:2 tai kapeampi). `object-fit: contain` pitää huolen siitä,
   * ettei katto koskaan litistä kuvaa väärään muotoon — kuva jää
   * kehyksensä sisään omissa mittasuhteissaan.
   *
   * Luokan .pysty antaa piirto kuvan latauduttua, kun luonnollinen
   * korkeus ylittää leveyden selvästi.
   */
  /* 30 → 27 % samasta syystä kuin vaakakuvan 42 → 36 % (23.8.2026):
   * pystykuva on kainalon korkein osa, ja juuri sen alle jäi jutun
   * loputtua tyhjä kaista. 27 prosentissa kuva on 890 pikselin
   * arkissa noin 240 px leveä ja 2:3-kuvana noin 270 px korkea. */
  .wiki-nosto.kainalo.pysty .kuvakehys { width: 27%; }

  /*
   * TÄYSLEVEÄ NOSTOKUVA (omistajan tilaus 23.8.2026): selvästi leveä
   * vaakakuva — panoraama tai maalaus, jonka suhde on ≥ 1,6 — ei
   * kellu kainalossa vaan levittäytyy koko palstalle jutun ylle, ja
   * leipäteksti palaa kahteen palstaan kuvan alle kuten kuvattomassa
   * nostossa. Luokan antaa js/maalehti.js kuvan latauduttua;
   * noston kenttä leveys: 'taysi'/'kapea' ohittaa automatiikan.
   */
  .wiki-nosto.kainalo.taysileve .kuvakehys {
    float: none;
    width: 100%;
    margin: 0.2rem 0 0.9rem;
  }

  .wiki-nosto.kainalo.taysileve .kuvakehys img {
    width: 100%;
    max-height: 520px;
    object-fit: contain;
  }

  .wiki-nosto.kainalo.taysileve .leipa {
    columns: 2;
    column-gap: 2.2rem;
  }

  .wiki-nosto.kainalo.pysty .kuvakehys img {
    max-height: 420px;
    object-fit: contain;
  }

  /* Lehtimaan pääkirjoitus etusivulla taittuu samalla tavalla. */
  .dialog.lehti #arrival-maa-intro {
    columns: 2;
    column-gap: 2.2rem;
    column-rule: 1px solid rgba(70, 51, 31, 0.25);
  }
}

/*
 * ── SISÄLTÖARKIT ISOLLA RUUDULLA (omistajan havainto 12.8.2026) ──
 *
 * `.dialog` on 620 px ja `.wiki-card` sama kaikilla ruuduilla, joten
 * iPadilla (834–1024 px pystyssä) "Lue lisää" -artikkeli jäi kapeaksi
 * puhelinpalstaksi keskelle isoa ruutua. Lehtiarkki (.dialog.arkki) on
 * jo täysleveä eikä sitä tarvitse koskea — mitattuna 738 px / 834 px ja
 * 928 px / 1024 px — mutta sen leipätekstin ympärillä on samaa vaivaa:
 * ingressi ja esittelyt ovat yksittäisiä kappaleita ilman rivimittaa.
 *
 * Katto nousee 768 pikselistä ylöspäin. Rivin mitta EI kuitenkaan
 * kasva samassa suhteessa: yli 75 merkin rivi eksyttää silmän
 * rivinvaihdossa, ja lehti on nimenomaan luettavaksi tehty. Nostojen
 * leipäteksti taittuu jo kahdelle palstalle (.wiki-nosto .leipa,
 * ≥ 700 px), joten sitä ei tarvitse rajata — ne kappaleet, jotka
 * juoksevat yhtenä palstana, saavat 38 em:n katon. Mitta on em eikä
 * pikseleitä, joten merkkimäärä pysyy samana kirjasinkoosta
 * riippumatta.
 *
 * 390 pikselin ulkoasu ei muutu: koko lohko elää media queryn sisällä.
 *
 * Raja 700 eikä 768 (omistajan palaute 18.8.2026 iPad-kaappauksesta:
 * "nähtävyysikkuna pitäisi olla iPadilla leveämpi"): 768 jätti
 * kapeimmat tabletit (esim. iPad mini pystyssä, 744 px) puhelimen
 * 620 pikselin palstaan. 700 on sama raja, jolla arkki ja palstat
 * vaihtavat leveään taittoon.
 */
@media (min-width: 700px) {
  #wiki-dialog { max-width: min(860px, 92vw); }
  .wiki-card { max-width: min(860px, 92vw); }

  /* Artikkelin palsta keskelle arkkia — otsikko, liuskat ja teksti
     samassa linjassa, jottei leveä arkki hajota lukusuuntaa. */
  .wiki-card #wiki-title,
  .wiki-card #wiki-kategoria,
  .wiki-card #wiki-extract,
  .wiki-card #wiki-source {
    max-width: 38em;
    margin-inline: auto;
  }
}

/* Lehden yksipalstaiset kappaleet: esittelyt. Lehden oma
 * raja pysyy 768:ssa — sen taitto ei ollut osa 18.8.2026 levennystä. */
@media (min-width: 768px) {
  .dialog.lehti .wiki-kategoria .johdanto,
  .dialog.lehti .nahtavyys-kappale { max-width: 38em; }
  /*
   * Etusivun leipäteksti kahdella palstalla (omistaja 20.8.2026:
   * "jaa teksti kahteen palstaan") — uuden tekstilinjan 7–10 virkkeen
   * johdatus latoutuu lehtimäisesti kuten kaupunkisivun nostot.
   * Kapealla näytöllä pysytään yhdessä palstassa (media queryn raja).
   */
  .dialog.lehti #arrival-intro {
    column-count: 2;
    column-gap: 2rem;
    max-width: none;
    text-align: justify;
    hyphens: auto;
  }
  .dialog.lehti #arrival-intro p { margin: 0 0 0.7em; }
  .dialog.lehti #arrival-intro p:last-child { margin-bottom: 0; }
}

/* Kuvan napautus avaa katselimen — kursori kertoo sen hiirikäyttäjälle. */
.arrival-image,
.wiki-image { cursor: zoom-in; }

/*
 * Kuvakatselin: koko ruudun tumma kerros avoimen dialogin sisällä, iso kuva
 * keskellä ja selailunuolet reunoilla. Suljetaan rastista tai taustasta.
 */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 20;
  /* Tausta kuultaa läpi (omistajan toive): kevyempi tummennus ja
   * pehmeä sumennus pitävät kuvan silti selkeästi erillään alta
   * kuultavasta kortista. */
  background: rgba(15, 10, 5, 0.62);
  -webkit-backdrop-filter: blur(5px);
  backdrop-filter: blur(5px);
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: pan-y;
}

.lightbox-img {
  max-width: 94vw;
  max-height: 88vh;
  object-fit: contain;
  border: 2px solid rgba(214, 188, 140, 0.5);
  border-radius: 6px;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.6);
}

.lightbox-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  min-width: 46px;
  min-height: 64px;
  font-size: 2rem;
  line-height: 1;
  background: rgba(28, 20, 12, 0.7);
  border: 1px solid rgba(214, 188, 140, 0.45);
  color: #f0e2c4;
  border-radius: 10px;
}

.lightbox-nav.prev { left: 0.6rem; }
.lightbox-nav.next { right: 0.6rem; }

.lightbox-close {
  position: absolute;
  top: 0.7rem;
  right: 0.7rem;
  min-width: 44px;
  min-height: 44px;
  font-size: 1.2rem;
  background: rgba(28, 20, 12, 0.7);
  border: 1px solid rgba(214, 188, 140, 0.45);
  color: #f0e2c4;
  border-radius: 999px;
}

.lightbox-counter {
  position: absolute;
  bottom: 0.9rem;
  left: 50%;
  transform: translateX(-50%);
  color: #e8d9b5;
  font-size: 0.9rem;
  letter-spacing: 0.08em;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
}

/* Kuvateksti suurennoksen alla: artikkelin oma selite kuvalle. */
.lightbox-caption {
  position: absolute;
  bottom: 2.4rem;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(40rem, 88vw);
  max-height: 4.2em;
  overflow: hidden;
  text-align: center;
  color: #f0e2c4;
  font-size: 0.88rem;
  line-height: 1.4;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}

/* Latausilmaisin: näkyy kunnes kuva on oikeasti perillä. */
.lightbox-loading {
  color: #e8d9b5;
  font-size: 1rem;
  letter-spacing: 0.12em;
  animation: lightbox-pulse 1.4s ease-in-out infinite;
}

@keyframes lightbox-pulse {
  0%, 100% { opacity: 0.9; }
  50% { opacity: 0.4; }
}

/*
 * ARTIKKELIN KUVA NIIN SUURENA KUIN SE ANTAA (omistajan toive
 * 6.8.2026: "kaikilla Wikipedia-artikkelisivuilla kuvat näytetään
 * mahdollisimman suurina").
 *
 * Ennen tässä oli `max-height: 320px`, ja se oli kahdesta rajoitteesta
 * jälkimmäinen: kuva HAETTIIN Wikipedian tiivistelmän pikkukuvana,
 * joka on mitattuna vain noin 330 pikseliä leveä (Madrid: 330 × 283,
 * alkuperäinen 1184 × 1016). Korkeusraja siis leikkasi kuvaa, joka oli
 * jo valmiiksi pieni. Molemmat korjattiin — haku pyytää nyt 1600
 * pikselin version (js/ui.js naytaWikiKuva), ja tässä kuva saa täyttää
 * palstan leveyden.
 *
 * `width: auto` on tahallinen: pientäkään kuvaa ei venytetä palstan
 * levyiseksi, koska venytetty pikkukuva on sumea eikä suuri.
 *
 * Korkeusraja on yhä olemassa mutta ruudun mitassa: pysty­kuva ei saa
 * täyttää koko sivua niin, ettei tekstiä näy ilman vieritystä.
 */
.wiki-image {
  display: block;
  width: auto;
  max-width: 100%;
  max-height: 78vh;
  margin: 0 auto 0.6rem;
  border-radius: 6px;
}

/* Lue lisää -lehden kuvakotelo kutistuu kuvan mittoihin, jotta laskuri
 * ja nuolet asettuvat kuvan eivätkä koko palstan reunoille. */
#wiki-kuvakotelo {
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 0.6rem;
}

#wiki-kuvakotelo .wiki-image { margin: 0; }

/* Artikkelin leipäteksti lehden lukukirjasimella (v304) — sama
 * typografia kuin nostoissa; kirjoituskone jää otsikoihin. */
.wiki-extract {
  font-family: var(--font-luku);
  font-size: 1.02rem;
  line-height: 1.62;
  color: #211d18;
  white-space: pre-wrap;
}

/* Koko artikkelin väliotsikot (renderArticle muotoilee tekstistä). */
.wiki-p { margin: 0 0 0.65rem; }

/* Omistaja 18.8.2026: "suurenna etusivun tekstin kokoa ipadilla.
   iphonella koko on sopiva." Lehden leipäteksti kasvaa leveällä
   ruudulla; otsikot, nimilaput ja kuvatekstit pysyvät ennallaan
   (niiden koot ovat omissa rem-säännöissään). */
@media (min-width: 700px) {
  .dialog.lehti .wiki-p { font-size: 1.08rem; }
}

.wiki-h2 {
  margin: 1.1rem 0 0.4rem;
  font-family: var(--font-type);
  font-weight: 700;
  font-size: 1.02rem;
  letter-spacing: 0.04em;
  border-bottom: 1px dashed rgba(70, 51, 31, 0.35);
  padding-bottom: 0.15rem;
}

.wiki-h3 {
  margin: 0.8rem 0 0.3rem;
  font-family: var(--font-type);
  font-weight: 700;
  font-size: 0.92rem;
  letter-spacing: 0.03em;
}

/*
 * Aikalaislainaus maastoartikkelissa: sisennetty ja kursiivissa,
 * jotta 1800-luvun ääni erottuu kertojan tekstistä yhdellä
 * silmäyksellä. Nimiörivi pienellä kuten lähdemaininta.
 */
.maasto-lainaus {
  margin: 0.9rem 0 0.9rem 0.9rem;
  padding-left: 0.8rem;
  border-left: 2px solid rgba(70, 51, 31, 0.35);
}

.maasto-lainaus-teksti {
  margin: 0 0 0.25rem;
  font-style: italic;
}

.maasto-lainaus-nimio {
  font-size: 0.8rem;
  opacity: 0.85;
}

/* Lähdemaininta on lisenssiehto, ei koriste: se näkyy aina. */
.wiki-source {
  margin-top: 0.7rem;
  font-size: 0.78rem;
  opacity: 0.8;
}

/*
 * Kuratoidun karusellikuvan teksti Lue lisää -ikkunassa: selite ja sen
 * jatkeena tekijä ja lisenssi. Samat luokat kuin nähtävyysjutun kuvalla
 * (.nahtavyys-selite, .nahtavyys-lahde), joten ilme on sama molemmissa
 * paikoissa — vain kehys on eri.
 */
.wiki-kuvateksti {
  margin: 0.35rem 0 0;
}

/* Tekijä ja lisenssi suurennoksen kuvatekstin JATKEEKSI samalle
 * riville, pienellä ja himmeällä (23.8.2026). */
.lightbox-lahde {
  display: inline;
  font-size: 0.66rem;
  opacity: 0.78;
}

/*
 * Isoisän luonnoskirjan pulma: piirros on osa korttia, ei kuvitusta sen
 * vieressä. Sama mustetyyli kuin kartan koristeissa — ohut viiva, ei väriä.
 */
.quiz-sketch {
  display: block;
  width: 100%;
  max-width: 340px;
  /* Korkeus on annettava erikseen: pelkkä viewBox ei anna svg:lle
     luontaista korkeutta flex-asettelussa, jolloin piirros litistyy pois. */
  aspect-ratio: 320 / 150;
  height: auto;
  flex: none;
  margin: 0 auto 0.8rem;
  color: #3b2a18;
}

.quiz-sketch .ink {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.quiz-sketch .ink-fill {
  fill: currentColor;
  fill-opacity: 0.72;
  stroke: currentColor;
  stroke-width: 1.2;
}

.quiz-sketch .ink-text {
  fill: currentColor;
  font-family: 'Courier New', monospace;
  font-size: 13px;
  text-anchor: middle;
}

/*
 * Lentoanimaatio: kone liitää reittiä pitkin ja punainen viiva piirtyy sen
 * perässä, kuten vanhoissa seikkailufilmeissä. Kerros on kartan päällimmäinen
 * eikä ota napautuksia vastaan — animaatio on puhtaasti kosmeettinen.
 */
.flight { pointer-events: none; }

.flight-trail {
  fill: none;
  stroke: #c2452f;
  stroke-width: 3.2;
  stroke-linecap: round;
  stroke-dasharray: 7 6;
  opacity: 0.9;
}

.flight-plane-body {
  fill: #2e2114;
  stroke: #2e2114;
  stroke-width: 1.4;
  stroke-linejoin: round;
}

/* Kone lentää selaimen omana muunnosanimaationa: origo koneen omassa
 * pisteessä, jotta käännös vastaa SVG-attribuutin käytöstä, ja
 * will-change nostaa koneen omalle kerrokselleen. */
.flight-plane {
  transform-box: view-box;
  transform-origin: 0 0;
  will-change: transform;
}

.flight-trail { will-change: stroke-dashoffset; }

/*
 * ALOITUSLENTO KARTALLA (omistaja 24.8.2026, Raamattu: ALOITUSLENTO
 * UUSIKSI — js/ui.js aloituslentoSisalla).
 *
 * Avauslento ei ole enää oma piirretty kohtauksensa kalvon päällä vaan
 * tapahtuu pelin omalla kartalla. Kalvosta jää jäljelle pelkkä repliikin
 * ja napin pino, joten sen tausta, sumennus ja pystykeskitys puretaan:
 * kartta näkyy sellaisenaan, ja teksti asettuu ruudun alalaitaan sinne,
 * missä lentoreitti ei kulje.
 */
.flight-overlay.kartalla {
  background: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  justify-content: flex-end;
}

/*
 * ISOISÄN VALOKUVA LENNOLLA (omistaja 3.9.2026: *"pelaaja löytäisi siis
 * matkakirjan välistä yhden kuvan lentokoneessa istuessaan isoisästään"*).
 * Kulunut cabinet card nousee kartan päälle vasemmasta alakulmasta
 * repliikin alettua, pehmeästi jarruttaen (Raamatun animaatiosääntö), ja
 * napautus suurentaa sen. EI suodatinta (ks. tests/lento-ajoitus).
 *
 * ── KORTTI HÄIPYY JOKA REUNASTAAN, JA ON ISOMPI (omistaja 5.9.2026
 * klo 00.35, sanatarkasti: *"isoisän kuva pitää häivyttää joka
 * reunastaan läpinäkyväksi ja tehdä vähän isommaksi"*) ─────────────
 *
 * KOKO on yksi muuttuja (--lento-valokuvan-leveys) ja se kasvoi noin
 * neljänneksen: työpöydällä min(30vw, 280px) → min(37.5vw, 350px),
 * puhelimessa min(44vw, 200px) → min(55vw, 250px).
 *
 * HÄIVYTYS ON MASKI EIKÄ SUODATIN (iOS-sääntö, ks.
 * tests/lento-ajoitus): kaksi lineaarista liukua — vaaka ja pysty —
 * yhdistetään leikkaukseksi, jolloin jokainen neljästä reunasta päätyy
 * läpinäkyvään eikä yhtäkään kovaa reunaa jää. Sama kaava kuin
 * aarrekuvan reunanpehmennyksellä (.reveal-overlay.paikallis
 * .reveal-aarrekuva), joka on todettu toimivaksi myös WebKitissä
 * (-webkit-mask-composite: source-in).
 *
 * VARJO ON POISSA. box-shadow piirtyy elementin LAATIKON mukaan eikä
 * maskin, joten se olisi jättänyt juuri sen terävän suorakaiteen, jonka
 * häivytyksen on määrä poistaa.
 *
 * KUVATEKSTI JÄÄ HÄIVYTYKSEN ULKOPUOLELLE: se on kortin oma <span>
 * kuvan alla, ei kuvan sisällä, joten "Isoisä, Bombay, 1873" pysyy
 * täysin luettavana. Sen negatiivinen ylämarginaali nostaa lapun
 * kiinni kuvan viimeiseen näkyvään riviin — muuten häivytetty alalaita
 * jättäisi lapun leijumaan irralleen.
 */
.lento-valokuva {
  --lento-valokuvan-leveys: min(37.5vw, 350px);
  --lento-valokuvan-haivytys-x: 15%;
  --lento-valokuvan-haivytys-y: 18%;
  position: absolute;
  left: clamp(0.8rem, 4vw, 3rem);
  /* Repliikin yläpuolella: teksti asuu alalaidassa (.flight-alaosa). */
  bottom: clamp(10rem, 30vh, 16rem);
  width: var(--lento-valokuvan-leveys);
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  opacity: 0;
  transform: translateY(28px) rotate(-7deg);
  transition: opacity 900ms var(--liike-pehmea), transform 900ms var(--liike-pehmea);
  z-index: 6;
}
.lento-valokuva.nakyy { opacity: 1; transform: translateY(0) rotate(-7deg); }
.lento-valokuva img {
  display: block;
  width: 100%;
  height: auto;
  -webkit-mask-image:
    linear-gradient(to right, transparent 0, #000 var(--lento-valokuvan-haivytys-x),
      #000 calc(100% - var(--lento-valokuvan-haivytys-x)), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 var(--lento-valokuvan-haivytys-y),
      #000 calc(100% - var(--lento-valokuvan-haivytys-y)), transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0, #000 var(--lento-valokuvan-haivytys-x),
      #000 calc(100% - var(--lento-valokuvan-haivytys-x)), transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 var(--lento-valokuvan-haivytys-y),
      #000 calc(100% - var(--lento-valokuvan-haivytys-y)), transparent 100%);
  mask-composite: intersect;
}
/*
 * Kuvateksti kortin alla, samassa kallistuksessa kuin kuva (omistaja
 * 3.9.2026: *"lisää lentokohtaukseen pienellä kuvateksti kuvan kanssa
 * vinosti: 'Isoisä, paikkakunta, 1873'"*). Kirjoituskoneen kirjasin,
 * kuin albumin kulmaan lyöty lappu.
 */
.lento-valokuva .lento-valokuvateksti {
  display: block;
  /* Lappu kiinni kuvan viimeiseen näkyvään riviin (ks. häivytys yllä). */
  margin-top: -0.6rem;
  font-family: var(--font-type);
  font-size: clamp(0.62rem, 1.4vw, 0.8rem);
  letter-spacing: 0.08em;
  color: #3a2a16;
  /* Kolme halokerrosta: lappu lukeutuu myös häivytetyn kuvan alalaidan
     ja terävän laattakartan päällä (harso ei enää auta, 5.9.2026). */
  text-shadow: 0 0 6px rgba(255, 246, 224, 0.95), 0 0 3px rgba(255, 246, 224, 0.95),
    0 0 1px rgba(255, 246, 224, 0.95);
  text-align: center;
}
.lento-valokuva:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
@media (max-width: 599px) {
  /*
   * Puhelimessa kortti on kapeammalla ruudulla suhteessa isompi, joten
   * se nostetaan hitusen ylemmäs pois repliikin päältä — ja koska sen
   * reunat ovat nyt läpinäkyviä, se ei enää katkaise lentoreittiä
   * yläkulmallaan (v1601: kortti sivusi viivaa).
   */
  .lento-valokuva {
    --lento-valokuvan-leveys: min(55vw, 250px);
    bottom: clamp(12rem, 34vh, 18rem);
  }
}
@media (prefers-reduced-motion: reduce) {
  .lento-valokuva { transition: none; }
}

/* Reitin lähtömerkki Lontoon kohdalla: sama punainen kuin viivalla.
   Britannia on käymättömänä maana sumun alla, joten ilman merkkiä
   reitin alkupää katoaisi harsoon. */
.aloituslento-piste {
  fill: #c2452f;
  opacity: 0.9;
}

/*
 * ==================================================================
 * LENTOKOHTAUKSEN KORISTEET (päätoimittajan taidesuunta 26.8.2026)
 * ==================================================================
 *
 * Omistajan havainto oli, että kohtaus on "vähän paljaannäköinen":
 * punainen viiva ja pieni kone tyhjällä kartalla. Lisät ovat kaikki
 * samaa 1873-akvarellikieltä ja kaikki transformia, peittävyyttä tai
 * liukua — EI SUODATTIMIA (iOS:n webapp-tila palauttaa suodatetun
 * kerroksen tyhjänä, ks. tests/sw.test.mjs).
 */

/* Kuljetun reitin katkojälki: vanhan matkakartan reittimerkintä, joka
   jää koneen taakse. Sama muste kuin tuoreella vetäisyllä mutta
   ohuempana ja haaleampana — jälki on vanhempi kuin kärki. */
.lento-katko {
  fill: none;
  stroke: #c2452f;
  stroke-linecap: round;
  opacity: 0.72;
}

/* Siipien vanavesi: kaksi ohutta viirua, jotka haalistuvat liu'ulla. */
.lento-vana {
  fill: none;
  stroke: url(#lento-vana);
  stroke-width: 1.6;
  stroke-linecap: round;
}

/* Koneen huojunta omassa ryhmässään (js/ui.js lennonHuojunta): pelkkä
   siirto, joten origolla ei ole väliä eikä transform-box tarvita. */
.flight-keinu { will-change: transform; }

/*
 * LAIVAREITIT MERELLE (omistajan pelitestipalaute v1119, poistetun
 * saapumisleiman tilalle — js/ui.js lennonLaivareitit).
 *
 * Vanhan merikartan reittimerkintä: ohut katkoviiva, jonka väri on
 * kartan omaa haalistunutta mustetta eikä lentoreitin punaista — laiva
 * ei kilpaile koneen kanssa. Katkoviivan jakso ja viivan paksuus
 * asetetaan js:stä, koska ne mitataan RUUDUN pikseleinä.
 */
.lento-laivareitti {
  fill: none;
  stroke: #4a3a24;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.2;
}

/*
 * Laiva reitillä: hyvin himmeä piste, joka kulkee hitaasti ja välkkyy
 * kevyesti. Liike ja välke ovat js-animaatioita (transform ja opacity),
 * eivät suodattimia — sama sääntö kuin harsopilvillä, ja sama lupa:
 * ne elävät DOMissa vain lennon ajan.
 *
 * Peittävyys tulee välkeanimaatiosta; tämä on lähtöarvo sitä ennen.
 */
.lento-laivapiste {
  fill: #4a3a24;
  opacity: 0.24;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  .lento-laivareitti,
  .lento-laivapiste { display: none; }
}

/* Lentokerros häipyy saapumisessa kalvon kanssa samaa tahtia — ilman
   tätä kone, viiva ja leima katoaisivat yhdessä kehyksessä. */
.flight.lento-poistuu {
  opacity: 0;
  transition: opacity 0.28s ease;
}

/*
 * Vinjetti lennon ajaksi: hyvin hento tummennus ruudun reunoihin, joka
 * nostaa kartan keskeltä esiin. Liuku on elementissä itsessään, joten
 * kartta ei joudu piirtymään uudelleen — ja koska kalvo on kartan
 * päällä, vinjetti häipyy kalvon mukana.
 */
.lento-vinjetti {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(
    118% 82% at 50% 44%,
    rgba(32, 21, 10, 0) 54%,
    rgba(32, 21, 10, 0.1) 78%,
    rgba(32, 21, 10, 0.26) 100%
  );
  opacity: 0;
  animation: lento-vinjetti-sisaan 1.8s ease forwards;
}

@keyframes lento-vinjetti-sisaan { to { opacity: 1; } }

/*
 * HARSOPILVET LENNON AJAKSI (omistajan lisätilaus 26.8.2026: *"Saisiko
 * lennon ajaksi animoitua kevyesti harsomaisia pilviä tai usvaa tai
 * jotain kartan päälle? Voisi liikkua hyvin hitaasti."*).
 *
 * Viisi laikkua, joiden pehmeys on radial-gradientissa eikä
 * suodattimessa. Liike on pelkkää transformia omalla kerroksellaan
 * (will-change), joten kartta ei piirry uudelleen niiden takia —
 * tämä on se ehto, jolla jatkuva animaatio ylipäätään saa olla kartan
 * päällä lennon aikana (vrt. js/ui.js isoAnimaatio).
 *
 * Jaksot ovat 88–146 sekuntia ja matkat muutama prosentti ruudusta:
 * yksikään pilvi ei ehdi lennon aikana käydä matkaansa loppuun.
 * Elementit ovat DOMissa vain lennon ajan.
 */
.lento-pilvet {
  position: absolute;
  inset: 0;
  z-index: 6;
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
  transition: opacity 1.6s ease;
}

.lento-pilvet.nakyy { opacity: 1; }

.lento-pilvet.poistuu {
  opacity: 0;
  transition: opacity 0.32s ease;
}

.lento-pilvi {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--koko);
  aspect-ratio: 1 / var(--korkeus);
  background: radial-gradient(
    closest-side,
    rgba(255, 252, 244, var(--kirkkaus)) 0%,
    rgba(255, 252, 244, calc(var(--kirkkaus) * 0.55)) 46%,
    rgba(255, 252, 244, 0) 100%
  );
  will-change: transform;
  animation: lento-pilvi-ajelehdi var(--kesto) linear infinite alternate;
  animation-delay: var(--viive);
}

@keyframes lento-pilvi-ajelehdi {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(var(--matka), var(--nousu), 0); }
}

@media (prefers-reduced-motion: reduce) {
  .lento-pilvi { animation: none; }
  .lento-vinjetti { animation: none; opacity: 1; }
}

/*
 * LENNON OMA NIUKKA KERROS (js/kartta.js aloituslennonNiukkuus,
 * omistajan pelitesti v1103:sta).
 *
 * KOHDEMAA PIMENNOKSEEN MUIDEN MUKANA. Fokusmoodin sumuverho jättää
 * käytyihin maihin aukot, ja peli siirtää nappulan perille jo lennon
 * alussa — kohdemaa jäi siis ainoana maana tarkaksi ja paljasti
 * määränpään ennen kuin kone oli siellä. Aukko on SVG-maskissa, joten
 * sitä ei voi peittää täältä: pelin oma verho menee lennon ajaksi
 * kokonaan piiloon ja lentokerros piirtää tilalle saman sävyisen
 * harson ilman aukkoja.
 *
 * DISPLAY EIKÄ HÄIVYTYS, toisin kuin muissa lennon piilotuksissa. Kaksi
 * verhoa on identtinen yhtä asiaa lukuun ottamatta (kohdemaan aukko),
 * joten välitön vaihto on huomaamaton — ristiinhäivytys sen sijaan
 * näkyisi, koska kaksi läpikuultavaa harsoa päällekkäin on tummempi
 * kuin kumpikaan yksin. Display myös takaa, ettei maskattua kerrosta
 * rasteroida lennon aikana lainkaan: kone ja sen perässä piirtyvä viiva
 * mitätöivät kaaren laatikon joka kehyksellä, ja maski jouduttiin
 * maalaamaan uudelleen sen alta. Mittaustulos ja Chromiumin todellinen
 * pullonkaula ovat js/kartta.js:n saman nimisessä osiossa.
 *
 * LENTOKERROKSEN HARSO ON VUOROSTAAN PIILOSSA AINA MUULLOIN. Lippu
 * poistuu lennon lopussa 280 ms ennen kuin js/ui.js tyhjentää
 * lentokerroksen; ilman tätä sääntöä molemmat harsot olisivat sen
 * hetken päällekkäin.
 *
 * HARSON ALLA ON NYT ATLAS EIKÄ VANHA LAUTA (omistajan linjaus
 * 25.8.2026, ilta: *"Vanha kartta pitää ottaa kokonaan pois pelistä
 * toistaiseksi."*). Aukoton harso jää silti tähän kohtaan sellaisenaan
 * — sen tehtävä on estää kohdemaata erottumasta ennen laskeutumista
 * (ks. yllä), eikä se tehtävä muuttunut mihinkään. Ero on siinä, mitä
 * harson läpi näkyy: ennen laudan piirros, nyt pergamentti ja
 * valmistuneiden maiden atlas-lehdet.
 */
body.kartalento .fokus-sumu { display: none; }

/*
 * PIILOSSA OLEVAT SYKKEET SEIS LENNON AJAKSI. Laatan sykkivä kehä ja
 * maataulun plus-nappi ovat lennon ajan häivytettyjä (opacity: 0), mutta
 * niiden animaatiot juoksevat silti: selain laskee molemmille uuden
 * tyylin joka kehyksellä siinä missä koneelle ja reittiviivallekin.
 * Mitattuna (Chromium, jäljitys 25.8.2026) lennon aikana oli käynnissä
 * viisi animaatiota, joista kolme kuului näkymättömiin kerroksiin.
 * Ne palaavat itsestään, kun lippu poistuu.
 */
body.kartalento .fokuslaatta-syke,
body.kartalento .fokus-maataulu-lehti { animation: none; }

.aloituslento-niukka { display: none; }

body.kartalento .aloituslento-niukka { display: block; }

/*
 * Reitin päiden nimet: Lontoo ja kohdekaupunki, ei muuta. Sama
 * kaunokirjoitus ja pergamenttihalo kuin fokuskartan lisänimillä
 * (.fokus-nimi), mutta tummempana ja hiukan harvennettuna — nämä ovat
 * lennon ainoat kaksi nimeä, ja ne luetaan harson läpi.
 *
 * HALON LEVEYS TULEE MÄÄREENÄ js/kartta.js:stä eikä täältä. Nimen koko
 * on laudan yksiköitä ja riippuu lennon mittakaavasta, joten kiinteä
 * pikselileveys olisi ruudulla milloin mitäkin — se lasketaan samasta
 * kertoimesta kuin kirjasinkoko.
 */
.aloituslento-nimi {
  font-family: var(--font-kauno);
  fill: rgba(52, 36, 22, 0.92);
  paint-order: stroke;
  stroke: rgba(240, 228, 200, 0.85);
  stroke-linejoin: round;
  letter-spacing: 0.04em;
}

/*
 * NIUKKA KARTTA LENNON AJAKSI (Raamattu: *"kartta on tällöin jo
 * fokusmoodin tapaan niukka"*). Sumuverhon hoitaa fokusmoodi itse;
 * tässä piiloutuu se pelitila, jonka peli on jo ehtinyt siirtää perille
 * — nappula, kohderenkaat ja laatat olisivat kohdekaupungissa vastassa
 * ennen kuin kone on edes lähtenyt. Häivytys eikä display, jotta ne
 * palaavat pehmeästi kun lippu poistuu.
 *
 * KAUPUNKIKERROS (.cities) JA LAATAN OMA KERROS (.fokuslaatta, jossa
 * napautusalue ja sykkivä kehä) TULIVAT MUKAAN 25.8.2026 kahdesta
 * syystä.
 * Ensinnäkin kohdekaupungin nimilappu (ATEENA, Kreeta) on samaa
 * pelitilaa kuin laattakin: se odotti valmiina määränpäässä. Toiseksi
 * fokusnäkymän laatta mitoitetaan RUUDULTA (js/ui.js
 * paivitaFokusLaatta), ja mitoitus päivittyy vasta kun näkymä on
 * asettunut — lennon aikana taas ei päivitetä mitään (ks. saman
 * tiedoston rasterointiehto, `flight-active`). Kamera-ajo Euroopan
 * yleiskuvaan jätti siis laatalle lähikuvan kertoimen, ja laatta
 * levisi ruudulla kultaiseksi kiekoksi. Piilossa oleva kerros ei voi
 * näyttää vanhentunutta mittaa, ja perillä mitta lasketaan uusiksi
 * ensimmäisessä piirrossa.
 */
body.kartalento .pawns,
body.kartalento .targets,
body.kartalento .tokens,
body.kartalento .cities,
body.kartalento .fokuslaatta,
body.kartalento .fokuskuvat {
  opacity: 0;
  pointer-events: none;
}

/*
 * SAMA KOSKEE KAHTA KERROSTA, JOTKA JÄIVÄT ENNEN LEHDEN PIILOON
 * (omistajan pelitesti 25.8.2026).
 *
 *   .fokuspisteet     kevyen kulun vihreä kohtaamispiste (js/fokuspiste.js)
 *                     — omistaja näki sen vilkkuvan kohdemaan päällä
 *                     kesken lennon, koska peli oli jo siirtänyt
 *                     matkaajan perille.

 * Häivytys eikä display, samasta syystä kuin yllä: ne palaavat pehmeästi
 * kun lippu poistuu.
 *
 *   .elaintakyt       maiden eläintäkymerkit (js/elaintaky.js) — omistajan
 *                     testikierros 30.8.2026 (iPad): merkit *"näkyvät
 *                     lennon aikana"* ympäri Eurooppaa, vaikka lennon
 *                     kartalla ei kuulu olla sisältömerkkejä. Kerroksen
 *                     oma astepiilotus (ELAINTAKY_NAKYY_ASTETTA) ei osu
 *                     tähän: lento zoomaa juuri sen rajan alle.
 */
body.kartalento .fokuspisteet,
body.kartalento .elaintakyt {
  opacity: 0;
  pointer-events: none;
}

/*
 * Selitevalikko on pelitilan työkalu, ei lentokohtauksen (omistaja
 * 30.8.2026: nappi näkyi avauslennon oikeassa yläkulmassa). JS piilottaa
 * kotelon myös aloitusruuduissa (js/karttaselite.js paivita, ehto
 * pickstart/aloituslento); tämä sääntö varmistaa saman lennon jokaisessa
 * kehyksessä riippumatta siitä, ehtiikö piirtoketju ajaa paivitan.
 */
body.kartalento .karttaselite {
  opacity: 0;
  pointer-events: none;
}

/*
 * KEKSINNÖT-LINSSI (omistaja 3.9.2026): matkakirja häviää näkyvistä ja
 * oikean yläkulman karttaselite poistuu, jotta linssin ilmiökuva pääsee
 * ylemmäs (css/aikajana.css .aikajana-ilmio). js/aikajana.js lisää ja
 * poistaa body.aikajana-paalla.
 */
body.aikajana-paalla .fact-card,
body.aikajana-paalla .karttaselite,
body.aikajana-paalla .fokus-kartuutsi,
body.aikajana-paalla .kartta-mittajana,
body.aikajana-paalla .fokus-viivain {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.5s ease;
}

/*
 * KARTTA ON LINSSIN AJAN TYHJÄ TAULU (omistaja 4.9.2026: *"Kartalla
 * näkyy myös kysymysmerkkejä"*). Tummennetun kartan läpi kuulsivat
 * pelin omat merkit: kohdemerkit nostosymboleineen ja nimiöineen sekä
 * eläintäyt. Linssin oma kertomus on sen lamput ja karuselli, eikä
 * pelaajan pidä osua pelin kohteisiin katselutilassa — merkit
 * häivytetään ja niiden osuma-alat vaietaan.
 *
 * KAUPUNKIEN JA MAASTON NIMET JÄÄVÄT (omistajan rajaus): ne ovat
 * kartan omaa painojälkeä ja auttavat paikantamaan lampun. Ne eivät
 * silti saa olla napautettavia, joten koko nimikerros on linssin ajan
 * mykkä; vain kohteen oma nimiö ja sen nostoviiva häviävät kokonaan.
 *
 * `pointer-events` erikseen jälkeläisille: kerroksen `none` ei estä
 * osumaa lapselta, joka on itse `pointer-events: all` (osuma-alat).
 */
body.aikajana-paalla .fokuskohteet,
body.aikajana-paalla .elaintakyt,
body.aikajana-paalla .karttanimi-kohde,
body.aikajana-paalla .karttanimi-nosto {
  opacity: 0;
  transition: opacity 0.5s ease;
}
body.aikajana-paalla .fokuskohteet,
body.aikajana-paalla .fokuskohteet *,
body.aikajana-paalla .elaintakyt,
body.aikajana-paalla .elaintakyt *,
body.aikajana-paalla .karttanimet,
body.aikajana-paalla .karttanimet * {
  pointer-events: none;
}

.pawns,
.targets,
.tokens,
.fokuskuvat {
  transition: opacity 0.5s ease;
}

/*
 * Lauta vaihtuu lennon alussa aloitusnäytöstä maailmankartalle, ja se on
 * väistämättä leikkaus: kaksi eri karttaa, ei mitään mistä toiseen
 * liu'uttaisiin. Lyhyt häivähdys pehmentää sen niin, ettei uusi lauta
 * pompahda ruudulle — kamera-ajo alkaa saman tien ja vie katseen
 * eteenpäin.
 */
body.kartalento #board { animation: kartalento-sisaan 0.55s ease; }

@keyframes kartalento-sisaan { from { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .pawns, .targets, .tokens, .fokuskuvat { transition: none; }
  body.kartalento #board { animation: none; }
}

/*
 * Nuoren herran repliikki kartan alla.
 *
 * EI TAUSTALAATIKKOA (omistajan tilaus 12.8.2026). Tumma planssi oli
 * kalvolla ainoa umpinainen pinta ja veti katseen kartalta; teksti
 * kirjoittuu nyt tummana suoraan kalvon vaalealle pergamentille, kuten
 * muukin kartan päälle kirjoitettu. Luettavuus tulee kolmesta asiasta,
 * joita ilman vaalea pohja ei riitä: musteenvahva väri (--map-ink,
 * kontrasti pergamenttiin yli 8:1), väljä riviväli ja vaalea
 * tekstivarjo, joka nostaa kirjaimet irti kartan viivoista siellä
 * missä kalvo on ohuimmillaan.
 *
 * Ei osumakohtaa — napautukset kuuluvat kalvolle ja napille.
 */
.flight-line {
  pointer-events: none;
  margin: 0;
  /* Kiinteä leveys ja rajattu asettelu: kirjoituskoneen naputus ei saa
   * leventää planssia merkki kerrallaan — jokainen leveysmuutos pakotti
   * koko kalvon asettelun uusiksi ja nyki lentoa. */
  width: 100%;
  max-width: 100%;
  contain: content;
  /* Pystytäyte on tekstivarjoa varten: contain: content rajaa maalauksen
     täytelaatikkoon, ja ilman tätä ylimmän ja alimman rivin hehku
     leikkautuisi juuri siitä mistä se nostaa kirjaimet kartasta irti. */
  padding: 0.35rem 0.6rem;
  color: var(--map-ink);
  font-family: var(--font-type);
  /*
   * KOKO NOSTETTU 1 rem → 1,25 rem (omistajan pelitestipalaute v1119:
   * *"KONEKIRJOITUSTEKSTI ISOMMAKSI lennossa — selvästi isompi
   * pistekoko, edelleen kirjoituskonekirjasin"*). Rivi on kartan
   * alalaidassa keskellä ulappaa, ja iPadin etäisyydeltä 16 pikselin
   * konekirjoitus jäi kartan omien paikannimien kokoiseksi. Kirjasin
   * on ennallaan (--font-type), vain mitta kasvoi.
   *
   * clamp pitää rivin kurissa kapealla ruudulla: 390 pikselin
   * leveydellä repliikki on kolme riviä, ja liian iso kirjasin
   * työntäisi sen kartan päälle.
   */
  font-size: clamp(1.2rem, 4.2vw, 1.45rem);
  line-height: 1.7;
  letter-spacing: 0.01em;
  text-align: center;
  text-shadow: 0 1px 0 rgba(247, 237, 216, 0.95), 0 0 7px rgba(247, 237, 216, 0.85);
  animation: flight-overlay-in 0.4s ease;
}

@media (prefers-reduced-motion: reduce) {
  .flight-trail, .flight-plane-body, .flight-line { display: none; }
}

/* Kuuntele kieltä: sama nappi kuin kulttuurinostojen näytteellä, mutta
   se asuu tervehdysrivin perässä eikä otsikkorivillä, joten se saa oman
   ylämarginaalinsa eikä veny palstan levyiseksi. */
.kieli-kuuntele {
  margin-top: 0.45rem;
  align-self: flex-start;
}

/*
 * Kehittäjätila (omistajan toive). Ulkoasu on tarkoituksella sama
 * pergamentti kuin muissa ikkunoissa: tämä ei ole erillinen työkalu
 * vaan pelin oma piilotettu asetus.
 */
.kehittaja-lomake {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  margin: 0.2rem 0 0.6rem;
}

.kehittaja-label {
  font-family: var(--font-type);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.kehittaja-kentta {
  font-family: var(--font-type);
  font-size: 1.4rem;
  letter-spacing: 0.35em;
  text-align: center;
  padding: 0.45rem 0.6rem;
  color: var(--map-ink);
  background: rgba(255, 255, 255, 0.45);
  border: 1px solid rgba(70, 51, 31, 0.55);
  border-radius: 90px 12px 84px 14px / 14px 84px 12px 90px;
}

.kehittaja-virhe {
  margin: 0;
  font-size: 0.85rem;
  color: #8c2f1d;
}

/* Ruudun mitat: kartan alareunan arvoitusta varten (ks. muistiinpanot).
   Pieni tasalevyinen teksti, jonka voi lukea kuvakaappauksesta. */
.kehittaja-mitat {
  margin: 0 0 0.6rem;
  padding: 0.5rem 0.6rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.72rem;
  line-height: 1.5;
  white-space: pre-wrap;
  color: #5a4326;
  background: rgba(255, 255, 255, 0.35);
  border: 1px dashed rgba(70, 51, 31, 0.5);
  border-radius: 8px;
}

.dialog-teksti { margin: 0 0 0.6rem; }

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 0.4rem;
}

/* Kehittäjätilassa kohteita ei piirretä lainkaan (omistajan toive):
   41 rengasta kerralla peitti kartan. Napautusalue (.target-hit) on
   näkymätön, ja versionumeron perässä lukee ": kehittäjä". */

/*
 * Lippukysymyksen kuva. Lippu on leveä ja matala eikä kestä samaa
 * rajausta kuin valokuva: se näytetään kokonaan (contain) ja kehystä
 * kavennetaan, jotta mittasuhteet pysyvät oikeina. Vaalea tausta
 * erottaa valkoiset kentät kortista — Japanin lippu katoaisi muuten.
 */
#quiz-photo.quiz-lippu {
  object-fit: contain;
  max-height: 26vh;
  background: rgba(252, 241, 212, 0.92);
  padding: 0.5rem;
  border-radius: 3px;
}


/* ── Tutki-kortti muistiinpanoarkkina ─────────────────────────────── */
/*
 * Omistajan toive: "tutki ikkuna piti olla melkein koko ruudun
 * kokoinen niin että sivu näyttää muistiinpanoarkilta. eli ääriviiva
 * käsinpiirretyn näköinen ja kartta näkyy vain hieman laitojen
 * ulkopuolelta blurrina."
 *
 * Kartta jää siis näkyviin kapeana kehyksenä, ei peittoon. Sumennus
 * tehdään backdrop-filterillä eli kerroksessa kortin TAKANA — ei
 * kartan omana filtterinä. Ero on ratkaiseva: iOS pudottaa
 * suodatetun SVG-kerroksen puskurin, ja kartta katosi kokonaan silloin
 * kun sitä kokeiltiin suoraan. Backdrop-filter ei koske karttaan.
 */
.dialog.arkki::backdrop {
  background: rgba(14, 9, 4, 0.34);
  -webkit-backdrop-filter: blur(6px) saturate(0.85);
  backdrop-filter: blur(6px) saturate(0.85);
}

/*
 * Dialogilla on oltava tarkalleen kortin mitat. Muuten kortti
 * leviää dialogin ulkopuolelle, arkki ei ole keskellä ruutua eivätkä
 * reunakerrokset osu kohdalleen.
 */
.dialog.arkki {
  width: calc(100vw - 1.6rem);
  max-width: none;
  /*
   * PYSTYMITAT OVAT ANKKUREITA, EIVÄT KORKEUSARVOJA (18.8.2026,
   * v784–v851-perheen juurisyy). Arkin alareuna oli tähän asti
   * johdettu korkeusARVOSTA — CSS:ssä 100dvh:sta, JS:ssä mitatuista
   * pikseleistä — ja jokainen arvolähde voi WebKitissä vanhentua:
   * dvh/vw jumiutuvat taustapaluussa, visualViewport valehtelee
   * hetkittäin ja resize-tapahtuma voi jäädä kokonaan tulematta,
   * jolloin JS:n kertaalleen kirjoittama pikselimitta jää voimaan
   * ikuisesti. Jokainen vanhentuma näkyi alareunassa: sumea
   * ::backdrop-kaista liian lyhyen arkin alla tai alanapit ruudun
   * alla liian pitkän.
   *
   * Uusi malli: arkki VENYTETÄÄN top/bottom-ankkureilla kiinnitetyn
   * asemointilaatikkonsa (fixed → asetteluviewportti) reunoihin ja
   * kortti täyttää sen prosenteilla. Ankkurit ja prosentit ratkeavat
   * suoraan asetteluviewportista, joka on WKWebView'ssä oikein
   * silloinkin kun dvh on jumissa (todennettu v784:ssä: clientHeight
   * oli oikein, dvh väärin — pikselimitathan luettiin juuri siitä).
   * Alareuna on siis MÄÄRITELMÄNSÄ MUKAAN näkyvän alueen alareuna
   * miinus turva-alue, ilman yhtään mittausta tai tapahtumaa.
   * Pystyarvot asettaa kumpikin media-lohko (< 700 ja ≥ 700 px);
   * tähän perussääntöön niitä ei kirjoiteta, ettei kaskadiin jää
   * kolmatta, medioiden kanssa kilpailevaa korkeuslähdettä.
   */
}

/*
 * ARKIN MITAT OVAT YHDESSÄ SÄÄNNÖSSÄ ILMAN :has():ia (omistajan
 * iPad-havainto 13.8.2026). Tässä oli mukana kaksoiskappale
 * `.dialog.arkki .dialog-card:has(#arrival-maa:not([hidden]))`, jonka
 * ainoa tehtävä oli voittaa saapumiskortin vanha 700 px:n katto. Koko
 * sääntö — myös tavallinen valitsin — kaatuu selaimessa, joka ei
 * jäsennä :has():ia, ja silloin arkki putoaa .dialogin oletusleveyteen
 * eli 620 pikselin palstaksi keskelle isoa iPadin ruutua. Katto on nyt
 * rajattu arkin ulkopuolelle (ks. .dialog:not(.arkki) .arrival-card),
 * joten tämä sääntö on taas pelkkää arkkia.
 */
.dialog.arkki .dialog-card {
  width: calc(100vw - 1.6rem);
  max-width: none;
  /*
   * Kortin pystymitta tulee media-lohkoista PROSENTTEINA dialogista
   * (height/max-height: 100%): kortti ei voi kasvaa dialoginsa yli
   * (omistajan havainto 16.8.2026 iPadilla, mitattu ylitys 32 px,
   * kun kortilla oli oma löysempi dvh-katto), eikä prosentti voi
   * vanhentua, koska se ratkeaa joka asettelussa uudelleen.
   */
  /*
   * Käsinpiirretty ääriviiva: epäsymmetrinen pyöristys molemmilla
   * akseleilla tekee reunasta piirretyn eikä lasketun. Sama keino kuin
   * pelin napeissa, mutta loivempi — arkki on iso, ja napin voimakas
   * kaari näyttäisi isossa koossa vinolta pahvilta.
   */
  /*
   * Reunaviiva on kartan rantaviivaa, ei katkoviivaa (omistajan
   * toive: "reuna pitäisi olla kuin maan ja meren raja kartoissa" ja
   * "vanhalta paperilehdeltä jonka reunaviiva on hieman elävä").
   *
   * Itse viiva piirretään SVG:nä (js/ui.js piirraArkinReuna), koska
   * se on ainoa tapa saada aallon korkeus pysymään samana kortin
   * koosta riippumatta. CSS:n border-image skaalaa aallon reunan
   * paksuuden mukana, ja 14 pisteen reunassa siitä jäi näkyviin alle
   * pikselin — eli suora viiva.
   *
   * Kortti itse leikataan samalla muodolla (clip-path asetetaan
   * JS:stä), joten paperin reuna ON piirretty viiva. Siksi kortilla
   * ei ole tässä omaa reunaa, pyöristystä eikä varjoa: ne piirtyisivät
   * suorakulmiona viivan alle. Varjo on omassa kerroksessaan, koska
   * clip-path leikkaisi sen pois.
   */
  border-color: transparent;
  border-radius: 0;
  /*
   * Sanomalehtipohja (omistajan päätös 5.8.2026, prototyypin
   * jälkeen): vaalea painopaperi ja suora leikattu reuna korvasivat
   * ruskean muistiinpanoarkin ja käsinpiirretyn aaltoreunan KAIKISSA
   * kaupungeissa — jokainen kaupunki saa lehden aikanaan. Kohina
   * säilyy paperin tuntuna; --card-bg:n tumma säteittäisliuku ei sovi
   * painopaperiin. Varjo on laatikon oma, koska leikkausta ei enää ole.
   */
  background-image: var(--paper-noise);
  background-color: #f5f0e2;
  background-blend-mode: multiply;
  box-shadow: 0 0 60px rgba(0, 0, 0, 0.5);
  position: relative;
  z-index: 1;
  /*
   * Väljempi marginaali kuin muissa korteissa (omistajan huomio: "liian
   * pieni marginaali reunoihin"). Arkki on nyt lähes ruudun kokoinen, ja
   * mitä isompi paperi, sitä leveämpää reunusta silmä odottaa. Lisäksi
   * reunaviiva elää ±5 pikseliä, joten kapea marginaali näyttää eri
   * levyiseltä eri kohdissa.
   */
  --arkki-reunus: 1.75rem;
  --arkki-yla: 1.7rem;
  /*
   * Mihin tarttuva osaston otsikko pysähtyy. Ei nolla: piirretty
   * paperireuna on 6 px kortin laatikon sisällä ja aaltoilee vielä
   * 5 px syvemmälle, joten nollassa otsikon viiva jäisi leikkauksen
   * ulkopuolelle. 0,85rem on syvin aallonpohja plus pieni vara.
   */
  --arkki-tarttuma: 0.85rem;
  /*
   * TARTTUVAN OTSIKON TAUSTA — TASAINEN VÄRI, EI KORTIN TAUSTAA.
   *
   * Ensimmäinen yritys antoi otsikolle saman taustan kuin kortille
   * (--paper-noise + --card-bg). Se näytti oikealta koodissa ja väärältä
   * ruudulla: --card-bg on SÄTEITTÄINEN LIUKUVÄRI, ja liukuväri
   * mitoitetaan sen elementin laatikkoon johon se maalataan. Kortissa
   * ympyrä on tuhat pikseliä leveä ja vaihtuu huomaamatta; kuudenkymmenen
   * pikselin korkuisessa otsikossa koko liuku puristuu otsikon mittaan,
   * ja tuloksena on tumma palkki jonka keskusta hohtaa.
   *
   * Mitattu omistajan kuvakaappauksesta: palkissa #ebd9b4 keskellä ja
   * #d0b686 reunassa, kun paperi sen alla on tasainen #e5d2a9. Omistaja:
   * "Miksi muutit ulkoasua, piti vain pitää ylhäällä näkyissä."
   *
   * Tilalla on tasainen pohjaväri ja SAMA paperin rakeisuus kuin
   * kortilla. Rakeisuus on 140 pikselin laatta eikä liukuväri, joten se
   * ei mitoitu elementin mukaan — se toistuu samankokoisena kaikkialla,
   * ja juuri siksi se kelpaa tähän vaikka liukuväri ei kelpaa.
   *
   * Pohjaväri ei ole valittu silmällä vaan laskettu siitä, mitä se
   * peittää: arkin yläosan paperi on mitattuna #e5d2a9, ja rakeisuus
   * tummentaa kertolaskulla noin 3,5 %, joten pohjan on oltava sitä
   * saman verran vaaleampi.
   */
  /* Sama sävy kuin arkin uusi painopaperi — tarttuvat otsikot ja
   * tarttumakaistat sulautuvat pohjaan. */
  --arkki-paperi: #f5f0e2;
  /*
   * Yläreunus EI ole kortin omaa pehmustetta vaan ensimmäisen palstan.
   * Syy on tarttuvassa aiherivissä: selaimet ovat eri mieltä siitä,
   * mihin `top: 0` pysäyttää tarttuvan elementin — Chromium sisä-
   * reunukseen, WebKit toisin. Kun yläpehmustetta ei ole, erimielisyys
   * katoaa: rivi pysähtyy paperin reunaan molemmissa.
   */
  /*
   * ALALAIDAN TURVA-ALUE MYÖS LEVEÄLLÄ RUUDULLA (omistajan havainto
   * 16.8.2026 iPadilla: "alanapit häviävät, saan ne hetkellisesti
   * näkyviin kun vedän sivua ylös sormella mutta kun vapautan sormen
   * sivu laskeutuu hieman ja napit katoavat").
   *
   * Varaus oli tähän asti vain puhelimen media queryssä (<700 px),
   * mutta kotipalkki on myös iPadissa: leveällä ruudulla kortin
   * alalaita jäi sen alle, ja napit sai näkyviin vain ylivenytyksellä.
   * env() on nolla laitteilla joilla palkkia ei ole, joten tämä ei
   * muuta mitään muualla.
   */
  padding: 0 var(--arkki-reunus) calc(1.9rem + env(safe-area-inset-bottom, 0px));
}

.dialog.arkki .arrival-palstat { padding-top: var(--arkki-yla); }

/* Aihesivuilla kaupunkipalstat ovat piilossa, ja silloin yläreunus on
 * annettava aiheelle — muuten otsikko alkaa suoraan paperin reunasta
 * (puhelimella tilapalkin alta). */
.dialog.arkki .arrival-palstat[hidden] ~ #arrival-kategoria { padding-top: var(--arkki-yla); }

@media (min-width: 700px) {
  .dialog.arkki .dialog-card {
    --arkki-reunus: 2.2rem;
    --arkki-yla: 2rem;
    /*
     * KOTIPALKIN VARA MYÖS TÄÄLLÄ (omistajan havainto 16.8.2026:
     * "vieläkin sama bugi alhaalla").
     *
     * Perussääntö sai varan jo v791:ssä, mutta tämä sääntö ylikirjoitti
     * sen pelkällä 2.2rem:llä — ja 700 px on juuri iPadin raja. Niinpä
     * korjaus päti puhelimeen muttei siihen laitteeseen, jolla vika
     * nähtiin. Arkki on tällä leveydellä koko ruudun korkuinen
     * (height: 100dvh, lehden sivu kädessä), joten alalaidan napit
     * osuivat suoraan kotipalkin alle.
     *
     * Korkeutta ei kavenneta, koska täysi korkeus on tarkoitus:
     * pehmuste on oikea paikka varata tila.
     */
    padding: 0 var(--arkki-reunus) calc(2.2rem + env(safe-area-inset-bottom, 0px));
  }
}

/*
 * Aiherivi tarttuu arkin yläreunaan.
 *
 * Omistaja aiheen vaihdosta: "parempi, mutta ei tarvitsisi vierittää
 * ollenkaan". Aiemmin napautus nosti rivin ylös vierittämällä — nyt
 * rivi on jo ylhäällä, joten napautus ei liikuta mitään. Aihe vaihtuu
 * rivin alla eikä näkymä liiku pikseliäkään.
 *
 * Rivi levenee palstan reunojen yli negatiivisella marginaalilla,
 * jottei alta vierivä teksti pilkota sivuilta. Pehmeä varjo alla
 * kertoo, että sisältö menee sen alitse.
 */
.dialog.arkki #arrival-liuskat {
  position: sticky;
  /* Kortilla ei ole yläpehmustetta, joten top: 0 pysäyttää rivin
   * tarkalleen paperin reunaan kaikissa selaimissa. */
  top: 0;
  z-index: 2;
  /*
   * Oma piirtokerros: tarttuvalla rivillä on blend-mode ja varjo,
   * jotka iOS piirtäisi muuten uudelleen joka vieritysruudulla —
   * vieritys tökki juuri tämän rivin kohdalla (omistajan havainto
   * 8.8.2026). translateZ(0) rasteroi rivin kerran ja loppu on
   * pelkkää liu'utusta.
   */
  transform: translateZ(0);
  margin-inline: calc(var(--arkki-reunus) * -1);
  padding-inline: var(--arkki-reunus);
  padding-top: 0.95rem;
  background-image: var(--paper-noise), linear-gradient(#f2e2bf, #ecdab2);
  background-blend-mode: multiply, normal;
  box-shadow: 0 7px 9px -7px rgba(70, 51, 31, 0.35);
}

/* Ulompi kiertynyt katkoviiva ei kuulu arkkiin — se oli juuri se
 * "tuollainen katkoviiva", jota omistaja ei halunnut. */
.dialog.arkki .dialog-card::before { display: none; }

/* Painomuste: ruskea muste näytti vaalealla painopaperilla haalealta,
 * joten leipäteksti ja isot otsikot tummenevat lähes mustaan — kuten
 * sanomalehdessä. Koskee vain arkkia; muu peli pitää ruskean. */
.dialog.arkki .wiki-nosto .teksti { color: #211d18; }

.dialog.arkki .wiki-kategoria .aihe-nimi,
.dialog.arkki #arrival-city { color: #16130f; }

/* Piirretyn aaltoreunan SVG-kerrokset (.arkin-varjo, .arkin-reuna)
 * poistuivat v299:ssä sanomalehtipohjan myötä — varjo on nyt kortin
 * oma box-shadow. */

@media (min-width: 700px) {
  .dialog.arkki,
  .dialog.arkki .dialog-card {
    /* Työpöydällä kartta saa näkyä leveämmältä: arkki ei kasva
     * ruudun mukana loputtomiin, koska rivi pitenisi lukukelvottomaksi.
     * Katto 960 px = sama taitto kuin isolla iPadilla (omistajan toive
     * 5.8.2026: "pitäisikö tutki-ikkuna olla kapeampi työpöydällä").
     * Yksi kanoninen lehtileveys kaikilla isoilla ruuduilla: mitä
     * testataan tabletilla, se pätee työpöydällä — leveä ruutu saa
     * lisää karttaa reunoille, ei lisää palstaa. */
    width: min(calc(100vw - 6rem), 960px);
  }

  /*
   * ANKKURIVENYTYS (18.8.2026, ks. perussäännön selostus): lehti on
   * koko turvallisen ruudun korkuinen sivu kädessä (omistajan toive
   * 5.8.2026), ja sen reunat MÄÄRITELLÄÄN reunoina eikä korkeutena.
   *
   *   ylareuna  = turva-ylä + 0.8rem
   *   alareuna  = näkyvä alareuna − turva-ala − 0.8rem
   *
   * 0.8rem on sama näkyvä rako (pehmusteen puolikas) molempiin
   * päihin kuin aiemmassa keskitysmallissa — kartta kuultaa siitä
   * sumennettuna kuten ennenkin, mutta raon koko ei enää riipu
   * yhdestäkään mitatusta korkeudesta. height: auto + margin 0
   * venyttää fixed-laatikon täsmälleen ankkureiden väliin; 100dvh:ta
   * ei käytetä, joten jumiutunut dvh ei voi liikuttaa alareunaa
   * (v784: taustapaluussa clientHeight — eli fixed-asemoinnin
   * laatikko — oli oikein, kun dvh oli väärin). Sivusuunnan
   * automarginaalit jäävät voimaan ja keskittävät arkin.
   *
   * max-height: none, koska UA:n modaalikatto (calc(100% − 6px −
   * 2em)) katkaisisi venytyksen ja margin-bottom ratkaisisi loput —
   * alareuna irtoaisi ankkuristaan.
   */
  .dialog.arkki {
    top: calc(var(--turva-yla) + 0.8rem);
    bottom: calc(var(--turva-ala) + 0.8rem);
    height: auto;
    max-height: none;
    margin-top: 0;
    margin-bottom: 0;
  }

  /* Kortti täyttää venytetyn dialogin: prosentti ratkeaa joka
   * asettelussa uudelleen eikä voi vanhentua. */
  .dialog.arkki .dialog-card {
    height: 100%;
    max-height: 100%;
  }

  /*
   * LYHYT KORTTI ON LYHYT (omistajan iPad-havainto 13.8.2026: kortin
   * *"alaosa on pelkkää tyhjää pergamenttia"*).
   *
   * Koko ruudun korkeus on LEHDEN mitta: lehtikaupungin sivu on aina
   * pidempi kuin ruutu, ja täysi korkeus tekee siitä sivun kädessä.
   * Lehdettömässä kaupungissa kortilla on vain otsikko, kuva, esittely
   * ja napit — iPadilla se on kolmasosa ruudusta, ja loput kaksi
   * kolmasosaa oli tyhjää paperia. Sisällön mittainen kortti on sama
   * paperi, vain oikean kokoisena; katto pitää pitkänkin kortin ruudulla
   * ja vieritys hoitaa lopun.
   *
   * Dialogi itse jää ruudun korkuiseksi läpinäkyväksi kehykseksi ja
   * keskittää lyhyen kortin. Ilman keskitystä kortti liimautuisi
   * yläreunaan: `position: fixed` -laatikko, jolla on sekä top että
   * bottom, venyy korkeudeltaan täyteen mittaan vaikka korkeus olisi
   * auto. Flex koskee vain korttia — sivunavigointi, lukijan kaiutin ja
   * pohjaan vievä väkänen ovat absoluuttisia. Valitsimessa on [open],
   * koska suljetun dialogin display on selaimen oma `none`.
   */
  .dialog.arkki:not(.lehti)[open] {
    display: flex;
    align-items: center;
    justify-content: center;
  }

  .dialog.arkki:not(.lehti) .dialog-card {
    height: auto;
    /* Prosentti venytetystä dialogista (= turvallinen ruutu miinus
     * raot), ei dvh:sta — sama ankkurioppi kuin lehdellä. */
    max-height: 100%;
  }
}

/*
 * OSASTON OTSIKKO KUIN SANOMALEHDESSÄ.
 *
 * Omistaja: "Kuvataide ja muut vastaavat pääotsikot saisivat olla paljon
 * isommalla, vähän kuin sanomalehdessä, voi olla joku viiva vielä otsikon
 * alla ja päällä."
 *
 * Kaksi viivaa eri paksuisina: paksu yllä, ohut alla. Se on vanhan
 * lehden osastoviiva, ja epäsymmetria on tarkoituksellinen — kaksi
 * samanpaksuista viivaa näyttäisi taulukolta, ei otsikolta.
 *
 * OTSIKKO TARTTUU YLÄREUNAAN (omistajan toive: "otsikko saisi pysyä
 * näkyvissä myös alas vierittäessä"). Pitkällä sivulla lukija ei muuten
 * enää tiedä, minkä osaston juttua lukee.
 *
 * Tarttumakohta ei ole nolla vaan --arkki-tarttuma, koska arkin
 * yläreuna EI ole kortin laatikon yläreuna: työpöydällä paperin reuna
 * on piirretty aaltoviiva (leikkaus alkaa noin 11 pikselin syvyydeltä)
 * ja puhelimessa yläreunassa on umpinainen turvakaista. Nollassa
 * otsikko jäisi kummassakin osittain piiloon.
 *
 * Ylle jäävä rako peitetään ::before-kerroksella: ilman sitä otsikon
 * yllä vilkkuisi kaistale vierivää tekstiä.
 */
.wiki-kategoria .aihe-nimi {
  position: sticky;
  top: var(--arkki-tarttuma, 0px);
  z-index: 3;
  /* Sama syy kuin #arrival-liuskat-rivillä: blend-mode tarttuvassa
   * elementissä nyki iOS:n vierityksen — oma kerros korjaa. */
  transform: translateZ(0);
  /* Yläreunuksen on oltava pehmustetta eikä marginaalia: marginaali
   * siirtäisi tarttumakohtaa alaspäin ja jättäisi raon. */
  margin: 0 0 1rem;
  padding: 0.42rem 0 0.34rem;
  background-color: var(--arkki-paperi, #eedab3);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  /* Leveys muuttujaan, koska kaistale otsikon yllä on väistettävä
   * täsmälleen tämän verran (ks. ::before alempana). */
  --osaston-viiva: 3px;
  border-top: var(--osaston-viiva) solid rgba(70, 51, 31, 0.85);
  border-bottom: 1px solid rgba(70, 51, 31, 0.55);
  font-family: var(--font-type);
  font-size: 1.45rem;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: 0.06em;
  text-align: center;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.92);
}

/*
 * Paperikaistale otsikon yllä: täyttää tarttumakohdan yläpuolisen raon,
 * jottei siinä vilkkuisi vierivää tekstiä.
 *
 * ALAREUNA ON OTSIKON LAATIKON YLÄREUNASSA, EI PEHMUSTEEN.
 *
 * `bottom: 100%` yksinään asettaa kaistaleen alareunan PEHMUSTELAATIKON
 * yläreunaan — ja reunaviiva on sen yläpuolella, laatikon ja pehmusteen
 * välissä. Kaistale peitti siis paksun osastoviivan kokonaan, ja
 * sanomalehden tuplaviivasta jäi jäljelle vain ohut alaviiva. Omistaja:
 * "Alkuperäinen tuplaviiva hävisi."
 *
 * Pseudoelementtiä ei voi laittaa viivan alle z-indeksillä: ::before
 * maalataan aina emonsa taustan JA reunan päälle samassa
 * pinoamiskontekstissa, myös negatiivisella z-indeksillä. Ainoa keino on
 * geometria — kaistale nostetaan viivan verran ylemmäs.
 *
 * Mitattu ennen korjausta: viivan kohdalla kirkkaus 201–206 eli paperia,
 * kun alaviiva luki 119.
 */
.wiki-kategoria .aihe-nimi::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + var(--osaston-viiva, 0px));
  height: calc(var(--arkki-tarttuma, 0px) + 2px);
  background-color: var(--arkki-paperi, #eedab3);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  pointer-events: none;
}

/*
 * Kuvakeliuskat mitoitetaan mahtumaan YHDELLE riville kapeimmalla
 * puhelimella (360 px). Yhdeksän liuskaa ja kahdeksan väliä on silloin
 * noin 33 pistettä liuskaa kohti, joten täyte on laskettu eikä
 * arvattu: 18 px kuvake + 2 × 4,5 px täyte + reunat.
 *
 * Tekstiliuska sai olla väljä; kuvakeliuska ei voi, koska omistajan
 * toive oli nimenomaan yksi rivi.
 */
.wiki-liuskat:has(svg) { gap: 0.15rem; }

.wiki-liuskat button svg { display: block; }

.wiki-liuskat button:has(svg) {
  padding: 0.3rem 0.28rem 0.34rem;
  min-width: 0;
}

/* Kapeimmilla puhelimilla (≤ 400 px) yhdeksän kuvaketta ei enää mahdu
 * riville v203:n leveämmillä arkkireunuksilla — kuvake ja täyte
 * kapenevat sen verran, että rivi pitää. */
@media (max-width: 400px) {
  .wiki-liuskat:has(svg) { gap: 0.12rem; }
  .wiki-liuskat button:has(svg) { padding: 0.28rem 0.2rem 0.32rem; }
  .wiki-liuskat button svg { width: 17px; height: 17px; }
}

/*
 * ── Puhelimen Tutki-arkki: koko ruutu ja paperireunus pois ────────
 *
 * Omistajan toive: "iphonella tutki ikkunan voisi levittää
 * kokonäytölle ja poistaa koko paperireunuksen."
 *
 * Koskee VAIN kapeaa ruutua. Tabletilla ja työpöydällä arkki on paperi
 * kartan päällä, ja piirretty reuna on sen idea.
 */
@media (max-width: 699px) {
  .dialog.arkki {
    width: 100vw;
    max-width: 100vw;
    /*
     * Koko ruutu ANKKURIVENYTYKSENÄ, ei 100dvh:na (18.8.2026, ks.
     * perussäännön selostus): inset 0 + height auto venyttää arkin
     * täsmälleen asetteluviewportin kokoiseksi. Jumiutunut dvh
     * teki tästä ennen joko liian lyhyen (sumea kaista ja kartta
     * kuultamassa alareunassa, v834:n oire) tai liian pitkän
     * (alanavigointi ruudun alla). Turva-alueet varataan edelleen
     * KORTIN pehmusteena, ei korkeutta kaventamalla.
     */
    inset: 0;
    margin: 0;
    height: auto;
    max-height: none;
  }

  .dialog.arkki .dialog-card {
    width: 100vw;
    max-width: 100vw;
    height: 100%;
    max-height: 100%;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    /*
     * Leikkausta ei enää tule JS:stä (aaltoreuna poistui v299:ssä),
     * mutta kumoaminen jää varmuudeksi vanhan session inline-tyylin
     * varalta.
     */
    clip-path: none !important;
    /* Kortti on koko ruutu: ilmestymisliike loisi transformin, jonka
     * sisään kiinnitetyt sivunuolet jäisivät. */
    animation: none;
    --arkki-reunus: 0.95rem;
    --arkki-yla: calc(0.85rem + env(safe-area-inset-top));
    /* Puhelimessa paperireunaa ei ole, mutta yläreunassa on umpinainen
     * turvakaista. Otsikko pysähtyy tarkalleen sen alareunaan. */
    --arkki-tarttuma: calc(env(safe-area-inset-top, 0px) + 0.55rem);
    /* Alalaidan varaus = sivunumero + kotipalkin turva-alue. */
    padding: 0 var(--arkki-reunus) calc(2.6rem + env(safe-area-inset-bottom));
  }

  /* Sama tarttuma myös DIALOGIN tasolle: ylälaidan hampurilainen on
   * dialogin (ei kortin) lapsi eikä perisi kortin muuttujaa — ilman
   * tätä nappi putosi puhelimen tilarivin päälle (omistajan kaappaus
   * 14.8.2026). */
  .dialog.arkki {
    --arkki-tarttuma: calc(env(safe-area-inset-top, 0px) + 0.55rem);
  }

  /*
   * UMPINAINEN KAISTA YLÄREUNAAN.
   *
   * Omistaja: "iPhoneilla vierittäessä yläreunan voisi muuttaa pelkäksi
   * pohjaväriksi, niin että kuvat ja teksti eivät sekoittuisi iPhonen
   * Dynamic Islandin kanssa."
   *
   * Kortti on koko ruudun kokoinen, joten vieritetty kuva kulkee suoraan
   * kellukkeen taakse. Kaista on kortin väristä paperia ja se peittää
   * turva-alueen kokonaan; sisältö katoaa sen alle siististi eikä
   * puoliksi. Kiinnitetty dialogiin eikä korttiin, jottei se vieri
   * sisällön mukana.
   */
  .dialog.arkki::before {
    content: '';
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: calc(env(safe-area-inset-top, 0px) + 0.55rem);
    /*
     * Pelkkä sumennus, ei täyttöväriä (omistajan toive 6.8.2026:
     * "saako värin vaihdettua pelkkään blurriin? siistimpi Dynamic
     * Islandin kanssa") — vanha kultainen --card-bg jäi eri sävyyn
     * kuin uusi painopaperi. Hento paperinsävy pitää kellon
     * luettavana, sumennus hoitaa loput.
     */
    background: rgba(245, 240, 226, 0.3);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    z-index: 4;
    pointer-events: none;
  }

  /* Pohjaan vievä väkänen poistui v666:ssa (omistaja 14.8.2026:
   * "Nuoli alas ja ala navigointi pois kokonaan") — ruudun ylä- ja
   * alareunan napautus vierittää päähän (ui.js kytkeTutkiSelaus). */

  /*
   * Laukku kapealla ruudulla (omistaja 18.8.2026): "iphonella
   * matkalaukku voisi olla hieman matalampi jotta karttaa näkyisi
   * enemmän. piilota myös karttanapit iphonella siksi aikaa kun
   * matkalaukku on auki jotta pelaaja näkee paremmin miten linssi
   * muuttaa karttaa." Sisältö vierii dialogissa kuten ennenkin;
   * body.laukku-auki kytketään js/ui.js openPassportissa ja puretaan
   * close-käsittelijässä.
   */
  .dialog.pillerin-alla { max-height: 72dvh; }
  body.laukku-auki .actions { display: none; }
}

/*
 * ── Tutki taitettuna lehtenä ──────────────────────────────────────
 *
 * Omistajan toive: "Tutkissivusta pitää tehdä kuin taitettu lehti. ...
 * Pelaaja voi yksinkertaisesti pyyhkäistä sivuja eteenpäin, jolloin
 * seuraavalle sivulle avautuisi aina yksi aihealue kerrallaan ja sen
 * alueen otsikko lukisi ylhäällä."
 *
 * Alalaidan sivupilleri ‹ 2/7 › (.tutki-navi) poistui v666:ssa
 * (omistaja 14.8.2026: "ala navigointi pois kokonaan") — sivut
 * vaihtuvat pyyhkäisyllä, sivun lopun alanapeilla ja
 * sisällysvalikosta.
 */

/*
 * ── LUKIJAN KAIUTIN (js/lukija.js) ───────────────────────────────
 *
 * Pieni kaiutin sivun ylälaidassa: napautus lukee sivun ääneen.
 * Ilme on sama huomaamaton mustepiirros kuin sivunumeropillerissä ja
 * matkakirjan kaiuttimessa — se ei saa kilpailla otsikon kanssa.
 *
 * Nappi on DIALOGIN lapsi eikä vierivän kortin sisällä (js/lukija.js
 * liitaLukija), joten se pysyy paikallaan kun pitkä juttu rullaa.
 */
/*
 * Valitsimissa on mukana `.dialog button`, koska dialogien yleissääntö
 * maalaa jokaisen napin pergamenttilaatikoksi aaltoreunoineen — pelkkä
 * `.lukija-nappi` häviäisi sille tarkkuudessa ja kaiuttimesta tulisi
 * iso valkoinen nappula otsikon päälle.
 */
button.lukija-nappi,
.dialog button.lukija-nappi {
  position: absolute;
  top: max(0.45rem, env(safe-area-inset-top, 0px));
  right: max(0.5rem, env(safe-area-inset-right, 0px));
  z-index: 6;
  width: 1.7rem;
  height: 1.7rem;
  min-height: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(246, 231, 198, 0.72);
  color: rgba(70, 51, 31, 0.6);
  box-shadow: none;
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease;
}

button.lukija-nappi:hover:not(:disabled),
button.lukija-nappi:focus-visible,
.dialog button.lukija-nappi:hover:not(:disabled),
.dialog button.lukija-nappi:focus-visible {
  background: rgba(246, 231, 198, 0.92);
  color: rgba(70, 51, 31, 0.95);
}

.lukija-nappi .viiva-ikoni svg { width: 1.05rem; height: 1.05rem; }

/*
 * Lehdessä kaiutin asuu tarttuvan otsikkorivin SISÄLLÄ kuten
 * hampurilainen (ui.js sijoitaLehtiKaiutin) ja keskitetään sen
 * riville — omistaja 14.8.2026: "lukita lukija napin oikeaan
 * reunaan samalle korkeudelle". Dialogiin kiinnitettynä nappi jäi
 * eri korkeudelle kuin otsikko, ja ero vaihteli lehtityypin mukaan.
 *
 * Ilme ja mitat samat kuin hampurilaisella (omistaja 14.8.2026:
 * "Kaiutinnappi saisi olla saman tyylinen ja kokoinen kuin
 * hampurilainen"): pelkkä mustepiirros ilman nappikehystä, 40 px:n
 * osuma-alue. Kuvake tarttuu napin OIKEAAN reunaan (peilikuva
 * hampurilaisen vasemmasta) — osuma-alue jatkuu vasemmalle.
 */
.wiki-kategoria .aihe-nimi > button.lukija-nappi,
.dialog #arrival-city > button.lukija-nappi {
  top: 50%;
  right: 0;
  transform: translateY(-50%);
  width: 2.1rem;
  height: 2.1rem;
  min-width: 40px;
  min-height: 40px;
  place-items: center end;
  background: none;
  box-shadow: none;
  color: #46331f;
}

/*
 * Ei ympyrää minkään tilan takana (omistajan tarkennus 15.8.2026:
 * "Poista pyöreä tausta kaiuttimen takaa"): myös luenta käynnissä
 * -tila ja osoitin näyttävät pelkän piirroksen. Luennan tilan kertoo
 * kuvakkeen meripihkainen muste — ja avoin säätöpaneeli napin alla.
 */
.wiki-kategoria .aihe-nimi > button.lukija-nappi:hover:not(:disabled),
.wiki-kategoria .aihe-nimi > button.lukija-nappi:focus-visible,
.dialog #arrival-city > button.lukija-nappi:hover:not(:disabled),
.dialog #arrival-city > button.lukija-nappi:focus-visible {
  background: none;
  color: rgba(70, 51, 31, 1);
}

.wiki-kategoria .aihe-nimi > button.lukija-nappi.lukee,
.dialog #arrival-city > button.lukija-nappi.lukee {
  background: none;
  box-shadow: none;
  color: #a8741a;
}

.wiki-kategoria .aihe-nimi > button.lukija-nappi .viiva-ikoni svg,
.dialog #arrival-city > button.lukija-nappi .viiva-ikoni svg {
  width: 24px;
  height: 24px;
}

/* Nimiö levittyy negatiivisilla marginaaleilla paperin reunaan asti —
   kaiutin tasataan sisällön oikeaan reunaan kuten hampurilainen
   vasempaan (--arkki-reunus). */
.dialog #arrival-city > button.lukija-nappi { right: var(--arkki-reunus, 0.95rem); }

/* Luenta käynnissä: kaiutin tummuu ja saa hennon kehän. Ääni ei näy
 * ruudulla, joten napin on kerrottava tilansa itse. */
button.lukija-nappi.lukee,
.dialog button.lukija-nappi.lukee {
  background: rgba(234, 184, 78, 0.34);
  color: rgba(70, 51, 31, 0.95);
  box-shadow: 0 0 0 2px rgba(70, 51, 31, 0.28);
}

/*
 * ── Luennan seuranta (omistajan tilaukset 14.8.2026) ──────────────
 *
 * Kuuluvat virkkeet maalataan kevyesti CSS Highlight -rajapinnalla
 * ("Saisiko tekstin kevyesti maalattua lause kerrallaan lukijan
 * rytmissä?"). Ilman rajapintaa koko kohta saa kevyen korostuksen
 * (.lukija-korostus). Meripihka on sama sävy kuin kaiuttimen
 * luentatilassa — yksi väri kertoo kaikkialla "tätä luetaan".
 *
 * Voimakkuus puolitettiin 18.8.2026 (omistaja): kun luenta kulkee
 * kokonaisina kappaleina, maalattu alue on virkkeen sijaan koko
 * kappale — täydellä voimalla se olisi keltainen laatta.
 */
::highlight(lukija-luenta) {
  background-color: rgba(234, 184, 78, 0.16);
}

.lukija-korostus {
  background: rgba(234, 184, 78, 0.08);
  border-radius: 2px;
}

/* Anfangin iso alkukirjain piirtyy omana ::first-letter-
 * fragmenttinaan, johon ::highlight ei osu (omistajan havainto
 * 15.8.2026: "korostus hyppää ensimmäisen kirjaimen yli") — se
 * maalataan siksi omalla säännöllään, kun soiva pala kattaa kohdan
 * alun. Tavallisessa kappaleessa sama väri kahdesti ei erotu. */
.lukija-eka-kirjain::first-letter {
  background-color: rgba(234, 184, 78, 0.16);
}

/* Sivu vierii luennan perässä kohdan alkuun; tarttuva otsikkorivi ei
 * saa jäädä kohdan päälle. */
.lukija-kohdalla { scroll-margin-top: 3rem; }

.dialog.arkki .lukija-kohdalla {
  scroll-margin-top: calc(var(--arkki-tarttuma, 0px) + 3.4rem);
}

/* ── Lukijan ohjauspaneeli (omistajan tilaus 14.8.2026) ───────────
 * Aukeaa kaiutinnapin alle luennan ajaksi: tauko/jatka, kappale
 * taakse ja eteen, kappalelaskuri ja lopetus. Sama paperinen sävy
 * kuin kaiuttimella, selvästi napakammat osumapinnat. */
/* Suorakaide, ei pilleri (omistajan tarkennus 15.8.2026: "Muuta
 * pillerisäädin äänelle suorakaiteen muotoon"). */
.lukija-paneeli {
  position: absolute;
  top: calc(max(0.45rem, env(safe-area-inset-top, 0px)) + 2rem);
  right: max(0.5rem, env(safe-area-inset-right, 0px));
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.3rem 0.45rem;
  border-radius: 0.3rem;
  background: rgba(246, 231, 198, 0.94);
  box-shadow: 0 3px 12px rgba(40, 28, 14, 0.24);
}

/* Piiloutunut soitin (automaattinen piilotus / kaiuttimen vipu) —
 * display: flex voittaisi hidden-attribuutin ilman tätä. */
.lukija-paneeli[hidden] { display: none; }

/* Lehdessä kaiutin istuu tarttuvassa otsikkorivissä, joten paneeli
 * laskeutuu otsikkorivin ALLE eikä ruudun yläkulmaan napin päälle.
 * Mitta kattaa korkeimmankin otsikon (etusivun nimiö ~3.4rem).
 * Oikea reuna samaan linjaan kaiuttimen kanssa (omistajan tarkennus
 * 15.8.2026: "tasaa oikeaan laitaan napin kanssa") — kaiutin istuu
 * sisällön oikeassa reunassa eli --arkki-reunuksen päässä paperin
 * reunasta. */
#arrival-dialog .lukija-paneeli {
  top: calc(var(--arkki-tarttuma, 0px) + 3.6rem);
  right: var(--arkki-reunus, 0.95rem);
}

.lukija-paneeli .lukija-paneeli-nappi {
  width: 2.1rem;
  height: 2.1rem;
  min-height: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: rgba(70, 51, 31, 0.82);
  box-shadow: none;
  cursor: pointer;
  transition: color 0.15s ease, background 0.15s ease;
}

.lukija-paneeli .lukija-paneeli-nappi:hover:not(:disabled),
.lukija-paneeli .lukija-paneeli-nappi:focus-visible {
  background: rgba(234, 184, 78, 0.3);
  color: rgba(70, 51, 31, 1);
}

.lukija-paneeli .viiva-ikoni svg { width: 1.2rem; height: 1.2rem; }

/* Jatkuva luenta (omistajan tilaus 15.8.2026): kytkin hehkuu samalla
 * meripihkalla kuin lukeva kaiutin, jotta päällä olo näkyy yhdellä
 * silmäyksellä. */
.lukija-paneeli .lukija-auto-nappi.aktiivinen {
  color: #a8741a;
  background: rgba(234, 184, 78, 0.24);
}

.lukija-paneeli .lukija-kappalerivi {
  min-width: 2.3rem;
  text-align: center;
  font-size: 0.74rem;
  font-variant-numeric: tabular-nums;
  color: rgba(70, 51, 31, 0.72);
  user-select: none;
}

/* ── Isoisän sitaatit visassa ja aarteessa ────────────────────────
 * Matkakirja lainaa pelkkää isoisän tarinaa (omistajan päätös
 * 8.8.2026); nimiö kertoo kehyksen, sitaatti on kursiivia kuin
 * vanha käsiala. */
.quiz-isoisa {
  margin: 0.35rem 0 0.6rem;
  padding: 0.55rem 0.75rem;
  background: rgba(90, 70, 40, 0.08);
  border-left: 2px solid rgba(70, 51, 31, 0.4);
}

.quiz-isoisa-nimio {
  margin: 0 0 0.25rem;
  font-family: var(--font-type);
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.6);
}

.quiz-isoisa-teksti {
  margin: 0;
  font-style: italic;
  line-height: 1.45;
  color: rgba(40, 30, 18, 0.92);
}

/*
 * TARKKUUS: valitsimessa on OLTAVA kaksi luokkaa. Yleissääntö
 * `.dialog p` (styles.css:5477, väri #5a4326) on tarkempi kuin paljas
 * `.reveal-isoisa`, joten tämän lohkon oma väri ei ole koskaan
 * purrut — pöllökortin pisin luettava piirtyi vaalealla
 * yleismusteella vaalean harson päälle, ja juuri se näytti
 * omistajasta epäselvältä (18.8.2026).
 */
.reveal-caption .reveal-isoisa {
  margin: 0.5rem 0 0.1rem;
  font-style: italic;
  font-size: 1rem;
  line-height: 1.5;
  max-width: 26rem;
  /* Paljastuskalvo on vaalea ja sumennettu (18.8.2026), joten pitkä
   * luettava on tummaa mustetta. HOHDE POISTETTU ja muste tummennettu
   * (omistaja 18.8.2026, pöllökortti): 5 px sumea vaalea varjo söi
   * kursiivin ohuet vedot, ja juuri tämä kappale on kortin pisin
   * luettava — se kärsi siitä eniten. */
  color: #2b1d0c;
}

.reveal-isoisa-nimio {
  display: block;
  font-family: var(--font-type);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  opacity: 0.65;
}

/* Sivunvaihdon liike: lyhyt liuku siihen suuntaan, johon selattiin. */
@keyframes tutki-sivu-vasemmalta {
  from { opacity: 0; transform: translateX(-2.2rem); }
}

@keyframes tutki-sivu-oikealta {
  from { opacity: 0; transform: translateX(2.2rem); }
}

/* Sivunkääntö pehmeästi molemmista päistä (omistajan tilaus
 * 15.8.2026: "siirtymät pehmeästi ... ease in ja out"). */
.wiki-kategoria.sivu-vasemmalta { animation: tutki-sivu-vasemmalta 0.26s ease-in-out; }
.wiki-kategoria.sivu-oikealta { animation: tutki-sivu-oikealta 0.26s ease-in-out; }

@media (prefers-reduced-motion: reduce) {
  .wiki-kategoria.sivu-vasemmalta,
  .wiki-kategoria.sivu-oikealta { animation: none; }
}

/*
 * ── KÄÄNTÖTEATTERI (js/sivunkaanto.js, omistaja 5.9.2026 "Tee 2.
 * Ensin"; Raamattu VALMIIT KIRJASTOT: STPAGEFLIP ENSIN) ──────────────
 *
 * Käännöksen ajaksi kortin päälle nostetaan kerros, jossa StPageFlip
 * kääntää kahta kortin kloonia. Kerros on dialogin lapsi kortin
 * JÄLKEEN (kloonien id:t eivät saa voittaa oikeaa korttia hauissa) ja
 * inert: kosketukset menevät sen läpi oikeaan korttiin, jonka oma
 * ele syöttää sormen paikan kirjastolle.
 *
 * Kirjaston oma tyyli (skriptin injektoima <style>) antaa
 * .stf__parentille position: relative ja transform: translateZ(0) —
 * valitsimet tässä ovat kaksiluokkaisia, jotta ne voittavat sen.
 * Kääre ei saa kirjastolta mittoja (sen CSS:ssä lukee .sft__wrapper),
 * joten kääre ja lohko täyttävät teatterin tässä.
 */
.dialog .sivunkaanto-teatteri {
  position: absolute;
  display: block;
  z-index: 20;
  overflow: hidden;
  pointer-events: none;
  transform: none;
}

.dialog .sivunkaanto-teatteri[hidden] { display: none; }

/* Taaksepäin = peilattu eteenpäin: sisältö peilataan takaisin. */
.dialog .sivunkaanto-teatteri.peilattu { transform: scaleX(-1); }
.dialog .sivunkaanto-teatteri.peilattu .sivunkaanto-sisus { transform: scaleX(-1); }

.dialog .sivunkaanto-teatteri .sivunkaanto-lohko,
.dialog .sivunkaanto-teatteri .stf__wrapper,
.dialog .sivunkaanto-teatteri .stf__block {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  min-width: 0;
  min-height: 0;
  max-width: none;
}

/*
 * Sivu: kirjasto kirjoittaa sijainnin, mitat, leikkauksen ja kierron
 * inline-tyyleinä (cssText) — tässä vain se, mitä se ei kirjoita:
 * paperin väri taitteen alle ja sisällön kääre.
 */
.sivunkaanto-sivu {
  overflow: hidden;
  background-color: var(--arkki-paperi, #f5f0e2);
  backface-visibility: hidden;
}

.sivunkaanto-sisus {
  position: absolute;
  inset: 0;
  /* Oma pinoamiskonteksti aina — myös silloin kun peilaus kumoutuu
   * (transform: none): kortin oma z-index ei saa nousta hunnun yli. */
  isolation: isolate;
}

/* Klooni täyttää sivun eikä toista kortin ilmestymisliikettä. */
.sivunkaanto-sivu .dialog-card {
  width: 100% !important;
  max-width: 100% !important;
  height: 100% !important;
  max-height: 100% !important;
  margin: 0 !important;
  animation: none !important;
  overflow-y: hidden;
}

/*
 * PAPERIN KÄÄNTÖPUOLI: kirjaston taite on sivun kopio, jonka se
 * kiertää ja leikkaa — sellaisenaan taitteessa lukisi sama teksti
 * oikein päin. Kopio saa luokan sivunkaanto-kaanto (js/sivunkaanto.js
 * vahdiKopioita): sisältö peilataan ja päälle lasketaan paperin
 * värinen huntu, jonka läpi painojälki kuultaa vaimeana ja
 * peilikuvana kuin ohuen lehtipaperin takaa. Peilatussa teatterissa
 * peilaukset kumoavat toisensa, joten siellä sisus jää suoraksi.
 *
 * HUNNUN TIIVIYS 0,88 → 0,95 (omistaja 5.9.2026 klo 19.50, sanatarkasti:
 * "Voi kuultaa mutta kääntöpuolella on liian iso kontrasti tumman ja
 * vaalean välillä jolloin paperi näyttää kiiltävältä"): kuultava
 * painojälki jää, mutta tumman ja vaalean ero painuu paperin sävyyn.
 */
.sivunkaanto-huntu {
  position: absolute;
  inset: 0;
  display: none;
  background-color: var(--arkki-paperi, #f5f0e2);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  opacity: 0.95;
  pointer-events: none;
  z-index: 2;
}

.sivunkaanto-kaanto .sivunkaanto-huntu { display: block; }
.sivunkaanto-kaanto .sivunkaanto-sisus { transform: scaleX(-1); }
.dialog .sivunkaanto-teatteri.peilattu .sivunkaanto-kaanto .sivunkaanto-sisus { transform: none; }


/*
 * ============================================================
 * LEHTITAITTO (omistajan toive 5.8.2026)
 *
 * Kaupungeilla, joilla on oma kansiosio (aihe id 'kaupunki',
 * pilottina Venetsia), Tutki-ikkunan etusivu taittuu paikallis-
 * lehdeksi: masto (pieni nimirivi, kaupungin nimi isolla,
 * päiväysrivi viivojen välissä), kaupungin oma osuus nostoineen
 * ja sen alla maa omana osastonaan. Muut kaupungit näyttävät
 * etusivun entiseen tapaan — nämä säännöt elävät vain
 * .dialog.lehti-luokan alla.
 * ============================================================
 */

/* Palstat allekkain: lehti luetaan ylhäältä alas, ei rinnakkain. */
.dialog.lehti .arrival-palstat { display: block; }

/*
 * PALSTAT LÄPINÄKYVIKSI ASETTELULLE (omistaja 14.8.2026): tarttuva
 * nimiö voi tarttua vain vanhempansa laatikon sisällä, ja
 * kaupunkilehden etusivulla radiorivi ja kohdekartta asuvat palstojen
 * ULKOPUOLELLA — palsta loppui kesken ja otsikko "vetäytyi ylös" heti
 * kun radiorivi ilmestyi. display: contents nostaa nimiön suoraan
 * vierivän kortin lapseksi, jolloin tarttuma kattaa koko sivun.
 * Rajaus :not([hidden]):lla: [hidden]-piilotus (display: none
 * !important) ei saa kumoutua. Vain lehtitaitto — perinteinen
 * saapumiskortti pitää palstansa.
 */
.dialog.lehti .arrival-palstat:not([hidden]),
.dialog.lehti .arrival-palstat:not([hidden]) > .arrival-palsta {
  display: contents;
}

/* display: contents pudottaa palstojen padding-topin (--arkki-yla) —
 * sama hengitystila annetaan ensimmäiselle riville (lehtitaitossa
 * masto on aina näkyvissä, ks. arrivalLehtiYla). */
.dialog.lehti .arrival-palstat:not([hidden]) > .arrival-palsta > :first-child {
  margin-top: var(--arkki-yla);
}

.lehti-ylarivi {
  margin: 0 0 0.1rem;
  font-family: var(--font-type);
  font-size: 0.6rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(70, 51, 31, 0.7);
}

/*
 * Nimiö on AINA keskitetty (omistajan ohje 8.8.2026: "Unohdettu
 * aarre pitäisi olla keskitetty"). Aiempi ratkaisu siirsi nimiön
 * kapealla ruudulla vasemmalle, koska keskitettynä se meni maaosion
 * kulmalinkin päälle — nyt törmäys puretaan toisin päin: kapealla
 * ruudulla kulmalinkki putoaa absoluuttisesta kulmasta omaksi
 * oikealle tasatuksi rivikseen nimiön ylle (DOM-järjestys), jolloin
 * kumpikaan ei väisty eikä mikään mene päällekkäin.
 */

/* Lehden nimiö: kaupungin nimi isolla antiikvalla keskitettynä. */
.dialog.lehti #arrival-city {
  margin: 0;
  text-align: center;
  font-size: clamp(1.9rem, 7.5vw, 2.8rem);
  line-height: 1.05;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/*
 * ── NIMIÖ TARTTUU YLÄREUNAAN (omistaja 14.8.2026) ───────────────────
 *
 * "Yläotsikko saisi jäädä yläreunaan näkyviin vieritettäessä, mutta
 * unohdettu aarre ja muut saisi jäädä piiloon." Vain iso nimi tarttuu:
 * kicker-rivi ja päiväysrivi vierivät sen alle. Sama sääntö kattaa
 * myös maalehden etusivun otsikon (sama #arrival-city-elementti).
 *
 * Tekniikka on sama kuin aihesivujen otsikolla (.aihe-nimi): tarttuma
 * --arkki-tarttumaan (paperin piirretty reuna / puhelimen turvakaista),
 * oma piirtokerros translateZ:llä (iOS:n vieritys nyki blend-modea)
 * ja paperitausta, jottei alta vierivä teksti kuulla läpi. Sivuun
 * levitys negatiivisella marginaalilla peittää palstan reunat.
 */
.dialog.arkki #arrival-city {
  position: sticky;
  top: var(--arkki-tarttuma, 0px);
  z-index: 3;
  transform: translateZ(0);
  margin-inline: calc(var(--arkki-reunus) * -1);
  padding: 0.28rem var(--arkki-reunus) 0.3rem;
  background-color: var(--arkki-paperi, #f5f0e2);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
}

/*
 * PAPERIKAISTA NIMIÖN YLLE LEVEILLÄ RUUDUILLA (omistaja 14.8.2026):
 * iPadilla tarttuvan otsikon yläpuolelle jää --arkki-tarttuman
 * korkuinen rako, jossa vierivä teksti näkyi terävänä. Kaista asuu
 * kortin SISÄLLÄ tarttuvana ensimmäisenä laatikkona: se pysyy
 * vieritysalueen yläreunassa ja peittää raon SAMALLA paperilla kuin
 * otsikon tausta (omistajan tarkennus 14.8.2026: "sumennuksen voi
 * poistaa ja vaihtaa vain sen pienen palan yläreunasta saman
 * väriseksi taustaksi kuin otsikon takana" — ensin kokeiltu sumennus
 * poistui). Negatiivinen alamarginaali kumoaa kaistan flow'ssa
 * viemän tilan; ::before on vapaa, koska arkki piilottaa kortin
 * kiertyneen reunaviivan (ks. "display: none" -sääntö ylempänä).
 * Puhelin pitää oman koko ruudun sumennuskaistansa
 * (.dialog.arkki::before media-lohkossa, Dynamic Island -päätös
 * 6.8.2026).
 */
@media (min-width: 700px) {
  .dialog.arkki .dialog-card::before {
    content: '';
    display: block;
    position: sticky;
    inset: auto;
    top: 0;
    z-index: 4;
    height: var(--arkki-tarttuma);
    margin: 0 calc(var(--arkki-reunus) * -1) calc(var(--arkki-tarttuma) * -1);
    border: 0;
    border-radius: 0;
    transform: none;
    background-color: var(--arkki-paperi, #f5f0e2);
    background-image: var(--paper-noise);
    background-blend-mode: multiply;
    pointer-events: none;
  }
}

/*
 * ── YLÄLAIDAN HAMPURILAINEN (omistaja 14.8.2026) ────────────────────
 *
 * Pysyvä valikkonappi lehden vasemmassa yläkulmassa. Nappi asuu
 * tarttuvan nimiön (#arrival-city) SISÄLLÄ ja keskitetään sen
 * riville: näin se on täsmälleen otsikon korkeudella ja otsikon ylä-
 * ja alaviivan sisäpuolella myös silloin, kun otsikko liikkuu
 * tarttumisen ääripäissä (omistajan tarkennus 14.8.2026 — dialogiin
 * kiinnitettynä nappi jäi väärälle korkeudelle). Siitä sisällys
 * aukeaa yläreunaan; maalehden alapalkin hampurilainen jää ennalleen.
 */
/*
 * Pelkät kolme viivaa ilman nappikehystä (omistajan tarkennus
 * 14.8.2026: "se voi olla kokonaan ilman ympäröivää nappia. Riittää,
 * että on vain se kolme viivaa") — osuma-alue on silti täydet 40 px,
 * kehys vain ei piirry.
 */
/* Valitsimessa on .dialog button mukana, koska dialogin yleinen
   nappisääntö (piirretty kehys ja vaalea pohja) voittaisi muuten
   pelkän luokan — kuvakkeen ympärille piirtyi laatikko (omistajan
   kaappaus 14.8.2026). */
.dialog button.lehti-hampurilainen {
  position: absolute;
  top: 50%;
  left: 0;
  transform: translateY(-50%);
  /* Nimiön oman pinon päällimmäiseksi (avattu sisällyslevy peittää
     napin — ulkopuolinen napautus sulkee levyn, ks. ui.js). */
  z-index: 1;
  width: 2.1rem;
  height: 2.1rem;
  min-width: 40px;
  min-height: 40px;
  display: grid;
  /* Viivat alkavat napin VASEMMASTA reunasta, eivät keskeltä:
     kuvakkeen on alettava täsmälleen samasta kohdasta kuin tekstin
     ja kuvien (omistajan tarkennus 14.8.2026) — osuma-alue jatkuu
     oikealle. Aihe-nimi alkaa valmiiksi sisällön reunasta (left 0);
     nimiö levittyy paperin reunaan asti, joten sille oma siirto. */
  place-items: center start;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: none;
  box-shadow: none;
  color: #46331f;
  cursor: pointer;
}

.lehti-hampurilainen svg {
  width: 24px;
  height: 24px;
}

/* Nimiö ulottuu negatiivisilla marginaaleilla paperin reunaan asti —
   sisällön vasen reuna on sen laatikossa --arkki-reunuksen kohdalla. */
#arrival-city > .lehti-hampurilainen { left: var(--arkki-reunus, 0.95rem); }

.lehti-hampurilainen[hidden] { display: none; }

.lehti-hampurilainen svg { display: block; }

/* Ylhäältä avattu sisällys laskeutuu yläreunaan (omistaja 14.8.2026);
   alhaalta avattu nousee kuten ennenkin. */
.sisallys-levy.ylhaalla {
  inset: 0 0 auto 0;
  border-top: 0;
  border-bottom: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 0 0 0.7rem 0.7rem;
  box-shadow: 0 0.6rem 1.4rem rgba(28, 20, 12, 0.28);
  /* Puhelimen turvakaista ei saa peittää otsikkoriviä. Hampurilainen
     jää levyn ALLE (nappi asuu nykyään nimiön sisällä kortissa) —
     sulku hoituu napauttamalla levyn ulkopuolelta. */
  padding-top: calc(var(--arkki-tarttuma, 0px) + 0.6rem);
  animation: sisallys-laskeutuu 180ms ease-out;
}

@keyframes sisallys-laskeutuu {
  from { transform: translateY(-100%); }
  to { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .sisallys-levy.ylhaalla { animation: none; }
}

/* Päiväysrivi tuplaviivan ja ohuen viivan välissä kuin sanomalehdessä. */
.lehti-alarivi {
  /* Ankkuri liitelinkille, joka tasataan rivin oikeaan reunaan. */
  position: relative;
  margin: 0.35rem 0 0.85rem;
  padding: 0.24rem 0;
  border-top: 3px double rgba(70, 51, 31, 0.75);
  border-bottom: 1px solid rgba(70, 51, 31, 0.5);
  font-family: var(--font-type);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(70, 51, 31, 0.85);
}

/*
 * Lehden etusivun kuvataitto: iso pääkuva maston alla, pienempien
 * kuvien pari esittelyn jälkeen. Kuvatekstit pienellä konekirjaimella
 * ja lähde vielä hillitymmin sen perässä.
 */
.lehti-paakuva { margin: 0.1rem 0 0.7rem; }

.lehti-kuvarivi {
  clear: both;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
  margin: 0.9rem 0 0.4rem;
}

.lehti-kuva { margin: 0; }

.lehti-kuva img {
  display: block;
  width: 100%;
  border: 3px solid #f7efdc;
  outline: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 2px;
  cursor: zoom-in;
}

/* Pääkuva saa olla iso mutta ei ruudun korkuinen; parin kuvat
 * rajataan samaan suhteeseen, jotta rivi pysyy tasakorkuisena. */
.lehti-paakuva .lehti-kuva img { max-height: 360px; object-fit: cover; }

/* Avauskuvakaruselli etusivun isossa kuvapaikassa (omistajan linjaus
 * 22.8.2026): kuvapaikka on herokuvien 3:2-suhteessa, joten generoitu
 * hero (1536×1024) täyttää sen tarkalleen ja näkyy RAJAAMATTOMANA.
 * Tätä leveämmät kuvat (panoraamat) rajautuvat sivuilta ja korkeammat
 * ylä- ja alareunasta, jolloin karusellin kaikki diat ovat saman
 * kokoisia eikä laatikko hypi kuvaa vaihdettaessa. Kokoruudun
 * suurennostila näyttää kuvan edelleen oikeassa koossaan.
 * (Korvaa 15.8.2026 linjauksen "panoraama saa olla pääkuvaa korkeampi
 * muttei viedä koko ruutua, katto 430 px".)
 * Kuvasuhde annetaan KUVALLE eikä kehykselle, koska kehys on figure,
 * jonka sisällä on kuvaikkunan lisäksi figcaption (selite ja lähde) —
 * kehyksen pakottaminen 3:2:een leikkaisi selitteen.
 * Kehyksen 300 px:n katto kuuluu nähtävyysikkunaan, EI etusivulle
 * (omistajan havainto 15.8.2026: "galleria etusivulla on väärän
 * kokoinen" — karuselli kutistui palstaa kapeammaksi). */
.lehti-paakuva .nahtavyys-kuvakehys {
  width: 100%;
  max-width: none;
  margin: 0 0 0.6rem;
}

.lehti-paakuva .nahtavyys-kuva {
  width: 100%;
  height: auto;
  max-height: none;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

.lehti-kuvarivi .lehti-kuva img { aspect-ratio: 4 / 3; object-fit: cover; }

.lehti-kuva .kuvateksti {
  margin: 0.3rem 0 0;
  font-family: var(--font-type);
  font-size: 0.78rem;
  line-height: 1.4;
  color: rgba(70, 51, 31, 0.85);
}

.lehti-kuvalahde {
  font-size: 0.62rem;
  color: rgba(70, 51, 31, 0.55);
}

/* ------------------------------------------------------------------ *
 * LÄHDERIVI KUVATEKSTIN JATKEEKSI (omistajan tilaus 23.8.2026,
 * kuvakaappaus Jerusalemin lehdestä)
 *
 * Lähderivi — "Matkakirjan havainnekuva", "Canaletto, Wikimedia
 * Commons (PD)" — oli oma kappaleensa kuvatekstin alla ja vei kuvan
 * alta oman rivinsä, vaikka se on lisenssimerkintä eikä juttua. Nyt se
 * juoksee kuvatekstin perässä SAMALLA RIVILLÄ ja entistä pienemmällä:
 * silmä lukee kuvatekstin loppuun ja ohittaa krediitin, mutta
 * krediitti on yhä näkyvissä niin kuin lisenssi vaatii.
 *
 * TOTEUTUS ON PÄÄOSIN CSS:SSÄ, koska DOM-rakenne vaihtelee kohteittain
 * (figcaption + kaksi spania, kuvakehys + kaksi p:tä). Kuvatekstin emo
 * palautetaan tavalliseksi lohkoksi — osa oli flex-pylväitä, ja
 * flex-lapsi on aina omalla rivillään riippumatta display-arvostaan —
 * ja molemmat osat asetetaan inline-virtaan. Rivitys hoituu silloin
 * itsestään: kun pari ei mahdu yhdelle riville, lähde jatkaa tekstin
 * tavoin seuraavalle eikä jää orvoksi omalle rivilleen.
 *
 * VÄLILYÖNTI TULEE ::before-SISÄLLÖSTÄ eikä DOM:ista. Osa lähderiveistä
 * kirjoitetaan uudestaan joka kuvanvaihdossa (js/tekijakortti.js
 * taytaLahderivi tyhjentää elementin), joten DOM:iin ujutettu
 * välilyönti katoaisi ensimmäisestä nuolenpainalluksesta. Tavallinen
 * välilyönti on samalla se rivinvaihtokohta, jota inline-virtaus
 * tarvitsee — ilman sitä selain pitäisi kuvatekstin viimeistä sanaa ja
 * lähteen ensimmäistä yhtenä katkeamattomana pötkönä.
 *
 * LUENTA EI MUUTU: sekä kuvateksti- että lähdeluokat ovat jo
 * LUKIJAN_OHITETTAVAT-listassa (js/lukija.js), ja ohitus koskee koko
 * alipuuta — lähteen siirtyminen kuvatekstin sisään ei tuo sitä
 * luentaan, eikä yksikään lähde päädy leipätekstielementin sisään.
 * ------------------------------------------------------------------ */
.lehti-kuvalahde::before,
.nahtavyys-lahde::before,
.lightbox-lahde::before,
.kuvateksti .kuvalahde::before,
.vinkki-hero .lahde::before { content: ' '; }
/* Aihesivun kainalokuvasta välilyönti ei kuulu tähän listaan enää
 * (23.8.2026): kuvateksti on poistettu, ja lähderivi on siellä yksin
 * omalla rivillään — ei mitään, minkä perään se jatkaisi. */

/* Postikortin ja suurennoksen lähde on nyt kuvatekstin sisällä
 * (js/ui.js): inline-virtaan ja kortin omaa lähdekokoa pienemmäksi. */
.kuvateksti .kuvalahde {
  display: inline;
  margin: 0;
  font-size: 0.56rem;
}

/*
 * ENNEN JA NYT -PARI etusivun pikkurivillä (omistajan idea 21.8.2026):
 * vasemmalla vanha vedos, oikealla sama kaupunki nykyään. Harmaasävy
 * on sama kuin matkakirjan postikortissa, ja rooliotsikko erottaa
 * parin muusta kuvarivistä ilman omaa palkkia.
 */
.lehti-kuva img.vanha-vedos { filter: grayscale(1) contrast(1.03); }

.lehti-kuva-rooli {
  font-family: var(--font-type);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.95);
}

/* Esittely on lehden pääjuttu: hieman leipätekstiä isompi. */
.dialog.lehti #arrival-intro {
  font-size: 1rem;
  line-height: 1.6;
}

/* Maa on lehden oma osasto: tuplaviiva erottaa, nimi osastonotsikkona. */
.dialog.lehti .arrival-maa {
  border-left: 0;
  padding-left: 0;
  margin-top: 1.2rem;
  border-top: 3px double rgba(70, 51, 31, 0.75);
  padding-top: 0.55rem;
}

.dialog.lehti .arrival-maa-rivi {
  justify-content: center;
  border-bottom: 1px solid rgba(70, 51, 31, 0.45);
  padding-bottom: 0.4rem;
  margin-bottom: 0.55rem;
}

.dialog.lehti .arrival-maa-nimi {
  font-size: 1.35rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/*
 * Alareunan napit lehtimäisiksi: tasalevyiset kehysruudut tuplaviivan
 * alla, kuin etusivun ilmoituspalsta. Uudet nimet ja tarinallinen
 * kohtaaminen tulevat omassa erässään — tämä on taiton osuus.
 */
.dialog.lehti .arrival-card .dialog-actions {
  border-top: 3px double rgba(70, 51, 31, 0.55);
  gap: 0.7rem;
}

.dialog.lehti .arrival-card .dialog-actions button {
  flex: 1 1 0;
  margin: 0;
  padding: 0.62rem 0.4rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  border-radius: 3px;
}

/*
 * Kohtaamisnappi houkuttelevaksi (omistajan toive 5.8.2026): täytetty
 * lämmin kulta erottaa päätehtävän selvästi Jatka matkaa -napista,
 * joka jää kehysnapiksi.
 */
.dialog.lehti .arrival-card .dialog-actions button.primary {
  background: linear-gradient(180deg, #e8b654, #d49a34);
  border: 1.5px solid #8a6118;
  color: #2d1f08;
  font-weight: 700;
  text-shadow: 0 1px 0 rgba(255, 235, 190, 0.5);
  box-shadow: 0 2px 6px rgba(70, 51, 31, 0.3);
}

.dialog.lehti .arrival-card .dialog-actions button.primary:hover:not(:disabled) {
  background: linear-gradient(180deg, #f0c268, #dda63f);
}

/*
 * Teosgalleria noston kuvan ympärillä (pilottina Venetsian Canaletto):
 * kotelo perii saapumiskuvan nuolet ja laskurin. Kotelo ottaa kuvan
 * paikan taitossa — myös kellutuksen leveällä ruudulla — ja kuva
 * istuu kotelossa ilman omaa marginaalia, jotta nuolet ja laskuri
 * pysyvät tarkalleen kuvan päällä.
 */
.wiki-nosto .nosto-galleria {
  margin: 0.15rem auto 0.5rem;
  /* Teosta vaihdettaessa uusi kuva latautuu hetken: ilman
   * vähimmäiskorkeutta kotelo lysähtäisi nuolineen kasaan ja sivu
   * hyppisi. */
  min-height: 140px;
}

.wiki-nosto .nosto-galleria img { margin: 0; }

/* Gallerian kelluntasäännöt (≥ 1000 px) poistuivat v300:ssa
 * palstataiton myötä: kotelo keskittyy perussäännöillään kuten
 * tavallinen nostokuva, ja kuva mitoittuu omilla ehdoillaan. */

/*
 * LEHDEN TEHTÄVÄLAATIKKO: minitehtävä (aihesivut) ja kulttuurivisa
 * (kaupunkisivu) samasta muotista.
 *
 * Omistajan palaute 21.8.2026 Rooman kakkossivusta: laatikko "istuu
 * tyylillisesti vähän huonosti lehteen. saa erottua, mutta saatko
 * tehtyä paremman tyylisen kaikin puolin?" Vanha visalaatikko oli
 * kirkas keltainen liukuväri pyörein kulmin ja valkoisin
 * pillerinapein — verkkolomake keskellä 1870-luvun sanomalehteä — ja
 * minitehtävällä oli oma katkoviivakehyksensä, eli sama tehtävä
 * kahdessa eri asussa.
 *
 * Nyt molemmat ladotaan lehden omilla keinoilla: tuplaviivakehys kuin
 * ilmoituspalstassa, harvennettu kapiteeliotsake oman viivansa
 * päällä, paperin oma sävy ja vastaukset äänestyslipukkeen riveinä
 * ruutuineen. Erottuminen tulee kehyksestä, otsakkeesta ja tyhjästä
 * tilasta — ei väristä, joka veisi laatikon eri painotuotteeseen kuin
 * sivun muu sisältö.
 */
.minitehtava,
.dialog.lehti .arrival-kulttuuri {
  clear: both;
  /* Reunus on muuttuja, koska otsakkeen ja vastausrivien viivat
   * vedetään kehyksestä kehykseen: ne kumoavat tämän saman mitan
   * negatiivisella marginaalilla. */
  --tehtava-reunus: 1.05rem;
  margin: 1.5rem 0 0.5rem;
  padding: 0.85rem var(--tehtava-reunus) 0.9rem;
  border: 3px double rgba(60, 44, 26, 0.6);
  border-radius: 0;
  /* Paperin oma sävy hitusen tummempana: laatikko on painettu samalle
   * arkille, ei liimattu sen päälle. */
  background: rgba(214, 190, 140, 0.22);
  box-shadow: none;
}

/*
 * Kapiteeliotsake. Minitehtävällä on oma elementtinsä (ui.js
 * piirraMinitehtava), visan otsake taas ladotaan viivaksi laatikon
 * yläreunaan: visan ainoa teksti tulee JS:stä kysymyksenä, eikä
 * pelilogiikkaan koskettu. Otsake kiinnittyy nimenomaan visalohkoon
 * eikä koko laatikkoon, jotta se katoaa lohkon mukana — kaupungilla
 * voi olla kulttuuriosa ilman kysymystä (ui.js naytaKulttuuri).
 */
.dialog .minitehtava .minitehtava-otsikko,
.dialog.lehti .arrival-kulttuuri #arrival-kulttuuri-visa::before {
  display: block;
  margin: 0 calc(-1 * var(--tehtava-reunus)) 0.55rem;
  padding: 0 var(--tehtava-reunus) 0.32rem;
  border-bottom: 1px solid rgba(60, 44, 26, 0.35);
  font-family: var(--font-type);
  font-size: 0.66rem;
  font-weight: 700;
  /* Harvennus jättää viimeisen kirjaimen perään ylimääräisen välin,
   * joka työntäisi keskitetyn rivin vasemmalle — sisennys kumoaa sen. */
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  text-align: center;
  text-transform: uppercase;
  color: rgba(60, 44, 26, 0.78);
}

.dialog.lehti .arrival-kulttuuri #arrival-kulttuuri-visa::before {
  content: 'Lehden kysymys';
}

/* Kysymys on laatikon otsikko ja se ladotaan lehden lukukirjasimella:
 * kirjoituskonefontti teki siitä lomakkeen kentän. Valitsin on kaksi
 * luokkaa pitkä, koska `.dialog p` värittäisi muuten kysymyksen
 * haaleaksi ruskeaksi. */
.dialog .minitehtava .minitehtava-kysymys,
.dialog.lehti .arrival-kulttuuri .kulttuuri-otsikko {
  margin: 0 0 0.5rem;
  font-family: var(--font-luku);
  font-size: 1.02rem;
  font-weight: 600;
  line-height: 1.45;
  color: #211d18;
}

/* Ratkaistun tehtävän kuittaus on ilmoitus eikä kysymys: se jää
 * laatikon viimeiseksi riviksi (ui.js piirraMinitehtava). */
.dialog .minitehtava .minitehtava-kysymys:last-child {
  margin-bottom: 0;
  font-weight: 400;
  font-style: italic;
}

/* Vastaukset äänestyslipukkeen riveinä: viivoitettu luettelo, jossa
 * jokaisella rivillä on oma rastiruutunsa. Viivat kuuluvat riveille
 * eivätkä luettelolle: vastattaessa rivit poistetaan (ui.js), ja
 * luettelon oma viiva jäisi roikkumaan tyhjänä palkkina. */
.minitehtava .kulttuuri-vaihtoehdot,
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 0;
  margin: 0.5rem calc(-1 * var(--tehtava-reunus)) 0;
}

.dialog .minitehtava .kulttuuri-vaihtoehdot button,
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  /* Kosketuskoko säilyy, vaikka rivi on litteä eikä nappi. */
  min-height: 44px;
  margin: 0;
  padding: 0.5rem var(--tehtava-reunus);
  border: 0;
  border-top: 1px solid rgba(60, 44, 26, 0.28);
  border-radius: 0;
  background: none;
  box-shadow: none;
  font-family: var(--font-luku);
  /* Perusvahvuus: lihavointi kuuluu kysymykselle, vaihtoehdot ovat
   * luetteloa. */
  font-weight: 400;
  font-size: 0.98rem;
  line-height: 1.35;
  text-align: left;
  color: #211d18;
}

/*
 * Lunasta juliste -nappi oikean vastauksen alle (omistajan tilaus
 * 22.8.2026): juliste ei enää aukea itsestään faktarivin päälle, vaan
 * pelaaja avaa sen luettuaan. Nappi on tehtävälaatikon ainoa
 * painikkeen näköinen painike, joten se saa erottua vaihtoehtoriveistä:
 * täysi leveys, musterajaus ja paperia vaaleampi pohja.
 */
.dialog .minitehtava .minitehtava-lunastus {
  display: block;
  width: 100%;
  min-height: 44px;
  margin-top: 0.5rem;
  padding: 0.5rem var(--tehtava-reunus);
  border: 1px solid rgba(60, 44, 26, 0.65);
  border-radius: 4px;
  background: rgba(255, 253, 245, 0.9);
  font-family: var(--font-luku);
  font-weight: 700;
  font-size: 0.98rem;
  color: #211d18;
  cursor: pointer;
}

.dialog .minitehtava .minitehtava-lunastus:hover,
.dialog .minitehtava .minitehtava-lunastus:focus-visible {
  background: #fffdf5;
  color: #16130f;
}

/* Rastiruutu rivin edessä kertoo, että riviltä valitaan yksi. */
.dialog .minitehtava .kulttuuri-vaihtoehdot button::before,
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button::before {
  content: '';
  flex: 0 0 auto;
  width: 0.8em;
  height: 0.8em;
  border: 1px solid rgba(60, 44, 26, 0.65);
  background: none;
}

.dialog .minitehtava .kulttuuri-vaihtoehdot button:hover:not(:disabled),
.dialog .minitehtava .kulttuuri-vaihtoehdot button:focus-visible,
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button:hover:not(:disabled),
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button:focus-visible {
  background: rgba(255, 253, 245, 0.9);
  color: #16130f;
}

/* Osoittimen alla ruutu täyttyy musteella — rivi on juuri rastittumassa. */
.dialog .minitehtava .kulttuuri-vaihtoehdot button:hover:not(:disabled)::before,
.dialog .minitehtava .kulttuuri-vaihtoehdot button:focus-visible::before,
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button:hover:not(:disabled)::before,
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button:focus-visible::before {
  border-color: rgba(60, 44, 26, 0.9);
  background: rgba(60, 44, 26, 0.85);
  box-shadow: inset 0 0 0 2px rgba(245, 240, 226, 0.95);
}

.dialog .minitehtava .kulttuuri-vaihtoehdot button:active:not(:disabled),
.dialog.lehti .arrival-kulttuuri .kulttuuri-vaihtoehdot button:active:not(:disabled) {
  background: rgba(214, 190, 140, 0.35);
}

/*
 * Palaute: painettu huomautus laatikon pohjalla, ei pyöreä ruutu.
 * Perustila (esim. "jo vastattu") on mustetta; oikea vastaus saa
 * vihreän — myös väärin menneen vastauksen palaute KERTOO oikean
 * vastauksen, joten sekin on vihreä mutta ohuempana (linjaus
 * 5.8.2026: punainen pohja näytti virheilmoitukselta).
 */
.minitehtava .kulttuuri-tulos,
.dialog.lehti .arrival-kulttuuri .kulttuuri-tulos {
  margin: 0.7rem 0 0;
  padding: 0.5rem 0.7rem;
  border: 0;
  border-left: 4px solid rgba(60, 44, 26, 0.55);
  border-radius: 0;
  background: rgba(60, 44, 26, 0.07);
  font-family: var(--font-luku);
  font-size: 0.95rem;
  line-height: 1.5;
  color: #211d18;
}

.minitehtava .kulttuuri-tulos.oikein-tulos,
.dialog.lehti .arrival-kulttuuri .kulttuuri-tulos.oikein-tulos {
  border-left-color: rgba(74, 124, 58, 0.9);
  background: rgba(106, 158, 84, 0.2);
}

.minitehtava .kulttuuri-tulos.vaarin-tulos,
.dialog.lehti .arrival-kulttuuri .kulttuuri-tulos.vaarin-tulos {
  border-left: 4px double rgba(74, 124, 58, 0.85);
  background: rgba(106, 158, 84, 0.1);
}

/*
 * PALKINTOJULISTE tehtävälaatikon kyljessä (omistajan tilaus
 * 21.8.2026: "juliste voisi näkyä jo pienenä kysymysten vierellä ja
 * aueta isommaksi sitten kun tulee oikea vastaus").
 *
 * Vedos ladotaan kuin lehden ilmoituskuva: se kelluu oikealle ja
 * teksti kiertää sen, mustesuikale kehyksenä ja harvennettu
 * kapiteelimerkintä alla. Väriä ei ole — laatikko on samaa painotyötä
 * kuin sivun muu sisältö, ja itse juliste on ainoa värillinen asia.
 *
 * Voittamaton vedos on haalistettu ja hieman epätarkka: pelaaja näkee
 * mistä pelataan muttei julisteen yksityiskohtia. Voitettu kirkastuu,
 * saa musteisen kehyksen ja on napautettava (js/ui.js
 * piirraJulistepalkinto).
 */
/*
 * Palkinnollinen laatikko ladotaan kahteen palstaan: vasemmalla
 * kysymys ja vastausrivit, oikeassa kapeassa palstassa juliste.
 * Kellutus olisi ollut yksinkertaisempi, mutta vastausrivit ovat
 * täysleveitä lipukkeita — ne olisivat menneet vedoksen ALTA, ja
 * kellunnan tyhjennys jätti laatikkoon ammottavan aukon (mitattu
 * 21.8.2026 Istanbulin kakkossivulla). Otsake pysyy koko laatikon
 * levyisenä, ja vedos ulottuu kysymyksestä palautteeseen.
 */
.minitehtava.minitehtava-palkinnollinen {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  column-gap: 0.9rem;
  align-items: start;
}

.minitehtava-palkinnollinen > .minitehtava-otsikko { grid-column: 1 / -1; }

.minitehtava-palkinnollinen > .minitehtava-kysymys,
.minitehtava-palkinnollinen > .kulttuuri-vaihtoehdot,
.minitehtava-palkinnollinen > .kulttuuri-tulos { grid-column: 1; }

/* Vastausrivit ylsivät kehyksestä kehykseen; palkintopalstan puolella
 * ne pysähtyvät palstan reunaan, jottei rivi kulje julisteen alta. */
.minitehtava-palkinnollinen > .kulttuuri-vaihtoehdot { margin-right: 0; }

.minitehtava .juliste-palkinto {
  grid-column: 2;
  /* Kysymyksestä palautteeseen: vedos on koko tehtävän palkinto,
   * ei yhden rivin kuvitus. */
  grid-row: 2 / span 3;
  width: 132px;
  margin: 0.1rem 0 0.6rem;
  text-align: center;
}

.minitehtava .juliste-palkinto img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(60, 44, 26, 0.55);
  /* Vedoksen oma varjo: juliste on painettu erikseen ja liimattu
   * sivulle, toisin kuin tehtävälaatikko itse. */
  box-shadow: 1px 2px 0 rgba(60, 44, 26, 0.18);
  opacity: 0.5;
  filter: grayscale(0.55);
  transition: opacity 260ms ease, filter 260ms ease;
}

.minitehtava .juliste-palkinto.voitettu img {
  opacity: 1;
  filter: none;
  border-color: rgba(60, 44, 26, 0.8);
  cursor: zoom-in;
}

.minitehtava .juliste-palkinto .juliste-merkki {
  margin: 0.3rem 0 0;
  font-family: var(--font-type);
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.24em;
  text-indent: 0.24em;
  text-transform: uppercase;
  color: rgba(60, 44, 26, 0.72);
}

.minitehtava .juliste-palkinto.voitettu .juliste-merkki { color: rgba(60, 44, 26, 0.95); }

.minitehtava .juliste-palkinto.voitettu:focus-visible {
  outline: 2px solid rgba(60, 44, 26, 0.75);
  outline-offset: 3px;
}

/* Kapea puhelin: vedos kapenee mutta pysyy kyljessä — ylle nostettuna
 * se työntäisi kysymyksen alas eikä olisi enää "kysymysten vierellä". */
@media (max-width: 430px) {
  .minitehtava.minitehtava-palkinnollinen { column-gap: 0.6rem; }
  .minitehtava .juliste-palkinto { width: 92px; }
}

/*
 * JULISTERIVI MATKALAUKUSSA (omistajan tilaus 22.8.2026: "Julisteet
 * voisi olla oma rivi laukussa mutta kuvakkeet todella pieniä, sama
 * korkeus kuin tekstillä ja näkyisi vain kolme viimeisintä. Perässä
 * olisi numeromäärä ja >> merkki.").
 *
 * Tämä KUMOAA 21.8.2026 tehdyn ruudukon (.laukku-julisteet), jossa
 * osasto kasvoi kokoelman mukana ja peitti loppupelissä laukun muun
 * sisällön. Rivi on nyt vakiokorkuinen: yksi tekstirivi, jonka päällä
 * kolme tuoreinta vedosta ratsastaa saman korkuisina kuin kirjaimet.
 */
.dialog .laukku-julisterivi {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  margin: 0.15rem 0 0.4rem;
  padding: 0.2rem 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  font-family: var(--font-type);
  font-size: 0.82rem;
  line-height: 1.3;
  letter-spacing: 0.03em;
  color: rgba(60, 44, 26, 0.9);
  text-align: left;
  cursor: pointer;
}

.dialog .laukku-julisterivi:hover .laukku-julisterivi-luku,
.dialog .laukku-julisterivi:focus-visible .laukku-julisterivi-luku {
  color: rgba(60, 44, 26, 0.95);
}

.laukku-julisterivi-nimio {
  /* Sama nimiötyyli kuin muilla laukun osastoilla (.passport-count). */
  text-transform: uppercase;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  color: rgba(60, 44, 26, 0.72);
}

.laukku-julisterivi-vedokset {
  display: flex;
  align-items: center;
  gap: 0.22rem;
  min-width: 0;
}

.laukku-julisterivi-vedokset img {
  display: block;
  /* Todella pieni: sama korkeus kuin tekstirivillä, leveys tulee
   * julisteen omasta 2:3-suhteesta. Suhde on myös kiinteänä, jottei
   * rivi nyi kuvan latautuessa. */
  height: 1.25em;
  width: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border: 1px solid rgba(60, 44, 26, 0.55);
  box-shadow: 1px 1px 0 rgba(60, 44, 26, 0.18);
}

.laukku-julisterivi-luku {
  margin-left: auto;
  white-space: nowrap;
  color: rgba(60, 44, 26, 0.8);
}

/*
 * JULISTEGALLERIA: laukun rivistä avautuva popup (omistajan tilaus
 * 22.8.2026: "julisteet vähän isommalla maanosien mukaan jaoteltuna").
 *
 * Kerrokset: huntu 65, galleria 66, ja gallerian päälle avautuva täysi
 * koko on tavallinen .postikortti.kulttuuri-suurennos (69/70). Näin
 * suurennos jää aina gallerian PÄÄLLE ilman erillistä pinologiikkaa.
 * Kortti asuu avoimen <dialog>-elementin sisällä (js/ui.js
 * suurennosIsanta), koska modaali elää selaimen top layerissa.
 */
.julistegalleria-huntu {
  position: fixed;
  inset: 0;
  z-index: 65;
  background: rgba(26, 18, 8, 0.28);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

.julistegalleria {
  position: fixed;
  inset: 0;
  z-index: 66;
  margin: auto;
  width: min(94vw, 760px);
  height: fit-content;
  max-height: 88dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0.6rem 0.9rem 1rem;
  background: #f8f3e6;
  border: 1px solid rgba(60, 44, 26, 0.35);
  border-radius: 3px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.45);
}

.julistegalleria-ylapalkki {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 0 0 0.4rem;
  padding: 0.25rem 0 0.35rem;
  background: #f8f3e6;
  border-bottom: 1px solid rgba(60, 44, 26, 0.22);
}

.julistegalleria-otsikko {
  margin: 0;
  font-family: var(--font-type);
  font-size: 1rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(60, 44, 26, 0.92);
}

.julistegalleria-luku {
  font-family: var(--font-type);
  font-size: 0.8rem;
  color: rgba(60, 44, 26, 0.65);
}

.dialog .julistegalleria-rasti {
  margin: 0 0 0 auto;
  padding: 0 0.3rem;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  font-size: 1.35rem;
  line-height: 1;
  color: rgba(60, 44, 26, 0.7);
  cursor: pointer;
}

.julistegalleria-ryhma { margin: 0.6rem 0 0; }

.julistegalleria-ryhma-otsikko {
  margin: 0 0 0.35rem;
  font-family: var(--font-type);
  font-size: 0.74rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: rgba(60, 44, 26, 0.7);
}

/*
 * Ruudukko täyttyy itsestään: kapealla puhelimella kaksi tai kolme
 * saraketta, leveällä useampi — ryhmät pinoutuvat allekkain eikä
 * mitään tarvitse mediakyselyillä siirtää.
 */
.julistegalleria-ruudukko {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 0.6rem;
}

.dialog .julistegalleria-vedos {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: center;
  cursor: zoom-in;
}

.dialog .julistegalleria-vedos img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border: 1px solid rgba(60, 44, 26, 0.6);
  box-shadow: 1px 2px 0 rgba(60, 44, 26, 0.2);
}

.julistegalleria-nimi {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--font-type);
  font-size: 0.6rem;
  line-height: 1.25;
  letter-spacing: 0.02em;
  color: rgba(60, 44, 26, 0.8);
}

/* Voittamaton paikka ja vielä ämpäriin viemätön kuva: sama tyhjä
 * kehys, jotta ryhmästä ei katoa ruutua kummassakaan tapauksessa. */
.dialog .julistegalleria-vedos.lukossa,
.dialog .julistegalleria-vedos.kuvaton {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  aspect-ratio: 2 / 3;
  border: 1px dashed rgba(60, 44, 26, 0.4);
  background: rgba(60, 44, 26, 0.05);
  font-family: var(--font-type);
  font-size: 1rem;
  color: rgba(60, 44, 26, 0.45);
}

.dialog .julistegalleria-vedos.lukossa { cursor: default; }

/*
 * Päivän sää lehden mastossa: hillitty rivi kuvakkeineen heti
 * päiväysrivin alla. Nappi ei näytä napilta — lehdessä sää on
 * tekstirivi — mutta "koko vuosi ›" -vihje kertoo, että siitä
 * aukeaa lisää.
 */
.dialog button.lehti-saa {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
  margin: -0.45rem 0 0.7rem;
  padding: 0.15rem 0.3rem;
  border: 0;
  border-radius: 4px;
  background: none;
  box-shadow: none;
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: rgba(70, 51, 31, 0.9);
  cursor: pointer;
}

.dialog button.lehti-saa svg {
  width: 17px;
  height: 17px;
  flex: 0 0 auto;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.dialog button.lehti-saa .saa-vihje {
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: rgba(122, 85, 20, 0.95);
  white-space: nowrap;
}

/* Vuosigraafi: muste ja kulta paperilla, sama kieli kuin kartalla. */
.vuosisaa-kortti { max-width: min(92vw, 460px); }

.vuosisaa-otsikko { font-weight: 700; }

/*
 * LUONNEHDINTA graafin ja lähderivin välissä (omistajan toive
 * 17.8.2026). Se on lehden leipätekstiä eikä kuvatekstiä: antiikva,
 * väljä riviväli ja täysi musteväri, jotta se erottuu alapuolisesta
 * hennosta lähderivistä eikä sekoitu siihen. Kortti on enintään noin
 * 460 pikseliä leveä, joten rivi jää tällä koolla runsaaseen
 * kuuteenkymmeneen merkkiin — luettava mitta kolmelle lauseelle.
 */
.vuosisaa-luonnehdinta {
  margin: 0.7rem 0 0;
  font-family: var(--font-luku);
  font-size: 0.86rem;
  line-height: 1.5;
  text-align: left;
  color: #2d2010;
}

.vuosisaa {
  display: block;
  width: 100%;
  background: rgba(255, 250, 238, 0.65);
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 6px;
}

/*
 * ── ELÄVÖITETTY VUOSIGRAAFI (omistajan tilaus 13.8.2026) ─────────────
 *
 * Sade on sateensinistä eikä mustetta: palkit erottuvat kultakäyrästä
 * yhdellä silmäyksellä ja lukevat vedeksi. Avautuessa palkit kasvavat
 * pohjaviivasta ylös porrastetusti (viive tulee JS:stä kuukausi-
 * järjestyksessä), käyrä piirtyy vasemmalta oikealle ja pisteet
 * ilmestyvät sen vanaan. Liikeherkkyys sammuttaa kaiken alla.
 */
.vuosisaa .saa-palkki {
  fill: rgba(96, 118, 142, 0.55);
  transform-box: fill-box;
  transform-origin: bottom;
  animation: saa-palkki-kasvu 600ms ease-out backwards;
}

@keyframes saa-palkki-kasvu {
  from { transform: scaleY(0); }
}

/*
 * VAIHTELUVYÖHYKE (omistajan toive 18.8.2026): kuukauden tyypillinen
 * ylin ja alin päivälämpö yhtenä nauhana keskilämpökäyrän takana.
 * Sävy on sama ruskea kuin käyrässä ja kultaliu'ussa, vain hyvin
 * ohuena — kaista on pergamentin varjo, ei uusi väri. Se ilmestyy
 * ennen käyrän piirtoa, jotta viiva näyttää nousevan omalta
 * alustaltaan eikä tyhjästä.
 */
.vuosisaa .saa-kaista {
  fill: rgba(164, 105, 28, 0.13);
  opacity: 0;
  animation: saa-ilmesty 800ms ease-out 200ms forwards;
}

/* Haalea kultaliuku käyrän alla (liukuväri SVG:n defsissä). */
.vuosisaa .saa-alue {
  fill: url(#vuosisaa-liuku);
  opacity: 0;
  animation: saa-ilmesty 900ms ease-out 450ms forwards;
}

.vuosisaa .saa-viiva {
  fill: none;
  stroke: #a4691c;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* pathLength="1" JS:ssä: piirto vasemmalta oikealle. */
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: saa-viiva-piirto 1100ms ease-out 150ms forwards;
}

@keyframes saa-viiva-piirto {
  to { stroke-dashoffset: 0; }
}

.vuosisaa .saa-piste {
  fill: #a4691c;
  opacity: 0;
  animation: saa-ilmesty 300ms ease-out forwards;
}

@keyframes saa-ilmesty {
  to { opacity: 1; }
}

/* Ääripäiden lukemat: halo pitää luvut luettavina palkkien päällä. */
.vuosisaa .saa-arvo {
  font-family: var(--font-type);
  font-size: 8.5px;
  font-weight: 700;
  fill: #8a5a12;
  paint-order: stroke;
  stroke: rgba(245, 240, 226, 0.9);
  stroke-width: 2.5px;
  opacity: 0;
  animation: saa-ilmesty 400ms ease-out 1100ms forwards;
}

.vuosisaa .saa-arvo-sade { fill: #4c6478; }

/* Kuluva kuukausi: haalea kaista pystyyn ja lihavoitu kirjain. */
.vuosisaa .saa-kuluva-kaista { fill: rgba(164, 105, 28, 0.09); }

.vuosisaa .saa-kuluva {
  font-weight: 700;
  fill: #7a5514;
}

@media (prefers-reduced-motion: reduce) {
  .vuosisaa .saa-palkki,
  .vuosisaa .saa-kaista,
  .vuosisaa .saa-alue,
  .vuosisaa .saa-viiva,
  .vuosisaa .saa-piste,
  .vuosisaa .saa-arvo { animation: none; }

  .vuosisaa .saa-viiva { stroke-dashoffset: 0; }

  .vuosisaa .saa-kaista,
  .vuosisaa .saa-alue,
  .vuosisaa .saa-piste,
  .vuosisaa .saa-arvo { opacity: 1; }
}

.vuosisaa .saa-apuviiva {
  stroke: rgba(70, 51, 31, 0.18);
  stroke-width: 0.7;
}

.vuosisaa .saa-pohjaviiva {
  stroke: rgba(70, 51, 31, 0.6);
  stroke-width: 1;
}

.vuosisaa .saa-akseli {
  font-family: var(--font-type);
  font-size: 8.5px;
  fill: rgba(70, 51, 31, 0.8);
}

/*
 * Maa numeroina — lehden tilastosivu (docs/valtion-analyysi.md).
 *
 * Sama muste+kulta kuin vuosisäägraafissa: kulta on maan oma käyrä,
 * ohut himmeä muste Suomen vertailuviiva ja ennusteosa piirretään
 * haaleampana kultana. Pyramidissa miehet ovat mustetta ja naiset
 * kultaa — samat kaksi väriä, ei uutta grafiikkakieltä.
 */
.maakayrat {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem 1.5rem;
  margin: 0.3rem 0 0.6rem;
}

/* Sama raja kuin lehtijutun palstataitolla: leveällä kaksi käyrää
 * rinnan, kapealla yksi allekkain. */
@media (min-width: 700px) {
  .maakayrat { grid-template-columns: 1fr 1fr; }
}

.maakayra-otsikko {
  margin: 0 0 0.3rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  font-weight: 700;
  color: #211d18;
}

.maakayra {
  display: block;
  width: 100%;
  background: rgba(255, 250, 238, 0.65);
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 6px;
}

.maakayra-viiva,
.maakayra-ennuste,
.maakayra-suomi,
.maakayra-toinen,
.maakayra-kolmas,
.maakayra-neljas {
  /* fill: none KOSKEE KAIKKIA VIIVALUOKKIA. Kolmas ja neljäs maa
   * unohtuivat tästä ensin, ja polyline täyttyi oletuksena mustalla:
   * käyrien väliin ilmestyi umpimusta läiskä (näkyi heti
   * kuvakaappauksesta, ei testeistä). */
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.maakayra-viiva { stroke: #a4691c; stroke-width: 1.8; }
.maakayra-viiva-piste { fill: #a4691c; }

/* Vertailulinssin toinen maa: punaruskea (--mark), sama kynä. */
.maakayra-toinen { stroke: #b03a2b; stroke-width: 1.4; opacity: 0.85; }
.maakayra-toinen-piste { fill: #b03a2b; opacity: 0.85; }

/*
 * Kolmas ja neljäs maa (v321, karttanäkymän vertailu). Värit ovat
 * samaa mustepalettia kuin kartta: sammaleenvihreä ja merimuste —
 * kulta, punaruskea, vihreä ja sininen erottuvat toisistaan myös
 * harmaasävyisenä, koska niiden tummuus on eri.
 */
.maakayra-kolmas { stroke: #4a6b3a; stroke-width: 1.4; opacity: 0.85; }
.maakayra-kolmas-piste { fill: #4a6b3a; opacity: 0.85; }
.maakayra-neljas { stroke: #35577f; stroke-width: 1.4; opacity: 0.85; }
.maakayra-neljas-piste { fill: #35577f; opacity: 0.85; }

.pyramidi-vertailu {
  fill: none;
  stroke: #b03a2b;
  stroke-width: 1.1;
  opacity: 0.85;
  stroke-linejoin: round;
}

/* Vertailulinssin maavalitsin: pieni kirjoituskonerivi, paperin värit. */
.vertailu-rivi {
  margin: -0.2rem 0 0.6rem;
  font-family: var(--font-type);
  font-size: 0.8rem;
  color: rgba(70, 51, 31, 0.85);
}

.vertailu-valitsin {
  margin-left: 0.2rem;
  padding: 0.15rem 0.35rem;
  font-family: var(--font-type);
  font-size: 0.8rem;
  color: #211d18;
  background: rgba(255, 250, 238, 0.8);
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 6px;
}

/* Ennuste himmeämmällä musteella — se on odotus, ei havainto. */
.maakayra-ennuste { stroke: #a4691c; stroke-width: 1.3; opacity: 0.45; }
.maakayra-ennuste-piste { fill: #a4691c; opacity: 0.45; }

.maakayra-suomi { stroke: rgba(70, 51, 31, 0.38); stroke-width: 1; }
.maakayra-suomi-piste { fill: rgba(70, 51, 31, 0.38); }

.maakayra-apuviiva { stroke: rgba(70, 51, 31, 0.18); stroke-width: 0.7; }
.maakayra-pohjaviiva { stroke: rgba(70, 51, 31, 0.6); stroke-width: 1; }

.maakayra-akseli {
  font-family: var(--font-type);
  font-size: 8.5px;
  fill: rgba(70, 51, 31, 0.8);
}

.maakayra-ennusteteksti { fill: rgba(164, 105, 28, 0.75); }

/* Isoisän aikakauden jälki akselin reunassa: pieni rengas ja vuosi. */
.maakayra-silloin { fill: none; stroke: #8a6114; stroke-width: 1.1; }
.maakayra-silloinvuosi { fill: rgba(138, 97, 20, 0.9); font-size: 7.5px; }

.pyramidi-miehet { fill: rgba(70, 51, 31, 0.55); }
.pyramidi-naiset { fill: rgba(164, 105, 28, 0.78); }
.pyramidi-ika { font-size: 7.5px; fill: rgba(70, 51, 31, 0.65); }

/* Tulkintalause käyrän alla: lehden ingressin ääni, mutta pienempänä. */
.maakayra-tulkinta {
  margin: 0.35rem 0 0;
  font-family: var(--font-luku);
  font-style: italic;
  font-size: 0.88rem;
  line-height: 1.45;
  color: rgba(33, 29, 24, 0.88);
}

/* "Silloin ja nyt" — isoisän päiväkirjan ääni käyrän alla. */
.maakayra-silloinrivi {
  margin: 0.25rem 0 0;
  font-family: var(--font-luku);
  font-style: italic;
  font-size: 0.82rem;
  line-height: 1.45;
  color: rgba(138, 97, 20, 0.95);
}

.maakayra-vdem { font-style: normal; }

.maakayra-lahde {
  margin: 0.7rem 0 0;
  font-size: 0.74rem;
  color: rgba(70, 51, 31, 0.68);
}

/*
 * Kohtaaminen visakortilla: hahmon tervehdys kirjoittuu otsikon ja
 * kysymyksen väliin kirjan kursiivilla — se on tarinaa, ei tehtävää.
 * Repliikki tuloksen alla erottuu samalla äänellä.
 */
.quiz-kohtaaminen {
  margin: 0.35rem 0 0.6rem;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-style: italic;
  font-size: 0.95rem;
  line-height: 1.5;
  color: rgba(58, 42, 22, 0.95);
}

/*
 * Aloita peli -nappi kohtaamisen tervehdyksen alla: peli (kysymys,
 * vaihtoehdot, tiimalasi) käynnistyy vasta painalluksesta, joten
 * kertojan luenta saa loppua rauhassa (omistajan toive 10.8.2026).
 */
.quiz-aloita {
  display: block;
  margin: 0.2rem auto 0.8rem;
}

/*
 * Loppuun pelattu kohtaaminen: tehtävänappi jää harmaana näkyviin
 * kertomaan tilanteen ("Tapaa Nikos" onnistumisen jälkeen, "Nikos ei
 * tavattavissa" kahden epäonnistumisen jälkeen) — omistajan sääntö
 * 10.8.2026. Ei varjoa eikä hover-eleitä: nappi on tila, ei kutsu.
 */
#arrival-yes.tehtava-pois,
#arrival-yes.tehtava-pois:hover {
  opacity: 0.55;
  filter: grayscale(1);
  cursor: default;
  box-shadow: none;
  transform: none;
}

/*
 * KOHTAAMISKUVA ON KORTIN YLÄOSAN ISO KUVA (omistajan tilaus
 * 1.9.2026: *"nuo aarrekuvat vaativat pelissä isomman kuva-alan …
 * voisit suunnitella kohtaamiskortin uudelleen niin että kuva näkyy
 * siinä isona. idea oli kai että kuvan alle tulee myös
 * kuvatekstiä"*).
 *
 * ENNEN: pieni muotokuva kellui tekstin oikealla puolella (pilotti
 * 10.8.2026: Ateena ja Sofia). NYT: kuvio on kortin levyinen lohko
 * heti otsikkorivin alla, kuvateksti sen alla ja hahmon tervehdys
 * vasta niiden jälkeen — sama järjestys kuin fokusvirran
 * oppituntikortilla, jossa kuva on kortin ensimmäinen asia.
 *
 * Kuvasuhde säilyy (`height: auto`), joten kuvaa ei rajata. Korkeus
 * on silti katossa: kapealla ruudulla kuva ei saa työntää kysymystä
 * kortin ulkopuolelle (kohta @media alempana), ja kortti itse rullaa
 * tarvittaessa (.dialog-card overflow-y).
 */
.quiz-kohtaaminen-kuvio {
  /* figuren selaimen oletusmarginaali pois: kuva on kortin levyinen. */
  margin: 0.1rem 0 0.7rem;
  padding: 0;
}

.quiz-kohtaaminen-kuvio[hidden] { display: none; }

.quiz-kohtaaminen-kuva {
  display: block;
  width: 100%;
  height: auto;
  /* Katto myös leveällä ruudulla: kuva saa olla komea, muttei niin
   * korkea että hahmon tervehdys jää kokonaan taitteen alle. */
  max-height: 52dvh;
  object-fit: contain;
  margin: 0 auto;
  /* Napautus avaa kuvan koko näytölle (30.8.2026). */
  cursor: zoom-in;
}

/*
 * VANHA PERGAMENTTIPIIRROS (assets/kohtaamiset/…): kuvan oma
 * vaalea pohja sulautetaan kortin paperiin (omistajan toive
 * 10.8.2026 ilta: kuva ei saa lukea laatikkona). Multiply hävittää
 * taustan ja säteittäinen maski pehmentää reunat paperiin.
 */
.quiz-kohtaaminen-kuva.piirros {
  mix-blend-mode: multiply;
  -webkit-mask-image: radial-gradient(ellipse at center, #000 55%, transparent 98%);
  mask-image: radial-gradient(ellipse at center, #000 55%, transparent 98%);
}

/*
 * UUSI KOHTAAMISVALOKUVA (R2, js/kohtaamiskuvat-data.js): valokuvalla
 * ei ole pergamenttipohjaa, ja multiply vain likaisi sen. Sulautus
 * tehdään kevyellä vinjetillä — kuvan keskusta on koskematon ja vain
 * reunat ja kulmat häipyvät paperiin, samalla kielellä kuin piirroksen
 * maski ja kätkökuva ("Sama sulautus kuin kohtaamiskuvalla").
 */
.quiz-kohtaaminen-kuva.valokuva {
  -webkit-mask-image: radial-gradient(ellipse at center,
    #000 56%, rgba(0, 0, 0, 0.82) 78%, rgba(0, 0, 0, 0.35) 92%, transparent 100%);
  mask-image: radial-gradient(ellipse at center,
    #000 56%, rgba(0, 0, 0, 0.82) 78%, rgba(0, 0, 0, 0.35) 92%, transparent 100%);
}

/*
 * Kuvateksti kuvan alle kortin omalla kursiivilla, ja lähderivi sen
 * jatkeeksi samalle riville pienemmällä — sama kuvateksti + kuvalähde
 * -malli kuin postikortissa ja suurennoksessa (js/ui.js, luokat
 * .kuvateksti / .kuvalahde).
 */
.quiz-kohtaaminen-kuvateksti {
  margin: 0.35rem 0 0;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-style: italic;
  font-size: 0.8rem;
  line-height: 1.45;
  color: rgba(58, 42, 22, 0.9);
}

.quiz-kohtaaminen-kuvateksti[hidden] { display: none; }

/*
 * KAPEA RUUTU (iPhone 390 × 844): kuva saa viedä korkeintaan noin
 * 45 % kortista, jotta tervehdys ja Aloita peli -nappi mahtuvat
 * samaan näkymään; loput kortista rullaa tarvittaessa (.dialog-card).
 * Kortin oma katto on 92dvh, joten 41dvh on siitä ~45 %.
 */
@media (max-width: 699px) {
  .quiz-kohtaaminen-kuva { max-height: 41dvh; }

  .quiz-kohtaaminen-kuvio { margin-bottom: 0.55rem; }
}

/*
 * KYSYMYSSIVUN PELKISTYS (omistajan tilaus 1.9.2026: *"kuvan voi
 * pienentää ja voi jättää edellisellä sivulla näkyneet tekstit pois,
 * niin jää selvemmin pelkkä kysymys näkyviin"*).
 *
 * Kohtaamiskortilla on kaksi sivua. Tervehdyssivulla kuva on iso
 * (säännöt yllä). Kun pelaaja painaa Aloita peli, js/visa.js lisää
 * dialogille luokan `kysymysvaihe`: tervehdys, kuvateksti ja varoitus
 * piilotetaan (js), ja kuva kutistuu tässä pieneksi pyöristetyksi
 * neliöksi. Näin kysymys + kaikki vaihtoehdot + tiimalasi mahtuvat
 * iPhonen 390 × 844 ruudulle ilman rullausta.
 *
 * Pieni neliö rajataan (`object-fit: cover`) eikä sulauteta vinjetillä:
 * maski söisi tässä koossa liikaa kuvasta, ja pyöristetty reuna lukee
 * tunnisteena — kuva on tässä muistutus siitä, kuka kysyy, ei taulu.
 */
.quiz.kysymysvaihe .quiz-kohtaaminen-kuvio {
  margin: 0 0 0.45rem;
}

.quiz.kysymysvaihe .quiz-kohtaaminen-kuva {
  width: 104px;
  height: 104px;
  max-height: none;
  object-fit: cover;
  border-radius: 12px;
  mix-blend-mode: normal;
  -webkit-mask-image: none;
  mask-image: none;
  box-shadow: 0 1px 6px rgba(52, 36, 16, 0.28);
}

/*
 * VIIMEISEN YRITYKSEN VAROITUS tervehdyssivulla: pelin oma ääni, ei
 * järjestelmäilmoitus — sama kirjan kursiivi kuin tervehdyksessä,
 * mutta tummemmalla ja ohuen punaruskean viivan takana, jotta se
 * erottuu hahmon puheesta.
 */
.quiz-varoitus {
  margin: 0.5rem 0 0.15rem;
  padding: 0.45rem 0.7rem;
  border-left: 3px solid rgba(150, 58, 34, 0.75);
  background: rgba(150, 58, 34, 0.08);
  border-radius: 0 6px 6px 0;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-style: italic;
  font-size: 0.92rem;
  line-height: 1.45;
  color: rgba(112, 42, 24, 0.95);
}

.quiz-varoitus[hidden] { display: none; }

/*
 * VIELÄ YKSI YRITYS -ohjaus väärän vastauksen tuloskortilla: pelaaja
 * ei saa luulla, että aarre on jo menetetty. Sama punaruskea ääni kuin
 * varoituksessa, mutta ilman laatikkoa — tuloskortilla on jo kehys.
 */
.quiz-uusi-yritys {
  display: block;
  margin: 0.4rem 0 0.1rem;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-style: italic;
  font-size: 0.9rem;
  line-height: 1.45;
  color: rgba(112, 42, 24, 0.95);
}

/* Kätkökuva laatattoman löydön tuloskortissa: löytö näkyy, ei vain
 * rivi tekstiä. */
.katko-kuva {
  display: block;
  width: min(55%, 170px);
  margin: 0.55rem auto 0.35rem;
  /* Sama sulautus kuin kohtaamiskuvalla: ei laatikkoa. */
  mix-blend-mode: multiply;
  -webkit-mask-image: radial-gradient(ellipse at center, #000 55%, transparent 98%);
  mask-image: radial-gradient(ellipse at center, #000 55%, transparent 98%);
  /* Napautus avaa kätkökuvan koko näytölle (30.8.2026). */
  cursor: zoom-in;
}

.quiz-result .kohtaaminen-repliikki {
  display: block;
  margin-top: 0.3rem;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-style: italic;
  font-size: 0.92rem;
  line-height: 1.45;
}

/*
 * Uutisosio maaosastossa: pieni nimiörivi ja otsikkolista kuin
 * lehden sähkeet. Otsikot ovat paikallisella kielellä sellaisinaan —
 * rivit ovat nappeja, joista uutinen aukeaa pelin kirjasimilla.
 */
.arrival-uutiset {
  margin: 0.7rem 0 0.3rem;
  border-top: 1px solid rgba(70, 51, 31, 0.45);
  padding-top: 0.4rem;
}

.uutiset-nimio {
  margin: 0 0 0.3rem;
  font-family: var(--font-type);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.8);
}

.dialog .uutiset-lista button.uutinen-rivi {
  display: block;
  width: 100%;
  margin: 0 0 0.3rem;
  padding: 0.1rem 0 0.35rem;
  border: 0;
  border-bottom: 1px dashed rgba(70, 51, 31, 0.3);
  border-radius: 0;
  background: none;
  box-shadow: none;
  text-align: left;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  /* Pieni ja hillitty (omistajan toive): sähkeet eivät saa varastaa
   * huomiota maan esittelyltä. */
  font-size: 0.82rem;
  font-weight: 700;
  line-height: 1.35;
  color: rgba(45, 32, 16, 0.9);
  cursor: pointer;
}

.dialog .uutiset-lista button.uutinen-rivi:hover {
  color: #7a5514;
}

/* Uutispopup: otsikko isolla antiikvalla, kuvaus alla, käännös kursiivilla. */
/*
 * Uutispopup on pikkulehti (omistajan toive 7.8.2026): leveämpi
 * kortti, jotta leipäteksti mahtuu kiertämään kellutetun kuvan.
 */
.uutinen-kortti { max-width: min(94vw, 660px); }

/* Ylärivi: jutun päiväys vasemmalla, käännösnappi oikealla. Oikeaan
 * reunaan jää rako kulman rastille. */
.uutinen-ylarivi {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  margin: 0 0 0.35rem;
  padding-right: 1.8rem;
}

.uutinen-paivays {
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  color: rgba(70, 51, 31, 0.75);
}

.dialog button.uutinen-kaanna {
  margin: 0;
  padding: 0.18rem 0.65rem;
  border: 1px solid rgba(70, 51, 31, 0.5);
  border-radius: 999px;
  background: rgba(255, 250, 238, 0.7);
  box-shadow: none;
  font-family: var(--font-type);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #2d2010;
  cursor: pointer;
}

.dialog button.uutinen-kaanna:disabled { opacity: 0.6; cursor: default; }

/* Lähteen nimiö kuin lehden masto: tuplaviiva yllä, ohut alla —
 * sama viivapari kuin Tutki-lehden päiväysrivillä (.lehti-alarivi). */
.uutinen-masto {
  margin: 0 0 0.8rem;
  padding: 0.26rem 0;
  border-top: 3px double rgba(70, 51, 31, 0.75);
  border-bottom: 1px solid rgba(70, 51, 31, 0.5);
  font-family: var(--font-type);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  text-align: center;
  color: #211d18;
}

.uutinen-otsikko {
  margin: 0 0 0.55rem;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.25;
  color: #16130f;
}

/* Kelluva kuva vapautetaan rungon lopussa, ettei lyhyt juttu jätä
 * kuvaa roikkumaan kortin ulkopuolelle. */
.uutinen-runko::after {
  content: "";
  display: block;
  clear: both;
}

.uutinen-kappale {
  margin: 0 0 0.55rem;
  /* Pitkä leipäteksti luetaan kirjan antiikvalla, ei konekirjaimin
   * (omistajan huomio 5.8.2026). Suomennos käyttää SAMAA tyyliä —
   * ei kursiivia (omistajan tarkennus 7.8.2026). */
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 0.98rem;
  line-height: 1.55;
  color: #211d18;
}

/*
 * Tekstipopupit (uutinen, vuosisää) tarvitsevat paperikortin:
 * kuvasuurennos kelluttaa kuvan tummaa pohjaa vasten, mutta pelkkä
 * teksti tummalla pohjalla näyttäisi irralliselta. Sama sulkeminen
 * ja tumma tausta kuin suurennoksessa.
 */
.postikortti.kulttuuri-suurennos.uutinen-kortti,
.postikortti.kulttuuri-suurennos.vuosisaa-kortti {
  width: min(92vw, 480px);
  padding: 1rem 1.1rem 0.9rem;
  cursor: pointer;
  color: #2d2010;
}

/* Uutiskortti on lehteä: leveämpi kuin sääkortti, jotta teksti
 * kiertää kuvaa (omistajan toive 7.8.2026). */
.postikortti.kulttuuri-suurennos.uutinen-kortti { width: min(94vw, 660px); }

/*
 * MIKSI PAPERI ON ::after EIKÄ ELEMENTIN TAUSTA: suurennoksen koko
 * ruudun huntu (::before, z-index -1) maalautuu CSS:n
 * maalausjärjestyksessä elementin OMAN taustan päälle mutta sisällön
 * alle — kuvakortissa kuva peittää hunnun, mutta tekstikortin tausta
 * jäisi hunnun taakse ja kortti näyttäisi tummalta. Siksi huntu
 * painetaan kerrosta alemmas (-2) ja paperi piirretään omana
 * kerroksenaan (-1) hunnun ja tekstin väliin.
 */
/* Myös sää aukeaa ilman taustan tummennusta (omistaja 5.8.2026):
 * huntu pois ja paperi elementille itselleen, kuten uutiskortilla. */
.postikortti.kulttuuri-suurennos.vuosisaa-kortti::before { display: none; }

.postikortti.kulttuuri-suurennos.vuosisaa-kortti {
  background: var(--arkki-paperi, #eedab3);
  border: 1.5px solid rgba(70, 51, 31, 0.6);
  border-radius: 8px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
}

.postikortti.kulttuuri-suurennos.uutinen-kortti .kuvateksti,
.postikortti.kulttuuri-suurennos.uutinen-kortti .kuvalahde,
.postikortti.kulttuuri-suurennos.vuosisaa-kortti .kuvateksti,
.postikortti.kulttuuri-suurennos.vuosisaa-kortti .kuvalahde {
  text-align: left;
  color: rgba(70, 51, 31, 0.75);
}

.postikortti.kulttuuri-suurennos.vuosisaa-kortti .kuvateksti {
  color: #2d2010;
  font-weight: 700;
}


/*
 * Suurennoksen kuvakotelo: nuolet ja laskuri asemoituvat täsmälleen
 * kuvan päälle (fit-content), myös kapean pystykuvan kohdalla.
 */
.suurennos-kuvakotelo {
  position: relative;
  width: fit-content;
  max-width: 100%;
  margin-inline: auto;
}


/*
 * Uutispopupin tarkennukset (omistaja 5.8.2026): tausta ei tummene —
 * kortti kelluu lehden päällä varjonsa varassa — ja pitkä artikkeli
 * vierii kortin sisällä. Sulkurasti kulmassa; myös kortin napautus
 * sulkee.
 */
.postikortti.kulttuuri-suurennos.uutinen-kortti::before { display: none; }

/*
 * MIKSI PAPERI ON TÄSSÄ ELEMENTILLÄ EIKÄ ::after-KERROKSELLA:
 * inset: 0 -kerros kattaa vain kortin näkyvän laatikon, ei
 * vieritettävää ylivuotoa — pitkä käännös valui paperin ohi
 * (omistajan kuvakaappaus 5.8.2026). Huntu (::before) on tältä
 * kortilta poissa, joten elementin oma tausta ei jää minkään alle.
 */
.postikortti.kulttuuri-suurennos.uutinen-kortti {
  max-height: 84dvh;
  overflow-y: auto;
  padding-right: 2.2rem;
  background: var(--arkki-paperi, #eedab3);
  border: 1.5px solid rgba(70, 51, 31, 0.6);
  border-radius: 8px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
}

.postikortti.kulttuuri-suurennos.uutinen-kortti::after { display: none; }

.dialog button.uutinen-sulku {
  position: absolute;
  top: 0.35rem;
  right: 0.4rem;
  width: 1.7rem;
  height: 1.7rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  box-shadow: none;
  font-size: 1.25rem;
  line-height: 1;
  color: rgba(70, 51, 31, 0.7);
  cursor: pointer;
}

/* Popupin erillinen otsikkosuomennos ja kursivoitu käännöslohko
 * poistuivat 7.8.2026: Käännä-nappi vaihtaa otsikon ja kappaleet
 * paikallaan samoihin tyyleihin. Sähkerivin pieni suomennos
 * (.uutinen-rivi-suomeksi) elää yhä alempana. */

/*
 * Maaosaston taitto leveällä ruudulla (omistaja: kartan oikealla
 * puolella oli tyhjäkäyntiä): uutissähkeet nousevat kartan viereen
 * oikeaan palstaan, ja esittelyteksti levittäytyy molempien alle.
 */
@media (min-width: 641px) {
  .dialog.lehti .arrival-maa {
    display: grid;
    grid-template-columns: 1.05fr 0.95fr;
    column-gap: 1.2rem;
    align-items: start;
  }

  .dialog.lehti .arrival-maa > * { grid-column: 1; }

  .dialog.lehti .arrival-maa .arrival-maa-rivi { grid-column: 1 / -1; }

  .dialog.lehti .arrival-maa .maa-oikea {
    grid-column: 2;
    grid-row: 2 / span 6;
  }

  .dialog.lehti .arrival-maa .arrival-uutiset {
    margin: 0;
    border-top: 0;
    padding-top: 0;
  }

  .dialog.lehti .arrival-maa #arrival-maa-intro { grid-column: 1 / -1; }
}

/*
 * Maan esittely on lehden pääkirjoitus (omistaja: "visuaalisesti
 * ponneton"): kirjan antiikva, väljempi riviväli ja anfangi.
 */
.dialog.lehti #arrival-maa-intro {
  margin-top: 0.5rem;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 1.02rem;
  line-height: 1.62;
  color: #2d2010;
}

/*
 * SAMA ANFANGI KAUPUNKILEHDEN ETUSIVULLE (omistajan palaute
 * 21.8.2026: "kaupunkisivulla saisi olla samat anfangit kuin
 * maasivulla"). Kirjain, koko, paino, kellutus ja väri ovat yhtä ja
 * samaa sääntöä maan pääkirjoituksen kanssa — kahdeksi säännöksi
 * kopioituna ne ajautuisivat erilleen ensimmäisellä säädöllä.
 *
 * VAIN ENSIMMÄISEEN KAPPALEESEEN. piirraLeipateksti (js/ui-apurit.js)
 * latoo esittelyn <p>-kappaleiksi, ja anfangi joka kappaleessa olisi
 * koristetta eikä lehteä. Kaupungit, joilla ei ole omaa esittelyä,
 * saavat vakiolauseen suorana tekstisolmuna ilman <p>:tä — yhden
 * rivin lause jää siis tarkoituksella ilman anfangia.
 */
.dialog.lehti #arrival-maa-intro::first-letter,
.dialog.lehti #arrival-intro > p:first-of-type::first-letter {
  float: left;
  font-family: var(--font-type);
  font-size: 3.1em;
  line-height: 0.82;
  font-weight: 700;
  padding: 0.06em 0.12em 0 0;
  color: rgba(70, 51, 31, 0.9);
}


/* Sähkeen suomennos otsikon alla: pieni, kevyt, ei etikettiä. */
.dialog .uutiset-lista button.uutinen-rivi .uutinen-rivi-suomeksi {
  display: block;
  margin-top: 0.12rem;
  font-style: italic;
  font-size: 0.74rem;
  font-weight: 400;
  line-height: 1.35;
  color: rgba(70, 51, 31, 0.68);
}

/* Artikkelin kuva popupissa: sama kehystys kuin lehden kuvilla. */
/*
 * Artikkelin kuva kelluu oikealla ja teksti juoksee sen ympäri kuin
 * lehtijutussa (omistajan toive 7.8.2026). Kuva elää rungon sisällä,
 * jotta kelluminen taittaa kappaleet — dir="auto" hoitaa myös
 * oikealta vasemmalle kirjoitettavat kielet, joilla teksti kiertää
 * kuvan vasemmalta.
 */
/* Valitsin on täsmällinen tarkoituksella: yleinen suurennossääntö
 * (.postikortti.kulttuuri-suurennos img) asettaa width: auto ja
 * keskityksen, ja se voittaisi lyhyemmän luokkaparin. */
.postikortti.kulttuuri-suurennos.uutinen-kortti .uutinen-kuva {
  float: right;
  width: min(46%, 270px);
  margin: 0.2rem 0 0.5rem 0.85rem;
  border: 3px solid #f7efdc;
  outline: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 2px;
}

/*
 * Sähkeen pikkukuva otsikon vieressä (omistajan toive 5.8.2026):
 * pieni neliö vasemmalla, otsikko suomennoksineen oikealla. Ilman
 * kuvaa rivi on pelkkää tekstiä — luokka kuvallinen kytkee ruudukon
 * vasta kun kuva on oikeasti saatu.
 */
.dialog .uutiset-lista button.uutinen-rivi.kuvallinen {
  display: grid;
  grid-template-columns: 3.4rem 1fr;
  gap: 0.55rem;
  align-items: start;
}

.dialog .uutiset-lista button.uutinen-rivi img {
  width: 3.4rem;
  height: 3.4rem;
  object-fit: cover;
  border: 2px solid #f7efdc;
  outline: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 2px;
}

.uutinen-rivi-teksti { display: block; min-width: 0; }

/*
 * Mediarivi: maan paikallisradio. Lehtitaitossa rivi istuu uutisten
 * alla oikeassa palstassa, jossa on tilaa. Ruudukko on kaksipalstainen
 * ja pitkä asemannimi lyhenee kolmella pisteellä sen sijaan että rivi
 * kiertyisi.
 */
.maa-media {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 0.4rem;
  margin: 0.6rem 0 0.2rem;
}

.maa-media .kulttuuri-kuuntele {
  margin-top: 0;
  padding: 0.26rem 0.45rem;
  font-size: 0.76rem;
  justify-content: center;
  min-width: 0;
}

.maa-media .kulttuuri-kuuntele > span:not(.live):not(.aika) {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

@media (min-width: 641px) {
  .dialog.lehti .arrival-maa .maa-oikea .maa-media { margin-top: 0.55rem; }
}

/*
 * ÄÄNIRIVIN KAKSI PUOLTA — ENNEN JA NYT (omistajan tilaus 21.8.2026:
 * "kaupunkilehden ääniriville kaksi puolta — vasemmalle vanha
 * äänitallenne, oikealle nykyinen radionappi").
 *
 * Pariluokka tulee vasta kun kaupungilla on vanha tallenne
 * (js/packs/vanhat-aanet.js). Ilman sitä rivi on entinen: yksi
 * radionappi, samat mitat kuin ennen — juuri siksi puolet ovat oma
 * luokkansa eivätkä .maa-median oletus.
 *
 * Puolet ovat pystysuoria pinoja, koska vasemmalla on nappia enemmän:
 * rooliotsikko yllä ja lähderivi alla. Oikea puoli saa saman
 * otsikkorivin, jotta napit ovat samalla korkeudella eikä pari
 * näytä kallistuvan.
 */
.maa-media-pari {
  align-items: start;
  column-gap: 0.55rem;
}

.aani-puoli {
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  min-width: 0;
}

/*
 * Kumpikin nappi venyy oman puolensa levyiseksi, jotta pari on pari
 * eikä kaksi eri kokoista lappua. Ilman tätä .kieli-kuuntelen oma
 * align-self: flex-start jättäisi radionapin tekstinsä mittaiseksi
 * vanhan tallenteen viereen.
 */
.aani-puoli .kulttuuri-kuuntele { align-self: stretch; }

/*
 * Rooliotsikko ladotaan samalla harvennetulla versaalilla kuin
 * etusivun kuvaparissa (.lehti-kuva-rooli) — sama merkintä, sama
 * painotuotteen kieli, olkoon kohde silmälle tai korvalle.
 */
.aani-rooli {
  font-family: var(--font-type);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.8);
}

/*
 * Vanha nappi on hillitympi kuin suora lähetys: himmeämpi pohja ja
 * katkoviivakehys kuin arkiston kortissa. Radio on tapahtuma, joka
 * soi juuri nyt; tallenne on paperia arkistolaatikossa.
 */
.vanha-kuuntele {
  background: rgba(244, 233, 210, 0.75);
  border-style: dashed;
}

.vanha-kuuntele:hover { background: rgba(250, 242, 224, 0.95); }

/*
 * Vuosiluku ei kutistu eikä katkea. Se on tallenteen tärkein tieto —
 * ilman sitä nappi voisi olla mikä tahansa äänite — joten pitkä nimi
 * lyhenee kolmeen pisteeseen ja vuosi jää aina näkyviin, samalla
 * tavalla kuin radionapin live-merkki ja kello.
 */
/*
 * Nimi saa käyttää koko napin leveyden. Radion asemannimille
 * asetettu 14 rem katkaisi levyn nimen jo puolivälistä, vaikka
 * napissa oli tilaa — asemannimi on lyhyt tunniste, levyn nimi on
 * lause.
 */
.maa-media .vanha-kuuntele > span:not(.aika):not(.vanha-vuosi) { max-width: none; }

.maa-media .vanha-kuuntele > span.vanha-vuosi {
  flex: 0 0 auto;
  overflow: visible;
  max-width: none;
  font-variant-numeric: tabular-nums;
  color: rgba(70, 51, 31, 0.8);
}

.aani-lahde {
  font-size: 0.62rem;
  line-height: 1.35;
  color: rgba(90, 74, 51, 0.8);
}

/*
 * Kapealla näytöllä napit allekkain (omistajan ohje). Kahtena
 * palstana puhelimessa kummankin napin teksti lyhenisi kolmeen
 * pisteeseen jo ensimmäisestä sanasta, eikä pelaaja näkisi kumman
 * tallenteen hän soittaa.
 */
@media (max-width: 520px) {
  .maa-media-pari { grid-template-columns: minmax(0, 1fr); row-gap: 0.5rem; }
}

/*
 * Kevyt blurrihuntu hunnuttomien popupien (uutinen, vuosisää)
 * taakse: ei tummennusta, vain hento sumennus joka irrottaa kortin
 * lehdestä. Oma elementti kortin alla (z 69 < kortin 70).
 */
.kevythuntu {
  position: fixed;
  inset: 0;
  z-index: 69;
  background: rgba(26, 18, 8, 0.08);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}

/*
 * ===================================================================
 * VERTAILUTILA JA VERTAILUNÄKYMÄ (v321)
 * ===================================================================
 *
 * Omistajan malli 7.8.2026: vertailulinssi ei enää upota näkymää
 * Tutki-osioon, vaan se ottaa karttanäkymän haltuunsa. Kaupungit
 * katoavat, maiden rajat näkyvät selvästi, ja pelaaja napauttaa
 * kartalta enintään kolme maata Suomen rinnalle. Alanapit korvautuvat
 * omalla palkilla, jonka oikeasta reunasta pääsee vertailuun.
 *
 * Sama malli kuin radiotilassa (body.radio-tila): tila piilottaa muun
 * toiminnan bodyn luokalla, jotta se purkautuu varmasti myös silloin
 * kun linssi sammuu jotain muuta kautta.
 */
body.vertailu-tila .fact-card,
body.vertailu-tila .actions {
  visibility: hidden;
  pointer-events: none;
}

/*
 * Kaupungit, laatat, nappulat ja kohteet pois: vertailussa katsotaan
 * maita. Reittiviivat jäävät tarkoituksella — ne ovat osa staattista
 * karttataidetta, joka rasteroidaan bittikartaksi isoilla laudoilla,
 * eikä css saa siihen otetta.
 */
body.vertailu-tila .cities,
body.vertailu-tila .tokens,
body.vertailu-tila .targets,
body.vertailu-tila .pawns { display: none; }

/*
 * Maiden rajat esiin: tavallisella kartalla korostetaan vain se maa,
 * jossa pelaaja seisoo, ja rajaviiva on hento. Vertailutilassa jokainen
 * maa on napautettava kohde, joten viiva tummenee ja saa oman
 * kerroksensa (.vertailu-maat).
 */
.vertailu-maa {
  fill: rgba(120, 96, 62, 0.06);
  stroke: rgba(70, 51, 31, 0.55);
  stroke-width: 1.1;
  stroke-linejoin: round;
  cursor: pointer;
}

.vertailu-maa:hover { fill: rgba(120, 96, 62, 0.16); }

/*
 * Valittu maa punaisella (omistajan toive). Sävy on sama punaruskea
 * kuin käyrän toisella maalla, jotta kartta ja graafi puhuvat samaa
 * kieltä; järjestysnumero erottaa maat toisistaan.
 */
.vertailu-maa.valittu {
  fill: rgba(176, 58, 43, 0.3);
  stroke: #b03a2b;
  stroke-width: 2.2;
}

.vertailu-maa-nimi {
  font-family: var(--font-hand);
  fill: rgba(70, 51, 31, 0.85);
  pointer-events: none;
  paint-order: stroke;
  stroke: rgba(247, 237, 216, 0.85);
  stroke-width: 3px;
}

/*
 * Alapalkki: korvaa Tutki- ja nopanheittonapit. Sama pilleri kuin
 * muissakin kelluvissa palkeissa, mutta koko leveydeltä keskitetty.
 */
.vertailu-palkki {
  position: fixed;
  left: 50%;
  bottom: max(0.6rem, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 45;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
  justify-content: center;
  max-width: min(96vw, 900px);
  padding: 0.35rem 0.5rem;
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 999px;
  background: rgba(247, 237, 216, 0.94);
  box-shadow: 0 6px 14px -8px rgba(40, 28, 16, 0.6);
}

.vertailu-ohje {
  font-family: var(--font-type);
  font-size: 0.78rem;
  color: rgba(70, 51, 31, 0.8);
  margin: 0 0.2rem;
}

.vertailu-lappu {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.2rem 0.55rem;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 999px;
  background: rgba(255, 250, 238, 0.9);
  font-family: var(--font-type);
  font-size: 0.8rem;
  color: var(--map-ink);
  cursor: pointer;
}

.vertailu-lappu:hover { background: rgba(176, 58, 43, 0.12); }

/* Värilaatta sitoo lapun, kartan ja käyrän toisiinsa. */
.vertailu-laatta {
  width: 0.7rem;
  height: 0.7rem;
  border-radius: 2px;
  border: 1px solid rgba(70, 51, 31, 0.45);
  flex: none;
}

.maakayra-viiva-laatta { background: #a4691c; }
.maakayra-toinen-laatta { background: #b03a2b; }
.maakayra-kolmas-laatta { background: #4a6b3a; }
.maakayra-neljas-laatta { background: #35577f; }

.vertailu-vertaa {
  padding: 0.25rem 0.8rem;
  border-radius: 999px;
  font-family: var(--font-type);
}

/*
 * Vertailunäkymä on sama arkki kuin Tutki-ikkuna: koko ruudun
 * korkuinen paperi, jonka laidoille kartta jää sumeana vain
 * leveimmillä ruuduilla (max-width alla).
 */
/*
 * Vertailuarkki on mahdollisimman iso (omistajan toive): kapealla
 * ruudulla koko ruutu, ja vasta leveimmillä näytöillä kartta jää
 * sumeana laidoille. Marginaali nollataan, koska <dialog> keskittää
 * itsensä automaattisilla marginaaleilla — ilman tätä 100vw:n kortti
 * työntyi ruudun oikean reunan yli (näkyi kuvakaappauksesta).
 */
.dialog.vertailu-arkki {
  width: min(100vw, 1400px);
  max-width: 100vw;
  margin: 0 auto;
  padding: 0;
}

.dialog.vertailu-arkki .dialog-card {
  width: 100%;
  max-width: 100%;
  height: 100dvh;
  max-height: 100dvh;
  box-sizing: border-box;
}

.vertailu-ylarivi {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
  padding: 0.45rem 0 0.5rem;
  background-color: var(--arkki-paperi, #eedab3);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  border-bottom: 1px solid rgba(70, 51, 31, 0.45);
}

/* Pois kytketty maa jää harmaaksi mutta pysyy palkissa. */
.vertailu-lappu[aria-pressed='false'] { opacity: 0.45; }

.vertailu-kortit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.8rem;
  margin: 0.8rem 0 1rem;
}

.vertailu-kortti {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 4px;
  background: rgba(255, 250, 238, 0.5);
}

.vertailu-kortti-nimi {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  font-family: var(--font-type);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--map-ink);
}

.vertailu-kortti .arrival-maa-kartta svg { max-height: 120px; }

/* Vertailukortin tunnusluvut: tiivis lista ilman palkkeja. */
.vertailu-luvut {
  list-style: none;
  margin: 0.2rem 0 0;
  padding: 0;
  font-family: var(--font-type);
  font-size: 0.74rem;
  color: rgba(70, 51, 31, 0.9);
}

.vertailu-luvut li { display: flex; justify-content: space-between; gap: 0.4rem; }
.vertailu-luku-nimio { opacity: 0.7; }

.vertailu-muuta { margin-left: auto; }

/*
 * ============ Maaosion aloitussivu (js/packs/maakartat.js) ============
 *
 * Iso korkokartta kelluu oikealle ja maaosaston sisältö (tunnusluvut,
 * tervehdykset, esittely) kiertää sen vasemmalta; uutiset ja mediarivi
 * tulevat kartan alle koko leveydeltä (omistajan taittotoive 7.8.2026).
 * #arrival-maa siirtyy tälle sivulle etusivulta — ks. piirraMaaEtusivu.
 */

/*
 * Liitelinkki päiväysrivillä ("Suomi-liite", omistajan taitto-ohje
 * 9.8.2026): sama rivi kuin päiväys, oikeaan reunaan viivojen
 * väliin tasattuna. Rivi itse on position: relative -ankkuri.
 */
.dialog button.maa-linkki {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  border: 0;
  /* Yleisen nappisäännön käsinpiirretty kulmapyöristys kaartaisi
   * alaviivan ylös vasemmalta — linkin viiva on suora. */
  border-radius: 0;
  background: none;
  padding: 0.1rem 0;
  min-height: 0;
  font-family: var(--font-type);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.85);
  border-bottom: 1px solid rgba(70, 51, 31, 0.45);
  cursor: pointer;
}

.dialog button.maa-linkki:hover:not(:disabled) {
  background: none;
  color: #16130f;
  border-bottom-color: #16130f;
}

/*
 * Kapealla ruudulla keskitetty päiväys ja oikean reunan liitelinkki
 * osuivat päällekkäin (omistajan havainto 9.8.2026, Ateena
 * iPhonella). Kun linkki on rivillä, päiväys siirtyy vasempaan
 * reunaan ja maan nimi jää pois — sama maa lukee linkissä heti
 * vieressä ("KREIKKA-LIITE"), joten tieto ei katoa. Ilman linkkiä
 * rivi pysyy keskitettynä entiseen tapaan.
 */
@media (max-width: 699px) {
  .lehti-alarivi:has(button.maa-linkki:not([hidden])) {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem;
    text-align: left;
  }

  .lehti-alarivi:has(button.maa-linkki:not([hidden])) .pvm-maa { display: none; }

  .lehti-alarivi:has(button.maa-linkki:not([hidden])) button.maa-linkki {
    position: static;
    transform: none;
    flex: none;
  }
}

.maakartta-kehys {
  float: right;
  width: min(58%, 340px);
  margin: 0.15rem 0 0.6rem 1rem;
}

/*
 * MAAN ETUSIVUN KARTTA ISOMMAKSI (omistajan palaute 21.8.2026:
 * "kartat etusivulla saisi olla isompi").
 *
 * Kiinteä 340 pikselin katto teki kartasta leveällä ruudulla sivun
 * sivuhuomion, vaikka se on koko sivun pääkuva. Katto on nyt kartan
 * OMASSA kuvasuhteessa: kehys ottaa palstasta niin paljon leveyttä
 * kuin --maakartta-katto sallii korkeutta, mutta enintään 58 %.
 * Pystymalli (Iso-Britannia) ei siis valu sivun mitan yli ja
 * neliömäinen saa koko palstan. Suhteen kertoo piirto kuvan
 * latauduttua (--maakartta-suhde, piirraMaaEtusivu); siihen asti
 * oletusarvo antaa kehykselle täyden 58 %:n leveyden, ja kehys on
 * joka tapauksessa tyhjä ennen kuin kuva on ladattu.
 *
 * Kuvaa ei rajata eikä venytetä: kehys myötäilee kuvasuhdetta, ja
 * kuva täyttää kehyksen entiseen tapaan (width: 100 %). Lähderivi
 * pysyy kartan alla kehyksen sisällä.
 *
 * VAIN LEVEÄLLÄ RUUDULLA (≥ 900 px). Sitä kapeammalla kelluva kartta
 * pysyy entisessä 340 pikselissään: siellä palstaa ei ole varaa antaa
 * pois, ja leveämpi kartta kaventaisi perustietolaatikon niin, että
 * sen sijoitusluvut jäisivät kartan alle. Alle 560 px:n täysleveä
 * kartta on oma sääntönsä alempana.
 *
 * Tämä koskee vain maan etusivua — kaupunkilehden kohdekartta ja
 * zoomattava karttaikkuna käyttävät samoja luokkia omilla mitoillaan.
 */
@media (min-width: 900px) {
  .maa-etusivu .maakartta-kehys {
    --maakartta-katto: min(72vh, 660px);
    /* Oletussuhde ennen latausta: leveä, eli täydet 58 %. */
    --maakartta-suhde: 1.6;
    width: min(58%, calc(var(--maakartta-katto) * var(--maakartta-suhde)));
    margin: 0.15rem 0 0.7rem 1.4rem;
  }
}

/*
 * Pitkulainen kartta (Turkki, suhde ≥ 1,6) ei kellu lainkaan: sen
 * viereen jäisi vain kapea tekstisuikale, ja korkeuskatolla se jäisi
 * naurettavan matalaksi. Se saa oman täysleveän lohkonsa tekstin
 * yllä — sama taitto kuin kapealla ruudulla. Luokan antaa piirto
 * kuvan latauduttua, kuten pystykuvan .pysty nostoissa.
 *
 * Tämä sääntö on media-ehtojen ulkopuolella tarkoituksella: myös
 * tabletin levyisellä ruudulla pitkulainen kartta on parempi
 * täysleveänä kuin 340 pikselin suikaleena tekstin vieressä.
 */
.maa-etusivu .maakartta-kehys.kartta-levea {
  float: none;
  width: 100%;
  margin: 0.15rem 0 0.8rem;
}

/*
 * MAAN KARTTA AUKEAA KOKORUUDULLE (omistajan tilaus 21.8.2026: "maan
 * kartta saisi olla klikattavissa koko näytölle"). Sama ele ja sama
 * katselin kuin kaupunkilehden kohdekartassa; kohdistin kertoo sen
 * ennen napautusta. Luokan antaa piirto (js/maalehti.js).
 */
.maakartta-kehys.kartta-avattava { cursor: zoom-in; }

/* Pisteet asemoidaan prosentteina KUVAN päälle, siksi oma kotelo,
 * jossa ei ole muuta kuin kuva (lähderivi venyttäisi pohjaa).
 * Kotelo on myös kokoruutuvihjeen sijoituskehys: lappu kuuluu kuvan
 * kulmaan eikä lähderivin päälle. */
.maakartta-kotelo { position: relative; }

.maakartta-kotelo img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 2px;
}

.maakartta-kehys .lahde {
  margin: 0.25rem 0 0;
  font-family: var(--font-type);
  font-size: 0.62rem;
  color: rgba(90, 74, 51, 0.75);
}

/*
 * MITTAKAAVAJANA kohdekartan vasempaan alakulmaan.
 *
 * Piirretty kuten paperikartan jana eikä kuten käyttöliittymän
 * kontrolli: ohut vaakaviiva, päissä pystyviivat ja niiden yllä
 * pieni teksti. Viivat ovat elementin omia reunoja (border), joten
 * janassa ei ole yhtään ylimääräistä solmua.
 *
 * Väri on kartan mustetta läpikuultavana ja alla on vaalea kaista,
 * jotta jana erottuu sekä vaalealta paperilta että tummalta
 * vedeltä — Dubain jana osuu lahdelmaan, Venetsian laguuniin.
 */
.kartta-mittajana {
  position: absolute;
  left: 3.2%;
  bottom: 5%;
  height: 6px;
  border: 1px solid rgba(44, 35, 24, 0.85);
  border-top: 0;
  background: linear-gradient(rgba(247, 240, 222, 0) 40%, rgba(247, 240, 222, 0.55) 40%);
  pointer-events: none;
}

.kartta-mittajana-teksti {
  position: absolute;
  left: 50%;
  bottom: calc(100% + 1px);
  transform: translateX(-50%);
  padding: 0 3px;
  font-family: var(--font-type);
  font-size: 0.58rem;
  line-height: 1.1;
  white-space: nowrap;
  color: rgba(44, 35, 24, 0.9);
  background: rgba(247, 240, 222, 0.72);
  border-radius: 2px;
}

/* Kaupunkipiste: musteen värinen täplä, pääkaupunki kullattuna ja
 * rengastettuna kuten pelilaudan kohdekaupunki. */
.maakartta-piste {
  position: absolute;
  width: 9px;
  height: 9px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: #2c2318;
  border: 1.5px solid #f7efdc;
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
  /* iOS maalaa napautuskorostuksen koko napin laatikolle — leikatulla
   * piirroksella se näkyi umpinaisena neliönä kuvan takana (omistajan
   * havainto 15.8.2026). Bodyn estosääntö ei periydy napeille. */
  -webkit-tap-highlight-color: transparent;
}

.maakartta-piste.paa {
  width: 12px;
  height: 12px;
  background: #c69e52;
  border-color: #2c2318;
}

.maakartta-nimi {
  position: absolute;
  left: calc(100% + 4px);
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-type);
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: #16130f;
  /* Nimi luettavaksi vuoriston päälläkin: hento paperinvärinen hehku. */
  text-shadow:
    0 0 3px rgba(247, 239, 220, 0.95),
    0 0 6px rgba(247, 239, 220, 0.9);
}

.maakartta-piste.paa .maakartta-nimi { font-weight: 700; }

/* Itäreunan kaupungit: nimi aukeaa pisteestä länteen. */
.maakartta-piste.nimi-vasen .maakartta-nimi {
  left: auto;
  right: calc(100% + 4px);
}

/* Maaosasto asuu tällä sivulla ilman etusivun palstaviivaa, ja
 * otsikko sekä minikartta jäävät pois: sivun otsikko kertoo maan ja
 * iso korkokartta korvaa ääriviivakartan. Lehtitaiton osastoviiva ja
 * kahden palstan grid (.dialog.lehti-säännöt) kumotaan — kellutus
 * hoitaa taiton, ja grid katkaisisi tekstin kierron kartan ympäri. */
.dialog.lehti .maa-etusivu .arrival-maa,
.maa-etusivu .arrival-maa {
  display: block;
  border-left: 0;
  border-top: 0;
  padding-left: 0;
  padding-top: 0;
  margin: 0;
}

/* Pääkirjoituksen kaksi palstaa eivät sovi kartan kiertoon. */
.dialog.lehti .maa-etusivu #arrival-maa-intro {
  columns: auto;
  column-rule: none;
}

/*
 * Täysleveän kartan alla teksti EI kierrä mitään, joten pääkirjoitus
 * saa lehtipalstansa takaisin: 888 pikselin rivi olisi toistasataa
 * merkkiä pitkä eikä sitä lue kukaan. Sama mitta kuin muilla
 * lehtisivuilla (@media 700px, #arrival-maa-intro).
 */
@media (min-width: 700px) {
  .dialog.lehti .maa-etusivu:has(.maakartta-kehys.kartta-levea) #arrival-maa-intro {
    columns: 2;
    column-gap: 2.2rem;
    column-rule: 1px solid rgba(70, 51, 31, 0.25);
  }
}

.maa-etusivu .arrival-maa-rivi,
.maa-etusivu .arrival-maa-kartta { display: none; }

/* Esittely leipätekstin kokoon — sivulla se on pääteksti, ei palsta. */
.maa-etusivu .arrival-intro {
  font-size: 1.02rem;
  line-height: 1.55;
}

/* Uutiset ja mediarivi kartan alle koko leveydelle. */
.maa-etusivu .maa-oikea {
  clear: both;
  padding-top: 0.6rem;
  margin-top: 0.4rem;
  border-top: 1px dashed rgba(70, 51, 31, 0.35);
}

/* Kapealla ruudulla kartta ei kellu vaan on oma täysleveä lohkonsa
 * tekstin yllä — kierto kävisi ahtaaksi. */
@media (max-width: 560px) {
  .maakartta-kehys {
    float: none;
    width: 100%;
    margin: 0.15rem 0 0.7rem;
  }
}

/*
 * ============ Sivuparannukset 7.8.2026 ============
 * Lippu maan aihesivujen otsikossa, ajankohta nostoriveillä,
 * maa-etusivun kuvanosto ja kaupunkisivun kohdekartta.
 */

/* Maan lippu aihesivun otsikossa ("Saksan historia" -> "Historia" +
 * lippu). Lippu kulkee tekstin perässä rivin sisällä ja keskittyy
 * otsikon kanssa (omistaja 14.8.2026: "lipun voisi keskittää otsikon
 * kanssa") — oikea reuna vapautui lukijan kaiuttimelle. */
.wiki-kategoria .aihe-nimi .aihe-lippu {
  display: inline-block;
  vertical-align: -0.12em;
  margin-left: 0.45em;
  height: 1.05em;
  width: auto;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* Lipun tarina (omistajan tilaus 15.8.2026): otsikkorivin lippu on
 * nappi, ja ikkunassa iso lippu, historia ja muut asut. */
.dialog .aihe-lippu-nappi {
  display: inline;
  /* Pehmuste + vastamarginaali kasvattavat osuma-alueen sormen
   * kokoiseksi asettelua muuttamatta (omistajan havainto 15.8.2026:
   * lippua joutui painamaan kahdesti — napautus osui napin viereen). */
  padding: 0.55rem;
  margin: -0.55rem;
  min-height: 0;
  border: none;
  background: none;
  cursor: pointer;
}

dialog.lippu-ikkuna {
  border: none;
  padding: 1rem;
  background: transparent;
  max-width: none;
  max-height: none;
  overflow: visible;
}

dialog.lippu-ikkuna::backdrop { background: rgba(20, 16, 10, 0.55); }
dialog.lippu-ikkuna:focus,
dialog.lippu-ikkuna:focus-visible { outline: none; }

/*
 * KEHYS JA VIERITYSKOTELO ERIKSEEN (omistajan iPad-havainto 18.8.2026:
 * "läpinäkyvyys bugi vieläkin" — Ranskan lippuikkuna tarkennustilassa).
 *
 * VIKA. Tarkennus sumentaa muun kortin (filter: blur(3px)). Filter
 * nostaa elementin omalle piirtokerrokselleen, ja WebKit ei leikkaa
 * omalle kerrokselle noussutta LASTA esi-isän pyöristettyyn
 * vierityskehykseen — Chromium leikkaa. Mitattu iPad-emuloinnilla:
 * tarkennustilassa sumennettu iso lippu on vieritetty kortin näkyvän
 * alueen yläpuolelle (esim. Saksa vaakatilassa y = −195…48, kortti
 * alkaa y = 142). Leikkaamattomana se piirtyy kortin pyöristetyn
 * yläreunan yli suorakulmaisin kulmin, ja blurin läpikuultava
 * halo näkyy vaaleana kaistana reunoilla. Juuri sen omistaja näki.
 *
 * KORJAUS. Yksi elementti ei voi sekä heittää varjoa ULOS että
 * leikata sisältöä tiukasti SISÄÄN: maski tai clip-path, joka pakottaa
 * leikkauksen myös kerroslapsille, söisi samalla laatikkovarjon (se
 * piirtyy reunalaatikon ulkopuolelle). Siksi tehtävät on jaettu:
 *
 *   .lippu-kehys  — paperi, reunaviiva, pyöristys, varjo, mitat
 *   .lippu-kortti — vieritys, pehmusteet ja LEIKKAUS (clip-path)
 *
 * clip-path rajaa piirtoalueen elementin oman geometrian mukaan, ei
 * pelkkänä overflow-vihjeenä, joten WebKit soveltaa sen myös
 * kerroslapsiin. Kehyksellä ei ole leikkausta, joten varjo säilyy.
 *
 * ULKOASU. Chromiumissa kuvat ovat pikselilleen samat kuin ennen —
 * paitsi yhdessä kohdassa, ja se on korjaus: kun kortin sisältö
 * ylittää 66vh:n (esim. Saksa), vanha rakenne piirsi reunaviivan
 * TUMMANA. Vieritettävän elementin tausta meni omalle kerrokselleen
 * eikä siis reunan alle, jolloin puoliläpikuultava reunaväri
 * (rgba(122, 85, 20, 0.32)) sekoittui kortin sijasta tummaan
 * taustaan. Nyt reuna on kehyksen oma ja aina samanvärinen — sama
 * vaalea viiva kuin lyhyillä korteilla on aina ollut.
 */
.lippu-kehys {
  width: min(27rem, calc(100vw - 1.4rem));
  /* Kaksi kolmasosaa ruudun korkeudesta (omistajan tilaus 15.8.2026:
   * "Tee pop-up-ikkunasta kaksi kolmasosaa korkuinen") — loppu
   * vierittyy kortin sisällä. */
  max-height: 66vh;
  display: flex;
  /* Kehyksen oma overflow ei leikkaa sen omaa varjoa (varjo ei ole
   * sisältöä), joten tämä on ilmainen toinen pidäke sisällölle. */
  overflow: hidden;
  border: 1px solid rgba(122, 85, 20, 0.32);
  border-radius: var(--radius);
  background-color: #f5f0e2;
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
}

.lippu-kortti {
  /* Tarkennetun versiolipun suurennoskerroin YHDESSÄ PAIKASSA: sekä
   * transform että js/liput.js:n vaakasiirron laskenta lukevat tämän,
   * jottei kerroin voi karata eri arvoihin. */
  --lippu-tarkennus-skaala: 1.7;
  width: 100%;
  /* min-height: 0 sallii vierityskotelon kutistua kehyksen 66vh:n
   * sisään; ilman sitä flex-lapsen vähimmäiskorkeus on sen sisältö,
   * eikä vieritystä syntyisi lainkaan. */
  min-height: 0;
  overflow-y: auto;
  padding: 0.7rem 0.8rem 0.8rem;
  /* Sisäkaari on kehyksen kaari miinus reunaviiva. */
  border-radius: calc(var(--radius) - 1px);
  -webkit-clip-path: inset(0 round calc(var(--radius) - 1px));
  clip-path: inset(0 round calc(var(--radius) - 1px));
  color: #211d18;
  font-family: var(--font-luku);
  text-shadow: none;
}

.lippu-ylarivi {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.lippu-otsikko {
  margin: 0;
  font-family: var(--font-type);
  font-size: 1.15rem;
  letter-spacing: 0.05em;
  color: #46331f;
}

.lippu-kortti .lippu-sulje {
  min-height: 0;
  padding: 0 0.35rem;
  border: none;
  background: none;
  color: rgba(70, 51, 31, 0.75);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

/* Iso lippu kortin levyisenä mutta pehmusteiden SISÄLLÄ (omistajan
 * palautteet 15.8.2026: ensin "Iso kuva isommaksi" — kortti leveni
 * 24 → 27 remiin — ja sitten "lippu saisi olla vähän pienemmällä,
 * jotta ei osu marginaaleihin"). */
.lippu-iso {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 3px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  background: rgba(255, 255, 255, 0.6);
}

/* Symboliikka boldatuin otsikoin (sininen =, valkoinen =, …). */
.lippu-symbolit { margin: 0.55rem 0 0.15rem; }

.lippu-symboli {
  margin: 0.18rem 0;
  font-size: 0.86rem;
  line-height: 1.45;
}

.lippu-symboli strong {
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  color: #46331f;
}

/* Vaakunat ja tunnukset: kuva vasemmalla, nimi + selite oikealla.
 * Rivi on nappi (napautus tarkentaa), joten nappioletukset nollataan. */
.lippu-tunnukset {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.4rem;
}

.lippu-kortti .lippu-tunnus {
  display: flex;
  gap: 0.65rem;
  align-items: flex-start;
  min-height: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  /*
   * OMA LÄPIKUULTAMATON PAPERI, EI background: none (omistajan
   * havainto 16.8.2026: "Vaakunat näkyvät vielä välillä väärin ja
   * välillä oikein"). Appearance-nollaus ei riittänyt: sumennus-
   * siirtymä (filter) nostaa napin omalle piirtokerrokselle, ja
   * WebKit lyö silloin ajoittain reiän kortin multiply-sekoitettuun
   * paperiin — napin alta paistoi dokumentin tumma pohja
   * (color-scheme: dark). Läpinäkyvä nappi ei voi luottaa takanaan
   * olevaan paperiin, joten se maalaa oman: sama väri ja rakeisuus
   * kuin kortissa, jolloin levy ei erotu — ja reikä ei näy koskaan.
   */
  background-color: var(--arkki-paperi, #f5f0e2);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  -webkit-appearance: none;
  appearance: none;
  /*
   * iOS:n napautuskorostus pois myös napin LAPSILTA (omistajan
   * bugiraportti 23.8.2026: syvätyn vaakunan taakse jäi ruskea
   * laatikko, joka katosi napauttamalla sivusta). body-tason
   * nollaus ei periydy img-elementtiin, joten iPad maalasi oman
   * tumman korostuksensa kuvan päälle ja se jäi näkyviin niin
   * kauan kuin kosketus "osoitti" kuvaa.
   */
  -webkit-tap-highlight-color: transparent;
  font: inherit;
  text-align: left;
  color: inherit;
  cursor: pointer;
}

/*
 * TARKENNUS (omistajan tilaus 15.8.2026): napautettu versiolippu
 * tai vaakuna kasvaa paikallaan noin kaksinkertaiseksi ja sen
 * selite näkyy terävänä; MUU kortti sumenee — ei erillistä
 * ikkunaa. Sumennus tehdään sisällölle (filter), koska kortti on
 * vierityskontti eikä kiinteä peittokerros kata sen koko sisältöä.
 */
/* Sumennus häivyttyy pehmeästi (omistajan tilaus 15.8.2026:
 * "Lippujen ja vaakunoiden suurennoksen voisi animoida"). */
.lippu-kortti > *,
.lippu-kortti .lippu-tunnukset > * { transition: filter 220ms ease; }

/* Versioliput kasvavat PAIKALLAAN transformilla (omistajan tilaus
 * 16.8.2026: "asettelu saisi pysyä paikoillaan kun yksi lippu
 * suurenee") — transform ei muuta taittoa, joten naapurit eivät
 * liiku. */
.lippu-kortti .lippu-versiot > * {
  transition: filter 220ms ease, transform 200ms ease;
}

.lippu-kortti.tarkennus > :not(.terava-haara) { filter: blur(3px); }
.lippu-kortti.tarkennus .terava-haara > :not(.tarkennettu) { filter: blur(3px); }

/* Tarkennettu kasvaa paikalleen pienestä. */
@keyframes lippu-kasvu {
  from { transform: scale(0.55); opacity: 0.4; }
  to { transform: scale(1); opacity: 1; }
}

.lippu-tunnus.tarkennettu {
  animation: lippu-kasvu 240ms ease;
  transform-origin: center top;
}

@media (prefers-reduced-motion: reduce) {
  .lippu-tunnus.tarkennettu { animation: none; }
  .lippu-kortti > *,
  .lippu-kortti .lippu-versiot > *,
  .lippu-kortti .lippu-tunnukset > * { transition: none; }
}

/* Tarkennettu versio ILMAN taustalaatikkoa (omistajan palaute
 * 15.8.2026: "Suurenna lippu isommaksi ja ota taustalaatikko
 * pois") — vain lippu ja tekstit terävinä sumean päällä. */
.lippu-kortti .lippu-versio.tarkennettu {
  position: relative;
  z-index: 6;
  /*
   * VAAKASIIRTO ENNEN SUURENNUSTA (omistajan bugiraportti 28.8.2026:
   * "lippuikkunan suurennoksen kuvateksti leikkautuu vasemmalta").
   *
   * Laatat ovat ruudukossa ja kasvavat KESKIPISTEENSÄ ympäri, joten
   * reunimmaisen sarakkeen laatta — ja etenkin sen laattaa leveämpi
   * selite — venyy kortin näkyvän alueen ulkopuolelle. Kortti leikkaa
   * (clip-path), joten teksti katkesi kesken sanan. js/liput.js mittaa
   * ylityksen ja kirjoittaa tarvittavan siirron tähän muuttujaan;
   * oletus 0 pitää keskisarakkeet ennallaan. Siirto on transform-
   * listan ENSIMMÄINEN osa, joten se on skaalaamattomia CSS-pikseleitä
   * eikä siihen tarvitse laskea 1,7-kerrointa.
   */
  transform: translateX(var(--tarkennus-x, 0px)) scale(var(--lippu-tarkennus-skaala));
  transform-origin: center;
  /* Paperi pysyy läpikuultamattomana myös tarkennettuna: transform-
   * kerros on juuri se paikka, jossa WebKitin reikä syntyy herkimmin.
   * Kortin värinen levy ei erotu sumean paperin päällä laatikoksi. */
  background-color: var(--arkki-paperi, #f5f0e2);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  border-color: transparent;
}

.lippu-versio.tarkennettu .lippu-versio-nimi {
  padding: 0.1rem 0.3rem;
  background: var(--arkki-paperi, #f5f0e2);
  border-radius: 3px;
  align-self: center;
}

.lippu-versio-selite { display: none; }

/* Selite kelluu laatan alla absoluuttisena, jottei sen ilmestyminen
 * muuta laatan kokoa (asettelu pysyy paikallaan). Fontti on pieni,
 * koska koko laatta on skaalattu 1,7-kertaiseksi. */
.lippu-versio.tarkennettu .lippu-versio-selite {
  display: block;
  position: absolute;
  top: calc(100% + 0.15rem);
  left: 50%;
  transform: translateX(-50%);
  /*
   * Selite on leveämpi kuin laatta, mutta se EI saa olla leveämpi kuin
   * kortin näkyvä alue: vaakasiirto voi työntää selitteen sisään vain
   * jos se ylipäätään mahtuu sinne. Yläraja on kortin sisäleveys
   * (kehys min(27rem, 100vw − 1.4rem) miinus pehmusteet 1.6rem ja
   * vieritysvarat 1.25rem) jaettuna suurennoskertoimella 1,7 — selite
   * elää skaalatun laatan koordinaatistossa. 390 ja 834 pikselin
   * ruuduilla 10rem voittaa, eli ulkoasu ei muutu; vasta noin 305 px
   * kapeammalla ruudulla raja puree.
   */
  width: min(10rem, calc((min(27rem, 100vw - 1.4rem) - 2.85rem) / 1.7));
  padding: 0.1rem 0.3rem 0.15rem;
  font-family: var(--font-luku);
  font-size: 0.55rem;
  line-height: 1.4;
  text-align: left;
  color: rgba(33, 29, 24, 0.92);
  background: var(--arkki-paperi, #f5f0e2);
  border-radius: 3px;
}

/*
 * Tarkennettuna PELKKÄ vaakuna isona, selite sen alla (omistajan
 * tilaus 16.8.2026: "vaakunoissa voisi näkyä pelkkä vaakuna ja
 * vielä isompana"). v760:n pergamenttilevy poistui — tumman
 * laatikon oikea syy oli Safarin natiivi nappimaalaus, joka on nyt
 * nollattu appearance: nonella.
 */
.lippu-tunnus.tarkennettu {
  flex-direction: column;
  align-items: center;
}

.lippu-tunnus.tarkennettu .lippu-tunnus-kuva {
  width: min(64%, 13rem);
}

.lippu-tunnus.tarkennettu .lippu-tunnus-teksti {
  padding: 0.25rem 0.4rem;
  background: var(--arkki-paperi, #f5f0e2);
  border-radius: 4px;
}

/* Sama nollaus napin lapsille — tap-highlight ei periydy. */
.lippu-kortti .lippu-tunnus *,
.lippu-kortti .lippu-versiot * { -webkit-tap-highlight-color: transparent; }

.lippu-tunnus-kuva { transition: width 160ms ease; }

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

.lippu-tunnus-kuva {
  width: 4.2rem;
  height: auto;
  flex: none;
}

.lippu-tunnus-nimi {
  margin: 0;
  font-family: var(--font-type);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  color: #46331f;
}

.lippu-tunnus-selite {
  margin: 0.15rem 0 0;
  font-size: 0.83rem;
  line-height: 1.45;
  color: rgba(33, 29, 24, 0.88);
}

.lippu-valinta {
  margin: 0.45rem 0 0.1rem;
  font-family: var(--font-type);
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  color: #46331f;
}

.lippu-valinta-selite,
.lippu-kappale {
  margin: 0 0 0.5rem;
  font-size: 0.86rem;
  line-height: 1.45;
  color: rgba(33, 29, 24, 0.9);
}

.lippu-versiot-otsikko {
  margin: 0.6rem 0 0.35rem;
  font-family: var(--font-type);
  font-size: 0.8rem;
  letter-spacing: 0.05em;
  color: #46331f;
}

.lippu-versiot {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.lippu-kortti .lippu-versio {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  align-items: stretch;
  min-height: 0;
  padding: 0.3rem;
  border: 1px solid rgba(70, 51, 31, 0.25);
  border-radius: 6px;
  /* Läpikuultamaton (entinen rgba-kuulto laskettu paperia vasten):
   * kuultava tausta näyttäisi WebKitin kerrosreiän läpi tumman
   * pohjan (sama vika kuin tunnusnapissa, ks. kommentti yllä). */
  background: #faf7ec;
  /* Sama appearance-nollaus kuin tunnusnapeilla (Safari). */
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}

.lippu-kortti .lippu-versio[aria-pressed="true"] {
  border-color: rgba(150, 116, 52, 0.75);
  background: #fef5de;
}

.lippu-versio-kuva {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(70, 51, 31, 0.3);
  border-radius: 2px;
}

.lippu-versio-nimi {
  font-family: var(--font-luku);
  font-size: 0.68rem;
  line-height: 1.25;
  text-align: center;
  color: rgba(33, 29, 24, 0.85);
}

/* Kehittäjän liitteiden valmiuschippi osion otsikossa (omistajan
 * tilaus 15.8.2026: "pienet värilliset tagit sen mukaan, onko kohta
 * valmis vai työstö vielä kesken"). */
.wiki-kategoria .aihe-nimi .kehittaja-tagi {
  display: inline-block;
  vertical-align: 0.15em;
  margin-left: 0.5em;
  padding: 0.1em 0.55em;
  border-radius: 999px;
  font-size: 0.42em;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-family: system-ui, sans-serif;
}

.wiki-kategoria .aihe-nimi .kehittaja-tagi.valmis {
  background: #e2efdc;
  color: #2c5e2a;
  border: 1px solid #8fb886;
}

.wiki-kategoria .aihe-nimi .kehittaja-tagi.kesken {
  background: #f7ecd2;
  color: #7a5a12;
  border: 1px solid #d4b96a;
}

/* Kehittäjän liitteiden taitto: yksi palsta, ei lehden koristeita
 * (omistaja 15.8.2026: "Poista palstat raamatun taitosta. Ei tarvitse
 * näyttää lehdeltä."). Anfangi estetään jo piirrossa (piirraLeipa);
 * tässä perutaan palstat ja lihavoitu aloitus. */
.wiki-kategoria.yksipalsta .wiki-nosto .leipa {
  columns: 1;
  column-rule: none;
}

/* Sama sääntö koskee kainalokuvaa (21.8.2026): kelluva kuva on
 * lehden taittoa, ja liitteessä kuva saa olla siinä missä on. */
.wiki-kategoria.yksipalsta .wiki-nosto .kuvakehys {
  float: none;
  width: 100%;
  margin: 0 auto 0.85rem;
}

.wiki-kategoria.yksipalsta .leipa-aloitus {
  font-weight: inherit;
}

/* ------------------------------------------------------------------ *
 * TILASTOT-LEHTI (kehittäjän liite, omistajan tilaus 18.8.2026)
 *
 * Leveä vetolaatikkotaulu: manner → maat → kaupungit. Taulu saa olla
 * leveämpi kuin ruutu, mutta VAIN omassa kotelossaan — sivu itse ei
 * saa koskaan vierittyä vaakaan (sama sääntö kuin poistuneen
 * työhuonesivuston tauluissa, mitattu 390 px ruudulla).
 *
 * Väritys on kevyt tarkoituksella (omistajan tarkennus 18.8.2026:
 * "hillityt sävyt ... ei kirkuvia liikennevaloja"). Sävyt ovat samat
 * kuin Raamatun valmiuschipeissä, joten kehittäjän liitteet puhuvat
 * yhtä väriä.
 * ------------------------------------------------------------------ */

/*
 * Taulu vierii omassa kotelossaan MOLEMPIIN suuntiin (omistajan tilaus
 * 23.8.2026: "tee otsikkorivistä pysyvästi näkyvä scrollatessa").
 * Korkeusraja on se, joka tekee sticky-otsikosta ylipäätään
 * mahdollisen: ilman sitä kotelo ei vieri pystyssä, jolloin thead
 * kiinnittyisi koteloon joka ei liiku, ja pystyvieritys tapahtuisi
 * jossain esivanhemmassa otsikon mukana. Lyhyt taulu ei yllä rajaan
 * eikä siis muutu.
 */
.tk-vieri {
  overflow-x: auto;
  overflow-y: auto;
  max-height: 70vh;
  -webkit-overflow-scrolling: touch;
  margin: 0 0 0.8rem;
}

.tk-taulu {
  border-collapse: collapse;
  width: max-content;
  min-width: 100%;
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
}

.tk-taulu th,
.tk-taulu td {
  padding: 0.28rem 0.4rem;
  border-bottom: 1px solid rgba(70, 51, 31, 0.16);
  text-align: left;
  vertical-align: top;
}

/*
 * Otsikkorivi jää paikalleen pystyvierityksessä, kuten nimisarake jää
 * vaakavierityksessä. HUOM aiempi vika (omistajan kaappaus 18.8.2026):
 * sticky-otsikko nosti solut omalle WebKit-kerrokselle ja osa
 * otsikoista katosi iPadilla vaakavierityksen aikana. Silloin
 * tk-vieri vieri vain vaakaan, joten top: 0 ei tarttunut mihinkään —
 * kerrosnosto tuli ilman mitään hyötyä. Nyt kotelolla on korkeusraja
 * ja se vierii myös pystyssä, joten otsikko tarttuu oikeasti. Sticky
 * tarvitsee peittävän taustan, muuten vierivä sisältö kuultaa läpi.
 */
.tk-taulu thead th {
  position: sticky;
  top: 0;
  z-index: 2;
  background: #f0e6cd;
  border-bottom: 1px solid rgba(70, 51, 31, 0.4);
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.tk-taulu .tk-num {
  text-align: center;
  white-space: nowrap;
}

/*
 * Nimisarake jää paikalleen vaakavierityksessä. Ilman tätä oikeanpuolen
 * sarakkeissa (Maalehti, Lippu, Radio) ei näy mistä rivistä on kyse —
 * juuri se teki leveästä taulusta lukukelvottoman ensimmäisessä
 * kaappauksessa. Sticky-solu tarvitsee peittävän taustan, muuten
 * vierivä sisältö kuultaa läpi.
 */
.tk-taulu .tk-nimi {
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 11rem;
  max-width: 17rem;
  background: #f5f0e2;
  box-shadow: 1px 0 0 rgba(70, 51, 31, 0.14);
}

.tk-taulu thead th.tk-nimi {
  z-index: 3;
  background: #f0e6cd;
}

.tk-manner > .tk-nimi { background: #f2e7ca; }
.tk-maa > .tk-nimi { background: #f4ecd9; }

/* Sisennys kertoo tason: manner vasemmassa laidassa, kaupunki syvimmällä. */
.tk-taulu .tk-taso-maa { padding-left: 1.1rem; }
.tk-taulu .tk-taso-kaupunki { padding-left: 2.1rem; }

.tk-nimi-sisus { display: flex; gap: 0.3rem; align-items: flex-start; }
.tk-nimi-teksti { flex: 1 1 auto; min-width: 0; }
.tk-nimi-rivi { display: flex; gap: 0.4rem; align-items: baseline; justify-content: space-between; }
.tk-nimi-rivi b { font-weight: 600; }

.tk-nuoli {
  flex: 0 0 auto;
  color: rgba(70, 51, 31, 0.6);
  transition: transform 0.15s ease;
}

.tk-rivi.auki .tk-nuoli { transform: rotate(90deg); }

.tk-manner > .tk-nimi b { font-size: 0.92rem; }
.tk-manner { background: rgba(217, 161, 59, 0.1); }
.tk-maa { background: rgba(217, 161, 59, 0.04); }

.tk-manner,
.tk-maa { cursor: pointer; }

.tk-manner:focus-visible,
.tk-maa:focus-visible { outline: 2px solid var(--accent-dark); outline-offset: -2px; }

.tk-osuus {
  flex: 0 0 auto;
  font-size: 0.66rem;
  color: rgba(70, 51, 31, 0.7);
  font-variant-numeric: tabular-nums;
}

.tk-lisa {
  margin-top: 0.12rem;
  font-size: 0.62rem;
  line-height: 1.3;
  color: rgba(70, 51, 31, 0.62);
}

.tk-palkki {
  height: 3px;
  margin: 0.18rem 0 0;
  border-radius: 999px;
  background: rgba(70, 51, 31, 0.14);
  overflow: hidden;
}

.tk-palkki-tayte {
  height: 100%;
  background: #8fb886;
}

/* Kolme sävyä: valmis, kesken, puuttuu. Neljäs (tk-tyhja) on rivi,
   jota sarake ei koske lainkaan — se jää kokonaan haaleaksi. */
.tk-valmis { background: #e2efdc; color: #2c5e2a; }
.tk-kesken { background: #f7ecd2; color: #7a5a12; }
.tk-puuttuu { color: rgba(70, 51, 31, 0.45); }

/*
 * Tuoreusmerkinnät (omistaja 20.8.2026): vasta valmistuneen kaupungin
 * nimipohja vihreänä versionumeroineen, työn alla olevan keltaisena.
 * Sävyt ovat samat kuin solujen valmis/kesken-luokissa, jotta taulu
 * pysyy yhtenä palettina.
 */
/*
 * VIITEKUVILLA ANKKUROIDUT HEROT (omistajan tilaus 24.8.2026).
 * Oranssi erottuu valmiusasteikon vihreästä ja harmaasta, koska se ei
 * kerro valmiudesta vaan siitä, MITEN kuva on tehty: onko generointi
 * ankkuroitu kohteen omiin Commons-valokuviin. Täysi tausta = koko erä
 * ankkuroitu, pelkkä ääriviiva = osa kuvista. Sävy on samaa hillittyä
 * sarjaa kuin muut (omistaja 18.8.2026: "ei kirkuvia liikennevaloja").
 */
.tk-taulu td.tk-viite-taysi {
  background: #f6e0c4;
  box-shadow: inset 0 0 0 1px rgba(160, 96, 24, 0.35);
}

.tk-taulu td.tk-viite-osa {
  box-shadow: inset 0 0 0 1px rgba(160, 96, 24, 0.5);
}

.tk-nimi.tk-tuore-valmis { background: #e2efdc; }
.tk-nimi.tk-tuore-tyossa { background: #f7ecd2; }
.tk-tuore-merkki {
  font-size: 0.72em;
  padding: 0.1em 0.5em;
  border-radius: 0.8em;
  background: rgba(255, 255, 255, 0.65);
  color: inherit;
  white-space: nowrap;
}
.tk-kaikki-nappi {
  font: inherit;
  font-size: 0.72em;
  padding: 0.15em 0.6em;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 0.8em;
  background: rgba(255, 255, 255, 0.5);
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}

/*
 * KIINTIÖPALKIT Tilastot-lehden viimeisellä sivulla (omistajan tilaus
 * 21.8.2026: "Siirrä alaosan tilastot tilasto lehdelle"). Palkit
 * piirrettiin ennen hampurilaisvalikkoon pienellä .palkki-*-tyylillä;
 * lehdessä ne saavat lukukelpoisemman koon ja saman pergamentti-
 * paletin kuin taulun muut palkit. Kapealla ruudulla yksi sarake,
 * leveämmällä siisti 2 × 2 — auto-fit venyttäisi työpöydällä kolmeen
 * sarakkeeseen ja jättäisi neljännen palkin yksin toiselle riville.
 */
.tk-kiintiot {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem 2rem;
  margin: 0.2rem 0 1.1rem;
}

@media (min-width: 30rem) {
  .tk-kiintiot { grid-template-columns: 1fr 1fr; }
}

.tk-kiintio { min-width: 0; }

.tk-kiintio-rivi {
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
  justify-content: space-between;
}

.tk-kiintio-nimi {
  font-family: var(--font-type);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.72);
}

.tk-kiintio-arvo {
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  color: rgba(70, 51, 31, 0.8);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tk-kiintio-ura {
  height: 7px;
  margin-top: 0.3rem;
  border-radius: 999px;
  background: rgba(70, 51, 31, 0.14);
  overflow: hidden;
}

.tk-kiintio-tayte {
  height: 100%;
  border-radius: 999px;
}

.tk-kiintio-tayte.vihrea { background: #6f9e57; }
.tk-kiintio-tayte.keltainen { background: #c6a23c; }
.tk-kiintio-tayte.punainen { background: #b0523c; }

.tk-kiintio-tyhja .tk-kiintio-arvo { color: rgba(70, 51, 31, 0.45); }

/* Tilannelehden tuoreet-chipit (omistaja 20.8.2026). */
.tuoreet { display: flex; flex-direction: column; gap: 0.5em; margin: 0 0 1em; }
.tuoreet-rivi { display: flex; flex-wrap: wrap; gap: 0.4em; align-items: baseline; }
.tuoreet-otsikko {
  font-size: 0.8em;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.7);
  margin-right: 0.3em;
}
.tuore-chip {
  font-size: 0.85em;
  padding: 0.2em 0.7em;
  border-radius: 1em;
  white-space: nowrap;
}
.tuore-chip.valmis { background: #e2efdc; color: #2c5e2a; }
.tuore-chip.tyossa { background: #f7ecd2; color: #7a5a12; }
.tk-tyhja { color: rgba(70, 51, 31, 0.28); }

.tk-ohjaus {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 0 0 0.6rem;
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
}

.tk-ohjaus-nimi {
  color: rgba(70, 51, 31, 0.7);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: 0.62rem;
}

.tk-vipu { display: flex; gap: 0.3rem; }

.tk-vipu-nappi {
  padding: 0.2rem 0.6rem;
  border: 1px solid rgba(70, 51, 31, 0.3);
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.tk-vipu-nappi[aria-pressed="true"] {
  border-color: rgba(150, 116, 52, 0.75);
  background: #f7ecd2;
  font-weight: 700;
}

.tk-selite {
  font-size: 0.68rem;
  line-height: 1.4;
  color: rgba(70, 51, 31, 0.68);
}

.tk-luvut .tk-nimi { min-width: 9rem; }

/* ------------------------------------------------------------------ *
 * MUSIIKKI-LEHTI (kehittäjän liite, omistajan tilaus 3.9.2026:
 * "kehittäjä hampurilaiseen voisi tehdä oman sivun taustamusiikeille,
 * jossa voisin käydä kuuntelemassa niitä")
 *
 * Rivilista, ei taulua: raitoja on parikymmentä ja jokainen tarvitsee
 * kaksi napautuskohdetta, joten sarakkeisiin ladottuna rivi menisi 390
 * px ruudulla rikki. Sävyt ovat Tilastot-lehden ja Raamatun chippien
 * omat, jotta kehittäjän liitteet puhuvat yhtä väriä.
 * ------------------------------------------------------------------ */

.mus-osasto {
  margin: 1.1rem 0 0.5rem;
  font-family: system-ui, sans-serif;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.7);
  border-bottom: 1px solid rgba(70, 51, 31, 0.18);
  padding-bottom: 0.25rem;
}

.mus-rivi {
  margin: 0 0 0.7rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid rgba(70, 51, 31, 0.14);
  border-radius: 3px;
  background: rgba(217, 161, 59, 0.05);
  font-family: system-ui, sans-serif;
}

/* Soiva raita erottuu listasta yhdellä silmäyksellä. */
.mus-rivi.soi {
  border-color: rgba(150, 116, 52, 0.75);
  background: #f7ecd2;
}

.mus-nimi {
  display: flex;
  gap: 0.5rem;
  align-items: baseline;
  justify-content: space-between;
  font-size: 0.85rem;
}

.mus-nimi b { font-weight: 600; }

.mus-tila {
  font-size: 0.66rem;
  white-space: nowrap;
  color: rgba(70, 51, 31, 0.55);
}

.mus-tila.olemassa { color: #2c5e2a; }
.mus-tila.puuttuu { color: #8a4b39; }

.mus-kaytto {
  margin: 0.25rem 0 0;
  font-size: 0.72rem;
  line-height: 1.45;
  color: rgba(70, 51, 31, 0.82);
}

/* Osoite katkeaa mistä tahansa: R2-polku on pitkä eikä saa venyttää
   sivua vaakaan (sama sääntö kuin Tilastot-lehden taulussa). */
.mus-polku {
  margin: 0.15rem 0 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.62rem;
  line-height: 1.35;
  color: rgba(70, 51, 31, 0.55);
  overflow-wrap: anywhere;
}

.mus-napit {
  display: flex;
  gap: 0.4rem;
  margin-top: 0.45rem;
}

.mus-napit .wiki-btn { font-size: 0.7rem; padding: 0.2rem 0.8rem; }

.mus-napit .wiki-btn[disabled] { opacity: 0.4; cursor: default; }

.mus-lahde,
.mus-huomio {
  margin: 0 0 0.7rem;
  font-family: system-ui, sans-serif;
  font-size: 0.68rem;
  line-height: 1.45;
  color: rgba(70, 51, 31, 0.68);
}

.mus-huomio {
  padding: 0.4rem 0.6rem;
  border-radius: 3px;
  background: #f7ecd2;
  color: #7a5a12;
}

.mus-sfx {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.5rem;
}

.mus-sfx-nappi {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.66rem;
  padding: 0.18rem 0.6rem;
}

.mus-sfx-nappi[disabled] { opacity: 0.4; cursor: default; }

/*
 * Numeroina-sivun avaava yleisluonnehdinta (omistajan palaute
 * 10.8.2026): datasta koottu 2–3 virkkeen luonnehdinta isolla ennen
 * käyriä — sivu alkaa tekstillä, ei suoraan ristikolla. Matalammat
 * käyrät (korkeus 106) tuovat rytmin ristikkoon ilman omaa sääntöä:
 * viewBox hoitaa mittasuhteen.
 */
.numeroina-ingressi {
  font-size: 1.18rem;
  line-height: 1.55;
  max-width: 40rem;
  margin: 0.2rem 0 0.35rem;
}

/*
 * Menovinkkisivun taitto (omistajan palaute 10.8.2026: "liian
 * listamainen... yksi iso kuva ja alustusteksti isommalla, listaa
 * voisi kaventaa"): johdanto on ingressi, avauskuva täyttää palstan
 * ja lista kapenee luettavaksi kaistaksi — sivu ei ole enää
 * tasapaksu pötkö.
 */
.vinkkisivu .johdanto {
  font-size: 1.16rem;
  line-height: 1.6;
  max-width: 40rem;
}

.vinkki-hero {
  margin: 0.9rem 0 1.2rem;
}

.vinkki-hero img {
  display: block;
  width: 100%;
  max-height: 20rem;
  object-fit: cover;
  border-radius: 6px;
  box-shadow: 0 2px 10px rgba(40, 28, 12, 0.25);
}

/*
 * Kuvateksti isolla, kreditti pienellä (omistajan palaute 10.8.2026:
 * "Kuvan kreditit pienemmällä ja isommalla kuvateksti").
 */
.vinkki-hero-teksti {
  margin-top: 0.35rem;
}

.vinkki-hero-selite {
  font-size: 0.98rem;
  line-height: 1.45;
}

/* Kreditti selitteen JATKEEKSI samalle riville (23.8.2026, ks.
 * "LÄHDERIVI KUVATEKSTIN JATKEEKSI"). Oikea tasaus lähti mukana: se
 * oli oman rivin tapa erottua, ja inline-virrassa se vain repisi
 * krediitin irti siitä lauseesta, jonka perään se kuuluu. */
.vinkki-hero .lahde {
  display: inline;
  margin: 0;
  font-size: 0.62rem;
  color: rgba(70, 51, 31, 0.68);
}

/*
 * Lista kulkee palstan levyisenä pienen sisennyksen takana (omistajan
 * tilaus 22.8.2026: "pienennä linkkien sisennystä").
 *
 * Ennen tässä oli 38 rem:n katto ja `margin-left: auto`, jolloin
 * sisennys ei ollut sisennys vaan jäännös: 888 pikselin arkissa lista
 * alkoi 280 pikselin päästä palstan vasemmasta reunasta eli lähes
 * puolivälistä (mitattu 22.8.2026, Venäjän Menovinkit), ja ryhmän
 * otsikkoviiva alkoi samasta kohdasta. Mitä leveämpi ruutu, sitä
 * suurempi aukko — juuri väärin päin.
 *
 * Nyt sisennys on KIINTEÄ ja pieni, samaa luokkaa kuin lehden
 * sisennetty luettelo: rivi alkaa 1,4 rem:n päästä palstan reunasta
 * riippumatta ruudun leveydestä, ja loppu rivistä on listan käytössä.
 * Rivin PITUUS rajataan siellä, missä se on lukemisen kysymys eli
 * selitystekstissä (.vinkki-selitys) — ei koko listan mitassa, jolloin
 * myös pikkukuvat ja nimet olisivat siirtyneet keskelle sivua.
 */
.vinkkisivu .vinkkilista,
.vinkkisivu .vinkki-ryhma {
  max-width: none;
  margin-left: 0;
  margin-right: 0;
}

/*
 * Sisennys on LEVEÄN ruudun asia. Puhelimessa (390 px) listalla ei
 * ollut sisennystä ennenkään — 38 rem oli leveämpi kuin koko palsta —
 * eikä pikkukuvan ja nimen edestä ole siellä varaa antaa pois
 * kahtakymmentä pikseliä. Raja on sama 700 px, jolla lehden muukin
 * taitto vaihtaa leveään malliin.
 */
@media (min-width: 700px) {
  .vinkkisivu .vinkkilista,
  .vinkkisivu .vinkki-ryhma { margin-left: 1.4rem; }
}

/*
 * Selityksen rivimitta pysyy luettavana, vaikka rivi on nyt palstan
 * levyinen: leveällä arkilla ilman kattoa selitys venyisi yli sadan
 * merkin riveiksi, ja hakemistoa on tarkoitus silmäillä.
 */
.vinkkisivu .vinkki-selitys { max-width: 46em; }

/* Ajankohta noston otsikkorivillä: pieni konekirjoitusleima. */
.nosto-aika {
  margin-left: auto;
}

/*
 * Kun rivillä on myös musiikkinappi, oikean reunan tyhjä tila kuuluu
 * VAIN ensimmäiselle oikean ryhmän jäsenelle: kaksi auto-marginaalia
 * jakoivat tilan ja Apple Music -pilleri kellui keskellä riviä
 * (omistajan havainto 10.8.2026: "siirrä apple music painike oikeaan
 * reunaan vuosiluvun viereen"). Sisarussääntö vie vuosileimalta
 * auton, jolloin nappi ja leima istuvat vierekkäin oikealla.
 */
.kulttuuri-musiikkilinkki ~ .nosto-aika,
.kulttuuri-musiikkinayte ~ .nosto-aika {
  margin-left: 0.45rem;
  padding: 0.1rem 0.4rem;
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 3px;
  font-family: var(--font-type);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  white-space: nowrap;
  color: #5a4a33;
  background: rgba(246, 231, 198, 0.6);
}

/* Maa-etusivun kuvanosto: koko leveys kartan ja uutisten väliin. */
.maa-etusivu-nosto {
  clear: both;
  margin-top: 0.6rem;
  padding-top: 0.6rem;
  border-top: 1px dashed rgba(70, 51, 31, 0.35);
}

/* Esittelyn kappalejaot näkyviin maaosion aloitussivulla (\n\n). */
.maa-etusivu #arrival-maa-intro { white-space: pre-line; }

/* Kaupunkisivun kohdekartta sivun lopussa. */
.kaupunkikartta {
  clear: both;
  margin-top: 1.1rem;
  padding-top: 0.7rem;
  border-top: 3px double rgba(70, 51, 31, 0.75);
}

/* Matkailijalle-osio kartan perässä (omistajan tilaus 15.8.2026):
 * sama kaksoisviivaerotin ja otsikkotyyli kuin karttalohkolla, ja
 * opasnappi keskitetään omalle rivilleen. */
.matkailijalle {
  clear: both;
  margin-top: 1.1rem;
  /* Vaaleampi paneeli kuin lehden paperi (omistaja 16.8.2026):
   * osio on pelin kevyt kulma ja saa hohtaa hieman valoisampana. */
  padding: 0.7rem 0.9rem 0.9rem;
  border-top: 3px double rgba(70, 51, 31, 0.75);
  border-radius: 0 0 8px 8px;
  background: #fcf8ec;
  /*
   * PANEELI PIIRRETÄÄN LOPPUUN (omistajan löytö 16.8.2026
   * iPad-kuvakaappauksesta): vaaleampi pohja loppui ilman reunaa
   * keskelle paperia, ja koska ero lehden paperiin on vain muutama
   * prosentti, raja luki ruudulla piirtovirheenä eikä paneelin
   * alareunana. Sivut ja alareuna saavat saman musteen ohuena
   * viivana ja paneeli kevyen varjon: nyt vaalea pohja on selvästi
   * esine paperin päällä.
   */
  border-right: 1px solid rgba(70, 51, 31, 0.28);
  border-bottom: 1px solid rgba(70, 51, 31, 0.28);
  border-left: 1px solid rgba(70, 51, 31, 0.28);
  box-shadow: 0 2px 6px -3px rgba(70, 51, 31, 0.4);
  /* Nauhan ankkuri: nauha kulkee osion yläreunasta oikeaan
   * sivureunaan. Leikkurina on nauhan oma kotelo
   * (.opas-nauha-kotelo, overflow: hidden), EI tämä osio — osion
   * leikkuri söi hiljaa ylivuotavan rivin, ja iPadilla kuvan
   * lähderivin viimeinen sana katosi sen alle. */
  position: relative;
}

.matkailijalle .wiki-btn {
  display: block;
  margin: 0.2rem auto 0;
}

.matkailijalle-kuva { position: relative; }

/*
 * YKSI DIAGONAALINEN KULMANAUHA (omistajan tarkennukset 16.8.2026:
 * "vain yksi diagonaali palkki jonka päällä pelkkä matkaopas" ja
 * "nauha kulkee kuvan reunan yli koko vaalean pohjan yläreunasta
 * oikeaan sivureunaan, hieman leveämpänä ja pehmeämmin värein").
 * Kotelo istuu koko osion kulmassa ja leikkaa nauhan päät osion
 * reunoihin; nauha on 45 asteessa ja ylittää kuvan reunan.
 */
.opas-nauha-kotelo {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  width: 10.8rem;
  height: 10.8rem;
  overflow: hidden;
  pointer-events: none;
}

button.opas-nauha {
  position: absolute;
  top: 2.9rem;
  right: -7.2rem;
  width: 22rem;
  min-height: 0;
  padding: 0.5rem 0;
  border: none;
  border-radius: 0;
  transform: rotate(45deg);
  /* Vaimennettu terrakotta ja murrettu paperi: sama perhe kuin
   * paletti 2.1, mutta pienempi kylläisyys ja kontrasti — nauha
   * on viite, ei huuto. */
  background: #b3775f;
  color: #f2e4d0;
  font-family: var(--font-type);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-align: center;
  box-shadow: 0 1px 3px rgba(58, 42, 21, 0.22);
  cursor: pointer;
  pointer-events: auto;
  -webkit-appearance: none;
  appearance: none;
}

button.opas-nauha:hover { filter: brightness(1.06); }

/* Kuva on oppaan sisäänkäynti — osoitin kertoo sen. */
.matkailijalle-kuva img { cursor: pointer; }

/* Leipätekstin lopun linkki oppaaseen (omistaja 16.8.2026).
 * Valitsin ja appearance-nollaus voittavat lehden yleisen
 * nappityylin — linkki näyttää linkiltä, ei napilta. */
.matkailijalle .opas-lue-lisaa {
  display: inline;
  min-height: 0;
  padding: 0;
  border: none;
  border-radius: 0;
  background: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
  font: inherit;
  letter-spacing: normal;
  text-transform: none;
  color: #1c6f6b;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

.matkailijalle .opas-lue-lisaa:hover { color: #b8402c; }

.kaupunkikartta-otsikko {
  margin: 0 0 0.6rem;
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  text-align: center;
  color: rgba(70, 51, 31, 0.85);
}

.kaupunkikartta-esittely {
  margin: 0 0 0.7rem;
  font-family: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  font-size: 1.02rem;
  line-height: 1.55;
  color: #2d2010;
}

/* Kaupunki kartalla -esittely kahdessa palstassa (omistajan tilaus
 * 15.8.2026). Kapealla ruudulla palsta ei mahdu lukemaan mukavasti,
 * joten alle 640 px palataan yhteen. */
.kaupunkikartta-palstat {
  columns: 2;
  column-gap: 1.6rem;
}

@media (max-width: 640px) {
  .kaupunkikartta-palstat { columns: 1; }
}

/* Matkailijalle-osion valokuva otsikon alla oikeassa laidassa
 * (omistajan tilaus 15.8.2026): teksti kiertää vasemmalta. */
.matkailijalle-kuva {
  float: right;
  width: clamp(10rem, 42%, 17rem);
  margin: 0.15rem 0 0.5rem 1rem;
}

.matkailijalle-kuva img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(70, 51, 31, 0.45);
  cursor: zoom-in;
}

.matkailijalle-kuva .kuvateksti {
  margin-top: 0.3rem;
}

/* Kelluva kuva ei saa vuotaa osion alle — opasnappi ja seuraava
 * lohko alkavat aina puhtaalta riviltä. */
.matkailijalle .wiki-btn,
.matkailijalle::after {
  clear: both;
}

.matkailijalle::after {
  content: "";
  display: block;
}

/* Kohdepiste on nappi, kun siitä aukeaa artikkeli: yleisen
 * nappisäännön mitat ja tausta nollataan täplän kokoon. */
.dialog button.maakartta-piste {
  min-height: 0;
  padding: 0;
  /* Yleinen nappisääntö toisi käsinpiirretyn kulmapyöristyksen —
   * täplä on täplä. */
  border-radius: 50%;
  cursor: pointer;
}

/* Nimen suunta ruuhkaisissa kohdissa: ylä/ala keskittää nimen
 * pisteen ylle tai alle, ettei keskustan nimilaput mene päällekkäin. */
.maakartta-piste.nimi-yla .maakartta-nimi,
.maakartta-piste.nimi-ala .maakartta-nimi {
  left: 50%;
  right: auto;
  top: auto;
  transform: translateX(-50%);
}

.maakartta-piste.nimi-yla .maakartta-nimi { bottom: calc(100% + 3px); }
.maakartta-piste.nimi-ala .maakartta-nimi { top: calc(100% + 3px); }

/* Lounaaseen: nimi pisteen alle ja vasemmalle (ahtain keskusta). */
.maakartta-piste.nimi-vasen-ala .maakartta-nimi {
  left: auto;
  right: calc(100% - 4px);
  top: calc(100% + 1px);
  transform: none;
}

.dialog button.maakartta-piste:hover:not(:disabled),
.dialog button.maakartta-piste:focus-visible {
  background: #c69e52;
  border-color: #2c2318;
}

/*
 * PIIRROSPISTE PYSYY TAUSTATTOMANA MYÖS HOVERISSA. Yllä oleva
 * korostus (0,4,1) voittaa piirrossäännön background: nonen (0,3,0),
 * ja iOS jättää napautetun napin tahmeaan hover-tilaan — leikatun
 * kuvan taakse ilmestyi kullanvärinen neliö, joka katosi vasta kun
 * hover siirtyi toiseen nappiin (omistajan havainto 15.8.2026;
 * työpöydällä ei näy, koska ohjelmallinen klikkaus ei aseta hoveria).
 */
.dialog button.maakartta-piste.kohde-piirros:hover:not(:disabled),
.dialog button.maakartta-piste.kohde-piirros:focus-visible {
  background: none;
  border-color: transparent;
}

/* Kohdekartan pisteet erottuvat kaupunkipisteistä kullalla —
 * huvipuistokartan merkkejä, joista useimmat voi avata. */
.maakartta-piste.kaupunki-kohde {
  width: 11px;
  height: 11px;
  background: #c69e52;
  border-color: #2c2318;
}

/* Kapealla ruudulla kohdekartta täysleveänä kuten maakartta. */
@media (max-width: 560px) {
  .kaupunkikartta .maakartta-kehys {
    float: none;
    width: 100%;
    margin: 0.15rem 0 0.7rem;
  }
}

/*
 * Kohdekartta 2.0 (omistajan taittopäätös 7.8.2026): iso kartta,
 * numeroympyrät ja selitteet tekstinä kartan alla.
 */

/*
 * ZOOMATTAVA KARTTAIKKUNA (omistajan tilaus 14.8.2026: "voiko
 * kaupunkikartasta tehdä zoomattavaa ... pyörisi nykyisessä
 * ikkunassa").
 *
 * Kehys on ikkuna, jonka koko ei muutu, ja lava on sen sisällä liikkuva
 * taso. Reunaviiva ja leikkaus kuuluvat siksi kehykselle: kuvan omalla
 * reunalla ne skaalautuisivat zoomatessa paksuiksi ja jäisivät
 * panoroitaessa keskelle ruutua.
 *
 * `touch-action: pan-y` on tarkka valinta. Se päästää yhden sormen
 * pystyvierityksen läpi (lehteä luetaan kartan päältäkin) mutta estää
 * selaimen oman nipistyszoomin, jolloin kahden sormen tapahtumat
 * tulevat kartalle asti. Zoomattuna sormi panoroi karttaa, ja silloin
 * mitään ei päästetä läpi.
 */
.kartta-kehys {
  position: relative;
  overflow: hidden;
  margin: 0.3rem 0 0.55rem;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 2px;
  touch-action: pan-y;
  /* Kokokontti, jotta valittu piirros voi mitata itsensä kartta-
   * ikkunan korkeudesta (cqh) — ks. .kohde-piirros.valittu. */
  container-type: size;
}

.kartta-kehys.zoomattu {
  touch-action: none;
  cursor: grab;
  user-select: none;
}

.kartta-kehys.zoomattu:active { cursor: grabbing; }

/*
 * KARTTA AUKEAA KOKORUUDULLE (omistajan tilaus 21.8.2026: "voisiko
 * kaupunkikartan saada klikattua kokoruudulle?"). Suurennoskohdistin
 * kertoo sen ennen napautusta — mutta vain lepotilassa: zoomattuna
 * napautus kuuluu panoroinnille, ja otekohdistimen on säilyttävä.
 * Valitsimissa on siksi kolme luokkaa, jotta ne voittavat yllä olevat
 * kaksiluokkaiset zoomatun kartan säännöt.
 */
.kartta-kehys.kartta-avattava { cursor: zoom-in; }

.kartta-kehys.kartta-avattava.zoomattu { cursor: grab; }

.kartta-kehys.kartta-avattava.zoomattu:active { cursor: grabbing; }

/*
 * NAPAUTUSOPASTE KARTAN OIKEASSA YLÄKULMASSA (omistajan tilaus
 * 18.8.2026). Ohje siirtyi esittelytekstin lopusta kartan päälle, eli
 * sinne, mitä se koskee — leipätekstistä se poistui kaikista
 * kaupungeista kerralla.
 *
 * Kyltti on KEHYKSEN lapsi eikä lavan, joten se ei zoomaa eikä
 * panoroi; vastaskaalausta ei siksi tarvita. Sävyt ovat samat kuin
 * mittajanan tekstilipukkeessa, jotta kartan päällä on yksi kieli eikä
 * kahta. Yläkulma on tarkoituksella: piirrokset ovat kartan keskellä
 * ja alaosassa, ja vasen alanurkka on mittajanan.
 *
 * `pointer-events: none` on välttämätön: kyltti ei saa syödä
 * panorointiotetta eikä alleen jäävän kohteen napautusta. Kapealla
 * ruudulla teksti rivittyy kahdelle riville (max-width), eikä
 * animaatiota ole lainkaan. z-index jää valitun piirroksen (5) alle,
 * jotta suurennettu kuva peittää opasteen eikä toisin päin.
 */
.kartta-opaste {
  position: absolute;
  top: 0.35rem;
  right: 0.35rem;
  z-index: 3;
  /* Leveällä ruudulla teksti mahtuu yhdelle riville, kapealla se
   * rivittyy kahdelle (55 % kartan leveydestä). */
  max-width: min(17rem, 55%);
  padding: 0.18rem 0.46rem;
  font-family: var(--font-type);
  font-size: 0.62rem;
  line-height: 1.3;
  letter-spacing: 0.02em;
  text-align: right;
  color: rgba(44, 35, 24, 0.92);
  background: rgba(247, 240, 222, 0.82);
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  pointer-events: none;
}

/*
 * MATKAKIRJAN IHMEEN SELITE (omistajan tilaus 2.9.2026: *"kartan
 * yläreunassa voisi olla selite: '*) matkakirjan ihme'"*). Sama asu ja
 * sama kieli kuin napautusopasteella — vain tähti edessä ja kartan
 * VASEMMASSA yläkulmassa, koska oikea on opasteen (perustelut
 * js/nahtavyydet.js). Merkki on kartan pisteen tähti pienennettynä,
 * ei toinen kuvake.
 */
.kartta-ihmeselite {
  position: absolute;
  top: 0.35rem;
  left: 0.35rem;
  z-index: 3;
  display: flex;
  gap: 0.28rem;
  align-items: center;
  padding: 0.16rem 0.46rem;
  font-family: var(--font-type);
  font-size: 0.6rem;
  line-height: 1.3;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: rgba(44, 35, 24, 0.92);
  background: rgba(247, 240, 222, 0.82);
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  pointer-events: none;
}

/*
 * KOKORUUDULLA SELITE VÄISTÄÄ ZOOMIPILLERIT. Kortin vasempaan
 * yläkulmaan kelluu suurennoksen oma zoomipainikepari
 * (.kartta-suurennos-tyokalut, top ja left 0,5 rem) — selite jäisi sen
 * alle. Se laskeutuu siksi pillerien alapuolelle; oikea yläkulma on
 * sulkurastin ja alakulma mittajanan, joten tämä on ainoa vapaa laita.
 */
.dialog .kartta-suurennos .kartta-kehys .kartta-ihmeselite {
  top: 3.1rem;
  left: 0.5rem;
}

/*
 * IHMEEN TÄHTI KOHDEMERKIN YLÄREUNASSA (omistajan tilaus 2.9.2026:
 * *"pienen tähden jokaisen kohteen yläreunaan, jos sinne on generoitu
 * myös tällainen historiallinen kuva"*).
 *
 * Tähti istuu merkin YLÄPUOLELLA hieman oikealla, kuten alaviitteen
 * tähti sanan perässä: piirroksen yläreuna on rakennuksen harja, ja
 * suoraan sen päälle asetettu merkki peittäisi juuri sen. Se ei ota
 * napautuksia vastaan — koko merkki on jo nappi, ja tähti on sen
 * lipuke, ei oma kohteensa. Piirros tulee samasta kirjastosta kuin
 * pääkartan tähtisymboli (js/fokusnosto-symbolit.js), joten kulta ja
 * musteääriviiva ovat .nostosym-tahti-säännön.
 */
.kohde-ihmetahti {
  position: absolute;
  top: -6px;
  right: -3px;
  width: 15px;
  height: 15px;
  overflow: visible;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3));
  pointer-events: none;
}

/* Täplämerkki on 13 px eli tähteä pienempi: tähti nousee sen päälle
 * hieman tiukemmin, jotta pari pysyy yhtenä merkkinä. */
.maakartta-piste.kohde-numero:not(.kohde-piirros) > .kohde-ihmetahti {
  top: -8px;
  right: -7px;
  width: 13px;
  height: 13px;
}

/* Suurennettuna piirros vuotaa laatikkonsa yli ja saa nimikyltin;
 * pikkutähti jäisi siihen irralleen laatikon reunalle. Se piiloutuu
 * samalla säännöllä kuin karttanimi (.kohde-piirros.valittu
 * .kohde-nimi) ja palaa, kun valinta puretaan. */
.kohde-piirros.valittu > .kohde-ihmetahti { display: none; }

/* Selitteen tähti on tekstin kokoinen eikä merkin: sama muoto, oma
 * mitta rivin sisällä. */
.kartta-ihmeselite-tahti {
  position: static;
  width: 0.74rem;
  height: 0.74rem;
  filter: none;
}

/*
 * SUURENNUSVIHJE KARTAN OIKEASSA ALAKULMASSA (omistajan tilaus
 * 21.8.2026). Samat sävyt ja sama kokoluokka kuin napautusopasteessa
 * ja mittajanan tekstilipukkeessa — kartan päällä puhutaan yhtä
 * kieltä. Kehyksen lapsi eikä lavan, joten se ei zoomaa eikä panoroi,
 * ja `pointer-events: none` pitää sekä panorointiotteen että
 * kokoruudun avaavan napautuksen ennallaan lapun alla.
 */
.kartta-suurennusvihje {
  position: absolute;
  right: 0.35rem;
  bottom: 0.35rem;
  z-index: 3;
  padding: 0.16rem 0.42rem;
  font-family: var(--font-type);
  font-size: 0.6rem;
  line-height: 1.3;
  letter-spacing: 0.04em;
  white-space: nowrap;
  color: rgba(44, 35, 24, 0.92);
  background: rgba(247, 240, 222, 0.82);
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 2px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  pointer-events: none;
}

/* Zoomattuna napautus ei enää avaa kokoruutua vaan panoroi, joten
 * vihje ei saa luvata sitä (ks. js/nahtavyydet.js). */
.kartta-kehys.zoomattu .kartta-suurennusvihje { display: none; }

.kaupunkikartta-kotelo { margin: 0.3rem 0 0.55rem; }

/* Kehyksen sisällä reuna on kehyksellä ja marginaalit sen ulkopuolella
 * — lavan on peitettävä ikkuna tarkalleen, tai zoomatessa reunaan
 * jäisi rako. */
.kartta-kehys > .kaupunkikartta-kotelo { margin: 0; }

.kartta-kehys > .maakartta-kotelo img {
  border: 0;
  border-radius: 0;
}

/*
 * Lava: kuva, kohdepisteet ja mittajana yhtenä liikkuvana tasona.
 * Origo on vasen ylänurkka, koska koko eleen laskenta (ui.js:
 * kytkeKarttaZoom) olettaa sen.
 */
.kartta-lava {
  --zoom: 1;
  transform-origin: 0 0;
}

/*
 * KARTTA JATKUU REUNOJEN YLI (omistajan tilaus 15.8.2026). Juliste on
 * piirretty ydinrajausta laajemmalta alueelta, ja lava on siksi
 * kehystä suurempi: leveys, kuvasuhde ja negatiivinen siirto tulevat
 * datasta (ui.js: piirraKaupunkiKartta, maakartat.js: ydinAla).
 *
 * Lava irtoaa virrasta, joten kehys tarvitsee oman korkeutensa —
 * aspect-ratio ydinrajauksesta. `content-box` on tarkka valinta eikä
 * tyyliseikka: reunaviiva on kehyksellä, ja border-box-laskennassa
 * kuvasuhde koskisi reunoja myöten, jolloin lepotilan korkeus
 * poikkeaisi ydinrajauksesta reunan paksuuden verran.
 */
.kartta-kehys.kartta-laajennettu { box-sizing: content-box; }

.kartta-lava.kartta-laajennettu { position: absolute; }

/* Piirros peittää koko lavan, satelliittikuva vain ydinrajauksen;
 * kumpikin saa paikkansa ui.js:stä (asetaKuvanAla). */
.kartta-lava.kartta-laajennettu img { position: absolute; }

/* Pehmennys vain napeista ja tuplanapautuksesta: sormen alla se
 * tuntuisi siltä, että kartta laahaa jäljessä. */
.kartta-lava.silea { transition: transform 0.18s ease-out; }

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

/*
 * KOKORUUTUKARTTA (omistajan tilaus 21.8.2026). Kortti on pelin
 * tavallinen suurennoskatselin (.postikortti.kulttuuri-suurennos):
 * tumma pohja, keskitys ja sulku tulevat sieltä sellaisinaan, ja
 * täällä mitoitetaan vain kloonattu karttakehys.
 *
 * MITOITUS ON KUVASUHTEEN VARASSA. Kehyksellä on oma aspect-ratio
 * (ydinrajauksesta tai kuvatiedostosta), joten korkeutta ei voi
 * asettaa suoraan — leveys lasketaan halutusta korkeudesta:
 * `korkeus × suhde`, katkaistuna ruudun leveyteen. Kumpi tahansa
 * raja tuleekin vastaan, KOKO kartta on näkyvissä eikä mitään
 * rajaudu pois. Kerroin --kartta-suhde tulee avaajalta
 * (js/nahtavyydet.js: avaaKarttaSuurennos), joka mittaa sen
 * paikallaan olevasta kehyksestä.
 *
 * TÄMÄ ON VARAMITOITUS (21.8.2026). Lopullisen leveyden asettaa
 * avaaja pikseleinä mitattuaan visualViewportista sen alan, joka
 * katsojalla oikeasti on näkyvissä — omistajan iPadilla CSS:n ruutu
 * ja silmän ruutu eivät olleet sama asia, ja kartta jäi pieneksi
 * mustan keskelle (ks. mitoitaKarttaSuurennos). Sama sääntö kummassakin:
 * leveyttä enintään 98 % ja kartalle korkeutta enintään 85 %.
 *
 * dvh eikä vh: puhelimen osoiterivi kutistaa näkyvän ruudun, ja
 * vh-mitta jättäisi kartan alareunan palkin alle.
 *
 * KORKEUSKATTO PURREE VAIN LEVEÄLLÄ RUUDULLA, ja siellä selite on
 * kahden rivin mittainen — kapealla ruudulla vaakakartta törmää aina
 * ensin leveysrajaan (98vw), jolloin korkeutta jää yli ja pitkäkin
 * selite mahtuu sen alle. Vaakakuva ei täytä puhelimen pystyruutua:
 * se on kuvasuhteen laki, ei mitoituksen puute, ja juuri siksi selite
 * saa sen alta jäävän tilan.
 */
.postikortti.kulttuuri-suurennos.kartta-suurennos {
  width: min(98vw, calc(85dvh * var(--kartta-suhde, 1.4)));
  max-height: 98dvh;
  /*
   * EI ZOOM-OUT-KOHDISTINTA: kokoruutukartta ei sulkeudu napautuksesta
   * (omistajan palaute 21.8.2026) vaan rastista ja Escapesta, ja
   * napautus kuuluu kartan omalle zoomille. Kohdistin, joka lupaa
   * sulkevansa, valehtelisi.
   */
  cursor: default;
}

/*
 * Pohja on TÄYSIN PEITTÄVÄ, toisin kuin kuvasuurennoksessa (0,88).
 * Kartan alla on lehden OMA selitelista samoilla sanoilla, ja läpi
 * kuultavana se asettui suurennoksen selitteen viereen
 * kaksoiskappaleeksi: kaksi samaa riviä hieman eri kohdissa luki
 * huonommin kuin yksikään. Kokoruutu on sitä paitsi juuri sitä —
 * koko ruutu.
 */
.postikortti.kulttuuri-suurennos.kartta-suurennos::before {
  background: #0b0805;
}

.kartta-suurennos .kartta-kehys {
  width: 100%;
  margin: 0;
  cursor: inherit;
  /* Kokoruudulla sormi kuuluu kartalle eikä sivulle: kortti peittää
   * lehden, eikä pyyhkäisy saa liikuttaa sen takana olevaa sivua.
   * Nipistys ja panorointi tulevat kartan omalta zoomilta
   * (kytkeKarttaZoom), joka lukee tapahtumat itse. */
  touch-action: none;
}

/*
 * MAALEHDEN KORKOKARTAN KOKORUUTUKEHYS (21.8.2026). Kehystä ei ole
 * sivulla lainkaan: se rakennetaan avattaessa pelkäksi ikkunaksi
 * kartan ympärille (js/maalehti.js), ja kuvasuhde on kuvan oma. Reuna
 * jää siksi pois — kehyksen reunaviiva veisi kuvasuhteesta kaksi
 * pikseliä, ja lavan alle jäisi rako, jota kohdekartassa ei ole.
 */
.kartta-suurennos .kartta-kehys.kartta-kuvakehys { border: 0; }

/*
 * OTEKOHDISTIN ZOOMATULLE KOKORUUTUKARTALLE. Sääntö on kolmiluokkainen
 * tarkoituksella: yllä oleva `.kartta-suurennos .kartta-kehys`
 * (0,2,0) voittaisi muuten kehyksen oman `.kartta-kehys.zoomattu`
 * -säännön, ja zoomattu kartta jäisi kokoruudulla ilman merkkiä siitä,
 * että sitä voi raahata.
 */
.kartta-suurennos .kartta-kehys.zoomattu { cursor: grab; }

.kartta-suurennos .kartta-kehys.zoomattu:active { cursor: grabbing; }

/*
 * ZOOMIPAINIKKEET KELLUVAT KARTAN PÄÄLLÄ (omistajan palaute
 * 21.8.2026: kokoruutukarttaa pitää voida zoomata). Rivi on kortissa
 * absoluuttisesti, koska kortin korkeus on laskettu kartan
 * kuvasuhteesta — virrassa oleva säädinrivi söisi kartalle varatun
 * tilan. Vasen yläkulma on vapaa: sulkurasti on oikealla.
 */
.dialog .kartta-suurennos .kartta-suurennos-tyokalut {
  position: absolute;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 4;
  margin: 0;
}

/* Sama vaalea lappu kuin sulkurastissa: tumman kokoruudun päällä
 * lehden paperinsävyinen pilleri jää muuten hailakaksi. */
.dialog .kartta-suurennos .kartta-suurennos-tyokalut button {
  background: rgba(247, 240, 222, 0.88);
  border-color: rgba(70, 51, 31, 0.45);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  color: rgba(44, 35, 24, 0.92);
}

.dialog .kartta-suurennos .kartta-suurennos-tyokalut button:hover:not(:disabled) {
  background: rgba(255, 250, 238, 0.98);
  border-color: rgba(70, 51, 31, 0.75);
}

/*
 * KUVASÄÄNNÖT TAKAISIN KARTAN OMIKSI. Kortin sisällä pätisivät muuten
 * postikortin kuvasäännöt (.postikortti img: kiinteä 330 px:n ikkuna
 * ja object-fit: cover; .kulttuuri-suurennos img: max-height 80dvh ja
 * vaalea pohja) — kartta rajautuisi laatikkoonsa ja piirroskohteet
 * venyisivät. Valitsimet ovat tarkoituksella kolmiluokkaisia, jotta ne
 * voittavat nuo säännöt paikasta riippumatta.
 */
.kartta-suurennos .kartta-kehys > .maakartta-kotelo > img {
  width: 100%;
  height: auto;
  max-width: none;
  max-height: none;
  margin-inline: 0;
  object-fit: contain;
  background: none;
  border: 0;
}

.kartta-suurennos .kartta-kehys img.kohde-piirros-kuva {
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin-inline: 0;
  object-fit: contain;
  background: none;
  border: 0;
}

/*
 * (Piirroskohteen numerolappu kokoruudulla oli tässä 22.–23.8.2026.
 * Se poistettiin, kun numerot lähtivät kartalta kokonaan: piirroksen
 * tunnistaa nyt sen alla lukevasta nimestä, ks. .kohde-nimi.)
 */

/*
 * Nimilista kartan alle. Sama ladelma kuin lehden
 * selitelistassa, mutta vaalealla musteella tummaa pohjaa vasten ja
 * keskitettynä kartan alle. Katto ja vieritys ovat varmistus pitkälle
 * listalle kapealla ruudulla: kortti ei saa kasvaa ruutua
 * korkeammaksi.
 */
.kartta-suurennos .kartta-suurennos-selitteet {
  justify-content: center;
  gap: 0.3rem 1rem;
  /* Sivupehmuste, ettei rivin viimeinen nimi päädy kiinni kortin
   * reunaan kapealla ruudulla. */
  margin: 0.45rem 0 0;
  padding: 0 0.5rem;
  max-height: 20dvh;
  overflow-y: auto;
}

.dialog .kartta-suurennos .kartta-selitteet .kartta-selite {
  color: rgba(247, 239, 220, 0.92);
  cursor: inherit;
}

/*
 * SELITERIVI AVAA JUTUN MYÖS KOKORUUDULLA (omistajan tilaus
 * 22.8.2026). Kortin oma `cursor: default` periytyisi yllä olevan
 * rivisäännön kautta myös avattavalle riville, ja osoitin lupaisi
 * vähemmän kuin rivi tekee. Valitsin on rivisääntöä tarkempi, jotta se
 * voittaa sen paikasta riippumatta.
 */
.dialog .kartta-suurennos .kartta-selitteet button.kartta-selite { cursor: pointer; }

.dialog .kartta-suurennos .kartta-selitteet button.kartta-selite:hover,
.dialog .kartta-suurennos .kartta-selitteet button.kartta-selite:focus-visible {
  color: #f0d9a4;
}

/* Lähderivi kartan alle kapeaksi riviksi, samaan vaaleaan sävyyn kuin
 * muissa suurennoksissa. */
.kartta-suurennos .kuvalahde {
  margin: 0.3rem 0 0;
  text-align: center;
}

/*
 * ZOOMATTU KARTTA LEVIÄÄ TYHJÄN PÄÄLLE (omistajan tilaus 22.8.2026:
 * "jos karttaa zoomaa se saisi levittyä tyhjän tilan päälle koko
 * näytöllä"). Kehyksen leveys ja korkeus tulevat silloin pikseleinä
 * avaajalta (js/nahtavyydet.js: levita), eikä kuvasuhde enää mitoita
 * korttia.
 *
 * Selite ja lähderivi väistyvät levityksen ajaksi. Ne veisivät juuri
 * sen pystytilan, joka kartalle annetaan, ja niiden tehtävä on
 * selittää KOKO kartan numerot — lähietäisyydeltä katsottaessa
 * näkyvissä on vain osa niistä. Lepotilaan palatessa molemmat
 * palaavat, joten mitään ei menetetä.
 */
.kartta-suurennos.kartta-levitetty .kartta-suurennos-selitteet,
.kartta-suurennos.kartta-levitetty .kuvalahde {
  display: none;
}

/*
 * Sulkurasti kartan oikeaan yläkulmaan kuvan päälle. Kortin oletusrasti
 * on tummanruskea paperia varten ja katoaisi tummalle pohjalle; kyltti
 * on siksi sama vaalea lappu kuin kartan opaste ja mittajanan teksti.
 */
.dialog .kartta-suurennos button.uutinen-sulku {
  z-index: 4;
  width: 2rem;
  height: 2rem;
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 3px;
  background: rgba(247, 240, 222, 0.88);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  color: rgba(44, 35, 24, 0.92);
}

/*
 * PIIRROS SUURENEE KOKORUUDULLAKIN KARTAN PÄÄLLÄ (omistajan palaute
 * 23.8.2026: "Koko näytöllä pitäisi suurentua samalla tavalla kuin
 * muuten. Nyt kuitenkin tulee tällainen lappu turhaan").
 *
 * Tämä KUMOAA saman päivän ensimmäisen ratkaisun, jossa napautus avasi
 * kermanvärisen kortin (.kartta-kohdekerros/.kartta-kohdekortti, nyt
 * poistettu) kartan päälle. Tilalla on täsmälleen sama läpinäkyvä
 * leikattu kuva kuin lehden valitussa piirroksessa: ei kehystä, ei
 * taustalappua, ei nappeja.
 *
 * Suurennos on KEHYKSEN lapsi (js/nahtavyydet.js: naytaSuurennus),
 * koska lavan koordinaatisto elää zoomin ja levityksen mukana —
 * kehyksessä se on aina kartan keskellä. Mitat ovat lehden mitat:
 * laatikko 37,5 cqh karttaikkunan korkeudesta ja kuva 200 % laatikosta
 * eli näkyvä 75 %. Jakoa zoomilla ei ole, koska --zoom asuu lavalla.
 * Valitsimessa on viisi luokkaa, jotta se voittaa myöhemmän
 * `.maakartta-piste.kohde-numero.kohde-piirros` -säännön 40 px:n koon.
 */
.kartta-suurennos .kartta-kehys > .maakartta-piste.kohde-piirros.kartta-kohdevalinta {
  left: 50%;
  top: 50%;
  width: 37.5cqh;
  height: 37.5cqh;
  min-height: 0;
  z-index: 5;
  cursor: pointer;
}

/*
 * Kuvan ylivuoto laatikon yli kuten lehdessä. Oma sääntö tarvitaan,
 * koska kokoruudun kuvasääntö (.kartta-suurennos .kartta-kehys
 * img.kohde-piirros-kuva, 0-3-1) on lehden .valittu-säännön (0-3-0)
 * jälkeen ja kutistaisi piirroksen takaisin laatikon kokoon.
 */
.kartta-suurennos .kartta-kehys .kohde-piirros.valittu img.kohde-piirros-kuva {
  left: -50%;
  top: -50%;
  width: 200%;
  height: 200%;
  max-width: none;
}

/*
 * Kartalla oleva pieni piirros pois näkyvistä suurennuksen ajaksi.
 * Lehdessä sama elementti kasvaa paikallaan, joten rakennus ei näy
 * kahtena; visibility (ei display) pitää kartan asettelun ennallaan.
 */
.kartta-suurennos .kohde-piirros.kohde-piirros-piilossa { visibility: hidden; }

/*
 * VASTASKAALAUS. Kaikki lavalla suurenisi zoomin mukana, myös se, mikä
 * ei ole karttaa: numeroympyrä on merkki eikä maisema, ja
 * kolminkertaisena se peittäisi juuri sen korttelin, jota katsotaan.
 * Sama koskee mittajanan viivoja ja tekstiä — jana ITSE saa venyä,
 * koska sen pituus on matka, mutta sen musteen ei pidä paksuta.
 *
 * Sama sääntö koskee maalehden korkokartan kaupunkitäpliä ja niiden
 * nimikylttejä (21.8.2026, kokoruutukartta): täplä on merkki kartalla
 * eikä maasto, ja nimi kuuluu lukea yhtä isona joka kertoimella.
 */
.kartta-lava .maakartta-piste {
  transform: translate(-50%, -50%) scale(calc(1 / var(--zoom)));
}

.kartta-lava .kartta-mittajana {
  height: calc(6px / var(--zoom));
  border-width: calc(1px / var(--zoom));
}

.kartta-lava .kartta-mittajana-teksti {
  transform: translateX(-50%) scale(calc(1 / var(--zoom)));
  transform-origin: bottom center;
}

/*
 * Kartan näkymävipu (omistajan tilaus 14.8.2026): piirretty juliste
 * ja satelliittikuva samasta rajauksesta. Rivi on kartan yllä oikeassa
 * reunassa ja kirjoituskoneen kokoa, koska se on kartan asetus eikä
 * lehden juttu — samalla logiikalla kuin lähderivi kartan alla.
 *
 * Työkalurivi jakaa saman rivin zoomipainikkeiden kanssa: molemmat
 * ovat kartan säätimiä, eikä niitä kannata ladota kahdelle riville.
 */
.kartta-tyokalut {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.3rem;
  margin: 0 0 0.15rem;
}

.kartta-zoomi { display: flex; gap: 0.3rem; }

.kartta-vipu {
  display: flex;
  justify-content: flex-end;
  gap: 0.3rem;
}

.dialog .kartta-tyokalut button {
  display: inline-flex;
  align-items: center;
  gap: 0.32rem;
  min-height: 0;
  padding: 0.2rem 0.6rem;
  font-family: var(--font-type);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.85);
  background: rgba(255, 250, 238, 0.6);
  border: 1px solid rgba(70, 51, 31, 0.35);
  /* Yleinen nappisääntö toisi käsinpiirretyn kulmapyöristyksen; tämä
   * rivi on kartan reunassa ja pysyy siistinä pillerinä. */
  border-radius: 999px;
  box-shadow: none;
}

.dialog .kartta-tyokalut button:hover:not(:disabled) {
  border-color: rgba(70, 51, 31, 0.75);
  background: rgba(255, 250, 238, 0.95);
}

/* Valittu näkymä on painettu musteella: se ei ole enää tarjous. */
.dialog .kartta-tyokalut button[aria-pressed="true"] {
  color: #fdf6e5;
  background: #46331f;
  border-color: #2c2318;
}

/*
 * Painetun napin hover EI saa vaalentaa taustaa: yllä oleva
 * hover-sääntö (0,4,1) voitti painetun tilan (0,3,1), jolloin iOS:n
 * tahmeassa hoverissa vaalea teksti jäi vaalealle pohjalle ja
 * "teksti katosi" (omistajan havainto 15.8.2026).
 */
.dialog .kartta-tyokalut button[aria-pressed="true"]:hover:not(:disabled) {
  background: #46331f;
  border-color: #2c2318;
}

/* Plus ja miinus ovat merkkejä eivätkä sanoja: merkki saa olla
 * näkymävivun tekstiä isompi, mutta painikkeen KORKEUS pysyy samana —
 * rivillä on kaksi säädinryhmää, ja eri korkuisina ne näyttäisivät
 * kahdelta eri työkalulta. Siksi line-height on lukittu. */
.dialog .kartta-tyokalut button.kartta-zoomi-nappi {
  min-width: 2rem;
  justify-content: center;
  padding: 0.2rem 0.55rem;
  font-size: 0.92rem;
  line-height: 0.72rem;
  letter-spacing: 0;
}

.dialog .kartta-tyokalut button.kartta-zoomi-nappi:disabled {
  opacity: 0.4;
  cursor: default;
}

/*
 * Mittajana satelliittikuvan päällä. Jana on piirretty paperin
 * väreillä vaalean julisteen päälle, ja satelliittikuvan tummassa
 * puistossa se katosi lähes kokonaan. Pituus ja teksti pysyvät
 * samoina — vahvistetaan vain tausta, jotta jana kelpaa molemmilla
 * pohjilla.
 */
.kaupunkikartta-kotelo.satelliittinakyma .kartta-mittajana {
  border-color: rgba(247, 240, 222, 0.9);
  background: linear-gradient(rgba(247, 240, 222, 0) 40%, rgba(247, 240, 222, 0.85) 40%);
}

.kaupunkikartta-kotelo.satelliittinakyma .kartta-mittajana-teksti {
  color: #2c2318;
  background: rgba(247, 240, 222, 0.92);
}

/*
 * OSM-merkintä pieneksi mutta EI pois (omistajan palaute 8.8.2026:
 * "paljon pienemmällä"). Merkintä on OpenStreetMapin lisenssiehto
 * (ODbL), joten se ei ole koriste vaan velvoite — siksi se pienenee
 * mutta pysyy luettavana ja omalla rivillään. Ilman tätä sääntöä rivi
 * peri lehden leipätekstin koon ja huusi kovempaa kuin kartan
 * kohdeselitteet.
 */
.kaupunkikartta > .lahde {
  margin: 0.1rem 0 0;
  font-family: var(--font-type);
  font-size: 0.58rem;
  line-height: 1.4;
  color: rgba(90, 74, 51, 0.8);
}

/*
 * NUMEROYMPYRÄSTÄ TÄPLÄKSI (omistajan tilaus 23.8.2026: "Ota numerot
 * pois kartalta myös kokosivun näkymässä mutta lisää kohteiden nimet
 * näkyviin yksinkertaisella tekstillä").
 *
 * Piirroksettomasta kohteesta ei voi poistaa merkkiä kokonaan — ilman
 * sitä kohdetta ei näkisi kartalla lainkaan — mutta numeroa se ei enää
 * tarvitse, koska nimi lukee sen alla (.kohde-nimi). Ympyrä kutistuu
 * siis 24 pikselistä täpläksi, joka on kartan merkki eikä lappu.
 *
 * Vaalea hiekka ja tumma reunaviiva ovat 8.8.2026 tehty valinta: ne
 * ovat ainoa asia, joka erottaa merkin vaalean kartan päältä nyt kun
 * sekä kartta että merkki ovat vaaleita. Luokan nimi on yhä
 * kohde-numero, koska se on kohdekartan merkin tunnus koodissa,
 * savukkeissa ja tarkistustyökaluissa — numeroa siinä ei enää ole.
 */
.maakartta-piste.kohde-numero {
  width: 13px;
  height: 13px;
  background: #e8d3a0;
  border: 1.5px solid #2c2318;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

/* Piirros numeron paikalla (omistajan tilaukset 15.8.2026): leikattu
 * kuva suoraan kartan päällä — ei ympyrää, taustaa, reunaa eikä
 * numerobadgea. Laatikko on ympyrää suurempi, koska leikatun kuvan
 * reunoilla on läpinäkyvää tyhjää; drop-shadow seuraa piirroksen
 * ääriviivaa, ei laatikkoa. Näkyvä koko 40 px (omistajan palautteet
 * 15.8.2026: 64 → "pienemmiksi" 48 → "vielä pienemmät" 40).
 *
 * Pienenä koko piirros on klikattavissa (omistajan tarkennus
 * 15.8.2026: osuma-alueen puolitus koskee vain SUURENNETTUA tilaa —
 * "siis silloin kun nähtävyys on isona kartalla, ei silloin kun se
 * on pienenä"). */
.maakartta-piste.kohde-numero.kohde-piirros {
  width: 40px;
  height: 40px;
  background: none;
  border: none;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
}

/*
 * PIIRROS SKAALAUTUU KARTAN MUKANA (omistajan tilaus 15.8.2026:
 * "Kuvat pitäisi pysyä saman kokoisina suhteessa karttaan kun
 * zoomataan"). Piirros on kartan maamerkki eikä käyttöliittymän
 * nappi, joten se EI saa numeroympyrän vastaskaalausta (yllä oleva
 * .kartta-lava-sääntö kumotaan tässä) — zoomatessa se kasvaa kartan
 * piirtoviivojen tahdissa.
 */
.kartta-lava .maakartta-piste.kohde-numero.kohde-piirros {
  transform: translate(-50%, -50%);
}

.kohde-piirros-kuva {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35));
  /* Klikki kuuluu napille, ei kuvalle — suurennettuna kuva vuotaa
   * laatikon yli, eikä ylivuoto saa napata napautuksia. */
  pointer-events: none;
}

/*
 * SUURENNETUN OSUMA-ALUE ON 50 % KUVASTA (omistajan tilaus
 * 15.8.2026: "pienennä nähtävyyden klikkaus 50 prosenttiin ...
 * silloin kun nähtävyys on isona kartalla"). Laatikko on puolet
 * näkyvästä kuvasta (37.5cqh) ja kuva vuotaa sen yli 200 %:iin eli
 * entiseen 75 %:n kokoon. Leikatun kuvan läpinäkyvälle reunalle
 * osuva klikkaus menee laatikon ohi karttaan ja PALAUTTAA valinnan —
 * juttu aukeaa vain kuvan keskiosasta tai kyltistä.
 */
.kohde-piirros.valittu .kohde-piirros-kuva {
  left: -50%;
  top: -50%;
  width: 200%;
  height: 200%;
  /* Globaali img { max-width: 100% } leikkaisi ylivuodon takaisin
   * laatikon kokoon — piirros kutistuisi osuma-alueen mukana. */
  max-width: none;
}

/*
 * VALITTU PIIRROS (omistajan tilaukset 15.8.2026, viimeisin
 * täsmennykset: 40 % → 65 % → 70 % → "75 koko"; keskitys ja paluu
 * paikalleen hoidetaan ui.js:ssä). Napautus lisää .valittu-luokan: piirros kasvaa
 * 65 %:iin KARTTAIKKUNAN korkeudesta (65cqh kehyskontista) ja nimikyltti aukeaa sen alle
 * (aina alle, ks. .kohde-kyltti); uusi napautus palauttaa —
 * ikkunaa ei avata. Jako zoomilla kumoaa lavan skaalan, joten
 * näkyvä koko on sama joka zoomiasennossa.
 */
.maakartta-piste.kohde-numero.kohde-piirros {
  transition: width 160ms ease, height 160ms ease,
    left 160ms ease, top 160ms ease;
}

.kartta-lava .maakartta-piste.kohde-numero.kohde-piirros.valittu {
  /* Laatikko on PUOLET näkyvästä kuvasta: kuva (200 %) täyttää
   * entisen 75 %:n karttaikkunasta, osuma-alue vain keskiosan. */
  width: calc(37.5cqh / var(--zoom));
  height: calc(37.5cqh / var(--zoom));
  z-index: 5;
}

@media (prefers-reduced-motion: reduce) {
  .maakartta-piste.kohde-numero.kohde-piirros { transition: none; }
}

/* Valitun kyltti korvaa hover-vihjeen — kaksi nimeä päällekkäin
 * olisi pahempi kuin ei kumpaakaan. */
.kohde-piirros.valittu .kohde-vihje { display: none; }

/* Piirros nähtävyysjutun avauskappaleen oikeassa laidassa (omistajan
 * tilaus 15.8.2026): teksti kiertää vasemmalta. Marginaalit nollassa
 * tarkoituksella — leikatun kuvan oma läpinäkyvä reuna on jo väljä. */
.nahtavyys-piirros {
  float: right;
  width: clamp(7rem, 34%, 11rem);
  height: auto;
  margin: 0;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.25));
}

/* Kyltti napautuksesta juttuun (omistajan tilaus 15.8.2026:
 * "klikkaamalla avautuvaa nimikylttiä pitäisi päästä kohteen
 * pop-up-ikkunaan") — ks. ui.js:n napautuskäsittelijä. Vastaskaalaus
 * zoomilla pitää kyltin näkyvän koon vakiona, koska valittu piste ei
 * enää skaalaa lapsiaan transformilla. */
.kohde-kyltti {
  display: none;
  position: absolute;
  left: 50%;
  /*
   * KYLTTI RAKENNUKSEN JALAN ALLE (omistajan tilaus 23.8.2026:
   * kyltti istui suurennetun piirroksen päällä ja peitti kuvaa).
   *
   * Paikka tulee mitattuna piirroksesta: js/nahtavyydet.js etsii
   * kuvan alimman läpinäkymättömän rivin ja kirjoittaa sen tähän
   * muuttujaan laatikon koordinaatistossa (kuva vuotaa laatikon yli
   * −50 %:sta 150 %:iin, joten kuvan alareuna on laatikon 150 %).
   * Varapaikka on koko kuvan alareuna: kyltti ei silloinkaan peitä
   * rakennusta, korkeintaan jää siitä hitusen irralleen.
   *
   * Kiinteä luku (aiemmin kuvan 73 %) ei voi toimia: neliön
   * kokoisissa miniatyyreissä korkea torni yltää alareunaan asti ja
   * matala rakennus jättää alleen leveän tyhjän kaistan.
   */
  top: var(--kyltti-top, 153%);
  transform: translateX(-50%) scale(calc(1 / var(--zoom, 1)));
  transform-origin: top center;
  padding: 0.2rem 0.55rem;
  white-space: nowrap;
  font-family: var(--font-type);
  /* Nimikyltin kirjasin 0,74rem → 0,95rem (omistajan tilaus
   * 18.8.2026: nimen pitää erottua vaivatta myös puhelimella).
   * Kyltti näkyy vain valitusta kohteesta kerrallaan ja kohde on
   * silloin keskitetty, joten kasvu ei kasaa nimiä päällekkäin
   * tiheälläkään kartalla. */
  font-size: 0.95rem;
  letter-spacing: 0.03em;
  color: #2c1e07;
  background-color: #f5f0e2;
  border: 1px solid rgba(70, 51, 31, 0.55);
  border-radius: 3px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}

.kohde-piirros.valittu .kohde-kyltti { display: block; }

/*
 * KOHTEEN NIMI KARTALLE NUMERON TILALLE (omistajan tilaus 23.8.2026:
 * "Ota numerot pois kartalta myös kokosivun näkymässä mutta lisää
 * kohteiden nimet näkyviin yksinkertaisella tekstillä. Koko voi olla
 * sen verran pieni että pitää vähän zoomata että näkee.")
 *
 * KOKO ON PIENI TARKOITUKSELLA. 0,6 rem on noin 9,6 px kartan omassa
 * mittakaavassa: lepotilassa nimi on hiljainen merkintä kartalla, ja
 * zoomatessa se kasvaa kartan tahdissa luettavaksi — juuri niin kuin
 * omistaja pyysi. Konekirjoituskirjasin on sama kuin mittajanalla ja
 * nimikyltillä, joten kartta puhuu yhtä kieltä.
 *
 * NIMI MENEE MERKIN ALLE, EI SEN PÄÄLLE. Piirroskohteella paikka on
 * mitattu rakennuksen jalka (--nimi-top, js/nahtavyydet.js:
 * asetaKylttiRaja) — sama mittaus, joka asettaa suurennetun kyltin.
 * Täplällä riittää täplän alareuna. Teksti on keskitetty ja katkeaa
 * enintään parille riville, jottei pitkä nimi ("Temppeliaukion
 * kirkko") vedä viivaa naapurikorttelin yli.
 *
 * VAALEA HALO, EI LAPPUA. Kartta on värikäs, ja umpinainen taustalappu
 * jokaisen kohteen alla peittäisi juuri sen kaupungin, jota katsotaan.
 * Paperinvärinen hehku irrottaa tekstin tiestöstä ilman, että kartta
 * katoaa sen alle — sama keino kuin maalehden korkokartan
 * kaupunkinimissä (.maakartta-nimi).
 *
 * pointer-events: none — nimi on merkintää, ei osumapintaa: napautus
 * menee sen läpi kartalle (tai merkille, joka on sen alla).
 */
.kohde-nimi {
  position: absolute;
  left: 50%;
  top: calc(100% + 2px);
  z-index: 1;
  width: 6.5rem;
  transform: translateX(calc(-50% + var(--nimi-siirto, 0px)));
  font-family: var(--font-type);
  font-size: 0.6rem;
  line-height: 1.15;
  letter-spacing: 0.02em;
  text-align: center;
  color: #16130f;
  text-shadow:
    0 0 3px rgba(247, 239, 220, 0.95),
    0 0 6px rgba(247, 239, 220, 0.9),
    0 0 9px rgba(247, 239, 220, 0.85);
  pointer-events: none;
  /*
   * NIMET NÄKYVÄT VAIN ZOOMATTUNA (omistaja 4.9.2026 ilta, Sarajevon
   * kuvakaappaus: "Kartassa ei pitäisi näkyä selitteitä"). Lepotilassa
   * kartta on pelkkiä merkkejä ja piirroksia; nimet ovat listassa
   * kartan alla ja tulevat kartalle vasta, kun pelaaja zoomaa — juuri
   * niin kuin 23.8. tilaus sanoi ("pitää vähän zoomata että näkee").
   * Kehys saa luokan .zoomattu js/karttazoom.js:stä.
   */
  opacity: 0;
  transition: opacity 0.35s ease-out;
}

.kartta-kehys.zoomattu .kohde-nimi { opacity: 1; }

/*
 * KAPEALLA RUUDULLA VIELÄ PIENEMPI. Kartan kohteet ovat kartalla
 * yhtä tiheässä joka ruudulla, mutta puhelimen lehdessä kartta on
 * noin 360 px leveä — sama nimiladelma vie siinä kaksinkertaisen
 * osuuden kartasta ja naapurien nimet menevät ristiin. Pienempi
 * kirjasin ja kapeampi palsta pitävät nimet omilla paikoillaan;
 * lukeminen tapahtuu puhelimella joka tapauksessa zoomaamalla tai
 * kokoruudulla.
 */
@media (max-width: 560px) {
  .kohde-nimi {
    width: 4.6rem;
    font-size: 0.5rem;
  }
}

/* Piirroskohteella nimi alkaa rakennuksen jalasta (mitattu) eikä
 * laatikon alareunasta: matala rakennus jättää laatikon alalaitaan
 * läpinäkyvää tyhjää, jossa nimi olisi turhan kaukana. */
.kohde-piirros > .kohde-nimi { top: var(--nimi-top, 104%); }

/*
 * NIMI EI KASVA KARTAN MUKANA (4.9.2026, samassa erässä kuin nimien
 * piilotus lepotilassa). Kun nimi näkyy vain zoomattuna, sen tehtävä
 * on olla luettava juuri silloin — ja zoomaus levittää merkit
 * erilleen vain, jos nimi pysyy ruudulla samankokoisena eikä paisu
 * merkkien mukana (Sarajevon kolme basaarikohdetta menivät ristiin
 * joka zoomilla, koska välit ja tekstit kasvoivat samassa suhteessa).
 * Piirros itse kasvaa lavan mukana, joten nimi vastaskaalataan
 * lavan --zoom-arvolla; täplä on jo vastaskaalattu, joten sen nimi
 * ei tarvitse kerrointa lainkaan. Origo tekstin yläreunassa pitää
 * nimen kiinni merkin jalassa.
 */
.kohde-piirros > .kohde-nimi {
  transform: translateX(calc(-50% + var(--nimi-siirto, 0px))) scale(calc(1 / var(--zoom, 1)));
  transform-origin: top center;
}
.kartta-kehys.zoomattu .kohde-nimi { font-size: 0.72rem; }

/*
 * NIMIÖN VÄISTÖ (omistajan tilaus 2.9.2026:n erässä, kun kartalle tuli
 * karsittuja karttanostoja). Merkki pysyy koordinaatissaan ja nimiö
 * siirtyy sivuun — sama periaate kuin pääkartan nimiöillä
 * (js/fokusniput.js sääntö 2). Siirto on 2,6 rem eli noin 40 % nimen
 * palstasta: se irrottaa naapurin nimestä mutta jättää nimen yhä
 * merkkinsä kylkeen. Puoli tulee datasta (`nimiPuoli`,
 * js/nahtavyydet.js).
 */
.maakartta-piste.kohde-nimi-vasen { --nimi-siirto: -2.6rem; }
.maakartta-piste.kohde-nimi-oikea { --nimi-siirto: 2.6rem; }

@media (max-width: 560px) {
  /* Kapealla ruudulla nimipalsta on 4,6 rem, joten sama 40 %. */
  .maakartta-piste.kohde-nimi-vasen { --nimi-siirto: -1.85rem; }
  .maakartta-piste.kohde-nimi-oikea { --nimi-siirto: 1.85rem; }
}

/*
 * NIMI KASVAA KARTAN MUKANA MYÖS TÄPLÄLLÄ. Täplä on merkki eikä
 * maisema, joten se saa lavan vastaskaalauksen (1/zoom) — nimi ei:
 * omistaja pyysi tekstin, jonka näkee zoomaamalla. Kerroin zoomilla
 * kumoaa vastaskaalauksen, jolloin nimi elää kartan mittakaavassa
 * kuten piirrosten nimet (piirros ei saa vastaskaalausta lainkaan).
 * Origo on tekstin yläreunassa, joten kasvu suuntautuu merkistä
 * alaspäin eikä sen päälle.
 */
.kartta-lava .maakartta-piste:not(.kohde-piirros) > .kohde-nimi {
  /* 4.9.2026: zoomkerroin poistettu — nimi pysyy ruudulla
   * samankokoisena kuin täplänsä (ks. .kohde-piirros > .kohde-nimi). */
  transform: translateX(calc(-50% + var(--nimi-siirto, 0px)));
  transform-origin: top center;
}

/* Valittu piirros näyttää nimensä isossa kyltissä (ks. .kohde-kyltti),
 * joten kartan pieni nimi väistyy suurennoksen ajaksi — sama sääntö
 * kuin hover-vihjeellä, ja samasta syystä: kaksi nimeä päällekkäin
 * olisi pahempi kuin ei kumpaakaan. */
.kohde-piirros.valittu .kohde-nimi { display: none; }

/*
 * Kohteen nimi hiiren alla — VAIN osoitinlaitteella.
 *
 * Sääntö on kokonaan `hover: hover` -kyselyn sisällä, joten
 * kosketuslaitteella vihjettä ei ole olemassa eikä sen olemassaolo voi
 * muuttaa napautuksen käytöstä millään tavalla: puhelimella ja
 * tabletilla napautus avaa jutun kuten ennenkin. Tämä on turvallisempi
 * kuin näyttää vihje ja piilottaa se kosketuksella, koska moni
 * kosketuslaite emuloi hoveria ensimmäisellä napautuksella.
 *
 * Vihje saa mennä kartan reunan yli: kotelossa ei ole leikkausta.
 */
.kohde-vihje { display: none; }

@media (hover: hover) and (pointer: fine) {
  .kohde-vihje {
    display: block;
    position: absolute;
    bottom: calc(100% + 7px);
    left: 50%;
    transform: translateX(-50%);
    padding: 0.16rem 0.45rem;
    white-space: nowrap;
    font-family: var(--font-type);
    font-size: 0.68rem;
    font-weight: 400;
    line-height: 1.3;
    color: #f4ead2;
    background: rgba(38, 29, 16, 0.94);
    border-radius: 3px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.35);
    opacity: 0;
    /* Vihje ei saa napata hiirtä: muuten se peittäisi viereisen
     * ympyrän ja vilkkuisi, kun osoitin osuu sen reunaan. */
    pointer-events: none;
    transition: opacity 0.12s ease-out;
  }

  /* Kolmio vihjeen alle, jotta se osoittaa omaan ympyräänsä silloinkin
   * kun ympyröitä on vierekkäin. */
  .kohde-vihje::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 4px solid transparent;
    border-top-color: rgba(38, 29, 16, 0.94);
  }

  /* Yläreunan kohteilla vihje aukeaa alaspäin: zoomattava kartta on
   * leikkaava ikkuna, ja ylöspäin aukeava vihje jäisi sen taakse
   * (ui.js merkitsee luokan kohteen paikasta). */
  .maakartta-piste.vihje-alle .kohde-vihje {
    bottom: auto;
    top: calc(100% + 7px);
  }

  .maakartta-piste.vihje-alle .kohde-vihje::after {
    top: auto;
    bottom: 100%;
    border-top-color: transparent;
    border-bottom-color: rgba(38, 29, 16, 0.94);
  }

  .maakartta-piste.kohde-numero:hover .kohde-vihje,
  .maakartta-piste.kohde-numero:focus-visible .kohde-vihje { opacity: 1; }
}

.kartta-selitteet {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1.1rem;
  margin: 0 0 0.35rem;
}

.dialog .kartta-selitteet .kartta-selite {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 0;
  padding: 0.1rem 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  color: #3a2d1c;
}

/* Kevyempi alleviivaus (omistajan toive 8.8.2026: "linkkitekstit
 * voisi olla vähän kevyemmin alleviivattu"). Kolme säädintä yhdessä:
 * ohuempi viiva, haaleampi sävy ja isompi väli tekstiin. Selitteitä on
 * kuusi vierekkäin, joten täysvahva viiva teki rivistä raidallisen —
 * nyt linkki näyttää linkiltä mutta nimi luetaan ensin. Osoittimen
 * alla viiva tummuu takaisin, eli affordanssi palaa juuri silloin kun
 * sitä tarvitaan. */
.dialog .kartta-selitteet button.kartta-selite {
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(70, 51, 31, 0.26);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.dialog .kartta-selitteet button.kartta-selite:hover:not(:disabled) {
  background: none;
  color: #16130f;
  text-decoration-color: #16130f;
}

/* Numeropallo. Kartan selitelistoista se poistui 23.8.2026 numeroiden
 * mukana (ks. .kohde-nimi); jäljellä se on nähtävyysjutun
 * kohdevalikossa (.nahtavyys-valikko-rivi), jossa numero kertoo
 * monesko kohde on lukuvuorossa. Vaalea hiekka ja tumma reunaviiva
 * ovat kartan merkin väreistä (8.8.2026), lähes musta numero antaa
 * tekstille noin 9:1 kontrastin. */
.kartta-selite-numero {
  flex: 0 0 auto;
  width: 1.2rem;
  height: 1.2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #e8d3a0;
  border: 1px solid #2c2318;
  color: #2c1e07;
  font-size: 0.64rem;
  font-weight: 700;
  line-height: 1;
}

/*
 * Päivän kuva (Commonsin päivän kuva) maaosion aloitussivun lopussa
 * — lehden kuvapalsta, vaihtuu joka päivä.
 */
.paivan-kuva {
  clear: both;
  margin-top: 0.8rem;
  padding-top: 0.6rem;
  border-top: 3px double rgba(70, 51, 31, 0.75);
}

.paivan-kuva-nimio { text-align: center; letter-spacing: 0.28em; }

.paivan-kuva img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 2px;
  margin: 0.2rem 0 0.35rem;
}

.paivan-kuva-selite {
  margin: 0 0 0.2rem;
  font-size: 0.82rem;
  line-height: 1.42;
  color: rgba(70, 51, 31, 0.82);
}

.paivan-kuva .lahde {
  margin: 0;
  font-family: var(--font-type);
  font-size: 0.62rem;
  color: rgba(90, 74, 51, 0.75);
}

/* ── NÄHTÄVYYSJUTTU ────────────────────────────────────────────────────
 *
 * Kaupunkikartan kohteen oma juttu (omistajan toive 7.8.2026:
 * "kirjoita itse nähtävyyksien tekstit ... kuvia voisi näyttää niiden
 * nostossa gallerian sijaan tekstin joukossa 3-5" ja "tee noista
 * teksteistä mahdollisimman selkeitä, käytä vuosiluku korostuksia,
 * lainaus nostoja ja lyhyitä kappaleita").
 *
 * Taitto on lehtijutun taitto: kapea palsta, ilmavat kappalevälit,
 * kuvat omina lohkoinaan tekstin seassa. Sama paperi ja kirjasin kuin
 * muualla lehdessä — arkki-luokka hoitaa pohjan.
 *
 * Nähtävyys on kelluva paperikortti kartan päällä, EI koko ruudun
 * lehtiarkki (kuten #arrival-maa:n newspaper-lukunäkymä). Se jakaa
 * silti arkki-luokan (sama paperi/kirjasin), ja arkki-luokalla on omat
 * leveys/korkeussääntönsä 700 px:stä ylöspäin (.dialog.arkki, .dialog.arkki
 * .dialog-card — rivi ~6625), jotka tekevät lehdestä koko ruudun
 * korkuisen ja -levyisen. Ilman tätä omaa kumoavaa sääntöä nähtävyys
 * peri saman: kortti täytti koko näytön leveyden JA korkeuden myös
 * tabletilla, tausta ei näkynyt reunoilla ja yläreuna painui pois
 * näkyvistä (omistajan löytö iPadilla 8.8.2026, kaappaus 834×1114).
 * Leveys+korkeus+marginaali on siis kumottava täällä nimenomaisesti,
 * samalla erottelutarkkuudella (dialog+arkki+nahtavyys-arkki = kolme
 * luokkaa) kuin kumottava sääntö, jotta myöhempi sijainti tiedostossa
 * ratkaisee. JOKAINEN kumottava ominaisuus (height, width, max-width)
 * on nollattava eksplisiittisesti — jos jättää yhdenkin asettamatta,
 * kaskadi hakee sen yhä aiemmasta arkki-säännöstä, koska "en aseta
 * mitään" ei voita "asetin jonkin arvon" samalla erottelutarkkuudella.
 */
.dialog.nahtavyys-arkki {
  /*
   * Keskitys on kumottava erikseen: .dialog.arkki asettaa
   * margin: 0 + inset: 0 (lehti täyttää ruudun, joten sillä ei ole
   * keskitettävää), ja pelkkä koon palautus jätti nähtävyyskortin
   * roikkumaan vasempaan yläkulmaan — iPhonella otsikko jäi
   * tilapalkin alle eikä taustasivu näkynyt vasemmalla (omistajan
   * löytö 8.8.2026, v368). inset: 0 + margin: auto on tapa, jolla
   * selain itse keskittää modaalin molemmilla akseleilla.
   */
  inset: 0;
  margin: auto;
  width: min(90vw, 640px);
  /*
   * fit-content, EI auto: .dialog on flex, ja auto-korkuinen dialogi
   * venyi maksimikorkeuteen, jolloin kortti keskittyi sen sisällä ja
   * dialogiin ankkuroidut napit (laskuri, kaiutin, paluunuoli) jäivät
   * ruudun yläreunaan irralleen kortista — ja hyppivät kortin
   * korkeuden eläessä (omistajan havainto 15.8.2026 iPadilla:
   * "yläosa hyppii"). fit-contentilla dialogi syleilee korttia ja
   * napit istuvat aina kortin yläkulmassa.
   */
  height: fit-content;
  /* Safe area mukaan: iOS:n loveus ja kotipalkki eivät saa syödä
   * kortin reunoja, joten pystyvara lasketaan niiden yli. */
  max-height: calc(100dvh - 3rem
    - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
}

/*
 * SAMA TURVA-ALUEIDEN SIJOITUS KUIN LEHTIARKILLA (ks. `.dialog.arkki`
 * ≥700 px). Nähtävyys- ja opasarkki palauttaa keskityksen omalla
 * `inset: 0; margin: auto` -säännöllään yllä, ja koska se tulee
 * tiedostossa myöhemmin samalla erottelutarkkuudella, se kumosi
 * lehtiarkin turvallisen ankkurilaatikon: arkki keskittyi taas KOKO
 * ruutuun ja turva-alueiden vähennys puolittui molempiin päihin
 * (mitattu 834x1112, ala 34 px: ylä- ja alarako kumpikin 41 px, eli
 * ylhäällä 41 px turhaa sumennettua kaistaa ja alhaalla vain 7 px
 * kotipalkin yli). Ankkurilaatikko siirretään siis täälläkin
 * turva-alueiden sisään; katto (100dvh − 3rem − turvat) on jo
 * valmiiksi juuri tämän laatikon mitta.
 *
 * Vain leveä ruutu: kapealla ruudulla arkki on ankkuroitu alareunaan
 * omalla marginaalillaan (`margin: auto auto calc(0.6rem + safe)`),
 * joka varaa kotipalkin tilan jo itse — inset lisäisi sen toiseen
 * kertaan.
 */
@media (min-width: 700px) {
  .dialog.nahtavyys-arkki {
    top: var(--turva-yla);
    bottom: var(--turva-ala);
  }
}

/*
 * OTSIKON PEITON JUURISYY (löytyi 16.8.2026, omistajan kolmas
 * havainto "otsikko jää puoliksi piiloon"): lehden tarttuva
 * paperikaista (.dialog.arkki .dialog-card::before, ≥700 px) osuu
 * myös nähtävyyskorttiin, koska dialogilla on sama arkki-luokka —
 * kaista maalasi paperia jutun otsikon yläosan PÄÄLLE heti
 * avauksesta asti. Vika ei siis ollut vieritystä laisinkaan
 * (scrollTop pysyi nollassa), minkä vuoksi v759:n ja v762:n
 * vieritysnollaukset eivät auttaneet. Nähtävyyskortissa ei ole
 * tarttuvaa nimiötä, joten kaistaa ei tarvita lainkaan.
 */
.dialog.arkki.nahtavyys-arkki .nahtavyys-kortti::before {
  content: none;
}

/*
 * Valitsimessa on .arkki mukana erottelutarkkuuden takia:
 * .dialog.arkki:not(.lehti) .dialog-card (0,4,0 — :not:n sisältö
 * lasketaan) voitti aiemman .dialog.nahtavyys-arkki-muodon (0,3,0),
 * jolloin max-height: inherit EI päässyt voimaan ja kortti sai
 * lehtisäännön katon calc(100dvh - 2.4rem). Se on 0,6rem korkeampi
 * kuin dialogin oma katto (100dvh - 3rem), joten kortti pisti
 * flex-keskitettynä ~5 px yli dialogin molemmista päistä (mitattu
 * 16.8.2026 otsikkopeittoa jäljittäessä).
 */
.dialog.arkki.nahtavyys-arkki .nahtavyys-kortti {
  width: auto;
  max-width: none;
  height: auto;
  /*
   * Katto INHERIT-arvolla, ei prosenttina: dialogin korkeus on auto,
   * ja prosentti autokorkuista vanhempaa vasten ei rajoita mitään —
   * kortti kasvoi dialogin ohi ja alareuna leikkautui iPhonella
   * (omistajan löytö 8.8.2026, East Side Gallery). inherit kopioi
   * dialogin dvh+safe-area-katon, jolloin pitkä juttu rullaa kortin
   * sisällä eikä jatku ruudun ali.
   */
  max-height: inherit;
  overflow-y: auto;
  overscroll-behavior: contain;
  /*
   * Vieritysankkurointi POIS (omistajan havainto 15.8.2026: "otsikko
   * jää puoliksi piiloon"): kun karusellin kuva latautuu avauksen
   * jälkeen, selain ankkuroi näkymän alempaan kappaleeseen ja juttu
   * liukuu alas — otsikko katoaa yläreunan taakse, vaikka kukaan ei
   * vierittänyt. Juttu avataan aina alusta, joten ankkuroinnista ei
   * ole tässä kortissa mitään hyötyä.
   */
  overflow-anchor: none;
  padding: 1.2rem 1.15rem 1rem;
}

/*
 * Kapealla ruudulla kortti on pohja-arkki: se lepää ruudun alareunassa
 * eikä kellu keskellä. Keskitetty kortti jätti alle kaistaleen tyhjää
 * taustaa (omistajan löytö 8.8.2026, Brandenburgin portti: "pop-up-
 * ikkuna saisi ulottua ihan alas asti"), koska pystyvara jakautui
 * margin: auto -keskityksessä puoliksi ylä- ja alapuolelle. Alareunaan
 * ankkuroituna koko vara on yläpuolella ja alareuna on kiinni ruudussa
 * — sama ele kuin lehden sisällysluettelolla, joka aukeaa alareunaan.
 */
@media (max-width: 699px) {
  .dialog.nahtavyys-arkki {
    /*
     * 10.8.2026: omistaja muutti 8.8:n pohja-ankkurin ("saisi ulottua
     * ihan alas asti") — "voisi olla aavistuksen irti myös
     * alareunasta, näyttäisi kivemmalta". Pieni rako alas kotipalkin
     * yli; kortti kelluu taas ja pyöristys palaa joka kulmaan.
     */
    margin: auto auto calc(0.6rem + env(safe-area-inset-bottom, 0px));
    max-height: calc(100dvh - 2.85rem
      - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
  }
}

/* Isolla ruudulla (iPad, työpöytä) nähtävyyskortti saa olla leveämpi
 * (omistajan palaute 15.8.2026: "liian kapea"; uudelleen 18.8.2026
 * iPad-kaappauksesta: yhä liian kapea) — teksti ja kuvat hengittävät,
 * mutta palsta pysyy luettavana: kirjoituskonekirjasin on niin leveää,
 * että rivi jää 860 pikselin kortissakin alle ~70 merkin. Sama mitta
 * ja raja kuin Lue lisää -arkilla (#wiki-dialog), jotta kartan kaksi
 * juttuikkunaa ovat samaa kokoa. JS asettaa saman mitan myös
 * pikseleinä (mitoitaNahtavyysDialogi), koska WKWebView'n jämähtänyt
 * viewportti voi valehdella tälle media querylle. Opas pitää oman
 * julistemittansa — sen taitto on viritetty 84 vw:lle. */
@media (min-width: 700px) {
  .dialog.nahtavyys-arkki:not(.opas-arkki) {
    width: min(92vw, 860px);
  }
}

@media (min-width: 760px) {
  .dialog.nahtavyys-arkki.opas-arkki {
    width: min(84vw, 840px);
  }
}

/* Vuosiluku ja kohdenumero otsikon yllä: pieni kirjasinkokoinen
 * leimarivi, joka kertoo ajan ennen kuin nimi ehtii kertoa paikan. */
.nahtavyys-aika {
  margin: 0 0 0.15rem;
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.72);
}

#nahtavyys-otsikko {
  margin: 0 0 0.7rem;
  line-height: 1.15;
}

/*
 * KAIUTIN OTSIKON PERÄSSÄ (omistajan tilaus 16.8.2026). Nappi asuu nyt
 * otsikon sisällä (ui.js avaaNahtavyys), joten oletussääntöjen absoluut-
 * tinen asemointi puretaan ja nappi ladotaan tekstin perään.
 *
 * Ilme on sama kuin lehden ja "Lue lisää" -ikkunan kaiuttimella: pelkkä
 * mustepiirros ilman nappikehystä ja ilman pyöreää taustaa. Osuma-alue
 * on 40 px, vaikka kuvake on pienempi.
 *
 * Valitsimessa on `.dialog button` mukana samasta syystä kuin muissakin
 * kaiutinsäännöissä: dialogien yleissääntö maalaa jokaisen napin
 * pergamenttilaatikoksi ja voittaisi muuten tarkkuudessa.
 */
#nahtavyys-otsikko > button.lukija-nappi,
.dialog #nahtavyys-otsikko > button.lukija-nappi {
  position: static;
  transform: none;
  display: inline-grid;
  place-items: center;
  vertical-align: baseline;
  width: 1.9rem;
  height: 1.9rem;
  min-width: 40px;
  min-height: 40px;
  margin-left: 0.35rem;
  /* Kuvake istuu otsikon riville: 40 px:n osuma-alue on isompi kuin
     rivinkorkeus, joten ylimääräinen tila ei saa venyttää riviä. */
  margin-block: -0.5rem;
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  color: rgba(70, 51, 31, 0.62);
  /* Kuvakkeen koko sidotaan otsikkoon (alla), joten napin on perittävä
     otsikon kirjasinkoko eikä käytettävä napin omaa. */
  font-size: inherit;
}

/*
 * KUVAKE OTSIKON KOKOISEKSI (omistajan tilaus 16.8.2026: "suurenna
 * kaiuttimen kuvaa otsikkoon sopivammaksi"). Yleissääntö antaa
 * kaiuttimelle 1,05rem eli 16,8 px, kun kohdekortin otsikko on
 * 1,35rem eli 21,6 px — kuvake näytti otsikon vieressä pieneltä.
 *
 * Mitta on nyt 1em eli TÄSMÄLLEEN otsikon kirjasinkoko, jolloin
 * kuvake ja kirjaimet ovat samaa korkeutta. Katto on 2rem, koska sama
 * otsikko kasvaa oppaassa julisteen kokoon (clamp .. 2.9rem) — ilman
 * kattoa kaiutin kasvaisi siellä mukana ja veisi puolet rivistä.
 */
/*
 * .icon-glyph asettaa kääreelle oman 1,15rem:n kirjasinkoon, joka
 * katkaisisi em-ketjun otsikkoon (mitattuna kuvake jäi 18 px:iin
 * 21,6 px:n sijaan). Perintä palauttaa ketjun.
 */
#nahtavyys-otsikko > button.lukija-nappi .icon-glyph,
.dialog #nahtavyys-otsikko > button.lukija-nappi .icon-glyph {
  font-size: inherit;
}

#nahtavyys-otsikko > button.lukija-nappi .viiva-ikoni svg,
.dialog #nahtavyys-otsikko > button.lukija-nappi .viiva-ikoni svg {
  width: min(1em, 2rem);
  height: min(1em, 2rem);
}

#nahtavyys-otsikko > button.lukija-nappi:hover:not(:disabled),
#nahtavyys-otsikko > button.lukija-nappi:focus-visible,
.dialog #nahtavyys-otsikko > button.lukija-nappi:hover:not(:disabled),
.dialog #nahtavyys-otsikko > button.lukija-nappi:focus-visible {
  background: none;
  color: rgba(70, 51, 31, 1);
}

/* Luennan tila kerrotaan meripihkaisella musteella, ei taustalla —
   sama linjaus kuin muissa kaiuttimissa. */
#nahtavyys-otsikko > button.lukija-nappi.lukee,
.dialog #nahtavyys-otsikko > button.lukija-nappi.lukee {
  background: none;
  box-shadow: none;
  color: #a8741a;
}

/* Lyhyet kappaleet: väljä riviväli ja selvä väli kappaleiden välissä,
 * jotta silmä löytää aina seuraavan aloituksen. */
.nahtavyys-kappale {
  margin: 0 0 0.85rem;
  line-height: 1.62;
}

/* Vuosiluvut korostuvat tekstissä: <b> ladotaan konekirjoituskirjasimella
 * kuten lehden muutkin numerot, jottei korostus näytä lihavoinnilta
 * vaan leimalta. */
.nahtavyys-kappale b {
  font-family: var(--font-type);
  font-weight: 600;
  font-size: 0.95em;
  letter-spacing: 0.02em;
}

/* Lainausnosto: leveä sisennys ja pystyviiva, ei lainausmerkkikoristetta. */
.nahtavyys-lainaus {
  margin: 1.1rem 0 1.15rem;
  padding: 0.1rem 0 0.1rem 0.9rem;
  border-left: 3px solid rgba(70, 51, 31, 0.4);
}

.nahtavyys-lainaus-teksti {
  margin: 0;
  font-size: 1.06rem;
  font-style: italic;
  line-height: 1.5;
}

.nahtavyys-lainaus-lahde {
  margin: 0.35rem 0 0;
  font-family: var(--font-type);
  font-size: 0.74rem;
  color: rgba(70, 51, 31, 0.72);
}

/*
 * Kuva tekstin seassa: PIENI, ei koko palstan levyinen (omistajan
 * korjaus 8.8.2026: "kuvat aivan liian isoja... pieni kuva tekstin
 * lomassa, ei koko palstan levyinen"). Keskitetty oma lohkonsa, selite
 * ja lähde mahtuvat samaan kapeaan mittaan kuvan alle.
 */
.nahtavyys-kuvakehys {
  margin: 0 auto 1rem;
  max-width: min(58%, 300px);
}

/*
 * Ensimmäinen kuva (omistajan ohje 8.8.2026): vaakakuva saa levitä
 * koko palstalle — se avaa jutun kuin lehden pääkuva. Pystykuva ei
 * kanna isona kapeassa kortissa, joten se pysyy vaakakuvaa
 * kapeampana. Suuntaluokan (kuva-vaaka/kuva-pysty) lisää ui.js kuvan
 * latauduttua.
 *
 * PIKSELIKATTO NOSTETTU 240 → 420 (omistajan havainto 16.8.2026
 * iPadilla: "tämä kuva näkyy liian pienenä"). Prosenttiosuus oli jo
 * oikea, mutta 240 px:n katto puri leveällä ruudulla ennen sitä: iPadin
 * kortti on yli tuhat pikseliä leveä, ja pystykuva jäi siinä
 * postimerkiksi. 46 % ratkaisee kapealla ruudulla kuten ennenkin, ja
 * katto vasta leveällä.
 */
.nahtavyys-ensikuva.kuva-vaaka { max-width: 100%; }
.nahtavyys-ensikuva.kuva-pysty { max-width: min(46%, 420px); }

/*
 * KAPEA RUUTU (omistajan iPhone-kaappaus 18.8.2026 Firenzen Galleria
 * dell'Accademiasta: "kuva näkyy tässä liian pienellä"). 46 % oli
 * mitoitettu leveän kortin rytmiin, mutta 390 px:n puhelimessa kortin
 * sisäleveys on ~340 px — pystykuvaksi jää 155 px eli postimerkki, ja
 * selite katkeaa kahden sanan riveiksi sen alle. Puhelimessa avauskuva
 * saa siis koko palstan kuten vaakakuvakin; sääntö osuu kaikkien
 * kaupunkien nähtävyysjuttuihin kerralla, koska ensikuvaluokan lisää
 * nahtavyydet.js jokaisen jutun ensimmäiseen kuvaan.
 *
 * TEKSTIN LOMASSA OLEVAT KUVAT EIVÄT MUUTU: .nahtavyys-kuvakehyksen
 * oma min(58%, 300px) ja kelluvat .nahtavyys-taittokuvat pysyvät
 * pieninä, koska omistaja tilasi ne nimenomaan pieniksi 8.8.2026
 * ("pieni kuva tekstin lomassa, ei koko palstan levyinen").
 */
@media (max-width: 699px) {
  .nahtavyys-ensikuva.kuva-pysty { max-width: 100%; }
}

/*
 * Tekstin lomaan taitetut kelluvat pikkukuvat (omistajan tilaus
 * 16.8.2026 opasartikkeliin: "Kuvia pitää lisätä näkymään
 * taitettuna sivulle eri kohtiin"). Kuvat kelluvat vuorotellen
 * oikeassa ja vasemmassa laidassa ja teksti kiertää ne — sivu ei
 * veny, toisin kuin peräkkäin ladotuilla kuvilla kävisi. Selite ja
 * lähde kulkevat kuvan alla tavallista pienemmällä, jotta kapea
 * kehys ei kasva tekstiä korkeammaksi.
 */
.nahtavyys-taittokuva {
  max-width: min(46%, 260px);
  margin: 0.25rem 0 0.7rem;
}
.nahtavyys-taittokuva.oikea { float: right; margin-left: 1.1rem; }
.nahtavyys-taittokuva.vasen { float: left; margin-right: 1.1rem; }
.nahtavyys-taittokuva .nahtavyys-selite { font-size: 0.76rem; }
.nahtavyys-taittokuva .nahtavyys-lahde { font-size: 0.56rem; }

/* Kellunta ei saa vuotaa jutun lopun nappien tai lähderivin alle. */
.nahtavyys-kortti .wiki-btn,
.nahtavyys-lahderivi,
.nahtavyys-lainaus {
  clear: both;
}

.nahtavyys-kuva {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 4px;
  cursor: zoom-in;
}

/* Selite ja lähde SAMAAN inline-virtaan (23.8.2026, ks. "LÄHDERIVI
 * KUVATEKSTIN JATKEEKSI"). Flex-pylväs oli juuri se, joka pakotti
 * lähteen omalle rivilleen. */
.nahtavyys-kuvateksti {
  margin: 0.3rem 0 0;
}

.nahtavyys-selite {
  font-size: 0.88rem;
  line-height: 1.4;
}

.nahtavyys-lahde {
  font-family: var(--font-type);
  font-size: 0.62rem;
  color: rgba(70, 51, 31, 0.66);
}

/*
 * Useamman kuvan karuselli (omistajan palaute 10.8.2026: lisäkuvat
 * karuselliin, ei peräkkäin). Selaus näyttää ja toimii kuten lehden
 * kuvakotelossa: nuolet ja laskuri tulevat .arrival-kuva-nuoli- ja
 * .arrival-kuva-laskuri-luokista, pyyhkäisy vaihtaa kuvaa (ui.js).
 * Ikkuna tarvitsee vain ankkurin nuolille ja pilleille.
 */
/*
 * IKKUNAN ON OLTAVA TÄSMÄLLEEN KUVAN KOKOINEN (omistajan kuvakaappaus
 * 17.8.2026 iPadilla, Firenzen Matkailijan opas: *"karussellikuvan
 * yläosaan piirtyy tumma alue — johtuu karusellista"*).
 *
 * Nuolet ovat `position: absolute; top: 0; bottom: 0` tämän ikkunan
 * suhteen, joten ne maalaavat laitaliukuvärinsä TÄSMÄLLEEN sinne, minne
 * ikkuna yltää. Oppaan ensimmäisessä jaksossa kainalotaulu kelluu
 * oikealla (`.opas-kainalo`, float: right), ja silloin nämä kaksi
 * laatikkoa käyttäytyvät eri tavalla:
 *
 *   – KUVA on lohkotason korvattu elementti, eikä sellainen saa CSS:n
 *     mukaan mennä kellukkeen päälle: se työntyi kellukkeen ali.
 *   – IKKUNA on tavallinen lohko, joka saa mennä kellukkeen ali: se
 *     alkoi siitä, mihin teksti loppui.
 *
 * Ikkunasta tuli siis kuvaa korkeampi, ja erotus jäi kuvan YLÄPUOLELLE
 * — juuri sinne maalautuivat molempien nuolialueiden tummat
 * liukuvärit. Mitattuna iPadin pystyasennossa 29 px ja vaaka-asennossa
 * 108 px leveä palkki paperin (ja kainalotaulun alarivien) päällä.
 *
 * `clear: both` vie koko kehyksen kellukkeiden alapuolelle, jolloin
 * ikkuna alkaa samasta kohdasta kuin kuva — kuva oli siellä jo ennen
 * tätä, joten taitto ei muutu, vain haamupalkki katoaa. `flow-root`
 * on vyö henkselien lisäksi: oma lohkomuotoiluympäristö pitää ikkunan
 * kuvan mittaisena, vaikka eteen tulisi joskus toinen kelluke.
 *
 * Nuolialueita EI kavenneta: laitanapautus on oppaan ja lehden yhteinen
 * ele (omistajan toive 10.8.2026), ja liukuväri on se, joka kertoo
 * laidan olevan selattava. Vika oli mitoituksessa, ei ominaisuudessa.
 */
.nahtavyys-karuselli { clear: both; }

.karuselli-ikkuna {
  position: relative;
  display: flow-root;
}

/* Henkilölinkki nähtävyystekstissä: nimi näyttää lehden linkiltä
 * (sama muste, pisteviiva-alleviivaus) mutta on nappi, joka avaa
 * henkilön oman jutun samaan dialogiin. */
.henkilo-linkki {
  background: none;
  border: 0;
  padding: 0;
  min-height: 0;
  font: inherit;
  color: rgba(107, 76, 34, 0.95);
  text-decoration: underline dotted rgba(107, 76, 34, 0.6);
  text-underline-offset: 0.15em;
  cursor: pointer;
}

.henkilo-linkki:hover,
.henkilo-linkki:focus-visible { color: rgba(70, 51, 31, 1); }

/* Lähdemaininta ilman fi.wikipedian artikkelia: pelkkä teksti, ei
 * linkkiä eikä nappia (omistajan spesifikaatio 8.8.2026). */
.nahtavyys-lahderivi {
  margin: 0.6rem 0 0;
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.05em;
  color: rgba(70, 51, 31, 0.66);
}

/*
 * Leveällä ruudulla juttu ei saa venyä liian pitkäksi riviksi.
 * Erottelutarkkuus (dialog.nahtavyys-arkki .nahtavyys-kortti) on sama
 * kuin yllä olevalla kumoavalla säännöllä, jotta tämä leveän ruudun
 * pehmuste voittaa sen eikä jää sen alle.
 */
@media (min-width: 700px) {
  .dialog.nahtavyys-arkki .nahtavyys-kortti { padding: 1.5rem 2rem 1.2rem; }
  .nahtavyys-kappale { font-size: 1.02rem; }
}

/* ── MATKAILIJAN OPAS ──────────────────────────────────────────────────
 *
 * Omistajan linjaus 16.8.2026 (Raamattu, Kaupungit): opas on pelin
 * kevyt ja viihteellinen osa, joka houkuttelee matkustamaan — se saa
 * käyttää muuta lehteä iloisempia värejä.
 *
 * PALETTI 2.1 (omistajan palaute 16.8.2026: 2.0:n paletti oli "hieman
 * kökkö" ja vaati uudelleenajattelun). Vika ei ollut sävyissä vaan
 * siinä, että aksentteja oli KOLME YHTÄ VAHVAA ja jokaisella oli oma
 * pohjavärinsä: turkoosi sää, keltainen raha, punainen linkit. Silmä
 * ei löytänyt niistä johtajaa, ja kolme eri sävyistä laatikkoa luki
 * kolmena irrallisena tarralla, vaikka ne ovat samaa lajia. Lisäksi
 * keltainen otsikko omalla pohjallaan jäi kontrastiin 2,1:1 — se ei
 * ollut vain makuasia vaan luettavuusvirhe.
 *
 * Uusi jako on HIERARKIA, ei aihekoodi. Kaksi aksenttia, selvin
 * rooleina:
 *
 *   PÄÄAKSENTTI terrakotta  = oppaan oma ääni. Otsikko, väliotsikot,
 *                             laatikoiden otsikot, nosto, "Parasta
 *                             täällä". Lämmin, joten se soittaa samaa
 *                             säveltä kuin paperi.
 *   TUKIAKSENTTI petrooli   = faktat ja uloskäynnit. Lämpötilat,
 *                             ulkoiset linkit ja "Hyvä tietää".
 *                             Viileä vastapaino, jota on vähän.
 *   KULTA                   = pelkkä koriste: parasta-rivien tähdet.
 *                             Tummennettu okraksi, jotta se yltää
 *                             AA-kontrastiin joka pohjalla.
 *
 * Laatikot saavat YHDEN yhteisen hiekkapohjan (--opas-sivu), joten ne
 * lukevat sarjana. Ainoa paikka, jossa lämmin ja viileä pohja
 * erottavat kaksi lohkoa toisistaan, ovat kainalot — siellä ero
 * TARKOITTAA jotain (parasta vs. varjopuolet).
 *
 * Vanhan matkajulisteen henki säilyy: painovärit ovat himmeitä ja
 * hieman likaisia, ei neonia, ja paperikohina jää päälle.
 */
/*
 * Muuttujat asetetaan sekä kortille että ARKILLE (dialogille), koska
 * oppaan omat kerrokset — pikkuseloste ja säägraafin suurennos — menevät
 * dialogin sisään mutta kortin ULKOPUOLELLE: <dialog>-modaali nostetaan
 * omaan ylätasoonsa, joten kerrosta ei voi lisätä kortin sisään. Ilman
 * arkin määrittelyä ne jäisivät ilman paletin värejä.
 */
.opas-arkki,
.nahtavyys-kortti.opas-kortti {
  --opas-pohja: #f8efdc;
  --opas-muste: #3a2a15;
  --opas-muste-hento: #6d5942;
  --opas-aksentti: #a53a22;
  --opas-aksentti-vesi: #f6ddc8;
  --opas-syva: #1d5a5e;
  --opas-syva-vesi: #e0eae7;
  --opas-kulta: #7f570b;
  --opas-sivu: #f2e5c8;
  --opas-viiva: rgba(165, 58, 34, 0.3);
}

/*
 * Lämmin pohja korvaa lehden viileän painopaperin (#f5f0e2) vain
 * oppaassa. Kohina jää päälle taustakuvana, joten paperin tuntu
 * säilyy — vaihdettu on vain sen alla oleva väri. Tämä koskee vain
 * korttia: arkki sai yltä pelkät muuttujat, ei uutta ulkoasua.
 *
 * VALITSIN ON KOLMIOSAINEN TARKOITUKSELLA (omistajan löytö
 * 16.8.2026 iPad-kuvakaappauksesta): arkin oma sääntö
 * `.dialog.arkki .dialog-card` on tarkempi kuin
 * `.nahtavyys-kortti.opas-kortti`, joten opas 2.1:n lämmin paperi ei
 * koskaan päässyt voimaan. Kortti jäi lehden viileäksi, ja oppaan
 * omat laatikot loistivat sitä vasten lämpiminä laikkuina — juuri se
 * raja, jonka omistaja näki ruudulla. Älä laske tarkkuutta takaisin.
 */
.dialog.arkki .dialog-card.opas-kortti {
  background-color: var(--opas-pohja);
  color: var(--opas-muste);
}

/*
 * OTSIKKO DISPLAY-KOKOON (omistajan palaute 16.8.2026: "'Matkailijan
 * Pariisi' -otsikko isommaksi"). Kortin oletusotsikko on 21,6 px
 * kirjoituskoneella; oppaassa se on julisteen nimiö.
 *
 * Kirjasin vaihtuu antiikvaksi (--font-luku), koska kirjoituskone
 * levenee display-koossa niin paljon, että kaksisanainen nimi katkeaa
 * puhelimessa kolmelle riville. Antiikva on oppaassa jo käytössä
 * nostossa ja laatikoiden leipätekstissä, joten se ei tuo korttiin
 * uutta ääntä — se vain nostaa nimen otsikon kokoiseksi.
 */
/*
 * TARTTUVA OTSIKKORIVI (omistajan tilaus 18.8.2026: "lisätä
 * matkaopassivulle samanlainen kelluva otsikko missä on kaiuttimen
 * kuva"). Sama resepti kuin lehden nimiöllä (#arrival-city): rivi
 * tarttuu vieritysalueen yläreunaan, levittyy negatiivisilla
 * marginaaleilla paperin reunaan ja saa oman paperitaustansa, jottei
 * alta vierivä teksti kuulla läpi. Oma piirtokerros translateZ:llä
 * samasta syystä kuin lehdessä (iOS:n vieritys nyki blend-modea).
 * top: 0 vaatii, ettei kortilla ole yläpehmustetta (selaimet ovat
 * eri mieltä top: 0:n paikasta pehmusteen kanssa, ks. lehtiarkin
 * kommentti) — pehmuste siirretään otsikkoriville itselleen.
 * Oikeaan reunaan jää tila kaiuttimelle (alla), ettei pitkä nimi
 * juokse napin alle.
 */
.dialog.arkki.nahtavyys-arkki.opas-arkki .nahtavyys-kortti { padding-top: 0; }

.opas-arkki #nahtavyys-otsikko {
  position: sticky;
  top: 0;
  z-index: 3;
  transform: translateZ(0);
  margin: 0 -1.15rem 0.55rem;
  padding: 0.7rem calc(1.15rem + 2.7rem) 0.4rem 1.15rem;
  background-color: var(--opas-pohja);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  font-family: var(--font-luku);
  font-size: clamp(2rem, 6.4vw, 2.9rem);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.01em;
  color: var(--opas-aksentti);
}

/* Kortin pehmuste levenee 700 px:ssä (1.15rem → 2rem); otsikkorivin
   levitys ja sisennys seuraavat samaa mittaa. */
@media (min-width: 700px) {
  .opas-arkki #nahtavyys-otsikko {
    margin-inline: -2rem;
    padding-inline: 2rem calc(2rem + 2.7rem);
  }
}

/*
 * Kaiutin otsikkorivin oikeaan reunaan, korkeussuunnassa keskitettynä
 * (omistajan tilaus 18.8.2026: "keskitä korkeussuunnassa se ja siirrä
 * oikeaan reunaan") — sama asema kuin lehden otsikkorivin
 * kaiuttimella. Kumoaa yleisen jutturivisäännön (yllä), joka latoo
 * napin otsikkotekstin perään.
 */
.opas-arkki #nahtavyys-otsikko > button.lukija-nappi,
.dialog.opas-arkki #nahtavyys-otsikko > button.lukija-nappi {
  position: absolute;
  top: 50%;
  right: 1.15rem;
  transform: translateY(-50%);
  margin: 0;
  place-items: center end;
}

@media (min-width: 700px) {
  .opas-arkki #nahtavyys-otsikko > button.lukija-nappi,
  .dialog.opas-arkki #nahtavyys-otsikko > button.lukija-nappi {
    right: 2rem;
  }
}

/* Kaiuttimen kuvake otsikkorivissä lehden kokoa (24 px) — otsikon
   em-koko (jopa 2.9rem) tekisi siitä rivin hallitsevan merkin. */
.opas-arkki #nahtavyys-otsikko > button.lukija-nappi .viiva-ikoni svg,
.dialog.opas-arkki #nahtavyys-otsikko > button.lukija-nappi .viiva-ikoni svg {
  width: 24px;
  height: 24px;
}

/* Säätöpaneeli laskeutuu tarttuvan otsikkorivin ALLE kaiuttimen
   linjaan — ei dialogin yläkulmaan otsikon päälle. Mitta kattaa
   korkeimmankin nimiön (2.9rem + pehmusteet). */
.opas-arkki .lukija-paneeli {
  top: 4.6rem;
  right: 1.15rem;
}

@media (min-width: 700px) {
  .opas-arkki .lukija-paneeli { right: 2rem; }
}

/* Kohde-/vuosirivi on oppaassa osaston nimi, ja se saa saman
 * lämpimän sävyn kuin muukin sivumuste. */
.opas-arkki .nahtavyys-aika { color: var(--opas-muste-hento); }

/*
 * Ingressi: yksi lause isommalla, kuin lehtijutun aloitus. Se on
 * mustetta eikä aksenttia — otsikko yläpuolella kantaa jo terrakotan,
 * ja kaksi peräkkäistä väripintaa söisi otsikon uuden koon.
 * Ohut viiva alla erottaa sen ensimmäisestä jaksosta.
 */
.opas-kortti .opas-ingressi {
  font-family: var(--font-luku);
  font-size: 1.24rem;
  line-height: 1.45;
  color: var(--opas-muste);
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--opas-viiva);
  margin-bottom: 1.1rem;
}

.opas-jakso { margin: 0 0 1.35rem; }

/*
 * Väliotsikko: pieni kirjoituskonerivi turkoosina, alla ohut viiva.
 * Sama leimatyyli kuin lehden muissa osastonimissä, jottei opas
 * karkaa omaksi sovelluksekseen — vain väri on iloisempi.
 */
.opas-valiotsikko {
  margin: 0 0 0.5rem;
  font-family: var(--font-type);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--opas-aksentti);
  border-bottom: 1px solid var(--opas-viiva);
  padding-bottom: 0.28rem;
}

/*
 * Jakson kuva on KOKO PALSTAN levyinen: opas luetaan ylhäältä alas,
 * eikä teksti kierrä kuvia lainkaan (omistajan havainto 16.8.2026:
 * ripoteltu kuvataitto on opasjutussa levoton). Erottelutarkkuus
 * riittää kumoamaan .nahtavyys-kuvakehyksen kapean oletusmitan.
 */
.opas-kortti .opas-kuva {
  max-width: 100%;
  margin: 0.75rem 0 0.2rem;
}

.opas-kortti .opas-kuva .nahtavyys-kuva {
  border: 1px solid rgba(58, 42, 21, 0.35);
  border-radius: 3px;
}

/*
 * KAPEA JAKSOKUVA (omistajan palaute 16.8.2026: "Leipomokuva voisi olla
 * pienemmällä ja teksti vasemmalla. Sama iltakuvalle").
 *
 * Poikkeus koskee vain niitä jaksoja, joiden kuva on merkitty
 * datassa kapeaksi: oletus on yhä koko palstan levyinen kuva. Kaksi
 * kapeaa kuvaa viiden jakson jutussa rytmittää sivun — viisi kapeaa
 * palauttaisi juuri sen ripotellun taiton, josta 2.0:ssa luovuttiin.
 *
 * Jakso saa oman lohkomuotoiluympäristönsä, jottei kelluke vuoda
 * seuraavan jakson väliotsikon viereen. Se tehdään jakson luokalla eikä
 * .opas-jakso:has(...)-valitsimella, koska rakenteen tosiasia ei saa
 * riippua :has-tuesta.
 */
.opas-jakso-kapea { display: flow-root; }

.opas-kortti .opas-kuva-kapea {
  float: right;
  width: 40%;
  margin: 0.15rem 0 0.6rem 1.1rem;
}

/* Kapealla ruudulla kuva palaa täysleveäksi: 40 % puhelimen palstasta
 * olisi noin 120 px, ja viereen jäävään tekstiin mahtuisi pari sanaa
 * riville. */
@media (max-width: 639px) {
  .opas-kortti .opas-kuva-kapea {
    float: none;
    width: auto;
    margin: 0.75rem 0 0.2rem;
  }
  /*
   * Kuva myös takaisin tekstin PERÄÄN. Leveällä ruudulla se on
   * DOMissa ennen leipätekstiä, koska kelluke tarvitsee tekstiä
   * kierrettäväkseen — täysleveänä sama järjestys panisi nämä kaksi
   * jaksoa lukemaan toisin päin kuin muut kolme.
   */
  .opas-jakso-kapea {
    display: flex;
    flex-direction: column;
  }
  .opas-kortti .opas-kuva-kapea { order: 1; }
}

/* ── KAINALOTAULU ─────────────────────────────────────────────────────
 *
 * Omistajan palaute 16.8.2026 opas 2.1:stä: "liian raskas taulukko. Tee
 * vain otsikkotasolla ja sijoita leipätekstin oikealle puolelle. Yksi
 * taulu jossa vain pohjaväri muuttuu."
 *
 * Opas 2.1:ssä pari oli kaksipalstainen paneeli ingressin alla, ja
 * kellukkeesta luovuttiin, koska koko perustelutekstin kanssa se olisi
 * jättänyt viereensä 317 px korkean kolon. Tässä versiossa se peruste
 * on poistunut: näkyvissä on enää otsikkotaso (aihe + tähdet), joten
 * yhdeksän riviä mahtuu noin 15 rem korkeuteen — eli suunnilleen
 * ensimmäisen jakson leipätekstin mittaan. Kelluke on siis nyt sitä,
 * mitä omistaja pyysi jo 2.1:ssä, ja mahtuu vasta nyt.
 *
 * YKSI KEHYS, KAKSI VYÖHYKETTÄ. Reunus, pyöristys ja typografia ovat
 * yhteiset; ainoa ero on pohjaväri (lämmin = suositukset, viileä =
 * varaukset). Siksi myöskään vyöhykeotsikot eivät vaihda väriä: jos ne
 * vaihtaisivat, eroja olisi kaksi eikä yksi.
 */
.opas-kainalo {
  float: right;
  width: 16rem;
  margin: 0.2rem 0 0.9rem 1.25rem;
  border: 1px solid rgba(58, 42, 21, 0.22);
  border-radius: 3px;
  /* Vyöhykkeiden pohjavärit leikkautuvat kehyksen pyöristykseen, jotta
   * taulu lukee yhtenä esineenä eikä kahtena päällekkäisenä lappuna. */
  overflow: hidden;
}

.opas-vyo { padding: 0.55rem 0.7rem 0.6rem; }

/*
 * POHJAVÄRI ON AINOA ERO. Se on oppaan ainoa paikka, jossa väri koodaa
 * sisältöä eikä hierarkiaa: lämmin = mitä kannattaa hakea, viileä =
 * mihin kannattaa varautua.
 */
.opas-vyo-lammin { background: var(--opas-aksentti-vesi); }
.opas-vyo-viilea { background: var(--opas-syva-vesi); }

.opas-vyo-otsikko {
  margin: 0 0 0.3rem;
  font-family: var(--font-type);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--opas-muste-hento);
}

.opas-vyo-lista {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Hiusviiva rivien väliin: taulussa on kaksi vyöhykettä ja yhdeksän
 * riviä, ja ilman jakoviivaa rivit sulautuisivat luetteloksi, jossa
 * silmä ei löydä kohtaa napautettavaksi. */
.opas-vyo-rivi + .opas-vyo-rivi { border-top: 1px solid rgba(58, 42, 21, 0.13); }

.opas-vyo-rivisisus {
  display: flex;
  width: 100%;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.3rem 0;
}

/*
 * Rivi on nappi. Yleinen nappisääntö toisi 42 px vähimmäiskorkeuden,
 * pyöristetyn reunuksen ja tumman paneelitaustan — kaikki nollataan,
 * jotta rivi näyttää riviltä. Elementti+luokka voittaa yleissäännön
 * tarkkuudessa.
 */
button.opas-vyo-nappi {
  min-height: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
  text-align: left;
  cursor: pointer;
}

.opas-vyo-nimi {
  font-family: var(--font-type);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.3;
  color: var(--opas-muste);
}

/*
 * Pisteviiva nimen alla kertoo, että rivin takana on lisää — ja se
 * näkyy myös kosketusnäytöllä, jossa hover-vihjettä ei ole. Tämä on
 * ainoa merkki: pieni nuoli tai plus joka riville olisi 16 rem
 * levyisessä taulussa enemmän koristetta kuin opastusta.
 */
.opas-vyo-nappi .opas-vyo-nimi {
  text-decoration: underline dotted rgba(58, 42, 21, 0.45);
  text-underline-offset: 0.2em;
}

button.opas-vyo-nappi:hover .opas-vyo-nimi,
button.opas-vyo-nappi[aria-expanded="true"] .opas-vyo-nimi {
  color: var(--opas-aksentti);
  text-decoration-color: var(--opas-aksentti);
}

/*
 * Pelin yleinen painikesääntö (button:hover → tumma #43331f) voittaa
 * näiden painikkeiden oman taustan, koska se on hover-valitsimena
 * tarkempi. Osoittimella kainalorivi ja säägraafi maalautuivat siksi
 * tummaksi laatikoksi lämpimän paperin päälle. Kumpikin kertoo
 * painettavuudesta jo muuten: rivi nimen värillä, graafi zoom-in-
 * osoittimella — tummaa laatikkoa ei tarvita kumpaankaan.
 */
button.opas-vyo-nappi:hover:not(:disabled),
button.opas-saagraafi-nappi:hover:not(:disabled) {
  background: none;
}

.opas-tahdet {
  flex: none;
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  line-height: 1;
  color: var(--opas-kulta);
}

/* Tyhjä tähti jää asteikoksi: sama merkki himmeänä, jotta kolmen ja
 * kahden tähden rivit erottuvat toisistaan ilman selitystä. */
.opas-tahti-tyhja { opacity: 0.26; }

/*
 * Kapealla ruudulla taulu on täysleveänä ingressin alla kuten ennenkin
 * (tehtävänanto): 16 rem kellukkeen viereen jäisi puhelimessa noin
 * 100 px leipätekstiä, jossa jokainen rivi katkeaisi parin sanan
 * jälkeen. Kelluke puretaan kokonaan, jottei taulu jää kellumaan
 * väliotsikon ja tekstin väliin puolileveänä.
 */
@media (max-width: 639px) {
  .opas-kainalo {
    float: none;
    width: auto;
    margin: 0.4rem 0 1rem;
  }
  /* Taulu nousee ensimmäisen väliotsikon YLÄPUOLELLE eli ingressin
   * alle. DOM-järjestys palvelee leveää näkymää (kelluke tarvitsee
   * tekstiä kierrettäväkseen), joten järjestys vaihdetaan asettelussa
   * eikä rakenteessa — vain tässä yhdessä jaksossa. */
  .opas-jakso-kainalo {
    display: flex;
    flex-direction: column;
  }
  .opas-jakso-kainalo .opas-kainalo { order: -1; }
}

/*
 * TEKSTINOSTO jaksojen 2 ja 3 väliin: yksi lause isolla antiikvalla,
 * koristeviivat ylä- ja alapuolella. Ei lainausmerkkejä — lause on
 * toimituksen oma nosto, ei sitaatti keneltäkään.
 */
.opas-nosto {
  clear: both;
  margin: 1.5rem 0;
  padding: 0.9rem 0.6rem;
  border-top: 3px double var(--opas-aksentti);
  border-bottom: 3px double var(--opas-aksentti);
  text-align: center;
}

.opas-nosto-teksti {
  margin: 0;
  font-family: var(--font-luku);
  font-size: 1.32rem;
  font-style: italic;
  line-height: 1.4;
  color: var(--opas-aksentti);
}

/*
 * LAATIKOT: YKSI YHTEINEN HIEKKAPOHJA kaikille kolmelle (paletti 2.1).
 * Aiemmin jokaisella laatikolla oli oma aksenttinsa ja oma vaalea
 * pohjansa, jolloin ne lukivat kolmena irrallisena tarrana — vaikka ne
 * ovat samaa lajia: sivuhuomioita leipätekstin rinnalla. Nyt laji
 * näkyy: sama pohja, sama otsikkoväri, sama reunus. Sisällön ero
 * kerrotaan otsikolla, ei värillä.
 *
 * Laatikko on aside eikä osa lukuvirtaa, joten se saa erottua — mutta
 * pohja on niin vaalea, että teksti pysyy mustana paperilla eikä
 * värilapulla.
 */
.opas-laatikko {
  clear: both;
  margin: 1.3rem 0;
  padding: 0.85rem 1rem 0.95rem;
  color: var(--opas-aksentti);
  background: var(--opas-sivu);
  border: 1px solid rgba(58, 42, 21, 0.18);
  border-left: 5px solid currentcolor;
  border-radius: 3px;
}

.opas-laatikko-otsikko {
  margin: 0 0 0.55rem;
  font-family: var(--font-type);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: inherit;
}

/* Laatikoiden leipäteksti on mustaa mustetta, ei aksenttia: aksentti
 * kantaa otsikon ja reunan, teksti pysyy luettavana. */
.opas-laatikko p,
.opas-laatikko dd,
.opas-laatikko dt { color: var(--opas-muste); }

.opas-parasaika {
  margin: 0 0 0.65rem;
  font-family: var(--font-luku);
  font-size: 1rem;
  line-height: 1.5;
}

/* ── VUOSIKÄYRÄ ───────────────────────────────────────────────────────
 *
 * Omistajan tilaus 16.8.2026: "lämpötilatauluun voisi leipätekstin
 * oikealle puolelle tuoda pienen kuvan vuosiennusteesta ja sitä
 * klikkaamalla se suurenisi isommaksi animoidusti."
 *
 * Kelluke on laatikon SISÄLLÄ ja ennen leipätekstiä, joten parasAika-
 * kappale kiertää sen. Kausilista on grid eikä siis kierrä kelluketta
 * vaan kaventuu sen viereen — se on tässä oikea käytös: taulukkomaiset
 * rivit näyttäisivät rikkinäisiltä, jos osa riveistä olisi kapeampia
 * kuin muut.
 */
/*
 * Kelluke on 15 rem eikä 12 rem: lehden graafissa on sadepalkit ja
 * kaksi asteikkoa, ja sen tekstit on mitoitettu 300 yksikön leveään
 * viewBoxiin. 12 rem:ssä akseliluvut menivät lukukelvottomiksi;
 * 15 rem on kapein leveys, jossa ne yhä erottuvat. Leipätekstille jää
 * yhä kierrettävää myös kortin kapeimmalla leveällä mitalla.
 */
.opas-saagraafi {
  float: right;
  width: 15rem;
  margin: 0.1rem 0 0.6rem 1rem;
}

/* Kuvaaja on nappi: yleisen nappisäännön mitat, reunus ja tumma tausta
 * nollataan, jotta napissa näkyy vain kuvaaja. */
button.opas-saagraafi-nappi {
  display: block;
  width: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: zoom-in;
}

/*
 * Graafi on lehden oma .vuosisaa (js/saa.js piirraVuosiSaa), joten
 * sen värit, animaatiot ja typografia tulevat lehden säännöistä —
 * täällä sitä ei tyylitellä uusiksi. Kelluke antaa vain mitat ja
 * kehyksen: opas 2.2:n oma käyräpiirrin CSS-sääntöineen poistettiin,
 * kun omistaja pyysi käyttämään "juuri samaa" graafia (16.8.2026).
 */

/* Kuvateksti on kelluketta varten oma sääntönsä: ilman sitä figcaption
 * perii oppaan väliotsikon terrakotan ja koon. */
.opas-saagraafi-teksti {
  margin: 0.3rem 0 0;
  font-family: var(--font-type);
  font-size: 0.64rem;
  line-height: 1.35;
  letter-spacing: 0.02em;
  color: var(--opas-muste-hento);
}

/*
 * MINIPONNAHDUS oppaan paletissa. Kupla on pelin yhteinen pikkuseloste
 * (avaaPikkuseloste), joka menee avoimen dialogin sisään — oppaassa
 * siis .opas-arkin lapseksi. Se saa oppaan paperin ja musteen, jottei
 * lämpimän arkin päälle avaudu pelin viileä paneelisävy; muoto,
 * asemointi ja sulkeminen pysyvät yhteisinä.
 */
.opas-arkki .pikkuseloste {
  background: var(--opas-pohja);
  color: var(--opas-muste);
  border-color: rgba(58, 42, 21, 0.4);
}

.opas-arkki .pikkuseloste-teksti { font-family: var(--font-luku); }

.opas-arkki button.pikkuseloste-sulje { color: var(--opas-muste-hento); }
.opas-arkki button.pikkuseloste-sulje:hover { color: var(--opas-aksentti); }

/*
 * SUURENNOS on lehden vuosisääkortti (js/lehti.js naytaVuosiSaa) —
 * sama ikkuna ja pohja kuin kaupunkilehdessä (omistajan tilaus
 * 18.8.2026), joten sillä ei ole oppaan omia tyylejä. Oppaan oma
 * FLIP-overlay (.opas-saa-overlay/.opas-saa-suuri) poistettiin
 * samalla kuin sen piirtokoodi.
 */

/* Kapealla ruudulla kuvaaja on täysleveänä laatikon yläosassa: 12 rem
 * kellukkeen viereen jäisi puhelimessa liian kapea tekstipalsta. */
@media (max-width: 639px) {
  .opas-saagraafi {
    float: none;
    width: auto;
    max-width: 20rem;
    margin: 0 auto 0.8rem;
  }
}

/*
 * Kausirivit: nimi ja kuukaudet vasemmalla, lämpöhaarukka ja
 * luonnehdinta oikealla. Grid eikä taulukko, koska kapealla ruudulla
 * sarakkeet menevät allekkain — taulukko ei taitu.
 */
.opas-kaudet {
  display: grid;
  gap: 0.3rem 0.9rem;
  margin: 0;
  align-items: baseline;
}

/*
 * Kausilista alkaa vuosikäyrän ALTA. Grid ei kierrä kelluketta vaan
 * kaventuu sen viereen — ja kaventuu koko korkeudeltaan, myös käyrän
 * loputtua. Mitattuna se jätti laatikon oikeaan laitaan noin 190 × 290
 * pikselin tyhjän alueen ja kavensi kausikuvaukset kolmelle riville.
 * clear: right maksaa parasAika-kappaleen alle noin 25 pikseliä tyhjää
 * ja antaa vastineeksi kausiriveille koko palstan.
 */
.opas-kaudet {
  grid-template-columns: minmax(7.5rem, auto) 1fr;
  clear: right;
}

.opas-kausi-nimi {
  margin: 0;
  font-family: var(--font-type);
  font-size: 0.82rem;
  letter-spacing: 0.04em;
}

.opas-kausi-sana { font-weight: 700; }

.opas-kausi-kk {
  display: block;
  font-size: 0.72rem;
  opacity: 0.7;
}

.opas-kausi-tiedot {
  margin: 0;
  font-family: var(--font-luku);
  font-size: 0.94rem;
  line-height: 1.4;
}

/* Lämpöhaarukka omalle rivilleen kirjoituskoneella: se on numero, ja
 * numerot ladotaan tässä pelissä aina kirjoituskoneella. Väri on
 * tukiaksentti: petrooli on paletissa 2.1 faktojen väri. */
.opas-kausi-lampo {
  display: block;
  font-family: var(--font-type);
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--opas-syva);
}

.opas-kausi-kuvaus { display: block; }

.opas-linkkilista {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* Ulkoinen linkki on paletissa 2.1 tukiaksentti: petrooli on faktojen
 * ja uloskäyntien väri, ja se erottaa linkin terrakottaotsikoista. */
.opas-linkki {
  font-family: var(--font-type);
  font-size: 0.9rem;
  color: var(--opas-syva);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.opas-linkki:hover,
.opas-linkki:focus-visible { color: var(--opas-muste); }

/*
 * Kapealla ruudulla kausirivin kuvaussarakkeeksi jäisi noin 150 px,
 * jossa jokainen rivi katkeaa parin sanan jälkeen. Kausi ladotaan
 * siksi allekkain: nimi ja kuukaudet samalle riville, tiedot alle.
 * Hintarivit pysyvät kahdessa sarakkeessa — niissä oikea sarake on
 * lyhyt luku eikä virke.
 */
@media (max-width: 559px) {
  .opas-kaudet { grid-template-columns: 1fr; gap: 0; }
  .opas-kausi-nimi {
    display: flex;
    align-items: baseline;
    gap: 0.45rem;
    margin-top: 0.6rem;
  }
  .opas-kausi-kk { display: inline; }
}

/* Leveällä ruudulla laatikot hengittävät ja kausirivit levenevät. */
@media (min-width: 700px) {
  .opas-laatikko { padding: 1rem 1.25rem 1.15rem; }
  .opas-kaudet { grid-template-columns: minmax(9rem, auto) 1fr; }
  .opas-nosto-teksti { font-size: 1.5rem; }
}

/* ── LEHDEN ALANAPIT ───────────────────────────────────────────────────
 *
 * Omistajan päätös 8.8.2026: "muuta kaupunkilehden navigointi alas niin
 * että tapaa henkilö x on vasta viimeisellä sivulla. aiemmilla sivuilla
 * on nappi seuraavalle (ja edelliselle jos on) sekä poistu."
 *
 * Kohtaaminen on lehden päätepiste, ei kilpailija lukemiselle. Sitä
 * ennen alapalkissa on pelkkä sivunvaihto — samannäköiset paperipainikkeet
 * kuin muutkin lehden napit, jotta rivi pysyy yhtenäisenä.
 */
.tutki-alanapit {
  display: contents;
}

.tutki-alanappi {
  font-family: var(--font-type);
}

/*
 * LEHDEN ALAPALKIN JÄRJESTYS (omistajan ohje 8.8.2026): Poistu aina
 * vasemmassa reunassa, eteenpäin vievä nappi aina oikeassa — joka
 * sivulla ja molemmissa lehdissä.
 *
 * Ilman tätä järjestys tuli DOM:sta: kohtaaminen oli ensimmäisenä ja
 * Poistu viimeisenä, eli lopetusnappi oli siinä reunassa, jota kohti
 * peukalo liikkuu edetessään. Sivua kääntävä ja lehdestä poistuva
 * nappi olivat vierekkäin ja vaihtoivat paikkaa sivun mukaan.
 *
 * Toteutus on order-arvoilla eikä DOM-järjestyksellä, koska
 * .tutki-alanapit on display: contents — napit ovat saman flexin
 * jäseniä, vaikka ne asuvat eri elementeissä. Näkyvä oikeanpuoleisin
 * on aina se, joka vie eteenpäin: sivuilla Seuraava, viimeisellä
 * sivulla kohtaaminen (Seuraava on silloin piilossa).
 */
.dialog.lehti .dialog-actions { justify-content: space-between; }
.dialog.lehti .dialog-actions #arrival-no { order: 0; }

/*
 * Poistu himmeämmäksi lehdessä (omistajan toive 9.8.2026): se on aina
 * tarjolla muttei koskaan se, mitä lukija on juuri tekemässä —
 * suuntanapit ja kätkö saavat erottua. Hover palauttaa täyden värin.
 */
.dialog.lehti .dialog-actions #arrival-no {
  color: rgba(70, 51, 31, 0.55);
  border-color: rgba(70, 51, 31, 0.3);
  background: none;
}

.dialog.lehti .dialog-actions #arrival-no:hover:not(:disabled) {
  color: var(--map-ink);
  border-color: rgba(70, 51, 31, 0.55);
  background: rgba(255, 255, 255, 0.6);
}
.dialog.lehti .dialog-actions .tutki-alanappi.sisallysnappi { order: 1; margin-right: auto; }
.dialog.lehti .dialog-actions .tutki-alanappi.edellinen { order: 2; }
.dialog.lehti .dialog-actions .tutki-alanappi.seuraava { order: 3; }
.dialog.lehti .dialog-actions #arrival-yes { order: 4; }

/* ── MAIDEN TIEDOT -TILA ───────────────────────────────────────────────
 *
 * Omistajan tilaus 8.8.2026: varuste, jolla minkä tahansa maan lehden
 * saa auki suoraan kartalta ilman että sinne matkustetaan nopalla.
 *
 * Sama karttatila kuin vertailussa: kaupungit väistyvät ja maat ovat
 * napautettavia. Ero on siinä, mitä napautus tarkoittaa — vertailu
 * kerää maita listalle, tämä avaa yhden maan luettavaksi. Siksi tässä
 * on korostettuna vain VALITTU maa, ei koko kartan nimistö.
 */
body.maatiedot-tila .cities,
body.maatiedot-tila .tokens,
body.maatiedot-tila .targets,
body.maatiedot-tila .pawns { display: none; }

body.maatiedot-tila .fact-card {
  visibility: hidden;
  pointer-events: none;
}

.maatiedot-maat { pointer-events: auto; }

.maatiedot-maa {
  fill: rgba(140, 110, 70, 0.05);
  stroke: rgba(70, 51, 31, 0.55);
  stroke-width: 1.1;
  cursor: pointer;
}

.maatiedot-maa:hover { fill: rgba(140, 110, 70, 0.13); }

/* Valittu maa: selvästi tummempi reuna ja lämmin täyttö, jotta näkee
 * heti mihin napautus osui — kartalla osuu helposti naapuriin. */
.maatiedot-maa.valittu {
  fill: rgba(176, 34, 34, 0.16);
  stroke: rgba(140, 30, 30, 0.9);
  stroke-width: 2.2;
}

/* Kartalle piirretty nimi + "i" poistui 14.8.2026: valitun maan nimi
   ja lippu näkyvät maakyltissä (maa-pilleri), josta lehti aukeaa. */

/* ── MAALEHDEN SISÄLLYSLUETTELO ────────────────────────────────────────
 *
 * Omistajan päätös 8.8.2026: maalehden etusivulla oli korkokartta,
 * ja "koko etusivu on turha" — kartta ei kerro mitä lehdessä on eikä
 * siitä pääse mihinkään. Tilalle sisällys: pieni kuva, otsikko ja
 * yhden rivin ingressi, kahdessa palstassa, jokainen rivi linkki.
 */
.sisallys {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.55rem 1.1rem;
  margin-top: 0.6rem;
}

.dialog .sisallys-rivi {
  display: flex;
  gap: 0.6rem;
  align-items: flex-start;
  /* Rivi ei saa litistyä sisältöään matalammaksi: pitkällä listalla
   * (Raamatun 19 sivua) ruudukko jakoi korkeuden tasan ja rivit
   * lomittuivat toistensa päälle (omistajan kaappaus 15.8.2026). */
  height: auto;
  width: 100%;
  padding: 0.5rem 0.55rem;
  min-height: 0;
  text-align: left;
  background: rgba(255, 252, 244, 0.55);
  border: 1px solid rgba(70, 51, 31, 0.22);
  border-radius: 6px;
  cursor: pointer;
}

.dialog .sisallys-rivi:hover:not(:disabled) {
  background: rgba(255, 246, 222, 0.9);
  border-color: rgba(150, 116, 52, 0.5);
}

/* Sama kiinteä ruutu kuin vinkkilistalla ja samasta syystä: pysty- ja
   vaakakuvat vuorottelevat, eivätkä otsikot saa hyppiä riviltä
   toiselle. */
.sisallys-kuva {
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  object-fit: cover;
  border: 1px solid rgba(70, 51, 31, 0.28);
  background: rgba(70, 51, 31, 0.06);
}

.sisallys-teksti { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }

.sisallys-otsikko {
  font-family: var(--font-type);
  font-size: 0.84rem;
  letter-spacing: 0.04em;
  color: #46331f;
}

/*
 * Ingressi katkaistaan kahteen riviin. Johdannon ensimmäinen virke on
 * kirjoitettu leipätekstiin eikä luetteloon, ja pisimmät venyivät
 * viideksi riviksi — silloin ruudukon rivit ovat eri korkuisia ja
 * luettelo lakkaa näyttämästä luettelolta. Kaksi riviä on
 * kompromissi: yksi rivi on noin neljäkymmentä merkkiä, mikä ei riitä
 * kertomaan sivusta mitään.
 */
.sisallys-ingressi {
  font-family: var(--font-luku);
  font-size: 0.82rem;
  line-height: 1.3;
  color: rgba(70, 51, 31, 0.78);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Kapealla ruudulla yksi palsta: kaksi palstaa jättäisi otsikoille
   noin 70 pikseliä, ja ne katkeaisivat joka sanan kohdalta. */
@media (max-width: 560px) {
  .sisallys { grid-template-columns: 1fr; }
}

/*
 * Alanapin kaksi riviä: suunta ja sen alla aihe, jolle nappi vie.
 */
/*
 * justify-content keskittää kaksirivisen sisällön myös pystysuunnassa:
 * rivin napit venyvät korkeimman (kaksirivinen Poistu lehdestä)
 * mittaisiksi, ja ilman sitä suunta ja aihe kasautuivat yläreunaan
 * (omistajan havainto 9.8.2026: "Keskitä paremmin seuraava ja
 * edellinen tekstit napeissa").
 */
.tutki-alanappi {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  line-height: 1.15;
}
.alanappi-suunta { font-size: 0.82rem; }

.alanappi-aihe {
  font-size: 0.66rem;
  opacity: 0.72;
  max-width: 17ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.alanappi-aihe:empty { display: none; }

/* Hampurilaisnappi on kuvake, ei tekstiä — se ei tarvitse kahta riviä. */
.dialog .tutki-alanappi.sisallysnappi { padding: 0.45rem 0.7rem; }

/*
 * Sisällys alapalkin valikosta: levy lehden päälle. Ei uutta
 * dialogia, koska lehti on jo dialogissa ja sisäkkäiset modaalit
 * sotkevat näppäimistön ja paluunapin.
 */
/*
 * Sisällys aukeaa ALAREUNAAN pop-uppina (omistajan toive 8.8.2026:
 * "Se saisi aueta tosin vain alareunaan pop uppina").
 *
 * Aiemmin tämä oli koko lehden peittävä levy. Se oli liikaa: lukija
 * hyppää sivulta toiselle ja palaa lukemaan, eikä lehden pidä kadota
 * väliltä. Nyt levy nousee alalaidasta, peittää enintään puolet
 * korkeudesta ja jättää luettavan sivun näkyviin yläpuolelle.
 *
 * inset ilman ylälaitaa: levy on niin korkea kuin sisältö vaatii,
 * max-height leikkaa pitkän luettelon ja jättää sen vieritettäväksi.
 */
.sisallys-levy {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 6;
  display: flex;
  flex-direction: column;
  padding: 0.75rem 1.1rem 1rem;
  /* Levy saa venyä pitkälle (omistajan palaute 14.8.2026: "saisi
   * venyä enemmän, jotta palaa kartalle -nappi näkyisi") — LISTA
   * vierii levyn sisällä ja paluurivi pysyy aina levyn pohjalla. */
  max-height: 76%;
  overflow: hidden;
  background: rgba(247, 240, 224, 0.98);
  border-top: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 0.7rem 0.7rem 0 0;
  box-shadow: 0 -0.6rem 1.4rem rgba(28, 20, 12, 0.28);
  animation: sisallys-nousee 180ms ease-out;
}

@keyframes sisallys-nousee {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .sisallys-levy { animation: none; }
}

.sisallys-levy-ylä {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-type);
  font-size: 0.86rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-bottom: 1px solid rgba(70, 51, 31, 0.35);
  padding-bottom: 0.4rem;
}

.dialog .sisallys-sulje {
  background: none;
  border: 0;
  box-shadow: none;
  min-height: 0;
  padding: 0 0.3rem;
  font-size: 1.4rem;
  line-height: 1;
  color: rgba(70, 51, 31, 0.75);
  cursor: pointer;
}

/* Vain lista vierii — paluurivi jää aina näkyviin levyn pohjalle
 * (omistajan kaappaus 14.8.2026: nappi jäi listan alle piiloon). */
.sisallys-levy > .sisallys {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Rivit sisältönsä korkuisina ja lista ylhäältä alkaen — ilman tätä
   * täyttä levyä pidempi lista puristui tasakorkuisiksi 18 px:n
   * riveiksi, jotka valuivat toistensa päälle (omistajan kaappaus
   * 15.8.2026, Raamatun sisällys). */
  grid-auto-rows: max-content;
  align-content: start;
}

/* Paluu kartalle levyn pohjalla (omistajan tilaus 14.8.2026):
 * täysleveä erotinviiva ja KUNNOLLINEN nappi oikeassa reunassa,
 * peukalon ulottuvilla (omistajan tarkennus 14.8.2026). Nappi saa
 * dialogin yleisen pergamentti-ilmeen — vain rivitys omaa. */
.sisallys-paluurivi {
  flex: 0 0 auto;
  display: flex;
  justify-content: flex-end;
  margin-top: 0.55rem;
  padding-top: 0.55rem;
  border-top: 1px solid rgba(70, 51, 31, 0.35);
}

.dialog .sisallys-paluu {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.9rem;
}

.dialog .sisallys-paluu .viiva-ikoni svg {
  width: 1.05rem;
  height: 1.05rem;
  display: block;
}

/*
 * "Lue X-liite" kaupunkilehden viimeisellä sivulla: täysleveä matala
 * palkki alanappien alla, samaan tapaan kuin etusivun Tapaa X
 * (omistajan toive 9.8.2026). Tiedoston lopussa, jotta se voittaa
 * lehden yleisen alanappisäännön samalla erottelutarkkuudella.
 */
.dialog .arrival-card .dialog-actions button.maa-liite-nappi {
  order: 9;
  flex: 1 1 100%;
  min-height: 0;
  padding: 0.45rem 0.8rem;
}

/* ── NÄHTÄVYYSPOPUPIN HAMPURILAISVALIKKO ──────────────────────────────
 *
 * Omistajan toive 10.8.2026: popupista pääsee suoraan saman kaupungin
 * muihin nähtävyyksiin. Nappi istuu kortin oikeassa yläkulmassa ja
 * valikko laskeutuu sen alle; rivit käyttävät kartan selitelistan
 * numeropallukkaa, joten numerot täsmäävät karttaan.
 */
.nahtavyys-valikko-nappi {
  position: absolute;
  top: 0.55rem;
  right: 0.6rem;
  z-index: 6;
  width: 2.1rem;
  height: 2.1rem;
  min-height: 0;
  padding: 0;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 6px;
  background: rgba(246, 231, 198, 0.9);
  color: rgba(70, 51, 31, 0.85);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
}

.nahtavyys-valikko-nappi:hover,
.nahtavyys-valikko-nappi[aria-expanded="true"] { color: rgba(70, 51, 31, 1); background: rgba(246, 231, 198, 1); }

/*
 * EDELLINEN/SEURAAVA NÄHTÄVYYS (omistajan toive 10.8.2026).
 *
 * Nuolet ovat kortin sisaruksia dialogissa eivätkä sen lapsia, joten
 * ne pysyvät ruudulla myös silloin kun pitkä juttu rullaa kortin
 * sisällä — sama syy, jonka takia ne on asemoitava dialogia vasten.
 * Avoin modaali on `position: fixed`, joten se kelpaa sellaisenaan
 * absoluuttisen asemoinnin ankkuriksi.
 *
 * Ulkoasu lainataan hampurilaisnapista (sama pergamentti, sama reunus)
 * eikä kuvakarusellin hennoista laitanuolista: nämä ovat popupin
 * reunalla eivätkä kuvan päällä, ja kortin oma tausta on vaalea.
 *
 * Kapealla ruudulla nuolet ovat kortin päällä (dialogi on 90vw, joten
 * sivuille jää vain muutama pikseli). Leveällä ne siirtyvät kortin
 * ULKOPUOLELLE taustan päälle, jolloin ne eivät peitä tekstiä: raja
 * 760px on ensimmäinen, jolla dialogi on jo 640px leveä ja marginaalia
 * jää 60px eli enemmän kuin nuolen 3,1rem.
 */
.dialog.nahtavyys-arkki .nahtavyys-nuoli {
  position: absolute;
  top: 50%;
  z-index: 8;
  width: 2.4rem;
  height: 2.4rem;
  min-height: 0;
  margin: 0;
  padding: 0;
  transform: translateY(-50%);
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 999px;
  background: rgba(246, 231, 198, 0.92);
  color: rgba(70, 51, 31, 0.85);
  font-size: 1.35rem;
  line-height: 1;
  cursor: pointer;
}

.dialog.nahtavyys-arkki .nahtavyys-nuoli:hover {
  color: rgba(70, 51, 31, 1);
  background: rgba(246, 231, 198, 1);
}

/* Paluunuoli yläreunassa (omistajan tilaus 15.8.2026): näkyy vain
 * kun henkilölinkki on vaihtanut jutun ja pinossa on paluupaikka.
 * Kortin sisarus kuten selausnuolet, joten se pysyy paikallaan
 * pitkääkin juttua rullatessa. */
.dialog.nahtavyys-arkki .nahtavyys-takaisin {
  position: absolute;
  top: 0.55rem;
  left: 0.6rem;
  z-index: 8;
  width: 2.1rem;
  height: 2.1rem;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 999px;
  background: rgba(246, 231, 198, 0.92);
  color: rgba(70, 51, 31, 0.85);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;
}

.dialog.nahtavyys-arkki .nahtavyys-takaisin:hover {
  color: rgba(70, 51, 31, 1);
  background: rgba(246, 231, 198, 1);
}

/*
 * Kapealla ruudulla nuoli RATSASTAA kortin reunalla: puolet napista on
 * taustan päällä, puolet kortin omassa sivupehmusteessa. Näin se on
 * sormelle riittävän iso peittämättä yhtään kirjainta.
 *
 * Mitat eivät ole makuasia. Dialogi on 90vw, joten sivuun jää noin
 * 5vw (≈19px 390px:n puhelimella) ja kortin pehmuste on 1.15rem
 * (≈18px). Napin puolikas on 1rem (16px), joten se mahtuu molempiin
 * ilman että teksti jää alle. Jos kortin pehmustetta joskus
 * kavennetaan, tämä siirto on laskettava uudestaan.
 */
.dialog.nahtavyys-arkki .nahtavyys-nuoli {
  width: 2rem;
  height: 2rem;
  font-size: 1.15rem;
}

.dialog.nahtavyys-arkki .nahtavyys-nuoli.edellinen { left: -1rem; }
.dialog.nahtavyys-arkki .nahtavyys-nuoli.seuraava { right: -1rem; }

/* Piilotus on kumottava nimenomaisesti: dialogin yleinen nappisääntö
   asettaa displayn, ja pelkkä [hidden] häviäisi sille kaskadissa. */
.dialog.nahtavyys-arkki .nahtavyys-nuoli[hidden] { display: none; }

/*
 * Kohdelaskurin ("5/6") säännöt poistettiin 16.8.2026 yhdessä
 * elementin kanssa (omistajan päätös). Sama tieto on aikarivillä.
 */

/*
 * Leveällä ruudulla nuolet siirtyvät kokonaan kortin ulkopuolelle
 * taustan päälle ja kasvavat. Raja 760px on ensimmäinen, jolla
 * dialogi on jo täydet 640px ja sivuun jää 60px eli enemmän kuin
 * nuolen 3.1rem.
 */
@media (min-width: 760px) {
  .dialog.nahtavyys-arkki .nahtavyys-nuoli {
    width: 2.4rem;
    height: 2.4rem;
    font-size: 1.35rem;
  }

  .dialog.nahtavyys-arkki .nahtavyys-nuoli.edellinen { left: -3.1rem; }
  .dialog.nahtavyys-arkki .nahtavyys-nuoli.seuraava { right: -3.1rem; }
}

.nahtavyys-valikko {
  position: absolute;
  top: 2.9rem;
  right: 0.6rem;
  z-index: 7;
  display: flex;
  flex-direction: column;
  max-width: min(80%, 20rem);
  max-height: 60vh;
  overflow-y: auto;
  padding: 0.3rem;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 8px;
  background: #f5f0e2;
  box-shadow: 0 8px 24px rgba(20, 14, 6, 0.35);
}

.nahtavyys-valikko-rivi {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 0;
  padding: 0.45rem 0.6rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: rgba(70, 51, 31, 0.92);
  font: inherit;
  font-size: 0.92rem;
  text-align: left;
  cursor: pointer;
}

.nahtavyys-valikko-rivi:hover { background: rgba(70, 51, 31, 0.08); }

.nahtavyys-valikko-rivi.nykyinen {
  background: rgba(70, 51, 31, 0.12);
  font-weight: 600;
}

/* ── VALOKUVAPULMA ─────────────────────────────────────────────────────
 *
 * Omistajan tilaus 10.8.2026 (sanasto docs/mantereen-resepti.md):
 * pulman vaihtoehdot ovat oikeita valokuvia. Kuva täyttää napin
 * yläosan, kirjain ja nimi jäävät riviksi alle. Kuvakoko on
 * rajattu, jotta kolme vaihtoehtoa mahtuu puhelimen ruudulle
 * yhdellä vierityksellä.
 */
.quiz-option.kuvallinen {
  flex-wrap: wrap;
  padding-top: 0.55rem;
}

.quiz-option-kuva {
  width: 100%;
  height: clamp(5.2rem, 18vh, 8.5rem);
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid rgba(70, 51, 31, 0.3);
}

.quiz-kuvalahteet {
  margin: 0.15rem 0 0;
  font-family: var(--font-type);
  font-size: 0.62rem;
  letter-spacing: 0.03em;
  color: rgba(70, 51, 31, 0.55);
}

/*
 * ==========================================================================
 * PIKKUSELOSTE — sijoitettu tiedoston loppuun tarkoituksella.
 *
 * Komponentti on liitettävissä mihin tahansa, myös <dialog>-korttien
 * sisään, ja siellä `.dialog button` (rivi ~4900) osuu siihen: se antaa
 * napeille pergamentin käsinpiirretyn epäsäännöllisen kulman ja oman
 * taustansa. Se sääntö on yhtä tarkka kuin luokkavalitsin ja tulee
 * myöhemmin, joten i-ympyrästä tuli sen alla vino suorakaide.
 *
 * Kaksi korjausta yhdessä: valitsimissa on elementtitarkennus
 * (`button.seloste-nappi`) ja lohko on tiedoston lopussa. Näin
 * komponentti näyttää samalta riippumatta siitä, mihin se liitetään —
 * mikä on koko sen idea.
 * ==========================================================================
 */
/*
 * PIKKUSELOSTE: tekstin kokoinen opastuslaatikko, ei ikkuna.
 *
 * Uusi komponentti (omistajan toive 11.8.2026: "sitä voidaan käyttää
 * muuallakin lyhyisiin opastuksiin"). Yhden virkkeen selitys ei ansaitse
 * koko ruudun dialogia: se peittäisi juuri sen, mitä pelaaja oli
 * katsomassa, ja vaatisi oman sulkemisensa. Laatikko kasvaa tekstin
 * mukaan ja katoaa heti kun sen ulkopuolelle napauttaa.
 *
 * Paikka lasketaan js/ui.js:ssä (avaaPikkuseloste) ankkurin viereen,
 * joten tässä on vain ulkoasu ja `position: fixed` — ei mitään, mikä
 * sitoisi laatikon johonkin tiettyyn paikkaan.
 */
button.seloste-nappi {
  /* Otsikon perässä: pieni ympyrä, joka ei riko rivin rytmiä. */
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.15rem;
  height: 1.15rem;
  /*
   * `min-height: 0` on pakollinen: yleinen button-sääntö asettaa
   * napeille 42 pikselin vähimmäiskorkeuden, ja se voittaa pelkän
   * `height`-arvon. Ilman tätä i-ympyrästä tuli pystysuora suorakaide.
   */
  min-height: 0;
  margin-left: 0.4rem;
  padding: 0;
  vertical-align: middle;
  border: 1px solid var(--accent);
  border-radius: 50%;
  background: transparent;
  color: var(--accent);
  font-family: var(--font-type);
  font-size: 0.68rem;
  font-style: italic;
  line-height: 1;
  cursor: pointer;
  outline-offset: 2px;
}

/*
 * Kosketusalue on isompi kuin ympyrä. Näkyvä ympyrä on 18 pikseliä,
 * johon on puhelimella vaikea osua; läpinäkyvä ::after venyttää
 * osuma-alan noin 40 pikseliin muuttamatta ulkoasua tai rivin korkeutta.
 *
 * Nimenomaan ::after eikä läpinäkyvä box-shadow: varjo ei ota vastaan
 * osoitintapahtumia, joten se olisi näyttänyt korjaukselta olematta
 * sellainen.
 */
button.seloste-nappi::after {
  content: '';
  position: absolute;
  inset: -0.65rem;
}

button.seloste-nappi:hover,
button.seloste-nappi[aria-expanded="true"] {
  background: var(--accent);
  color: var(--panel);
}

.pikkuseloste {
  position: fixed;
  z-index: 60;
  /*
   * Leveys tekstin mukaan, mutta puhelimen ruutu on katto: omistaja
   * pelaa iPhonella, ja 320 pikselin ruudulla kiinteä leveys valuisi
   * reunan yli.
   */
  width: max-content;
  max-width: min(19rem, calc(100vw - 2.5rem));
  padding: 0.6rem 1.6rem 0.6rem 0.75rem;
  border: 1px solid var(--overlay-line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--map-ink);
  box-shadow: 0 6px 18px rgba(20, 12, 4, 0.4);
  /* Näkyviin vasta kun paikka on laskettu, ettei laatikko vilahda nurkassa. */
  opacity: 0;
  transition: opacity 0.12s ease-out;
}

.pikkuseloste.nakyy { opacity: 1; }

.pikkuseloste-teksti {
  margin: 0;
  font-size: 0.82rem;
  line-height: 1.4;
}

button.pikkuseloste-sulje {
  position: absolute;
  top: 0.15rem;
  right: 0.15rem;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--map-ink-soft);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}

button.pikkuseloste-sulje:hover { color: var(--map-ink); }

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

/* ===========================================================================
   ALANAPPIRIVI — KAKSI PAIKKAA (js/ui.js piirraToimintorivi)
   ---------------------------------------------------------------------------
   Vasemmalla Liiku (monitoiminappi, kompassi), oikealla Tutki
   (suurennuslasi). Paikkoja oli kolme 12.8.2026 alkaen ja keskimmäisenä
   Viisas Pöllö; omistajan linjaus 24.8.2026 (Raamatun osio "Fokusmoodi")
   siirsi pöllön pysyvästi kelluvaksi sivuelementiksi ja jätti riville
   *"vain Liiku- ja Tutki-napit"*. Pöllön paikan tyylit (.pollo-paikka)
   jäävät alle, koska rivipaikka on palautettavissa yhdellä lipulla
   (js/pollo.js POLLO_ALANAPPIRIVISSA).

   Matkustusnapit eivät levitä riviä vaan LIUKUVAT koko rivin päälle, joten
   rivi on aina täsmälleen kahden napin levyinen. Liu'un ollessa auki
   MOLEMMAT perusnapit väistyvät — myös monitoiminappi, joka liu'un avasi
   (omistajan havainto v589, iPhone: rivissä näkyi neljä nappia kolmen
   sijaan).
   =========================================================================== */

.toimintorivi { position: relative; }

.toimintorivi-perus {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
  justify-items: stretch;
}

/* Tyhjä paikka pitää ruudukon kaksiosaisena, vaikka Tutki ei olisi
   tarjolla — Liiku ei saa venyä yksin koko rivin levyiseksi. */
.rivi-tyhja { visibility: hidden; }

/*
 * FOKUSNÄKYMÄN YHDEN NAPIN RIVI (omistajan pelitestitilaus 24.8.2026,
 * ulkoasu uusittu 25.8.2026).
 *
 * Tutki muutti kaupungin laattaan, ja alariville jää vain Liiku. Tyhjää
 * paikkaa EI jätetä: silloin nappi jäisi riippumaan vasempaan reunaan
 * kuin toinen olisi unohtunut. Liuku (matkustusnapit) on absoluuttinen
 * ja peittää rivin entiseen tapaan, joten se ei tarvitse omaa sääntöä.
 *
 * NAPPI ON SANA, EI PALKKI EIKÄ NELIÖ (omistajan tarkennus 25.8.2026:
 * *"muutetaan tekstinapiksi (LIIKU) ja keskitetään sivusuunnassa ruudun
 * alareunaan"*). Väliaikoina se oli ensin 20rem levyinen palkki ja
 * sitten kompassineliö kartuutsin rinnalla; kumpikin kumottiin. Leveys
 * tulee nyt sanasta ja pehmusteesta, korkeus sormen mitasta, ja kartta
 * näkyy sen molemmin puolin.
 *
 * KIRJASIN ON KARTUUTSIN KÄSIALAA: harvennettu versaali, sama kuin maan
 * nimessä ja mittajanassa (.fokus-kartuutsi). Kuvake jää piiloon —
 * nappi on sama iconButton kuin muuallakin, joten sekä kompassi että
 * teksti ovat olemassa ja fokusnäkymä valitsee niistä sanan.
 */
.toimintorivi.rivi-yksi .toimintorivi-perus {
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
}

.toimintorivi.rivi-yksi .monitoimi-nappi {
  width: auto;
  min-width: 7rem;
  max-width: min(100%, 14rem);
  min-height: 44px;
  margin-inline: auto;
  padding: 0.5rem 1.7rem;
}

.toimintorivi.rivi-yksi .monitoimi-nappi .viiva-ikoni { display: none; }

/*
 * MATKUSTA ON KULLATTU PÄÄNAPPI (Arkkikirjasto-linjaus 26.8.2026;
 * omistaja samana iltana: *"Matkusta napin väri ei sovi pelin
 * väripalettiin"* — kumoaa v1119:n "kevyen oranssin", joka jäi
 * paletin ulkopuoliseksi lohenpunaksi). Matkusta on kartan etenevä
 * päävalinta, joten se puhuu samaa kultaa kuin Aloita peli ja
 * varmistuksen Kyllä (button.primary): sama liukuväri, sama
 * mustereuna, tumma teksti.
 *
 * body[data-mode] on tarpeen, koska kartan yleinen nappisääntö
 * (body[data-mode] .actions button) asettaa saman ominaisuuden.
 */
body[data-mode] .toimintorivi.rivi-yksi .monitoimi-nappi {
  background: linear-gradient(180deg, #eab84e, #d09024);
  border-color: var(--accent-dark);
  color: #2c1e07;
  font-weight: 700;
}

body[data-mode] .toimintorivi.rivi-yksi .monitoimi-nappi:hover:not(:disabled) {
  background: linear-gradient(180deg, #f3c661, #d9a13b);
}

/* Estettynä kulta laimenee pergamentiksi — ei katoa, ei kutsu. */
body[data-mode] .toimintorivi.rivi-yksi .monitoimi-nappi:disabled {
  background: rgba(208, 144, 36, 0.14);
  border-color: rgba(122, 85, 20, 0.3);
  color: rgba(44, 30, 7, 0.45);
  font-weight: 400;
}

.toimintorivi.rivi-yksi .monitoimi-nappi .icon-label {
  /* Alle 520 px napit kutistuvat muualla pelkiksi ikoneiksi
     (.icon-label display:none). Tämä nappi on päinvastainen: ikoni on
     piilossa ja sana on koko nappi, joten ilman tätä riviä puhelimella
     jäisi tyhjä laatikko — mitattu 390 px:n ruudulla. */
  display: inline;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  /* Harvennus lisää tilaa myös viimeisen kirjaimen jälkeen; pieni
     siirto palauttaa sanan optiseen keskiöön. */
  text-indent: 0.18em;
  font-size: 0.86rem;
}

/* Pöllön paikka: nappi asuu js/pollo.js:ssä ja siirtyi tänne joka
   piirrolla, kunnes omistajan linjaus 24.8.2026 teki kellunnasta
   pysyvän. Tyylit jäävät lipun (POLLO_ALANAPPIRIVISSA) varalle;
   grid-venytys pitäisi napin samankokoisena kuin naapurinsa. */
.pollo-paikka { display: grid; }
.pollo-paikka > .pollo-nappi { width: 100%; }

/*
 * Liuku peittää koko rivin: kolme matkanappia (jalan, laiva, lento)
 * jakaa rivin tasan keskenään, joten kumpikaan perusnapeista ei jää
 * niiden viereen näkyviin. Matkanappeja on yhä kolme, vaikka rivissä on
 * kaksi paikkaa: liuku on oma flex-rivinsä eikä noudata ruudukkoa.
 * Kiinni ollessaan liuku on sekä läpinäkyvä että napautuksille
 * läpäisemätön — muuten se söisi Liiku- ja Tutki-nappien napautukset.
 *
 * Liuku suljetaan napauttamalla rivin ulkopuolelta (kartta) tai
 * valitsemalla jokin matkanapeista; monitoiminappi on auki-tilassa
 * piilossa, joten se ei enää ole neljäs nappi rivissä.
 */
.toimintorivi-liuku {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  gap: 0.5rem;
  opacity: 0;
  pointer-events: none;
  transform: translateX(-8%);
  transition: transform 0.22s ease, opacity 0.18s ease;
}

.toimintorivi-liuku > button { flex: 1 1 0; min-width: 0; }

/*
 * Liu'un napit ovat aina pelkkiä ikoneita.
 *
 * Matkustustapoja on kolme (jalan, laiva, lento) ja ne jakavat rivin
 * kolmeen yhtä suureen paikkaan, aivan kuten perusnapitkin. Selite
 * kelpaa vain hiirelle, joka näkee saman titlestä; ilman tätä sääntöä
 * nimet olisivat leveällä ruudulla puskeneet napit ahtaiksi ja
 * kaventaneet ikonit tunnistamattomiksi.
 */
.toimintorivi-liuku .icon-label { display: none; }
.toimintorivi-liuku > button { padding-left: 0.35rem; padding-right: 0.35rem; }

.toimintorivi.liuku-auki .toimintorivi-liuku {
  opacity: 1;
  pointer-events: auto;
  transform: translateX(0);
}

/*
 * Peittyvät napit väistyvät liu'un alta — kaikki kolme.
 *
 * Ilman tätä pöllö ja suurennuslasi näkyivät liu'un nappien läpi (napit
 * ovat läpikuultavia kartan päällä), ja rivi näytti neljältä napilta
 * kolmen sijaan. Sama koski monitoiminappia, joka jäi ennen näkyviin
 * matkanappien viereen: omistaja laski iPhonella neljä nappia, vaikka
 * matkustustapoja on kolme. Nyt väistyvät kaikki, ja liuku saa koko
 * leveyden.
 *
 * visibility viivästetään häivytyksen loppuun: näkymätön nappi katoaa
 * myös sarkainkierrosta ja ruudunlukijalta, mutta pitää paikkansa
 * ruudukossa, joten rivin korkeus ja liu'un mitat säilyvät.
 */
.toimintorivi-perus > * {
  transition: opacity 0.18s ease, visibility 0s;
}

.toimintorivi.liuku-auki .toimintorivi-perus > * {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}

@media (prefers-reduced-motion: reduce) {
  .toimintorivi-liuku,
  .toimintorivi-perus > *,
  .toimintorivi.liuku-auki .toimintorivi-perus > * { transition: none; }
}

/* ===========================================================================
   VIISAS PÖLLÖ — chat-paneeli (js/pollo.js)
   ---------------------------------------------------------------------------
   PÖLLÖ KELLUU AINA (omistajan linjaus 24.8.2026). Ennen nappi eli
   kahdessa paikassa: kartalla alanappirivin keskimmäisenä ja lehdessä
   kelluvana. Nyt se on kelluva molemmissa — Raamatun osio "Fokusmoodi":
   *"pöllö pysyvästi leijuvana sivuelementtinä kaikissa tiloissa"*.
   Alanappirivin paikka (.pollo-paikka alempana) on tallella lipun takana
   (js/pollo.js POLLO_ALANAPPIRIVISSA), mutta sitä ei enää käytetä.

   KELLUNNALLA ON KAKSI KOTIA. Lehtinäkymässä nappi siirtyy modaalin
   sisään ja ruudun oikeaan alakulmaan, jossa on tyhjää. Pelinäkymässä
   samassa kulmassa ovat alanapit ja kartan zoomiportaat, joten siellä
   nappi nousee alanappirivin yläpuolelle (.pollo-kelluu-kartalla).

   PANEELI ON PAPERIA (omistajan linjaus 12.8.2026). Tumma laatikko vaihtui
   samaan painopaperiin kuin kaupunkilehden arkki (.dialog.arkki
   .dialog-card): vaalea pohja, kohinapinta ja tumma muste. Samalla
   poistuivat yläpalkin otsikko ja ×-nappi — paneeli suljetaan napauttamalla
   sen ulkopuolelle tai Esc-näppäimestä (js/pollo.js seuraaSulkemista).

   TERÄVYYS. Paneeli asuu DOMissa alanappirivin sisällä eli .turn-cardin
   alla, ja peri sieltä pergamentin vaalean tekstivarjon (body[data-mode]
   .turn-card: 0 0 6px vaalea hehku). Tummalla pohjalla vaalean tekstin
   ympärille syntyi hehkureunus, joka täytti kirjainten sisukset — teksti
   näytti iPhonella suttuiselta (omistajan havainto v589). Varjo on nyt
   nollattu koko paneelista, leipäteksti on lukukirjasimella (--font-luku)
   ja kirjasinkoot on nostettu puhelinluettaviksi.
   =========================================================================== */

/*
 * Kelluva muoto: pyöreä nappi lehden oikeassa alalaidassa.
 *
 * IRTI REUNASTA (omistajan pelitestitilaus 26.8.2026). Nappi oli
 * 0.7rem päässä ruudun laidasta ja näytti liimatulta kiinni kulmaan;
 * 1.1rem antaa sille oman ilmansa. Muutos koskee molempia kelluntoja,
 * jotta nappi ei hypi sivusuunnassa lehteä avattaessa.
 *
 * VÄRI ON KAHDENLAINEN, ks. .pollo-kelluu-kartalla alempana: lehdessä
 * nappi on tumma peitelaatta vaalean paperin päällä, kartalla vaalea
 * pergamentti — molemmissa se erottuu alustastaan, mikä on koko värin
 * tehtävä.
 */
.pollo-nappi.pollo-kelluu {
  position: fixed;
  right: calc(1.1rem + env(safe-area-inset-right, 0px));
  bottom: calc(3.6rem + env(safe-area-inset-bottom, 0px));
  z-index: 40;
  width: 2.9rem;
  height: 2.9rem;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid var(--overlay-line);
  border-radius: 50%;
  background: var(--overlay-card);
  color: var(--paper);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}

.pollo-nappi.pollo-kelluu .icon-label { display: none; }
.pollo-nappi.pollo-kelluu .viiva-ikoni svg { width: 1.7rem; height: 1.7rem; }
.pollo-nappi.auki { color: var(--accent); }

/*
 * KELLUNTA PELINÄKYMÄSSÄ (omistajan ohje 24.8.2026: kelluva pöllö ei saa
 * peittää zoom-nappeja eikä alanappeja).
 *
 * KORKEUS. Alanappirivi (.turn-card) on kartan pohjalla: bottom 0.9rem,
 * pehmuste 0.2rem ja napin oma korkeus noin 2,6rem — eli sen yläreuna on
 * runsaat 3,7rem ruudun alalaidasta. Pöllö nousee sen yläpuolelle
 * 5,3rem korkeuteen, jolloin Liiku- ja Tutki-nappien väliin jää selvä
 * rako myös silloin kun rivi on kapea ja napit ovat lähellä oikeaa
 * reunaa. Fokusnäkymässä alalaidassa on lisäksi mittajana (oikea
 * alanurkka), ja pöllö on sen yläpuolella samasta syystä.
 *
 * SIVUSUUNTA. Kartan oikea reuna on vapaa: zoomiportaat (.zoomi)
 * poistettiin 27.8.2026 eleiden tieltä, joten mikään ei ole tämän
 * tiellä. Sama 1.1rem kuin lehtinäkymässä pitää napin samalla
 * pystylinjalla molemmissa tiloissa, jolloin se ei hypi sivusuunnassa
 * lehteä avattaessa.
 *
 * Turva-alue lasketaan mukaan molempiin suuntiin: iPhonen alapalkki ei
 * saa syödä nappia (viewport-fit=cover on index.html:n metassa).
 */
/*
 * VÄRI: KARTALLA VAALEA PERGAMENTTI (omistajan pelitestitilaus
 * 26.8.2026: *"tee siitä vaaleampi, ikoni erottuu silti"*).
 *
 * Pelin tumma peiteväri (--overlay-card) luki kartan seepiapinnalla
 * mustana täplänä — se on lehden modaalin väri, ja lehdessä se on
 * oikein, koska siellä alusta on vaaleaa paperia. Kartalla alusta on jo
 * pergamenttia, joten nappi saa saman paperin kuin alanapit
 * (body[data-mode] .actions button): vaalea pohja, ohut mustekehys ja
 * tumma muste, jolloin pöllö on kartan kaluste eikä sen päälle liimattu
 * painike. Muste tummuu samalla, tai ikoni katoaisi vaaleaan pohjaan.
 *
 * Sääntö on VAIN kartalla: lehdessä vaalea nappi vaalealla paperilla
 * jäisi näkymättömäksi.
 */
.pollo-nappi.pollo-kelluu.pollo-kelluu-kartalla {
  bottom: calc(5.3rem + env(safe-area-inset-bottom, 0px));
  border-color: rgba(122, 85, 20, 0.42);
  background: rgba(250, 243, 226, 0.82);
  color: var(--map-ink);
  box-shadow: 0 2px 8px rgba(46, 30, 14, 0.22);
}

/*
 * Paneeli avautuu napin yläpuolelle, joten sekin nousee saman verran —
 * muuten napin ja paneelin väliin ei jäisi rakoa lainkaan.
 *
 * VAIN TABLETILLA JA TYÖPÖYDÄLLÄ. Kapealla ruudulla (max-width: 560px
 * -lohko alempana) paneeli venyy laidasta laitaan ja alanappirivi
 * piilotetaan koko keskustelun ajaksi, joten siellä sen alalaita on
 * tarkkaan viritetty ruudun reunaan eikä siihen kosketa. Ilman tätä
 * mediaehtoa kolmen luokan valitsin jyräisi puhelimen mitat.
 */
@media (min-width: 561px) {
  .pollo-paneeli.pollo-paneeli-kelluu.pollo-paneeli-kartalla {
    bottom: calc(8.8rem + env(safe-area-inset-bottom, 0px));
  }
}

/*
 * PÖLLÖ ILMESTYY LÖYTYESSÄÄN (omistajan tilaus 18.8.2026). Peli alkaa
 * ilman pöllöä, ja nappi tulee riviin vasta kun ensimmäinen laatta on
 * kääntynyt. Ilman pientä nytkäystä se vain olisi yhtäkkiä siinä —
 * yksi kertaluonteinen liike riittää kertomaan, että rivi sai uuden
 * jäsenen. Sama hillitty ele kuin laukkunapin .laukku-elo.
 */
.pollo-nappi.pollo-ilmestyy { animation: pollo-ilmesty 0.75s ease-out 1; }

@keyframes pollo-ilmesty {
  0% { transform: scale(0.4); opacity: 0; }
  55% { transform: scale(1.12); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .pollo-nappi.pollo-ilmestyy { animation: none; }
}

/*
 * PÖLLÖN VIHJEKUPLA (omistajan toive 13.8.2026: *"Pöllö voi tarpeen
 * mukaan vinkata, jos pelaaja ei osaa painaa mitään nappia."*).
 *
 * Sama paperi ja muste kuin pöllöpaneelissa, mutta kupla on pieni ja
 * kiinteä lause — ei keskustelua. Se asuu bodyssa ja asemoidaan JS:stä
 * pöllönapin päälle (js/pollo.js asetaVihjeenPaikka), koska nappi
 * vaihtaa paikkaa rivin, kartan ja lehden välillä.
 *
 * Kupla OTTAA napautuksen ja sulkeutuu siitä (omistaja 18.8.2026:
 * "Pöllön puhekuplia pitää häipyä jos sitä koskettaa") — aiempi
 * pointer-events: none päästi kosketuksen kartalle, mutta silloin
 * kuplaa ei saanut pois tieltä.
 */
.pollo-vihje {
  position: relative;
  z-index: 40;
  cursor: pointer;
  max-width: min(17rem, calc(100vw - 1.6rem));
  padding: 0.5rem 0.7rem;
  border-radius: 0.6rem;
  border: 1px solid rgba(122, 85, 20, 0.32);
  /*
   * KELLERTÄVÄ PERGAMENTTI, EI VALKOINEN (omistajan pelitestipalaute
   * v1119: *"KELLERTÄVÄ pohja — pelin paperi/pergamenttisävy nykyisen
   * valkoisen sijaan, sama sävymaailma kuin matkapäiväkirjalaatikko"*).
   *
   * Sävy on sama kuin matkakirjakortin paperilla (.fact-card.pieni,
   * rgba(244, 231, 202)) — kupla ja päiväkirja ovat ruudulla yhtä
   * aikaa, ja kaksi eri valkoista vieretysten näytti kahdelta eri
   * peliltä. Muuttuja pitää kärjen (::after) samassa sävyssä.
   */
  --kuplan-paperi: #f4e7ca;
  background: var(--kuplan-paperi);
  color: #211d18;
  font-family: var(--font-luku, Georgia, serif);
  font-size: 0.92rem;
  line-height: 1.35;
  /* Pergamentin oma varjo; kortin vaalea hehkuvarjo ei periydy tänne,
     koska kupla ei ole vuorolaatikon sisällä. */
  text-shadow: none;
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.28);
  animation: pollo-vihje-saapuu 220ms ease-out;
}

.pollo-vihje[hidden] { display: none; }

/*
 * Valikkovihje on pinon ulkopuolinen yksittäiskupla (js/pollo.js
 * naytaVihje 'valikko'): se kelluu itse, koska se osoittaa ruudun
 * toiseen laitaan hampurilaisnappiin.
 */
.pollo-vihje-yksin { position: fixed; }

/*
 * ── KUPLAPINO (omistajan tilaus 3.9.2026) ───────────────────────────
 *
 * *"uusi kupla tulee vanhan alle siirtäen pehmeästi aiemman kuplan
 * ylöspäin … maksimikorkeus jonka jälkeen kuplat feidautuvat yläosasta
 * näkymättömiin pienellä läpinäkyvyysliu'ulla, mutta ovat pelaajan
 * skrollattavissa … kuplien oikeaan yläreunaan pieni x."*
 *
 * Kehys kelluu pöllönapin yläpuolella ja on asemoitu ALAREUNASTAAN
 * (js/pollo.js asetaPinonPaikka), joten pino kasvaa ylöspäin. Kuplat
 * ovat oikeaan reunaan tasattuja, koska kärki on kuplan oikeassa
 * alanurkassa ja osoittaa pöllöön.
 */
.pollo-kuplapino-kehys {
  position: fixed;
  z-index: 40;
  max-width: min(23rem, calc(100vw - 1.6rem));
  /*
   * Kehys ankkuroidaan oikeasta reunasta (js/pollo.js asetaPinonPaikka),
   * ja sen siirrot — napin liike, ruudun koon muutos — liukuvat samalla
   * käyrällä kuin pino itse (omistaja 3.9.2026: "töksähdellen").
   */
  transition: right 380ms var(--liike-pehmea), bottom 380ms var(--liike-pehmea);
}

.pollo-kuplapino-kehys[hidden] { display: none; }

.pollo-kuplapino {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
  /*
   * KORKEUS RIITTÄÄ USEALLE KUPLALLE (omistajan tilaus 3.9.2026:
   * *"puhekuplat näkyvät vain yksi kerrallaan … puhekuplien korkeutta
   * pitää kasvattaa, jotta useampi kupla mahtuu kerralla näkyviin"*).
   *
   * Mitoitus: tavallinen puhekupla on 2–3 riviä eli noin 5 rem korkea,
   * ja väli on 0.5 rem. 34 rem kantaa siis 5–6 kuplaa kerralla, ja
   * 900 px:n työpöytäruudulla 60vh (540 px) on sama mitta — pino
   * kasvaa napista ylöspäin ja jättää ruudun yläkolmanneksen vapaaksi.
   * Ylivuoto ei katoa: häivytys ja vieritys hoitavat pidemmät sarjat.
   */
  /*
   * KAHDEKSAN RIVIN KATTO (omistaja 4.9.2026: *"noin 8 tekstirivin
   * korkeudella puhekuplan yläreuna alkaa muuttua näkymättömäksi. ja
   * pelaaja voisi skrollata puhekuplia ylös ja alas, jos ne eivät mahdu
   * tuon 8 rivin sisään"*). Rivi on 0.92 rem × 1.35 ≈ 1.24 rem, joten
   * kahdeksan riviä kahden kuplan pehmusteineen ja välineen on noin
   * 14 rem; yli jäävä osa häipyy yläreunasta (.pollo-kuplapino-yli) ja
   * on vieritettävissä.
   */
  max-height: min(60vh, 14rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Kärki ja varjo mahtuvat: leikkaava overflow söisi ne muuten. */
  padding: 0.5rem 0.6rem 0.7rem;
  margin: -0.5rem -0.6rem -0.7rem;
  scrollbar-width: none;
}

.pollo-kuplapino::-webkit-scrollbar { display: none; }

/*
 * Puhelin: pino saa nousta korkeammalle kuin ennen (3.9.2026), mutta
 * ei yli puolen kartasta — 52vh jättää kartalle enemmistön ja kantaa
 * silti kolme tavallista kuplaa.
 */
@media (max-width: 599px) {
  .pollo-kuplapino { max-height: min(52vh, 14rem); }
}

/*
 * Ylivuoto: pino on täynnä, joten yläreuna häivytetään ja loput jäävät
 * vieritettäviksi. Luokan asettaa js/pollo.js paivitaYlivuoto, koska
 * CSS ei osaa kysyä onko sisältöä enemmän kuin tilaa.
 */
.pollo-kuplapino-yli .pollo-kuplapino {
  mask-image: linear-gradient(to bottom, transparent 0, #000 2.6rem);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 2.6rem);
}

/*
 * Sulkunappi kehyksen oikeassa yläkulmassa: sama paperinen pikkuruksi
 * kuin nostokorteilla (.fokusnosto-kortti-sulje), mutta pyöreänä ja
 * puoliksi kuplan ulkopuolella, jottei se peitä ensimmäistä riviä.
 */
.pollo-kuplapino-sulje {
  position: absolute;
  top: -0.55rem;
  right: -0.25rem;
  /* Kuplien z-index on 40 samassa pinoutuskontekstissa: ruksin on
     oltava niiden yläpuolella, tai napautus osuu kuplaan. */
  z-index: 41;
  display: grid;
  place-items: center;
  width: 1.55rem;
  height: 1.55rem;
  min-height: 0;
  padding: 0;
  border: 1px solid rgba(122, 85, 20, 0.42);
  border-radius: 50%;
  background: rgba(245, 240, 226, 0.94);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
  color: rgba(33, 29, 24, 0.7);
  font-size: 0.72rem;
  line-height: 1;
  cursor: pointer;
}

.pollo-kuplapino-sulje:hover,
.pollo-kuplapino-sulje:focus-visible {
  background: rgba(245, 240, 226, 1);
  color: #16130f;
}

/* Pieni kärki alaspäin kohti pöllönappia. */
.pollo-vihje::after {
  content: '';
  position: absolute;
  bottom: -7px;
  right: 1.1rem;
  width: 12px;
  height: 12px;
  background: var(--kuplan-paperi, #f4e7ca);
  border-right: 1px solid rgba(122, 85, 20, 0.32);
  border-bottom: 1px solid rgba(122, 85, 20, 0.32);
  transform: rotate(45deg);
}

/*
 * KÄRKI VAIN PINON VIIMEISELLÄ (omistajan tilaus 26.8.2026, kuplapino
 * 3.9.2026). Alin kupla on pöllön vieressä ja pitää kärkensä; muut
 * luopuvat omastaan, koska kärki osoittaisi suoraan toisen kuplan
 * paperiin.
 */
.pollo-kuplapino .pollo-vihje:not(:last-child)::after { display: none; }

/*
 * Kärki ylöspäin: valikkovihje ankkuroituu hampurilaisnapin ALLE
 * (js/pollo.js naytaVihje kohteella 'valikko'), joten kärjen on
 * osoitettava ylös kohti nappia — muuten kupla näyttäisi puhuvan
 * tyhjälle kartalle.
 */
.pollo-vihje-ylos::after {
  bottom: auto;
  top: -7px;
  border-right: none;
  border-bottom: none;
  border-left: 1px solid rgba(122, 85, 20, 0.32);
  border-top: 1px solid rgba(122, 85, 20, 0.32);
}

@keyframes pollo-vihje-saapuu {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: translateY(0); }
}

/*
 * PINON KUPLA TULEE ALHAALTA (omistajan tilaus 3.9.2026). Uusi kupla
 * nousee paikalleen pehmeästi jarruttaen, ja samalla FLIP-siirtymä
 * (js/pollo.js lisaaPinoon) työntää vanhat ylöspäin. Kaksi liikettä,
 * yksi ele.
 */
/*
 * SAMA KESTO JA KÄYRÄ KUIN VANHOJEN NOUSULLA (js/pollo.js PINON_NOUSU_MS
 * 380 ms, --liike-pehmea): uusi kupla nousee oman korkeutensa verran
 * alhaalta samaan tahtiin kuin vanhat väistyvät ylös — yksi liike, ei
 * pomppu vanhojen liu'un rinnalla (omistaja 3.9.2026).
 */
.pollo-kuplapino .pollo-vihje {
  animation: pollo-kupla-saapuu 380ms var(--liike-pehmea);
}

/*
 * LUUKUSTA, EI RÄPSÄHTÄEN (omistaja 4.9.2026 iltapäivä: *"vanhat eivät
 * saisi räpsähtää vaan ensin vanhat liukuisivat pehmeästi ylöspäin ja
 * samalla alaosasta (kuin näkymättömästä luukusta) liukuisi näkyviin
 * uusi kupla yhtä pehmeästi"*). Kupla lähtee kokonaan pinon alareunan
 * takaa (oma korkeus + kärjen vara) täydessä näkyvyydessä: pinon
 * overflow leikkaa sen, joten se nousee esiin reunan alta eikä
 * häivy sisään.
 */
@keyframes pollo-kupla-saapuu {
  from { transform: translateY(calc(100% + 0.8rem)); }
  to { transform: translateY(0); }
}

/* Liikeherkkyys: kupla vain ilmestyy, ei liiku. */
@media (prefers-reduced-motion: reduce) {
  .pollo-vihje { animation: none; }
  .pollo-kuplapino-kehys { transition: none; }

  .pollo-kuplapino .pollo-vihje {
    animation: pollo-kupla-havahtuu 120ms linear;
  }

  @keyframes pollo-kupla-havahtuu {
    from { opacity: 0; }
    to { opacity: 1; }
  }
}

/*
 * JUHLAKUPLA: TIETÄJÄTASON NOUSU (omistajan tilaus 18.8.2026).
 *
 * Sama kupla kuin vihjeellä — sama paperi, sama kärki, sama paikannus
 * — mutta sisältönä uuden tason iso muotokuva, sen kalevalainen värssy
 * kursiivilla kahdella rivillä ja onnittelulause. Nousu ei anna mitään
 * muuta kuin nimikkeen, joten tämä hetki on koko palkinto ja saa olla
 * kuplaperheen juhlavin.
 */
.pollo-vihje-juhla {
  max-width: min(19rem, calc(100vw - 1.6rem));
  padding: 0.7rem 0.8rem 0.65rem;
  text-align: center;
}

.pollo-vihje-avatar {
  display: block;
  width: 6.5rem;
  height: 6.5rem;
  margin: 0 auto 0.45rem;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid rgba(122, 85, 20, 0.55);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
}

/* Värssy on runoa: kursiivi, kaksi säettä omilla riveillään. */
.pollo-vihje-varssy {
  margin: 0 0 0.4rem;
  font-style: italic;
  font-size: 0.9rem;
  line-height: 1.35;
  color: #46331f;
}

.pollo-vihje-sae { display: block; }

.pollo-vihje-lause {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.4;
}

/*
 * ISOISÄN MAADOITUS KEVYEN KULUN SAAPUMISKUPLASSA (omistajan päätös
 * 27.8.2026; js/pollo.js naytaMaadoitus).
 *
 * Sama pergamentti, kärki ja paikannus kuin muilla kuplilla — yksi
 * ero: kupla on hitusen LEVEÄMPI, koska maadoitus on kokonainen
 * puheenvuoro eikä yhden rivin ohje, ja 17 rem:n kaistalla se venyi
 * kymmenen rivin torniksi.
 *
 * PELKKÄ PUHE (omistajan tilaus 3.9.2026: *"pelkät puhekuplat"*).
 * Ylärivinä oli puhujan yliviivattu nimilappu; se toistui pinossa
 * kuplasta toiseen eikä kertonut enää mitään uutta, joten se ja sen
 * tyylit (.pollo-vihje-nimilappu) poistuivat. Nimi näkyy yhä
 * chatissa. Kaista pysyy samana: teksti sai päinvastoin lisää tilaa,
 * kun avauskuplan kuvasarake katosi (js/pollo.js naytaAvauskupla).
 */
.pollo-vihje-maadoitus {
  max-width: min(21rem, calc(100vw - 1.6rem));
  padding: 0.55rem 0.75rem 0.6rem;
}

/* Kappaleväli vain kappaleiden VÄLIIN: ensimmäisen yläpuolella on jo
   kuplan oma pehmuste. */
.pollo-vihje-maadoitus .pollo-vihje-lause + .pollo-vihje-lause {
  margin-top: 0.45rem;
}

/*
 * LIVIAN AVAUSKUPLA ALOITUSVALINNASSA (omistajan tilaus 29.8.2026;
 * js/livia.js, js/pollo.js naytaAvauskupla).
 *
 * EI ENÄÄ OMAA ASUA (omistajan tilaus 3.9.2026: *"tässä ei tarvita
 * ollenkaan tuota kuvaketta … Eli pelkät puhekuplat"*). Kuplassa oli
 * puheen vieressä pyöreä kuvapaikka odottamassa Livian kasvokuvaa, ja
 * sitä varten oma flex-asettelu ja leveämpi kaista
 * (.pollo-vihje-avaus, .pollo-vihje-puhe, .pollo-vihje-kuvapaikka,
 * .pollo-vihje-kasvot). Kuvake luki ruudulla tunnistamattomana
 * tahrana, joten sarake ja sen tyylit poistuivat; avauskupla on nyt
 * tavallinen .pollo-vihje-maadoitus. Vain lennähdys jäi.
 */

/*
 * LIVIA LENNÄHTÄÄ PAIKALLE: kevyt saapumisliike sarjan ensimmäiselle
 * kuplalle (omistaja 29.8.2026). Ei uutta hahmoanimaatiota — kupla
 * tulee oikealta ja alhaalta, kuin lintu olisi juuri laskeutunut
 * ruudun laidasta. Seuraavat repliikit saavat kuplaperheen tavallisen
 * ilmestymisen.
 */
.pollo-vihje-lennahtaa { animation: livia-lennahtaa 420ms ease-out; }

@keyframes livia-lennahtaa {
  from { opacity: 0; transform: translate(22px, 10px) rotate(2deg); }
  to { opacity: 1; transform: translate(0, 0) rotate(0); }
}

/* Liikeherkkyys: kupla vain ilmestyy, kuten muutkin kuplat. */
@media (prefers-reduced-motion: reduce) {
  .pollo-vihje-lennahtaa { animation: none; }
}

.pollo-paneeli {
  /*
   * Paneelin oma väripaletti. Sävyt on otettu kaupunkilehdestä: paperi
   * #f5f0e2 ja painomuste #211d18 ovat samat kuin .dialog.arkki
   * .dialog-cardissa, jotta pöllön paneeli tuntuu samalta arkilta kuin
   * lehti. Muuttujat pitävät sävyt yhdessä paikassa, koska paneelin
   * sisällä on kymmenkunta osaa.
   */
  --pollo-paperi: #f5f0e2;
  --pollo-paperi-2: #ece2c8;
  --pollo-muste: #211d18;
  --pollo-muste-himmea: #6b5a45;
  --pollo-korostus: #7a5514;
  --pollo-viiva: rgba(122, 85, 20, 0.32);

  position: fixed;
  right: calc(0.7rem + env(safe-area-inset-right, 0px));
  bottom: calc(7.2rem + env(safe-area-inset-bottom, 0px));
  z-index: 41;
  display: flex;
  flex-direction: column;
  /*
   * ── KORKEUS ON KIINTEÄ, EI SISÄLLÖN MUKAINEN (omistaja 13.8.2026) ──
   *
   * *"Pöllönäkymä voisi heti aueta täyteen korkeuteensa. Se nimittäin
   * myös häiritsee, kun korkeus pikkuhiljalleen kasvaa."*
   *
   * Ennen tässä oli `max-height`, joten paneeli kasvoi jokaisen
   * striimatun rivin myötä ja koko laatikko eli vastauksen alla. Nyt
   * mitta on `height`: paneeli on avatessaan sen kokoinen kuin se on
   * vastauksen lopussakin. Sivutuotteena vastauksen alle varattu tyhjä
   * (js/pollo.js viritaTyhjaTila) mitataan vakaasta korkeudesta.
   *
   * clamp pitää mitan järkevänä myös maisema-asennossa, jossa
   * laskukaavan arvo jäisi muuten olemattomaksi. dvh eikä vh: iOS:n
   * osoiterivi söi vh-mitasta osan, ja paneelin alalaita jäi kaaren
   * taakse.
   *
   * iPadilla ja työpöydällä paneeli on hieman entistä leveämpi ja
   * selvästi korkeampi, mutta se EI ylety alanappirivin päälle —
   * leveällä ruudulla napit ovat kaukana paneelista ja käytössä.
   * Puhelimen omat mitat ovat media-lohkossa (max-width: 560px).
   *
   * POIKKEUS: tuore keskustelu aukeaa sisällön korkuisena
   * (.pollo-alku alempana) — täysi kiinteä korkeus astuu voimaan
   * ensimmäisestä kysymyksestä, kerralla eikä vähitellen.
   */
  width: min(24rem, calc(100vw - 1.4rem));
  height: clamp(14rem, calc(100dvh - 11rem - env(safe-area-inset-bottom, 0px)), 40rem);
  border: 1px solid var(--pollo-viiva);
  border-radius: var(--radius);
  /* Sama painopaperi kuin lehden arkissa: kohina kertaantuu värin päälle. */
  background-color: var(--pollo-paperi);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  color: var(--pollo-muste);
  /* Leipäteksti lukukirjasimella, kuten lehden jutut. */
  font-family: var(--font-luku);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}

/*
 * ── PUHELIMELLA PÖLLÖ PEITTÄÄ ALANAPIT (omistaja 13.8.2026) ──────────
 *
 * *"Pöllö voisi iPhonessa ainakin tulla tai alkaa alanappien päältä
 * peittäen ne. Ja koko pop-up-ikkuna voisi olla korkeampi, mahtuu
 * paremmin tekstiä näkyviin. — Pöllötilassa kuitenkaan ei tehdä mitään
 * muuta, niin se voi peittää reilumminkin karttaa."*
 *
 * Paneeli seisoi alanappirivin yläpuolella (bottom 7.2rem) ja jätti
 * kartan napit näkyviin, vaikka keskustelun aikana niistä ei ole
 * mitään hyötyä. Kapealla ruudulla se maksoi kaksi riviä tekstiä.
 * Puhelimella paneeli laskeutuu siis kotipalkin viereen ja venyy sen
 * verran korkeammaksi kuin ruutu antaa. Alalaita jää turva-alueen
 * yläpuolelle, jottei iPhonen kotipalkki leikkaa nappiriviä.
 *
 * Sulkeminen ei kärsi: paneeli suljetaan napauttamalla sen ULKOPUOLELLE
 * (js/pollo.js seuraaSulkemista) tai Esc-näppäimestä, ei peittyneestä
 * pöllönapista.
 *
 * MITAT (omistajan tarkennus 13.8.2026): *"kartta saa jäädä näkyviin
 * hieman alhaalla ja sivuilla, mutta alanapit pitää peittyä kokonaan ja
 * sitten vähän enemmän ylhäälle voi jäädä tilaa."*
 *
 * Leveys ei tule `width`istä vaan MOLEMMISTA reunoista: `left` ja
 * `right` samalla kaavalla, `width: auto`. Silloin keskitys ei riipu
 * yhdestäkään leveyslaskennasta — reunavälit ovat aina yhtä suuret,
 * vaikka ruudun leveys tai turva-alueet muuttuisivat. Sivuille ja
 * alalaitaan jää 0,7 rem, josta kartta pilkottaa; ylhäältä paneeli
 * jättää selvästi enemmän tilaa (katto 38 rem), jotta MATKAKIRJASTA-
 * kaistale ja yläkartta kehystävät sen.
 */
@media (max-width: 560px) {
  .pollo-paneeli {
    left: calc(0.7rem + env(safe-area-inset-left, 0px));
    right: calc(0.7rem + env(safe-area-inset-right, 0px));
    bottom: calc(0.7rem + env(safe-area-inset-bottom, 0px));
    width: auto;
    height: clamp(14rem, calc(100dvh - 9rem - env(safe-area-inset-bottom, 0px)), 38rem);
  }

  /*
   * ── ALANAPIT VÄISTYVÄT PÖLLÖN AJAKSI (omistaja 13.8.2026) ──────────
   *
   * *"Eikä napit peity kokonaan alhaalla."* Paneelin alle jää nyt
   * tarkoituksella pieni rako, josta kartta näkyy — ja samasta raosta
   * kurkkivat myös kartan alanapit. Peittämisen sijaan koko alanappirivi
   * (matkustustavat, pöllö, tutki ja niiden pergamenttilevy) piilotetaan
   * siksi ajaksi kun keskustelu on auki. Pöllötilassa niitä ei käytetä,
   * ja paneeli suljetaan sen ulkopuolelle napauttamalla tai Escillä —
   * ei peittyneestä pöllönapista.
   *
   * `visibility` eikä `opacity`: paneeli on kortin JÄLKELÄINEN, ja vain
   * visibility voidaan kytkeä jälkeläisessä takaisin päälle. Luokan
   * asettaa ja poistaa js/pollo.js (avaa/sulje), joten piilotus ei jää
   * päälle paneelin sulkeuduttua.
   *
   * Sääntö on media-lohkon sisällä: tabletilla paneeli ei ylety nappien
   * päälle, joten siellä ne saavat näkyä ja toimia normaalisti.
   */
  body.pollo-auki .turn-card {
    visibility: hidden;
    pointer-events: none;
  }

  body.pollo-auki .pollo-paneeli {
    visibility: visible;
    pointer-events: auto;
  }
}

/*
 * ── ALKUTILA: TUORE KESKUSTELU AUKEAA SISÄLLÖN KORKUISENA (omistajan
 * tilaus 18.8.2026: "pöllön alkuteksti ja sen alla kaksi kysymystä, ja
 * vierittämällä saisi vielä kolme kysymystä lisää näkyviin") ──────────
 *
 * Ennen ensimmäistä kysymystä paneelissa on vain alkuteksti ja
 * kysymyskuplat, ja kiinteä täysi korkeus jättäisi niiden alle ison
 * tyhjän paperin. Alkutilassa korkeus tulee siksi sisällöstä, ja katto
 * on selvästi täyttä matalampi: näkyviin mahtuu alkuteksti ja parisen
 * ensimmäistä kysymystä, ja loput löytyvät vierittämällä SAMAA yhtä
 * pintaa alaspäin — näkyvä määrä elää ruutukoon ja rivityksen mukana,
 * mitään ei mitata pikseleinä. Luokan poistaa ensimmäinen kysymys
 * (js/pollo.js kysy) KERRALLA ennen vastausta, joten kiinteän korkeuden
 * sääntö (omistaja 13.8.2026, ks. .pollo-paneeli) pysyy voimassa:
 * korkeus ei koskaan kasva vähitellen vastauksen aikana.
 *
 * Sama sääntö kelpaa puhelimelle ja isolle ruudulle: katto on remeissä
 * ja dvh-laskussa, ja kahden luokan valitsin voittaa molempien
 * lohkojen height-rivit ilman media-ehtoja.
 *
 * ── KATTO NOSTETTU: KOKO TERVEHDYS KERRALLA (omistajan tilaus
 * 27.8.2026: *"pöllön kupla saisi avautua korkeampana jotta pulun
 * kaikki teksti mahtuisi kerralla näkyviin"*) ────────────────────────
 *
 * JUURISYY oli tämän säännön kolmas arvo: katto oli 17rem = 272 px,
 * ja siitä paneelin oma kehys (alanappirivi, reunat, virran täyte) söi
 * ~82 px. Keskusteluvirralle jäi 190 px. Livian TUURAAJA-tervehdys
 * (js/pollo.js TERVEHDYS, viisi virkettä) vie kapealla ruudulla yksin
 * 160 px, ja sen alle tulevat vielä avausehdotukset — sisältöä 271 px,
 * tilaa 190 px. Virta vieritti itsensä pohjaan, ja tervehdyksen ALKU
 * jäi ruudun yläpuolelle: omistaja näki puheenvuoron alkavan keskeltä
 * virkettä. Katto ei siis rajoittanut mitään ylimääräistä tyhjää vaan
 * leikkasi tekstiä.
 *
 * Katto on nyt kolmiosainen, ja jokainen osa vartioi eri asiaa:
 *
 *   14rem  — alaraja: matalinkin paneeli on käytettävä.
 *   66dvh  — SE, JOKA YLEENSÄ RATKAISEE. Paneeli saa kahden kolmasosan
 *            osuuden näkymästä; loppukolmannes jää kartalle yläreunaan,
 *            joten paneeli ei koskaan peitä koko ruutua.
 *   100dvh − 11rem — vanha turvaraja, ennallaan. Matalalla näkymällä
 *            (maisema-asento, avattu näppäimistö) tämä alittaa 66dvh:n,
 *            ja min() valitsee sen: paneelin yläpuolelle jää tilaa
 *            samalla kaavalla kuin ennenkin.
 *   32rem  — yläraja: leveällä ruudulla 66dvh kasvaisi järjettömäksi,
 *            eikä alkutila saa koskaan yltää täyden paneelin (38–40rem)
 *            korkeuteen — tuore keskustelu on yhä matalampi kuin käyty.
 *
 * `height: auto` säilyy, joten paneeli mitoittaa itsensä SISÄLLÖN
 * mukaan tuohon kattoon asti: tervehdys + ehdotukset tarvitsevat
 * iPhonella ~353 px ja iPadilla ~376 px, eli paneeli aukeaa juuri sen
 * korkuisena eikä varaa turhaa paperia. Vieritys ei katoa mihinkään —
 * jos sisältöä on kattoa enemmän (näppäimistö auki, iso tekstikoko),
 * virta vierittyy kuten ennenkin.
 */
.pollo-paneeli.pollo-alku {
  height: auto;
  max-height: clamp(
    14rem,
    min(66dvh, calc(100dvh - 11rem - env(safe-area-inset-bottom, 0px))),
    32rem
  );
}

/*
 * EI HEHKUA. Kaikki paneelin teksti nollaa perityn pergamenttivarjon —
 * tämä on se sääntö, joka teki teksteistä jälleen teräviä. Valitsin on
 * tarkoituksella tarkempi kuin body[data-mode] .actions button, joka
 * yltää paneelin nappeihin asti.
 */
.pollo-paneeli,
body[data-mode] .actions .pollo-paneeli,
body[data-mode] .actions .pollo-paneeli * { text-shadow: none; }

/*
 * ── ESTETTY NAPPI HIMMENEE, MUTTA EI KATOA ───────────────────────────
 *
 * JUURISYY omistajan havaintoon 13.8.2026 ("sanelussa ei näy vielä
 * mitään tekstiä napissa"): paneeli asuu alanappirivin sisällä, joten
 * kartan oma sääntö `body[data-mode] .actions button:disabled` yltää
 * myös paneelin nappeihin — ja se on tarkempi (kolme luokkaa ja kaksi
 * elementtiä) kuin paneelin omat säännöt. Kartalla sääntö on oikea:
 * siellä estetty nappi saa sulaa pergamenttiin, koska pohjana on
 * piirretty kartta. Chatin paperilla se riisui napilta taustan ja jätti
 * tekstin 45 %:n musteeksi — mitattuna läpinäkyvä pohja ja
 * rgba(58, 42, 22, 0.45) teksti vaalealla paperilla. Juuri niin
 * pysäytysneliö ja sana "Lopeta" katosivat siksi aikaa, kun pöllö haki
 * ehdotuksia tai vastausta (asetaKesken estää koko syöterivin).
 *
 * Paneelilla on oma himmennyksensä (opacity 0.5), joten kartan sääntö
 * kumotaan paneelin osalta yhtä tarkalla valitsimella — ei
 * !importantilla, vaan lisäämällä .pollo-paneeli valitsinketjuun.
 */
body[data-mode] .actions .pollo-paneeli button:disabled {
  opacity: 0.5;
  border-color: var(--pollo-viiva);
  background: var(--pollo-paperi);
  color: var(--pollo-korostus);
}

/* Keskustelun napit ovat hitusen tummempaa paperia kuin syöterivin,
   ja pitävät sävynsä myös estettyinä. */
body[data-mode] .actions .pollo-paneeli button.pollo-ehdotus:disabled {
  background: var(--pollo-paperi-2);
  color: var(--pollo-muste);
}

/*
 * Ehdotukset ovat KESKUSTELUVIRRASSA, eivät paneelin yläreunassa
 * (omistajan havainto 13.8.2026). Aiemmin laatikko oli paneelin oma
 * ylin osa, jolloin se jäi lukituksi vanhan vastauksen päälle ja näytti
 * kuuluvan siihen. Nyt se vierii viestien mukana ja saa saman muodon
 * kuin vastauksen alla olevat jatkokysymykset (.pollo-jatkot).
 */
.pollo-ehdotukset {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin: 0 0 0.6rem;
}

button.pollo-ehdotus {
  padding: 0.4rem 0.55rem;
  min-height: 0;
  border: 1px solid var(--pollo-viiva);
  border-radius: 8px;
  background: var(--pollo-paperi-2);
  color: var(--pollo-muste);
  font-family: inherit;
  font-size: 0.85rem;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
}

/*
 * ── OSOITETTU NAPPI EI SAA NIELLÄ TEKSTIÄÄN (omistajan bugi 27.8.2026:
 * *"linkin väri muuttuu vääräksi osoitettaessa"*, kaappauksessa
 * jatkokysymysnappi tummanruskeana ja teksti tuskin näkyvissä) ────────
 *
 * JUURISYY: paneelin napit ovat tavallisia <button>-elementtejä, ja
 * tiedoston alun yleissääntö
 *
 *     button:hover:not(:disabled) { background: #43331f; }
 *
 * maalaa jokaisen napin taustan TUMMANRUSKEAKSI. Pöllöpaneelin omat
 * hover-säännöt vaihtoivat vain TEKSTIN värin tummaan kultaan
 * (--pollo-korostus, #7a5514) eivätkä koskeneet taustaan lainkaan.
 * Lopputulos oli #7a5514 mustan ruskean #43331f päällä — kontrasti
 * 1,6:1, eli teksti katosi juuri sinä hetkenä, jona pelaaja osoittaa
 * nappia. Sama vika koski kolmea nappiperhettä: .pollo-ehdotus
 * (avausruudun ehdotukset, valmiit kysymykset ja vastausten
 * jatkokysymykset), .pollo-ehdota ja alarivin .pollo-nappula.
 *
 * SÄÄNTÖ TÄSTÄ ETEENPÄIN: paneelin napissa tausta ja teksti liikkuvat
 * AINA yhdessä. Jos tausta tummuu, teksti vaalenee paperiin; jos
 * tausta pysyy paperina, teksti pysyy musteena. Osoitettu jatkokysymys
 * on siis mustetäplä paperilla — sama ele kuin pelin muissakin
 * napeissa, mutta paneelin omalla paletilla ja luettavana.
 *
 * :focus-visible on mukana, jotta näppäimistöllä kulkeva näkee saman
 * korostuksen kuin hiirellä osoittava, ja :active kertoo painalluksen.
 * .actions-ketju on mukana samasta syystä kuin :disabled-säännössä
 * yllä: kartan pergamenttinapeilla on tarkempi valitsin, joka muuten
 * voittaisi tämän jos pöllö joskus palaa alanappiriviin.
 */
button.pollo-ehdotus:hover:not(:disabled),
button.pollo-ehdotus:focus-visible,
body[data-mode] .actions .pollo-paneeli button.pollo-ehdotus:hover:not(:disabled),
body[data-mode] .actions .pollo-paneeli button.pollo-ehdotus:focus-visible {
  border-color: var(--pollo-korostus);
  background: var(--pollo-muste);
  color: var(--pollo-paperi);
}

button.pollo-ehdotus:active:not(:disabled),
body[data-mode] .actions .pollo-paneeli button.pollo-ehdotus:active:not(:disabled) {
  background: var(--pollo-korostus);
  color: var(--pollo-paperi);
}

button.pollo-ehdotus:disabled { opacity: 0.5; cursor: default; }

.pollo-virta {
  flex: 1;
  min-height: 3rem;
  padding: 0.7rem 0.6rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  /*
   * Selaimen oma vieritysankkuri pois: se siirtää vierityskohtaa itse,
   * kun sisältö muuttuu, ja juuri sitä liikettä vastaan koko varattu
   * tyhjä (js/pollo.js viritaTyhjaTila) on rakennettu. Ankkuri on
   * meidän, ei selaimen.
   */
  overflow-anchor: none;
}

/*
 * Vastauksen alle varattu tyhjä (js/pollo.js viritaTyhjaTila). Pelkkää
 * tilaa: korkeus tulee skriptiltä eikä lohkolla ole muuta tehtävää.
 * Nollamitat kirjataan tähän, jottei mikään perityvä sääntö kasvattaisi
 * sitä — varauksen koon pitää olla täsmälleen se, mikä on mitattu.
 */
.pollo-tyhja {
  margin: 0;
  padding: 0;
  border: 0;
}

/* Vastaukset ovat pitkähköä leipätekstiä, joten ne käyttävät samaa
   lukukirjasinta kuin lehden jutut (--font-luku, paneelin perintö).
   Pelaajan oma kysymys pysyy kirjoituskoneessa, jotta puheenvuorot
   erottuvat toisistaan. Koot ovat puhelinluettavia: alle 13 pikselin
   teksti ei ole tässä kirjasimessa enää terävää. */
.pollo-viesti {
  margin: 0 0 0.55rem;
  font-size: 0.9rem;
  line-height: 1.5;
}

.pollo-viesti:last-child { margin-bottom: 0; }

/*
 * PÖLLÖN VASTAUKSEN RIVINVAIHDOT NÄKYVIIN.
 *
 * Vastaus voi päättyä omaan osioonsa ("Livian lisäys:", ks. workerin
 * järjestelmäkehote), joka kuuluu omalle rivilleen. Vastaus asetetaan
 * tekstisisältönä eikä sitä tulkita merkkauksena, joten ainoa keino
 * erottaa rivi on antaa selaimen kunnioittaa mallin rivinvaihtoa.
 * pre-line riittää: se säilyttää rivinvaihdot mutta kutistaa
 * ylimääräiset välilyönnit, eikä vaadi mitään uutta muotoilukerrosta.
 * Koskee vain pöllön puheenvuoroa — pelaajan kysymys on yksi rivi.
 */
.pollo-viesti.pollo-pollo { white-space: pre-line; }

.pollo-kayttaja {
  padding: 0.35rem 0.5rem;
  border-radius: 8px;
  background: var(--pollo-paperi-2);
  color: var(--pollo-muste);
  font-family: var(--font-type);
  font-size: 0.85rem;
}

.pollo-pollo {
  font-family: var(--font-luku);
  font-size: 0.95rem;
  color: var(--pollo-muste);
}

/*
 * ── VASTAUSTEKSTI EI OLE KURSIIVIA (omistaja 13.8.2026) ──────────────
 *
 * *"saisiko strimitekstin ilman kursiivia"*.
 *
 * JUURISYY: tämä sääntö osui kahteen paikkaan yhdellä nimellä.
 * Odotusrivi (Livian mietintämuoto) on viestikupla, jolla luokka
 * kuuluu olla — mutta
 * js/pollo.js asetti saman luokan myös PANEELIIN odotuksen ajaksi, ja
 * paneelista kursiivi ja himmeä muste periytyivät kaikkeen sisältöön.
 * Striimattu vastaus kirjoittui siis kursiivilla ja muuttui pystyksi
 * vasta valmistuessaan — sama teksti kahdessa asussa.
 *
 * Valitsimessa on nyt .pollo-viesti mukana, ja paneelin oma odotustila
 * on eri luokka (.pollo-kesken, ei tyyliä täällä). Kursiivi kuuluu vain
 * sille yhdelle riville, joka ei ole pöllön puhetta.
 */
.pollo-viesti.pollo-odottaa { color: var(--pollo-muste-himmea); font-style: italic; }

/*
 * ── EHDOTUSTEN ODOTUSRIVI (omistajan tilaus 28.8.2026: "Generoinnin
 * aikana saisi näkyä pieni odotusanimaatio"). ──
 *
 * Kysymysehdotukset generoidaan palvelimella, ja sen ajan ehdotusrivi
 * oli tyhjä — pelaajalle sama asia kuin "ei kysymyksiä". Rivin paikalle
 * tulee nyt SAMA odotusrivi kuin vastausta odottaessa (yllä) eli Livian
 * vaihtuva mietintämuoto, vain ehdotusnapin kokoon kutistettuna: uutta
 * odotuskieltä ei ole, ja rivi perii kursiivin ja himmeän musteen
 * .pollo-odottaa-säännöstä.
 *
 * Animaatio on hidas hengitys eikä pyörivä ratas: pöllön pinta on
 * paperia ja mustetta, eikä latauskiekko kuulu siihen. Liike on myös
 * ainoa merkki siitä, että jotain on tulossa — pysähtynyt rivi
 * näyttäisi virheeseen jääneeltä.
 */
.pollo-ehdotukset .pollo-ehdotus-odotus {
  margin: 0;
  padding: 0.4rem 0.55rem;
  font-size: 0.85rem;
  line-height: 1.3;
  animation: pollo-odotus-hengitys 1.8s ease-in-out infinite;
}

@keyframes pollo-odotus-hengitys {
  0%, 100% { opacity: 0.45; }
  50% { opacity: 1; }
}

/*
 * Liikeherkälle lukijalle rivi jää paikalleen luettavana: teksti
 * kertoo saman kuin liike (sama sääntö kuin muualla pelissä).
 */
@media (prefers-reduced-motion: reduce) {
  .pollo-ehdotukset .pollo-ehdotus-odotus { animation: none; opacity: 0.85; }
}

/*
 * ── PÖLLÖ IRTI REUNASTA JA VÄLJEMPI ISOLLA RUUDULLA (omistaja
 * 13.8.2026 ilta: "Pöllö saisi olla hieman irti reunasta. Teksti
 * aavistuksen isompaa ja aavistuksen isompi marginaali"). ──
 *
 * Koskee tablettia ja työpöytää. Puhelimen mitat (max-width: 560px
 * -lohko yllä) on viritetty erikseen omien havaintojen pohjalta, eikä
 * niihin kosketa: kapealla ruudulla jokainen pikseli ja kirjasinkoon
 * askel on jo käytetty tarkkaan. Lohko on tekstisääntöjen JÄLKEEN,
 * koska samanvahvuisista valitsimista myöhempi voittaa — ennen niitä
 * media queryn koot eivät koskaan pääsisi voimaan.
 */
@media (min-width: 561px) {
  .pollo-paneeli {
    right: calc(1.5rem + env(safe-area-inset-right, 0px));
  }

  /* Aavistuksen isompi marginaali: teksti irti paneelin laidoista. */
  .pollo-virta { padding: 1rem 0.95rem; }

  /* Aavistuksen isompi teksti — samat suhteet, kaikki askeleen ylös. */
  .pollo-viesti { font-size: 0.97rem; }
  .pollo-pollo { font-size: 1.02rem; }
  .pollo-kayttaja { font-size: 0.9rem; }
  button.pollo-ehdotus { font-size: 0.9rem; }
}

/*
 * ALLEVIIVATTU LINKKI KESKELLÄ VASTAUSTA (omistajan tilaus 12.8.2026).
 *
 * Kun paikallishaku löytää osuvan jutun, vastaustekstin oma maininta
 * siitä muuttuu linkiksi — erillistä nappia ei silloin tarvita.
 * Alleviivaus on katkoviiva samalla kynällä kuin varapolun napin
 * kehys, jotta pelinsisäinen linkki näyttää samalta kummassakin
 * muodossa.
 */
a.pollo-tekstilinkki {
  color: var(--pollo-korostus);
  text-decoration: underline;
  text-decoration-style: solid;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  cursor: pointer;
}

/*
 * ── "EHDOTA SISÄLTÖÄ" PANEELIN OIKEASSA YLÄKULMASSA (omistajan tilaus
 * 18.8.2026) ──────────────────────────────────────────────────────────
 *
 * Kapea rivi paneelin yläreunassa, sisältönä vain pieni tekstinappi
 * oikealla. Rivi on flow'ssa eikä virran päälle asemoitu, jottei nappi
 * peitä vieritettävää keskustelua; paneelissa ei silti ole yläpalkkia
 * — rivi on paljasta paperia ilman otsikkoa tai viivaa. Nappi avaa
 * saman ehdotuslomakkeen kuin hampurilaisvalikon "ehdota sisältöä"
 * (js/ui.js naytaPalauteKulmasta), ks. js/pollo.js rakenna().
 */
.pollo-ylarivi {
  display: flex;
  justify-content: flex-end;
  padding: 0.4rem 0.55rem 0;
}

button.pollo-ehdota {
  padding: 0.12rem 0.55rem;
  min-height: 0;
  border: 1px solid var(--pollo-viiva);
  border-radius: 999px;
  background: var(--pollo-paperi-2);
  color: var(--pollo-korostus);
  font-family: inherit;
  font-size: 0.72rem;
  line-height: 1.5;
  cursor: pointer;
}

/*
 * Sama juurisyy kuin jatkokysymysnapissa (ks. .pollo-ehdotus:hover):
 * pelkkä kehyksen tummennus jätti yleissäännön tumman taustan voimaan.
 * Pikkupilleri pysyy paperilla — se on kulman hiljainen tekstinappi
 * eikä saa loimottaa tummana — ja saa hoverissa vain lämpimän sävyn
 * sekä täyden musteen tekstiinsä.
 */
button.pollo-ehdota:hover,
button.pollo-ehdota:focus-visible,
body[data-mode] .actions .pollo-paneeli button.pollo-ehdota:hover {
  border-color: var(--pollo-korostus);
  background: rgba(122, 85, 20, 0.16);
  color: var(--pollo-muste);
}

/*
 * ── VALMISKYSYMYKSET KESKUSTELUVIRRASSA (omistajan tilaus 18.8.2026:
 * "kaikki saisi olla samalla yhdellä sivulla") ────────────────────────
 *
 * Käsin kirjoitetut avauskysymykset (js/packs/pollo-kysymykset.js)
 * ovat kuplia SAMASSA vierityspinnassa kuin muukin keskustelu, heti
 * pöllön alkutekstin perässä — ei erillistä aluetta, jakoviivaa eikä
 * väkästä. Korkeus tulee luonnollisesta sisältövirrasta: paneelin
 * avautuessa näkyy alkuteksti ja parisen ensimmäistä kysymystä, loput
 * löytyvät alaspäin vierittämällä (js/pollo.js naytaValmiit). Napit
 * ovat samaa muotoa kuin ehdotukset (.pollo-ehdotus).
 */
.pollo-valmiit {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.3rem;
  margin: 0 0 0.6rem;
}

/*
 * Osoitettu artikkelilinkki TUMMUU SAMALLA KYNÄLLÄ eikä vaihda väriä.
 * Aiemmin hover lisäsi vain lämpimän täplän tekstin alle ja jätti
 * sävyn ennalleen, jolloin osoitus näkyi lähinnä taustan sameutumisena.
 * #5a3d0d on sama kulta pari askelta tummempana (--pollo-korostus on
 * #7a5514): linkki pysyy linkkinä, ei muutu leipätekstiksi, ja
 * kontrasti paperilla nousee. Alleviivaus paksuuntuu, jotta ele näkyy
 * myös ilman väriaistia. :focus-visible saa saman asun kuin hover.
 */
a.pollo-tekstilinkki:hover,
a.pollo-tekstilinkki:focus-visible {
  color: #5a3d0d;
  background: rgba(122, 85, 20, 0.12);
  text-decoration-thickness: 2px;
}

a.pollo-tekstilinkki:active { color: var(--pollo-muste); }

/*
 * PÖLLÖLINKKI: [[avainkäsite]] keskellä vastausta (omistajan tilaus
 * 13.8.2026).
 *
 * Toinen linkkilaji, joten se on myös näytettävä toisenlaisena:
 * artikkelilinkki vie pelin omaan juttuun ja on YHTENÄINEN viiva kullan
 * sävyssä, pöllölinkki kysyy pöllöltä lisää ja on PISTEVIIVA himmeässä
 * musteessa. Ero näkyy silloinkin, kun molemmat ovat samassa lauseessa.
 */
a.pollo-kasitelinkki {
  color: var(--pollo-muste-himmea);
  text-decoration: underline;
  text-decoration-style: dotted;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  cursor: pointer;
}

/*
 * Pöllölinkin hover tummeni aiemmin suoraan --pollo-muste-arvoon, joka
 * on TÄSMÄLLEEN leipätekstin väri: osoitettu linkki näytti siis siltä
 * kuin se olisi lakannut olemasta linkki. #4a3d2e on sama himmeä
 * muste tummempana — ero leipätekstiin säilyy, kontrasti paranee.
 * Pisteviiva paksuuntuu, jotta ele näkyy myös ilman väriaistia.
 */
a.pollo-kasitelinkki:hover,
a.pollo-kasitelinkki:focus-visible {
  color: #4a3d2e;
  background: rgba(107, 90, 69, 0.12);
  text-decoration-thickness: 2px;
}

a.pollo-kasitelinkki:active { color: var(--pollo-muste); }

/* Katkennut striimi: yksi hienovarainen rivi vastauksen alla. Se ei ole
   pöllön puhetta vaan tilatieto, joten se on kursiivia ja himmeää. */
.pollo-virherivi {
  color: var(--pollo-muste-himmea);
  font-size: 0.82rem;
  font-style: italic;
}

/* ---------------------------------------------------------------------
   KEVYT KUVAPOPUP nähtävyyslinkin päällä (js/pollo.js avaaKuvapopup).

   Linkki nähtävyysjuttuun avaa ensin pelkän kuvan ja sen valmiin
   kuvatekstin — vilkaisun, ei lukusessiota. Kortti on samaa paperia kuin
   chat-paneeli, ja se sulkeutuu napauttamalla kortin ulkopuolelle. Chat
   jää auki taustalle, joten paluu keskusteluun ei vaadi mitään.
   --------------------------------------------------------------------- */

/*
 * Popup on <dialog> eikä paneelin sisään asemoitu kerros: alanappirivi
 * on muunnettu (transform), ja muunnettu esivanhempi nappaa
 * position: fixed -kerroksen itseensä — kortti asettui ruudun sijasta
 * rivin sisään. Ylin kerros ratkaisee sen ja pitää kortin myös auki
 * olevan lehden päällä.
 */
dialog.pollo-kuvatausta {
  margin: auto;
  max-width: 100vw;
  max-height: 100dvh;
  padding: 1rem;
  border: none;
  background: transparent;
  overflow: visible;
}

dialog.pollo-kuvatausta[open] {
  display: grid;
  place-items: center;
}

dialog.pollo-kuvatausta::backdrop { background: rgba(20, 16, 10, 0.55); }

dialog.pollo-kuvatausta:focus,
dialog.pollo-kuvatausta:focus-visible { outline: none; }

.pollo-kuvakortti {
  --pollo-paperi: #f5f0e2;
  --pollo-paperi-2: #ece2c8;
  --pollo-muste: #211d18;
  --pollo-muste-himmea: #6b5a45;
  --pollo-korostus: #7a5514;
  --pollo-viiva: rgba(122, 85, 20, 0.32);

  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  /*
   * LEVEYS SEURAA RUUTUA (omistajan havainto 16.8.2026: "pöllön kuvat
   * aukeavat liian pieninä ainakin iPadissa"). Katto oli 20rem eli
   * 320 px riippumatta ruudusta, joten iPadilla popup jäi pikkuruiseksi
   * keskelle isoa näyttöä. 40rem on sama 640 px kuin nähtävyysarkin
   * leveys (.dialog.nahtavyys-arkki, min(90vw, 640px)) — popup on nyt
   * saman kokoinen kuin muutkin kortit eikä keksi omaa mittaansa.
   * Puhelimella ratkaisee edelleen calc(100vw - 2rem).
   */
  width: min(40rem, calc(100vw - 2rem));
  /*
   * dvh eikä vh, ja turva-alueet mukaan: sama sääntö kuin arkeilla.
   * vh ei jousta iOS:n osoiterivin mukana, ja ilman turvavarausta
   * pystykuva ylsi loveuksen ja kotipalkin ali.
   */
  max-height: calc(100dvh - 3rem - var(--turva-yla) - var(--turva-ala));
  overflow-y: auto;
  padding: 0.6rem;
  border: 1px solid var(--pollo-viiva);
  border-radius: var(--radius);
  background-color: var(--pollo-paperi);
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  color: var(--pollo-muste);
  font-family: var(--font-luku);
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
  text-shadow: none;
}

img.pollo-kuva {
  display: block;
  width: 100%;
  height: auto;
  /*
   * Korkeuskatto tuli leveyden mukana: kun kortti sai kasvaa 640
   * pikseliin, pystykuva olisi venynyt niin korkeaksi, että kuvateksti
   * ja Avaa juttu -nappi olisivat jääneet vieritettävän alle. Katossa
   * on varattu tila kuvatekstille, napille ja pehmusteille. Selain
   * kaventaa kuvan itse suhteessa, joten margin-inline pitää sen
   * keskellä korttia.
   */
  max-height: calc(100dvh - 14rem - var(--turva-yla) - var(--turva-ala));
  margin-inline: auto;
  object-fit: contain;
  border-radius: 6px;
  /* Sama seepiasävytys kuin lehden kuvilla ei kuulu tänne: kuva on
     popupin ainoa sisältö ja saa näkyä sellaisenaan. */
}

.pollo-kuvateksti {
  margin: 0;
  color: var(--pollo-muste-himmea);
  font-size: 0.82rem;
  line-height: 1.4;
}

button.pollo-kuvanappi {
  align-self: flex-start;
  min-height: 0;
  padding: 0.35rem 0.7rem;
  border: 1px solid var(--pollo-korostus);
  border-radius: 8px;
  background: transparent;
  color: var(--pollo-korostus);
  font-family: var(--font-type);
  font-size: 0.82rem;
  cursor: pointer;
}

button.pollo-kuvanappi:hover { background: rgba(122, 85, 20, 0.12); }

/* Lähdelinkki Wikipedian kuvan alla (pollo.js avaaWikiKuva):
   ulkopuolinen kuva ei koskaan esiinny ilman lähdettään. */
a.pollo-kuvalahde {
  margin: 0;
  color: var(--pollo-muste-himmea);
  font-size: 0.75rem;
  text-decoration: underline;
}

/* Vastauksen pikkukuva kuplan oikeassa yläkulmassa (omistajan tilaus
   15.8.2026): teksti kiertää kuvan, napautus avaa ison version. Kiinteä
   koko on valmiin kuvan rajauskehys, ei etukäteen varattu paikka — nappi
   lisätään kuplaan vasta img:n load-tapahtumassa (js/pollo.js
   naytaVastausKuva), joten kehys ei koskaan ole tyhjä. */
.pollo-viesti .pollo-vastauskuva {
  float: right;
  width: 5.2rem;
  height: 5.2rem;
  margin: 0.1rem 0 0.35rem 0.55rem;
  padding: 0;
  border: 1px solid rgba(70, 51, 31, 0.45);
  border-radius: 6px;
  overflow: hidden;
  background: none;
  cursor: zoom-in;
  min-height: 0;
}

.pollo-vastauskuva img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Jatkokysymykset vastauksen alla. Samaa muotoa kuin avausruudun
   ehdotukset (.pollo-ehdotus), mutta virran sisällä: ne kuuluvat juuri
   siihen vastaukseen, jonka perässä ne ovat. */
.pollo-jatkot {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin: 0 0 0.6rem;
}

/* Pelinsisäiset linkit vastauksen alle. Ne rakennetaan paikallisen haun
   tuloksista, ei mallin tekstistä, joten ne osoittavat aina johonkin. */
.pollo-linkit {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin: 0 0 0.6rem;
}

button.pollo-linkki {
  padding: 0.35rem 0.5rem;
  min-height: 0;
  border: 1px dashed var(--pollo-korostus);
  border-radius: 8px;
  background: transparent;
  color: var(--pollo-korostus);
  font-family: inherit;
  font-size: 0.82rem;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
}

/*
 * Katkoviivainen linkkinappi voitti yleissäännön jo ennestään (sama
 * tarkkuus, myöhempi sijainti tiedostossa), joten sen tausta pysyi
 * vaaleana. Tässä lisätään vain :focus-visible ja :active, jotta
 * näppäimistökäyttäjä saa saman korostuksen — ja tausta kirjoitetaan
 * näkyviin myös hoveriin, ettei sääntöjen järjestys ole se, mikä
 * pitää napin luettavana.
 */
button.pollo-linkki:hover:not(:disabled),
button.pollo-linkki:focus-visible {
  background: rgba(122, 85, 20, 0.12);
  color: var(--pollo-korostus);
}

button.pollo-linkki:active:not(:disabled) {
  background: rgba(122, 85, 20, 0.22);
  color: var(--pollo-muste);
}

/*
 * "Ei hereillä" -ilmoitus on paneelin ainoa sisältö ennen käyttöönottoa,
 * joten se on myös se teksti, jonka omistaja näki suttuisena. Otsikko on
 * tumma kulta paperilla (sama sävy kuin lehden otsikoissa), lisärivi
 * himmeää mustetta — molemmat riittävän isoina luettaviksi.
 */
.pollo-nukkuu { text-align: center; padding: 0.7rem 0.3rem; }

.pollo-nukkuu-otsikko {
  margin: 0 0 0.45rem;
  color: var(--pollo-korostus);
  font-size: 1rem;
  line-height: 1.35;
}

.pollo-nukkuu-lisa {
  margin: 0;
  color: var(--pollo-muste-himmea);
  font-size: 0.85rem;
  line-height: 1.45;
}

/* ---------------------------------------------------------------------
   SYÖTTÖALUE: matala nappirivi paneelin pohjalla (omistajan linjaus
   12.8.2026). Vasemmalla näppäimistö kolmasosan leveydeltä, oikealla
   mikrofoni kahden kolmasosan. Selitetekstejä ei ole — kuvakkeiden
   merkitys on aria-labelissa ja titlessä. Rivi on tarkoituksella matala:
   ennen tässä oli 3,4 rem korkea pyöreä mikki ja kaksi tekstiriviä, mikä
   söi neljäsosan paneelista.
   --------------------------------------------------------------------- */

.pollo-syote {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  border-top: 1px solid var(--pollo-viiva);
  /* Hitusen tummempi paperi erottaa pohjarivin arkista ilman omaa väriä. */
  background: var(--pollo-paperi-2);
  padding: 0.4rem 0.45rem 0.45rem;
}

/*
 * Kolme nappia: näppäimistö 1, kaiutin 1, mikrofoni 2 (omistajan
 * tilaus 12.8.2026). Suhteet tulevat flexistä eivätkä gridistä
 * tarkoituksella: laite, joka ei osaa sanella tai lukea, piilottaa
 * oman nappinsa, ja flexissä jäljelle jäävät jakavat rivin samassa
 * suhteessa — gridissä tilalle jäisi tyhjä sarake.
 */
.pollo-sanelu {
  display: flex;
  gap: 0.4rem;
}

button.pollo-kirjoita { flex: 1 1 0; }
button.pollo-kaiutin { flex: 1 1 0; }
button.pollo-mikki { flex: 2 1 0; }

/* Kaikki alarivin napit ovat samaa matalaa muotoa. */
button.pollo-nappula {
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 2.25rem;
  padding: 0.15rem 0.3rem;
  border: 1px solid var(--pollo-viiva);
  border-radius: 8px;
  background: var(--pollo-paperi);
  color: var(--pollo-korostus);
  cursor: pointer;
}

button.pollo-nappula .viiva-ikoni svg { width: 1.15rem; height: 1.15rem; }
/*
 * Sama juurisyy kolmannen kerran (ks. .pollo-ehdotus:hover): kehys
 * tummeni, mutta yleissääntö maalasi taustan tummanruskeaksi ja
 * kuvake jäi tummaksi tummalle. Alarivi pysyy paperilla — kuvakkeet
 * piirtyvät currentColorilla, joten teksti- ja viivaväri seuraavat
 * mukana. Päällä oleva kaiutin ja kuunteleva mikki ovat tarkoituksella
 * täyteisiä; niiden omat säännöt ovat tämän alapuolella ja voittavat
 * tämän myös osoitettuina.
 */
button.pollo-nappula:hover:not(:disabled),
button.pollo-nappula:focus-visible,
body[data-mode] .actions .pollo-paneeli button.pollo-nappula:hover:not(:disabled) {
  border-color: var(--pollo-korostus);
  background: var(--pollo-paperi-2);
  color: var(--pollo-korostus);
}
button.pollo-nappula:disabled { opacity: 0.5; cursor: default; }

/*
 * Kuunteleva mikki on ainoa täyteinen nappi paneelissa, joten sen sävy
 * kirjoitetaan paneelin luokan alle: kartalla .actions-napeille on oma
 * pergamenttisääntö, joka muuten voittaisi tämän.
 */
/*
 * Kaiutin päällä: sama täyteinen muoto kuin kuuntelevalla mikillä,
 * mutta ilman sykettä — vipu on päällä, se ei tee juuri nyt mitään.
 * Valitsin on paneelin luokan alla samasta syystä kuin mikillä:
 * kartan .actions-napeilla on oma pergamenttisääntönsä.
 */
.pollo-paneeli button.pollo-kaiutin.paalla,
body[data-mode] .actions .pollo-paneeli button.pollo-kaiutin.paalla {
  background: var(--pollo-korostus);
  color: #f7f1e2;
  border-color: var(--pollo-korostus);
}

/* Kehittäjäkoodin kenttä: näkyy vain kehittäjätilassa, ja sen kuuluu
   olla huomaamaton — se on työkalu, ei pelin osa. */
.pollo-kehittaja { display: flex; }

input.pollo-kehittaja-kentta {
  flex: 1;
  min-width: 0;
  padding: 0.3rem 0.45rem;
  border: 1px dashed var(--pollo-viiva);
  border-radius: 8px;
  background: transparent;
  color: var(--pollo-muste-himmea);
  font-family: var(--font-type);
  font-size: 0.8rem;
}

input.pollo-kehittaja-kentta::placeholder { color: var(--pollo-muste-himmea); opacity: 0.7; }

/*
 * SANELUTILA NÄKYY NAPISSA (omistajan tilaus 13.8.2026). Kuunnellessaan
 * nappi on täyteinen, siinä on pysäytysneliö ja sana "Lopeta", ja se
 * sykkii kevyesti. Sisältö on kahdessa sarakkeessa, koska lepotilan
 * nappi on yhden kuvakkeen ruutu (place-items: center).
 *
 * Toinen valitsin on pidempi tarkoituksella: kartan estosääntö
 * (ks. "ESTETTY NAPPI HIMMENEE, MUTTA EI KATOA") on tarkempi kuin
 * lyhyt muoto, ja se söi kuuntelevalta mikiltä taustan sinä hetkenä,
 * kun sanelu ja lähtenyt kysymys menivät päällekkäin. Kuunteleva nappi
 * on täyteinen aina — myös estettynä.
 */
.pollo-paneeli button.pollo-mikki.kuuntelee,
body[data-mode] .actions .pollo-paneeli button.pollo-mikki.kuuntelee {
  grid-auto-flow: column;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  background: var(--pollo-korostus);
  color: #f7f1e2;
  border-color: var(--pollo-korostus);
  animation: pollo-syke 1.4s ease-in-out infinite;
}

.pollo-mikki-teksti {
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  line-height: 1;
}

@keyframes pollo-syke {
  0%, 100% { box-shadow: 0 0 0 0 rgba(122, 85, 20, 0.45); }
  60% { box-shadow: 0 0 0 0.45rem rgba(122, 85, 20, 0); }
}

/* Sanelun tilarivi kertoo vain hetkellisen tilan. Tyhjänä se ei vie
   tilaa lainkaan, joten paneelin pohja pysyy matalana. */
.pollo-sanelu-tila {
  margin: 0;
  color: var(--pollo-muste-himmea);
  font-size: 0.82rem;
  line-height: 1.35;
  text-align: center;
}

.pollo-sanelu-tila:empty { display: none; }

.pollo-rivi { display: flex; gap: 0.35rem; }

input.pollo-kentta {
  flex: 1;
  min-width: 0;
  padding: 0.45rem 0.55rem;
  border: 1px solid var(--pollo-viiva);
  border-radius: 8px;
  background: var(--pollo-paperi);
  color: var(--pollo-muste);
  font-family: inherit;
  /* 16 px estää iOS:n automaattisen zoomin kenttään napautettaessa. */
  font-size: 16px;
}

input.pollo-kentta::placeholder { color: var(--pollo-muste-himmea); }
input.pollo-kentta:disabled { opacity: 0.6; }

button.pollo-laheta {
  width: 2.3rem;
  border: 1px solid var(--pollo-viiva);
  border-radius: 8px;
  background: var(--pollo-paperi);
  color: var(--pollo-korostus);
  font-size: 1rem;
  cursor: pointer;
}

button.pollo-laheta:hover:not(:disabled) { border-color: var(--pollo-korostus); }
button.pollo-laheta:disabled { opacity: 0.5; cursor: default; }

@media (prefers-reduced-motion: reduce) {
  button.pollo-mikki.kuuntelee { animation: none; }
}

/* ── Lukijaäänen säädin (kehittäjätila, 14.8.2026) ────────────────
 * Valikon Äänet-osion nappi ja dialogin kentät. Dialogi perii
 * .dialog-kortin ulkoasun; tässä vain rivien asettelu. */
.puhe-saadin-nappi { margin-top: 0.35rem; }

/* TYÖHUONE (omistajan tilaus 15.8.2026): kolme tyylinappiin puettua
 * riviä (kuvake + nimi) ja niiden alla tilannepalkit. Napit ovat
 * varustenappien sukua: sama kulmapyöristys ja kultareuna, mutta
 * täysleveinä riveinä, koska nämä ovat komentoja eivätkä tila-
 * valintoja. */
.tyohuone-nappi {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.45rem 0.6rem;
  border: 1px solid rgba(198, 158, 82, 0.45);
  border-radius: 10px;
  text-align: left;
}

.tyohuone-nappi .viiva-ikoni svg {
  width: 1.15rem;
  height: 1.15rem;
}

/*
 * FOKUSMOODIN VERTAILUKYTKIMET VALIKOSSA (omistajan tilaus 25.8.2026:
 * ylärivin napit saivat uudet tehtävät, ja nämä siirtyivät tänne).
 *
 * Kytkin ei ole oikotie vaan päälle/pois-tila, joten sen on näytettävä
 * tilansa: painettuna kullalla ja pienellä pallolla rivin lopussa.
 * ::after eikä toinen elementti — sisältö on tilan kuvaus, ei nappia.
 */
.tyohuone-nappi[aria-pressed]::after {
  content: '○';
  margin-left: auto;
  font-size: 0.8em;
  opacity: 0.55;
}

.tyohuone-nappi[aria-pressed='true'] {
  border-color: rgba(234, 184, 78, 0.8);
  color: var(--kulta, #eab84e);
}

.tyohuone-nappi[aria-pressed='true']::after {
  content: '●';
  opacity: 1;
}

.puhe-saadin-rivi {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.5rem 0;
}

.puhe-saadin-rivi label { min-width: 4.2rem; }
.puhe-saadin-rivi select { flex: 1 1 auto; font: inherit; padding: 0.3rem 0.4rem; }
.puhe-saadin-rivi input[type="range"] { flex: 1 1 auto; }
.puhe-saadin-rivi b { min-width: 3.2rem; text-align: right; font-variant-numeric: tabular-nums; }

.puhe-saadin-label { display: block; margin: 0.5rem 0 0.25rem; }

.puhe-saadin-ohje {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  padding: 0.4rem 0.5rem;
}

/* Pelin oletusprompti kentän alla vertailua varten (omistajan tilaus
 * 15.8.2026): pieni ja vaimea, ettei se kilpaile itse kentän kanssa. */
.puhe-oletusohje {
  margin: 0.3rem 0 0;
  font-size: 0.78rem;
  line-height: 1.35;
  opacity: 0.72;
}

/* ==================================================================
 * PRO-SISÄLLÖNTUOTTAJAT (js/ehdotukset.js, js/tekijakortti.js).
 *
 * Kaksi pintaa: palautelomakkeen taitettu pro-osio, jossa kutsuttu
 * ammattilainen kirjautuu koodillaan, ja pelaajalle avautuva
 * tekijäsivu kuvan lähderiviltä. Molemmat perivät talon valmiit
 * tyylit (.periaate-* ja lippuikkunan kortti), joten tässä on vain
 * se, mikä on uutta.
 * ================================================================== */

/*
 * "Unohda tunnukseni" — toissijainen nappi paperin päällä. Pelin
 * .ghost on suunniteltu tummalle laudalle, ja vaalealla lomakkeella
 * sen teksti katosi taustaan (mitattu selainsavukkeen kaappauksesta
 * 18.8.2026). Siksi tälle napille oma vaimea mutta luettava väri.
 */
.pro-ulos {
  margin-top: 0.5rem;
  width: 100%;
  border: 1px solid rgba(122, 85, 20, 0.45);
  background: rgba(255, 252, 240, 0.7);
  color: #6d5a3c;
  font-family: var(--font-type);
  font-size: 0.82rem;
  text-shadow: none;
}

/*
 * MATERIAALIN LÄHETYS (omistaja 25.8.2026). Kirjautuneen tuottajan
 * lohko on lomakkeen pisin osa, joten sen ryhmät erotetaan väliotsikon
 * ilmavuudella eikä uusilla laatikoilla — paperi pysyy paperina.
 * Kentät perivät .periaate-kentta-tyylin; tässä on vain ero.
 */
.pro-materiaali .periaate-valiotsikko { margin-top: 1.1rem; }

/* Lisenssivalinta on select, jonka oma nuoli ei peri kentän kirjasinta. */
.pro-materiaali-lisenssi {
  font-family: var(--font-type);
  font-size: 0.9rem;
}

/*
 * Tekijäsivu on kertaluontoinen työ, joten se taittuu väkäsen taakse
 * materiaalin alle. Väkänen on osion sisäinen, ei uusi lohko: siksi
 * kevyempi yläviiva kuin .periaate-ehdotuksella oletuksena.
 */
.pro-profiililohko > summary {
  cursor: pointer;
  margin: 0;
}

/*
 * Lähderivin tekijännimi on painike, ei linkki: se ei vie ulos vaan
 * avaa pelin oman kortin. Ulkoasu on silti tekstin oma — lähderivi
 * ei saa muuttua nappuloiden riviksi.
 */
/*
 * VALITSIMESSA ON MUKANA `.dialog button` (2.9.2026, sama kaava kuin
 * .reveal-jatka-lohkossa): lähderivi elää myös dialogien sisällä
 * (kaupunkilehti, nähtävyysikkuna), ja dialogien yleissääntö
 * `.dialog button` (0,1,1) voittaa pelkän luokan (0,1,0). Ilman tätä
 * tekijän nimi peri dialogin pergamenttilaatikon — reunus, pyöristetyt
 * kulmat ja 42 px:n korkeus keskellä pientä lähderiviä.
 */
.tekija-nappi,
.dialog button.tekija-nappi {
  min-height: 0;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
  cursor: pointer;
  /* Suurennoksen paperi ohittaa eleet (pointer-events: none) ja sääntö
     periytyy — nappi ottaa ne takaisin itselleen (ks. seuraava lohko). */
  pointer-events: auto;
}

.tekija-nappi:hover,
.tekija-nappi:focus-visible,
.dialog button.tekija-nappi:hover,
.dialog button.tekija-nappi:focus-visible { text-decoration: underline; }

/* ------------------------------------------------------------------ *
 * HAVAINNEKUVAN SELITE (omistajan hyväksyntä 1.9.2026)
 *
 * Lähderivin maininta "Matkakirjan havainnekuva" on painike, joka
 * avaa selitteen siitä, miksi peli piirtää osan kuvistaan itse
 * (js/havainnekuva.js). Ulkoasu on TARKOITUKSELLA melkein olematon:
 * kevyt pisteviiva himmeällä musteella, ei väriä eikä nappulan
 * muotoa. Lähderivi on lisenssimerkintä kuvatekstin perässä pienellä
 * — jos se alkaisi näyttää linkiltä, se veisi huomion kuvatekstiltä,
 * jota sen on tarkoitus vain seurata.
 *
 * ERI VIIVA KUIN TEKIJÄNAPILLA: tekijänappi käyttää
 * text-decorationia, joka piirtyy tekstin päälle kirjainten väliin.
 * Tässä viiva on border-bottom, jotta se on yhtenäinen kaista sanan
 * alla eikä katkeile pilkkujen kohdalta — omistajan sana oli
 * "pisteviiva-alleviivaus". Molemmat voivat esiintyä samalla rivillä
 * (pro-tuottajan havainnekuva), ja silloin ero on se, kumpi on mitä.
 *
 * KAKSI KORJAUSTA 2.9.2026 (omistajan bugiraportti iPhonella, Kreikan
 * Olympian Zeus-patsaan ihmekortti: *"Havainnekuvasta puuttuu popup
 * linkki. Tarkista kaikkialta pelistä että linkki tulee näkyviin"*).
 * Kumpikin vika oli suurennoksissa, eli juuri siellä, missä ihmeen
 * havainnekuvaa katsotaan isona:
 *
 *   1. VIIVA SEURAA TEKSTIÄ, EI LUETTELOA POHJISTA. Tässä oli
 *      luettelo kolmesta "tummasta" säiliöstä, joille viiva
 *      vaihdettiin vaaleaksi. Kaksi niistä ei ole tumma: sekä
 *      .fokuskohde-zoomkehys että .fokuszoom-kehys ovat vaaleaa
 *      pergamenttia (#f8f3e6), joten valkoinen pisteviiva katosi
 *      niissä kokonaan ja rivi näytti pelkältä tekstiltä. Luettelo on
 *      poistettu: viiva otetaan currentColorista, jolloin se on aina
 *      samaa mustetta kuin lähderivin teksti — vaalea vaalealla,
 *      tumma tummalla, ilman että uusi säiliö pitää muistaa lisätä
 *      mihinkään. Ensimmäinen rivi on varasävy vanhoille selaimille
 *      (sama kaksoiskirjoitus kuin .nosto-linkillä).
 *   2. NAPPI OTTAA NAPAUTUKSET VASTAAN MYÖS SUURENNOKSESSA. Molempien
 *      suurennosten paperi ohittaa eleet (pointer-events: none),
 *      jotta napautus paperin päällä sulkee kuvan — ja koska sääntö
 *      periytyy, se sammutti myös tämän napin. Selite ei siis
 *      auennut, vaan napautus sulki suurennoksen. Sama korjaus kuin
 *      reaktiorivillä (.reaktiot-suurennos): nappi ottaa eleet
 *      takaisin itselleen. Painallus pysähtyy nappiin
 *      (js/havainnekuva.js stopPropagation), joten kuva ei sulkeudu
 *      sen alta.
 *   3. VALITSIMESSA ON MUKANA `.dialog button`. Sama savuke paljasti
 *      kolmannen puolen samasta viasta: kaupunkilehti ja
 *      nähtävyysikkuna ovat dialogeja, ja yleissääntö `.dialog button`
 *      (0,1,1) voitti pelkän luokan (0,1,0) — lehden kuvatekstissä
 *      selite ei ollut pisteviivainen sana vaan pergamenttilaatikko
 *      pyöristetyin kulmin ja 42 px korkeana. Kaava on talon oma (ks.
 *      .reveal-jatka).
 * ------------------------------------------------------------------ */
.havainnekuva-selite,
.dialog button.havainnekuva-selite {
  min-height: 0;
  margin: 0;
  padding: 0;
  border: none;
  border-bottom: 1px dotted rgba(70, 51, 31, 0.55);
  border-bottom-color: color-mix(in srgb, currentColor 55%, transparent);
  border-radius: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-decoration: none;
  cursor: pointer;
  /* Ks. kohta 2 yllä: suurennoksen paperi ohittaa eleet, nappi ei saa. */
  pointer-events: auto;
}

.havainnekuva-selite:hover,
.havainnekuva-selite:focus-visible,
.dialog button.havainnekuva-selite:hover,
.dialog button.havainnekuva-selite:focus-visible {
  border-bottom-color: rgba(70, 51, 31, 0.9);
  border-bottom-color: currentColor;
  border-bottom-style: solid;
}

/* Palautenappi selitepopupin pohjalla: tavallinen primary-nappi, mutta
   koko leveydeltä, koska se on ikkunan ainoa toiminto. */
.havainnekuva-palautenappi {
  display: block;
  width: 100%;
  margin: 0.7rem 0 0;
}

/*
 * KUVAVINKKILOMAKE POPUPISSA (js/kuvavinkki.js avaaKuvapalaute).
 * Lomake on sama kuin valikossa, mutta minipopupin kortti on kapeampi
 * kuin valikon lomakepalsta — kentät venytetään kortin leveyteen,
 * jottei select jää puoleen väliin.
 */
.kuvavinkki-popup .periaate-ehdotus {
  margin: 0;
  padding: 0;
  border: none;
}

.kuvavinkki-popup .periaate-kentta,
.kuvavinkki-popup .periaate-nimio { width: 100%; }

/* Oikeuslohko erottuu omaksi ryhmäkseen: kaksi pakollista valintaa,
   jotka eivät saa hukkua vapaaehtoisten kenttien sekaan. */
.kuvavinkki-oikeudet {
  margin: 0.6rem 0;
  padding: 0.5rem 0.6rem;
  border: 1px solid rgba(70, 51, 31, 0.22);
  border-radius: 0.4rem;
  background: rgba(70, 51, 31, 0.04);
}

.kuvavinkki-oikeudet > .periaate-valiotsikko { margin-top: 0; }

/* Palautteen kohderivi: mistä kuvasta palaute annetaan. */
.kuvavinkki-kohde { font-style: italic; }

/* Tekijäsivu: sama kerros ja kortti kuin lippuikkunassa. */
dialog.tekija-ikkuna {
  border: none;
  padding: 1rem;
  background: transparent;
  max-width: none;
  max-height: none;
  overflow: visible;
}

dialog.tekija-ikkuna::backdrop { background: rgba(20, 16, 10, 0.55); }
dialog.tekija-ikkuna:focus,
dialog.tekija-ikkuna:focus-visible { outline: none; }

.tekija-kortti {
  width: min(24rem, calc(100vw - 1.4rem));
  max-height: 66vh;
  overflow-y: auto;
  padding: 0.7rem 0.8rem 0.9rem;
  border: 1px solid rgba(122, 85, 20, 0.32);
  border-radius: var(--radius);
  background-color: #f5f0e2;
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
  color: #211d18;
  font-family: var(--font-luku);
  text-shadow: none;
}

.tekija-ylarivi {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.tekija-otsikko {
  margin: 0;
  font-family: var(--font-type);
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  color: #46331f;
}

.tekija-kortti .tekija-sulje {
  min-height: 0;
  padding: 0 0.35rem;
  border: none;
  background: none;
  color: rgba(70, 51, 31, 0.75);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

/* Muotokuva: pieni ja keskitetty, ei lehden levyinen valokuva. */
.tekija-kuva {
  display: block;
  width: 9rem;
  max-width: 60%;
  height: auto;
  margin: 0 auto 0.7rem;
  border: 1px solid rgba(70, 51, 31, 0.4);
  border-radius: 6px;
}

.tekija-esittely {
  margin: 0 0 0.6rem;
  font-size: 0.94rem;
  line-height: 1.55;
}

.tekija-linkkilista {
  margin: 0.6rem 0 0;
  padding-left: 1.1rem;
}

.tekija-linkkirivi { margin: 0.25rem 0; }

.tekija-linkki {
  color: #7a5514;
  font-family: var(--font-type);
  font-size: 0.9rem;
  text-underline-offset: 4px;
}

/* Ulkoisen linkin merkintä samalla nuolella kuin muualla pelissä. */
.tekija-linkki::after { content: ' ↗'; text-decoration: none; }

.tekija-tila,
.tekija-huomio {
  margin: 0.6rem 0 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: #6d5a3c;
}

/* ── MINIPOPUP JA TIETÄJÄN TASOGALLERIA ────────────────────────────────
 *
 * Omistajan tilaus 18.8.2026: matkalaukun i-nappi avaa kevyen
 * selitysikkunan, ja ikkuna tehdään UUDELLEENKÄYTETTÄVÄNÄ PALIKKANA
 * (js/minipopup.js) — tasogalleria on sen ensimmäinen käyttäjä.
 *
 * Sama pergamentti ja sama kehys/kortti-jako kuin lippuikkunassa (ks.
 * .lippu-kehys ja sen pitkä perustelu): kehys maalaa paperin, reunan ja
 * varjon, kortti vierittää ja LEIKKAA sisällön pyöristyksen sisään.
 * Tausta sumenee kevyesti — minipopup avataan usein matkalaukun päältä,
 * ja sumennus erottaa selityksen siitä näkymästä, jota se selittää.
 */
dialog.minipopup {
  border: none;
  padding: 1rem;
  background: transparent;
  max-width: none;
  max-height: none;
  overflow: visible;
}

dialog.minipopup::backdrop {
  background: rgba(20, 16, 10, 0.5);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
}

dialog.minipopup:focus,
dialog.minipopup:focus-visible { outline: none; }

.minipopup-kehys {
  width: min(24rem, calc(100vw - 1.4rem));
  /* Sama kaksi kolmasosaa kuin lippuikkunassa: pidempi sisältö
     vierittyy kortin sisällä eikä ikkuna kasva ruudun yli. */
  max-height: 66vh;
  display: flex;
  overflow: hidden;
  border: 1px solid rgba(122, 85, 20, 0.32);
  border-radius: var(--radius);
  background-color: #f5f0e2;
  background-image: var(--paper-noise);
  background-blend-mode: multiply;
  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
}

.minipopup-kortti {
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  padding: 0.7rem 0.8rem 0.85rem;
  border-radius: calc(var(--radius) - 1px);
  -webkit-clip-path: inset(0 round calc(var(--radius) - 1px));
  clip-path: inset(0 round calc(var(--radius) - 1px));
  color: #211d18;
  font-family: var(--font-luku);
  text-shadow: none;
}

.minipopup-ylarivi {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}

.minipopup-otsikko {
  margin: 0;
  font-family: var(--font-type);
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  color: #46331f;
}

.minipopup-kortti .minipopup-sulje {
  min-height: 0;
  padding: 0 0.35rem;
  border: none;
  background: none;
  color: rgba(70, 51, 31, 0.75);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

.minipopup-teksti {
  margin: 0 0 0.5rem;
  font-size: 0.92rem;
  line-height: 1.5;
}

/*
 * MAASTONIMEN POPUP (js/karttanimet.js avaaMaastoPopup): selitys,
 * vuoren korkein huippu ja linkki Wikipediaan. Faktarivi on pientä
 * kapiteelia kuten muissakin korteissa oleva mittarivi, ja linkki
 * on kortin viimeinen rivi omalla rivillään.
 */
.maastopopup-fakta {
  font-variant: small-caps;
  letter-spacing: 0.04em;
  opacity: 0.8;
}
/*
 * LINKKI ON KORTIN MUSTETTA EIKÄ SELAIMEN SINISTÄ. Sama sääntö kuin
 * lähderivin linkeillä (.source-line a): väri peritään, ja linkin
 * kertoo pisteviiva.
 */
.maastopopup-wiki {
  display: inline-block;
  font-size: 0.88rem;
  color: inherit;
  text-decoration: underline dotted;
}

/*
 * TASOGALLERIA: kymmenen muotokuvaa ruudukkona, nimi ja raja kuvan
 * alla. Ruudut ovat auto-fill-neliöitä, jolloin kapealla puhelimella
 * rivissä on kolme ja laajemmalla neljä — sama tapa kuin laukun
 * varusteruudukossa.
 */
/* Yläosa: selitys vasemmalla, nykyinen taso isona oikealla. */
.tietaja-galleria-yla {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin: 0 0 0.7rem;
  /* Turvaventtiili kaikkein kapeimmille ruuduille: isompi avatar
     (18.8.2026) putoaa mieluummin tekstin alle keskitettynä kuin
     puristaa selityksen kahden sanan levyiseksi palstaksi. */
  flex-wrap: wrap;
}

.tietaja-galleria-selitys {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.55;
  /* Perusleveys, jonka alle selitys ei kutistu ennen rivitystä.
     8,5 rem pitää selityksen kuvan rinnalla 360 px:n puhelimessa; sitä
     kapeammilla flex-wrap pudottaa kuvan tekstin alle keskitettynä. */
  flex: 1 1 8.5rem;
}

.tietaja-nykyinen {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  flex: none;
}

/*
 * Nykyisen tason avatar (omistaja 18.8.2026: "Iso kuva voisi olla
 * vielä isompi"). 6,4 rem → min(9rem, 40vw): 360 px:n puhelimessa
 * 9 rem = 144 px, jolloin selitykselle jää yhä yli 9,5 rem eikä rivi
 * katkea, ja sitä kapeammilla vw-katto pienentää kuvaa ennen kuin
 * flex-wrap ehtii pudottaa sen omalle rivilleen.
 */
.tietaja-nykyinen-kuva {
  width: min(9rem, 40vw);
  height: min(9rem, 40vw);
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(122, 85, 20, 0.6);
  background: rgba(255, 255, 255, 0.35);
  box-shadow: 0 0 0 4px rgba(217, 161, 59, 0.22);
}

.tietaja-nykyinen-nimi {
  font-family: var(--font-type);
  font-size: 0.78rem;
  color: #46331f;
  text-align: center;
}

.tietaja-galleria {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.2rem, 1fr));
  gap: 0.55rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tietaja-galleria-kohta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  padding: 0.3rem 0.2rem;
  border: 1px solid transparent;
  border-radius: 0.5rem;
  text-align: center;
}

/* Nykyinen taso saa kehyksen ja kevyen kullan: oma kohta löytyy
   yhdellä silmäyksellä ilman että muut hukkuvat. */
.tietaja-galleria-kohta.nykyinen {
  border-color: rgba(122, 85, 20, 0.55);
  background: rgba(217, 161, 59, 0.18);
}

/* Saavuttamaton himmenee kevyesti — matkan pituus saa näkyä. */
.tietaja-galleria-kohta.saavuttamaton { opacity: 0.45; }

.tietaja-galleria-kuva {
  width: 3.4rem;
  height: 3.4rem;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid rgba(122, 85, 20, 0.5);
  background: rgba(255, 255, 255, 0.35);
}

.tietaja-galleria-nimi {
  font-family: var(--font-type);
  font-size: 0.7rem;
  line-height: 1.25;
  color: #46331f;
}

.tietaja-galleria-raja {
  font-size: 0.65rem;
  font-variant-numeric: tabular-nums;
  color: rgba(70, 51, 31, 0.7);
}

/* ------------------------------------------------------------------ *
 * REAKTIOT — viisi kaiverrettua symbolia sisällön alalaidassa ja
 * lehden väliotsikoiden päässä (js/reaktiot.js).
 *
 * LEPOTILASSA YKSI NAPPI: voittajasymboli ja äänimäärä lähderivin
 * kokoisena, samaa mustetta kuin krediitti, ilman taustaa ja ilman
 * kehystä ennen kuin siihen koskee. Napautus levittää viisi symbolia
 * äänimäärineen samalle riville. Väri kirkastuu vasta osoitettaessa —
 * silloin nappi kertoo olevansa nappi.
 *
 * Rivi kelluu kuvien alapuolelle (clear) kuten lähderivi ja
 * pöllöpoiminnat, jottei se päädy kainalokuvan viereen.
 * ------------------------------------------------------------------ */

.reaktiorivi {
  clear: both;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.5rem;
  margin: 0.55rem 0 0;
}

.reaktio-napit {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

button.reaktionappi {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Kosketuskohde on isompi kuin muste: 30 px riittää sormelle ilman
     että kuvake kasvaa lähderivin yli. */
  min-width: 30px;
  min-height: 30px;
  padding: 0.2rem 0.25rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  box-shadow: none;
  color: rgba(70, 51, 31, 0.5);
  cursor: pointer;
  transition: color 140ms ease-out, border-color 140ms ease-out;
}

button.reaktionappi:hover:not(:disabled) {
  color: rgba(70, 51, 31, 0.92);
  border-color: rgba(70, 51, 31, 0.28);
}

button.reaktionappi:focus-visible {
  outline: 2px solid rgba(156, 107, 23, 0.8);
  outline-offset: 1px;
}

button.reaktionappi:disabled {
  opacity: 0.4;
  cursor: default;
}

.reaktio-ikoni,
.reaktio-lepoikoni {
  display: inline-flex;
  pointer-events: none;
}

/* Äänimäärä kuvakkeen perässä: tabulaarinen, jottei luku hyppää
   napissa, kun 9:stä tulee 10. */
.reaktio-luku {
  margin-left: 0.18rem;
  font-family: var(--font-type);
  font-size: 0.66rem;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  pointer-events: none;
}

.reaktio-luku:empty { display: none; }

/*
 * LEPOTILAN NAPPI. Ilman ääniä se on haalea seppele ilman lukua —
 * kutsu eikä ilmoitus. Oma ääni tummentaa sen, jotta pelaaja näkee
 * yhdellä silmäyksellä äänestäneensä jo.
 */
button.reaktio-lepo.tyhja { opacity: 0.42; }

button.reaktio-lepo.oma {
  color: rgba(70, 51, 31, 0.92);
  border-color: rgba(70, 51, 31, 0.3);
}

/*
 * AVATTU RIVI: viisi symbolia lukuineen. Kevyt pergamenttikapseli
 * erottaa valikon leipätekstistä ilman että se muuttuu valikkolaatikoksi.
 */
.reaktio-valikko {
  display: flex;
  align-items: center;
  gap: 0.05rem;
  padding: 0.1rem 0.25rem;
  border: 1px solid rgba(70, 51, 31, 0.22);
  border-radius: 999px;
  background: rgba(255, 252, 244, 0.6);
}

.reaktio-valikko[hidden] { display: none; }

button.reaktio-symboli {
  min-width: 28px;
  padding: 0.18rem 0.2rem;
}

/* Oma ääni: tummempi muste ja kevyt kehä — ei täytettyä nappia. */
button.reaktio-symboli.oma {
  color: #7a5514;
  border-color: rgba(122, 85, 20, 0.45);
  background: rgba(156, 107, 23, 0.1);
}

/* Jo ilmoitettu virhe: tahran saa yhä äänestää, mutta kenttä ei aukea
   uudestaan — himmennys kertoo sen ilman erillistä tekstiä. */
button.reaktio-symboli.ilmoitettu:not(.oma) { opacity: 0.55; }

/*
 * VÄLIOTSIKON NAPPI (js/reaktiot.js piirraOtsikonReaktio). Rivin
 * PÄÄSSÄ eikä leipätekstin päällä: margin-left: auto työntää sen
 * otsikkorivin oikeaan reunaan, ja pienempi kuvake pitää sen otsikon
 * mittasuhteissa. Ei clearia — otsikkorivi ei kellu.
 */
.reaktiorivi.reaktiot-otsikko {
  clear: none;
  flex: 0 0 auto;
  margin: 0 0 0 auto;
  gap: 0.2rem;
}

.reaktiot-otsikko button.reaktionappi {
  min-width: 26px;
  min-height: 26px;
  padding: 0.1rem 0.2rem;
}

/* Pienemmässä koossa hiusviiva katoaa pergamenttiin: kuvake kutistuu
   mutta muste vahvistuu, jotta seppeleen lehdet erottuvat vielä
   16 pikselissä. CSS voittaa SVG:n oman stroke-width-attribuutin. */
.reaktiot-otsikko .reaktio-ikoni svg,
.reaktiot-otsikko .reaktio-lepoikoni svg {
  width: 16px;
  height: 16px;
  stroke-width: 1.75;
}

/* Väliotsikon lepotila saa hiukan enemmän mustetta kuin leipätekstin:
   otsikkorivi on tiheämpi, ja 0.42 hukkui siihen kokonaan. */
.reaktiot-otsikko button.reaktio-lepo.tyhja { opacity: 0.5; }

/* Otsikkorivin kuittaus veisi tilaa otsikolta: ääni riittää kuvitukseksi. */
.reaktiot-otsikko .reaktio-kuittaus { display: none; }

/* Napautuksen kuittaus: kuvake nytkähtää kerran, ei enempää. */
@keyframes reaktio-poks {
  0% { transform: scale(1); }
  35% { transform: scale(1.28) rotate(-8deg); }
  100% { transform: scale(1); }
}

button.reaktio-poks .reaktio-ikoni {
  animation: reaktio-poks 380ms ease-out;
  color: #7a5514;
}

@media (prefers-reduced-motion: reduce) {
  button.reaktio-poks .reaktio-ikoni { animation: none; }
}

.reaktio-kuittaus {
  font-family: var(--font-type);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: rgba(70, 51, 31, 0.72);
}

.reaktio-kuittaus:empty { display: none; }

/*
 * VIRHEIKKUNA. Mustetahra avaa minipopupin (js/minipopup.js — sama
 * komponentti kuin pöllörivin i-nappi), koska virheilmoitus tarvitsee
 * tilaa ja kohdistuksen: lehden marginaaliin avautuva textarea jäi
 * puhelimella näppäimistön alle.
 */
.reaktio-virheikkuna {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.reaktio-virheohje {
  margin: 0;
  font-size: 0.84rem;
  line-height: 1.4;
  color: rgba(50, 36, 22, 0.9);
}

/* Livian ääni: kursiivi erottaa sen ohjeesta — tämä on hahmo, ei
   käyttöliittymän teksti. */
.reaktio-livia {
  margin: 0;
  font-family: var(--font-type);
  font-size: 0.8rem;
  font-style: italic;
  line-height: 1.4;
  color: rgba(70, 51, 31, 0.85);
}

.reaktio-livia[hidden] { display: none; }

textarea.reaktio-teksti {
  width: 100%;
  box-sizing: border-box;
  padding: 0.4rem 0.5rem;
  border: 1px solid rgba(70, 51, 31, 0.32);
  border-radius: 4px;
  background: rgba(255, 252, 244, 0.75);
  color: rgba(50, 36, 22, 0.94);
  font-family: inherit;
  font-size: 0.82rem;
  line-height: 1.35;
  resize: vertical;
}

.reaktio-lomakenapit {
  display: flex;
  gap: 0.4rem;
}

.reaktio-lomakenapit button {
  padding: 0.25rem 0.7rem;
  min-height: 0;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 999px;
  background: rgba(255, 252, 244, 0.7);
  color: rgba(50, 36, 22, 0.92);
  font-family: inherit;
  font-size: 0.76rem;
  cursor: pointer;
}

.reaktio-lomakenapit button:hover:not(:disabled) { border-color: rgba(70, 51, 31, 0.7); }

.reaktio-lomakenapit button:disabled { opacity: 0.45; cursor: default; }

/* Virheikkuna on kapea: se on yksi kenttä ja kaksi nappia, ei näkymä. */
.minipopup-kortti.minipopup-reaktio { max-width: 30rem; }

/*
 * KUVASUURENNOS. Postikortin ja kartan suurennoksen paperi on tummempi
 * pergamentti ja teksti keskitettyä, joten rivikin keskitetään — ja
 * kartan suurennoskehys ohittaa eleet (pointer-events: none), joten
 * juuri tämä rivi on otettava takaisin osoittimen ulottuville.
 */
.reaktiot-suurennos {
  justify-content: center;
  pointer-events: auto;
  margin-top: 0.2rem;
}

/* ------------------------------------------------------------------ *
 * PÖLLÖPOIMINNAT — tallennetut kysymys–vastaus-pillerit artikkelin
 * lopussa (omistajan tilaus 23.8.2026).
 *
 * Pilleri on lehden paperilla oleva kapseli, ei pöllön paneelin nappi:
 * sama muoto kuin pöllön kysymysehdotuksissa, mutta mustetta
 * pergamentilla, jotta rivi kuuluu juttuun eikä chattiin. Rivi kelluu
 * kuvien alapuolelle (clear) kuten lähderivi.
 * ------------------------------------------------------------------ */

.pollo-poiminnat {
  clear: both;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  margin: 0.9rem 0 0;
  padding-top: 0.6rem;
  border-top: 1px solid rgba(70, 51, 31, 0.18);
}

.pollo-poiminnat-nimio {
  font-family: var(--font-type);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(70, 51, 31, 0.62);
}

button.pollo-pilleri {
  padding: 0.3rem 0.7rem;
  min-height: 0;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 999px;
  background: rgba(255, 252, 244, 0.7);
  color: rgba(50, 36, 22, 0.92);
  font-family: inherit;
  font-size: 0.8rem;
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
}

button.pollo-pilleri:hover { border-color: rgba(70, 51, 31, 0.7); }

/* Laitteen oma, vielä kuratoimaton pari: katkoviiva kertoo, ettei se
   näy pelaajille ennen kuin se on committoitu pakettiin. */
button.pollo-pilleri.oma { border-style: dashed; }

/* Pöllön chatin poimintanappi vastauksen alla. */
.pollo-poimintarivi {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.5rem;
}

button.pollo-poimintanappi {
  padding: 0.25rem 0.6rem;
  min-height: 0;
  border: 1px solid var(--pollo-viiva);
  border-radius: 999px;
  background: var(--pollo-paperi-2);
  color: var(--pollo-muste);
  font-family: inherit;
  font-size: 0.75rem;
  cursor: pointer;
}

button.pollo-poimintanappi:disabled { opacity: 0.5; cursor: default; }

.pollo-poimintatila {
  font-size: 0.72rem;
  color: var(--pollo-muste);
  opacity: 0.8;
}

/* Minipopupin poistorivi (kehittäjätila): nappi + kuittaus avatun
   kysymyksen alla, erotettu vastauksesta pienellä välillä. */
.minipopup-poistorivi {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

/* Työhuoneen vientisivu (Tilannelehti → Pöllöpoiminnat). */
.poimintavienti-avain {
  margin: 0.7rem 0 0.2rem;
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
}

.poimintavienti-pari { margin: 0 0 0.15rem; font-size: 0.85rem; }

.poimintavienti-lohko {
  margin: 0.8rem 0 0;
  padding: 0.6rem;
  max-height: 40vh;
  overflow: auto;
  border: 1px solid rgba(70, 51, 31, 0.25);
  border-radius: 6px;
  background: rgba(255, 252, 244, 0.7);
  font-size: 0.72rem;
  white-space: pre-wrap;
  word-break: break-word;
}

.poimintavienti-napit { display: flex; gap: 0.5rem; margin-top: 0.6rem; }

/* ─────────────────────────────────────────────────────────────────
 * KUVAGALLERIA — "Lisää kuvia tästä kohteesta" (omistajan tilaus
 * 23.8.2026, js/kuvagalleria.js).
 *
 * Galleria EI SAA näyttää lehden omalta kuvitukselta, koska se ei ole
 * sitä: kuvat tulevat suoraan avoimista kokoelmista eikä niitä ole
 * valittu lehteen. Lehden kuva on paperinvalkoisella palstalla,
 * rajattuna ja kuvatekstitettynä; tämä on tumma KONTAKTIARKKI —
 * tasakokoisia ruutuja tiiviissä ruudukossa, jokaisen alla
 * konekirjoitettu tekijä- ja lisenssirivi. Sävyt ovat pelin omat
 * (--bg, --paper, --accent) ja kirjasin --font-type, joten arkki on
 * yhä samasta maailmasta — se on vain eri huone.
 * ───────────────────────────────────────────────────────────────── */

/* Nappi jutun ja kartan alla: erottuva mutta hillitty, ei lehden
 * kuvakalustetta. Katkoviiva sanoo "tämä vie ulos". */
.kuvagalleria-nappi {
  display: block;
  width: 100%;
  margin: 1rem 0 0.2rem;
  padding: 0.6rem 0.8rem;
  border: 1px dashed rgba(70, 51, 31, 0.55);
  border-radius: 3px;
  background: rgba(70, 51, 31, 0.06);
  color: var(--map-ink);
  font-family: var(--font-type);
  font-size: 0.82rem;
  letter-spacing: 0.03em;
  text-align: center;
  cursor: pointer;
}

.kuvagalleria-nappi::before { content: "▦ "; opacity: 0.7; }
.kuvagalleria-nappi:hover { background: rgba(70, 51, 31, 0.12); }
.kuvagalleria-nappi:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Kerros koko ruudun yli. z-index 70 kuten postikorteilla: sama
 * kerros, jossa dialogin päälle piirretyt suurennokset asuvat. */
.kuvagalleria {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: flex;
  justify-content: center;
  /* TÄYSIN LÄPINÄKYMÄTÖN POHJA. Ensimmäinen versio oli 0.92-alfa, ja
   * jutun teksti kuulsi arkin läpi (mitattu kuvakaappauksesta): kaksi
   * tekstiä päällekkäin on lukukelvoton eikä galleria erottunut lehden
   * omaksi huoneekseen. Kerros on ikkuna, ei kalvo. */
  background: #0e0904;
}

.kuvagalleria-arkki {
  position: relative;
  width: min(100%, 1100px);
  max-height: 100dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: calc(1.2rem + var(--turva-yla)) 1rem calc(2rem + var(--turva-ala));
  color: var(--ink-light);
  font-family: var(--font-type);
  /* Hento paperinrakeisuus tummalla: arkki on yhä paperia, mutta
   * pimennetty pöytävalossa. Oma väri pohjalle, jottei arkki jää
   * läpikuultavaksi kalvoksi. */
  background-color: var(--bg);
  background-image: var(--paper-noise);
  background-blend-mode: overlay;
  box-shadow: 0 0 0 1px rgba(217, 161, 59, 0.18);
}

.kuvagalleria-sulku {
  position: sticky;
  top: 0;
  float: right;
  z-index: 2;
  width: 2.1rem;
  height: 2.1rem;
  border: 1px solid var(--overlay-line);
  border-radius: 50%;
  background: rgba(46, 33, 20, 0.9);
  color: var(--ink-light);
  font-family: var(--font-type);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.kuvagalleria-otsikko {
  margin: 0 2.6rem 0.35rem 0;
  font-size: 1.15rem;
  letter-spacing: 0.05em;
  color: var(--paper);
}

/* Selitys on gallerian tärkein rivi: se kertoo, ettei kukaan ole
 * valinnut näitä kuvia. Siksi se on ennen kuvia eikä niiden jälkeen. */
.kuvagalleria-selitys {
  max-width: 44rem;
  margin: 0 0 0.9rem;
  padding-left: 0.7rem;
  border-left: 2px solid var(--accent-dark);
  font-size: 0.78rem;
  line-height: 1.5;
  color: rgba(243, 230, 208, 0.78);
}

.kuvagalleria-tila {
  margin: 1.2rem 0;
  font-size: 0.82rem;
  line-height: 1.5;
  color: rgba(243, 230, 208, 0.72);
}

.kuvagalleria-osasto { margin: 1.1rem 0 0; }

.kuvagalleria-osastonimi {
  margin: 0 0 0.1rem;
  font-size: 0.78rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.kuvagalleria-osasteselite {
  margin: 0 0 0.7rem;
  font-size: 0.7rem;
  color: rgba(243, 230, 208, 0.55);
}

/* Kontaktiarkki: tasakokoisia ruutuja, ei lehden vaihtelevia
 * palstaleveyksiä. */
.kuvagalleria-ruudukko {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.7rem;
}

@media (min-width: 700px) {
  .kuvagalleria-ruudukko { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); }
}

.kuvagalleria-kortti {
  margin: 0;
  padding: 0.3rem 0.3rem 0.35rem;
  border: 1px solid rgba(217, 161, 59, 0.22);
  background: rgba(46, 33, 20, 0.55);
}

.kuvagalleria-kuvanappi {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: #14100a;
  cursor: zoom-in;
}

.kuvagalleria-pikkukuva {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* Tekijä ja lisenssi EIVÄT ole koriste: pilari 2 vaatii ne jokaiseen
 * kuvaan, joten rivi ei katkea kolmeen pisteeseen vaan taittuu. */
.kuvagalleria-lahde {
  margin-top: 0.3rem;
  font-size: 0.62rem;
  line-height: 1.35;
  color: rgba(243, 230, 208, 0.72);
  word-break: break-word;
}

.kuvagalleria-linkki { color: var(--accent); text-decoration: underline; }

.kuvagalleria-lisaa {
  display: block;
  margin: 0.8rem auto 0;
  padding: 0.5rem 1.1rem;
  border: 1px solid var(--overlay-line);
  border-radius: 3px;
  background: rgba(46, 33, 20, 0.8);
  color: var(--ink-light);
  font-family: var(--font-type);
  font-size: 0.76rem;
  cursor: pointer;
}

/* Yhden kuvan katselin gallerian sisällä. */
.kuvagalleria-katselin {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 1rem;
  background: rgba(10, 7, 3, 0.95);
  cursor: zoom-out;
}

.kuvagalleria-isokuva {
  max-width: 100%;
  max-height: 78dvh;
  object-fit: contain;
  background: #14100a;
}

.kuvagalleria-isonimi {
  max-width: 36rem;
  margin: 0;
  font-size: 0.82rem;
  text-align: center;
  color: var(--paper);
}

.kuvagalleria-isolahde {
  max-width: 36rem;
  font-size: 0.68rem;
  text-align: center;
  color: rgba(243, 230, 208, 0.72);
}

/* ===========================================================================
   FOKUSNÄKYMÄN DYNAAMISET MITAT (js/fokusmitat.js)
   ---------------------------------------------------------------------------
   Omistajan tilaus 25.8.2026 (Raamatun osio "JATKUVA KARTTA JA DYNAAMISET
   MITAT"): mittajana ja maan kartuutsi eivät ole enää poltettuina
   esirenderöityyn kuvaan vaan pelin piirtämiä ja RUUTUUN ankkuroituja.
   Siksi ne ovat tavallisia HTML-elementtejä .map-panen sisällä: ne eivät
   skaalaudu zoomissa eivätkä liiku panoroinnissa, ja pienellä ruudulla
   niiden koon ja pinoamisen hoitaa mediakysely eikä käsin laskettu
   fonttiskaalaus.

   PAIKAT. Kartuutsi vasempaan alanurkkaan, mittajana oikeaan — kuten
   1873-atlaksen lehdessä. Kumpikaan ei saa peittää kelluvaa pöllöä
   (.pollo-kelluu-kartalla: oikea reuna, 5rem korkeudella).

   ALANAPPIRIVI EI OLE ENÄÄ ESTE (omistajan pelitestitilaus 26.8.2026).
   Fokusnäkymässä rivissä on vain Liiku, ja se on nyt pieni NELIÖ, joka
   asettuu kartuutsin RINNALLE samaan alalaitaan (ks. "FOKUSNÄKYMÄN
   ALANAPPIRIVI" alempana). Siksi kartuutsi saa jäädä alanurkkaan joka
   ruudulla eikä nouse enää nappirivin yläpuolelle pinoon, kuten se teki
   niin kauan kuin rivi oli 560 pikselin levyinen kortti.

   EI SUODATTIMIA. Sama iOS-sääntö kuin kartan kerroksilla
   (tests/rules.test.mjs); text-shadow ei ole suodatin eikä varaa omaa
   piirtopuskuria.
   =========================================================================== */

.fokusmitat {
  position: absolute;
  left: 0.7rem;
  /*
   * Oikea reuna on väljempi kuin vasen, koska mittajanan päätylukema
   * on KESKITETTY janan päätyviivan kohdalle (kuten prototyypissä) ja
   * työntyy siis puolet leveydestään janan ulkopuolelle. .map-panessa
   * on overflow: hidden, joten 0.7rem leikkasi "250 km":stä puolet
   * pois — mitattu 1280 px:n ruudulla.
   */
  right: 2.2rem;
  bottom: 0.9rem;
  z-index: 3;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 0.6rem;
  /* Säiliö on leveä mutta läpinäkymätön vain lapsissaan: kartta,
     alanapit ja pöllö toimivat sen läpi. */
  pointer-events: none;
}

.fokusmitat[hidden] { display: none; }

/*
 * KARTUUTSI JÄÄ NÄKYVIIN TAULUN AUETESSA (omistaja 26.8.2026). Tässä
 * oli `.fokusmitat.taulun-alla { opacity: 0 }`, koska taulu oli ruudun
 * levyinen alalevy ja peitti sekä kartuutsin että janan. Nyt taulu
 * nousee kartuutsin kohdalta SEN YLÄPUOLELLE ja kartuutsi on taulun
 * otsikko — häivytys veisi tauluun jääneiltä luvuilta maan nimen.
 */

/* Lennon ja kartta-ajon ajaksi pois, samoin kuin muutkin kartan
   kelluvat merkinnät (vrt. .maa-pilleri ja .turn-card). */
body.flight-active .fokusmitat,
body.kartalento .fokusmitat,
body.flight-active .fokus-maataulu,
body.kartalento .fokus-maataulu,
body.flight-active .fokus-maatauluhuntu,
body.kartalento .fokus-maatauluhuntu,
body.flight-active .fokus-viivaimet,
body.kartalento .fokus-viivaimet { opacity: 0; pointer-events: none; }

/*
 * KARTUUTSI on tekstiä paperilla, ei nappilaatikko (omistajan tarkennus
 * 25.8.2026: *"ulkoasu edelleen atlas-kartuutsi, ei nappilaatikko"*).
 * Painettavuus tulee siis muualta kuin kehyksestä: kosketusala on
 * vähintään 44 px korkea, aria kertoo mitä nappi tekee, ja
 * kohdistusrengas näkyy näppäimistöllä. Vaalea halo pitää musteen
 * luettavana sekä maaston että ulapan päällä.
 */
.fokus-kartuutsi {
  pointer-events: auto;
  display: block;
  min-height: 44px;
  margin: 0;
  padding: 0.1rem 0.35rem;
  border: 0;
  border-radius: 4px;
  background: none;
  box-shadow: none;
  color: rgba(58, 40, 25, 0.92);
  font-family: var(--font-type);
  text-align: left;
  cursor: pointer;
  text-shadow:
    0 0 4px rgba(244, 232, 205, 0.95),
    0 0 10px rgba(244, 232, 205, 0.7);
}

/*
 * YLEINEN NAPPITAUSTA EI SAA PALATA MISSÄÄN TILASSA (omistajan
 * pelitestipalaute v1101, iPad: alarivi "ΕΛΛΑΣ · Hellas ·
 * kuningaskunta v. 1873" oli lukukelvoton tumman laatan päällä).
 *
 * SYY MITATTIIN SELAIMESSA eikä arvattu: kartuutsin alle ilmestyi
 * täsmälleen sen kokoinen laatta värillä #43331f, joka on tyylitiedoston
 * YLEINEN `button:hover:not(:disabled)` (rivi ~1540).
 *
 * KOSKETUSNÄYTÖLLÄ :hover JÄÄ PÄÄLLE napautuksen jälkeen, ja kartuutsia
 * napautetaan aina — se on maataulun ainoa avain. Vika oli siis pysyvä
 * juuri siinä tilanteessa, jossa maataulu on auki.
 *
 * TARKKUUS ON LASKETTAVA, EI ARVATTAVA. Yleisen säännön tarkkuus on
 * (0,2,1): kaksi pseudoluokkaa (`:hover`, `:not(:disabled)`) ja yksi
 * elementti. Pelkkä `.fokus-kartuutsi:hover` on (0,2,0) ja HÄVIÄÄ
 * elementtiosassa — mitattu selaimessa, tausta jäi tummaksi. Siksi
 * tässä toistetaan sama muoto elementteineen ja `:not`-osineen, jolloin
 * tarkkuus on (0,3,1) eikä ratkaisu ole kiinni tiedoston järjestyksestä.
 */
.fokus-kartuutsi,
button.fokus-kartuutsi:hover:not(:disabled),
button.fokus-kartuutsi:focus:not(:disabled),
button.fokus-kartuutsi:active:not(:disabled) {
  border: 0;
  background: none;
  box-shadow: none;
}

.fokus-kartuutsi:hover { color: rgba(40, 26, 14, 0.98); }
.fokus-kartuutsi:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.fokus-kartuutsi-nimi {
  display: block;
  font-size: 1.35rem;
  line-height: 1.1;
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* Kartuutsin alleviivaus kuten lehdessä: ohut muste, ei kehys. */
.fokus-kartuutsi-viiva {
  display: block;
  width: 100%;
  max-width: 15rem;
  height: 1px;
  margin: 0.22rem 0 0.2rem;
  background: rgba(74, 52, 33, 0.55);
}

/*
 * ALARIVI: maan oma nimi ja pieni aikakauden valtiomuoto (omistaja
 * 25.8.2026). Rivi ei katkea, koska "ΕΛΛΑΣ · Hellas · kuningaskunta v.
 * 1873" on yksi ajatus — jos jonkin maan yhdistelmä ei mahtuisi
 * kapealle ruudulle, valtiomuotokenttä jätetään pois datasta
 * (js/packs/fokus-grc.js) eikä riviä typistetä tässä.
 *
 * Tyhjä alarivi (maa, jonka omaa nimeä ei tunneta) kutistuu pois
 * itsestään, koska molemmat palat ovat tyhjiä tekstisolmuja.
 *
 * OMA, TIHEÄMPI HALO. Rivi on kartuutsin pienintä tekstiä ja sen pituus
 * riippuu maasta: "ΕΛΛΑΣ · Hellas · kuningaskunta v. 1873" on lyhyt
 * verrattuna Bulgarian riviin, ja mitä pidemmälle rivi ulottuu, sitä
 * varmemmin sen loppupää osuu kartuutsin alta ulapan sijaan vuoristoon.
 * Kartuutsin oma halo (4 px ja 10 px) on mitoitettu 1,35rem:n
 * versaalille; 0,66rem:n kursiivilla sama säde jättää kirjaimen
 * ohuenkin viivan kiinni maastoon. Kolme tiheämpää kerrosta pitää rivin
 * luettavana koko pituudeltaan taustasta riippumatta — text-shadow eikä
 * suodatin, kuten kaikkialla muuallakin (tests/rules.test.mjs).
 */
.fokus-kartuutsi-alarivi {
  display: block;
  line-height: 1.25;
  white-space: nowrap;
  color: rgba(74, 52, 33, 0.88);
  text-shadow:
    0 0 3px rgba(244, 232, 205, 0.98),
    0 0 6px rgba(244, 232, 205, 0.92),
    0 0 12px rgba(244, 232, 205, 0.8);
}

.fokus-kartuutsi-paikallinen {
  font-size: 0.78rem;
  letter-spacing: 0.08em;
}

.fokus-kartuutsi-aika {
  font-size: 0.66rem;
  font-style: italic;
  color: rgba(74, 52, 33, 0.72);
}

/*
 * MITTAJANA: vuorottelevat tummat ja vaaleat lohkot, päissä 0 ja
 * valittu pyöreä pituus. Leveys tulee js/fokusmitat.js:stä
 * muuttujana — se on laskettu ruudun mittakaavasta eikä ole vakio.
 */
.fokus-jana {
  --jana-leveys: 120px;
  flex: 0 0 auto;
  font-family: var(--font-type);
  color: rgba(58, 40, 25, 0.9);
  text-shadow: 0 0 4px rgba(244, 232, 205, 0.95);
}

.fokus-jana[hidden] { display: none; }

.fokus-jana-palkki {
  display: flex;
  width: var(--jana-leveys);
  height: 7px;
  border: 1px solid rgba(74, 52, 33, 0.85);
}

.fokus-jana-lohko { flex: 1 1 0; }
.fokus-jana-lohko:nth-child(odd) { background: rgba(74, 52, 33, 0.85); }

.fokus-jana-luvut {
  display: flex;
  width: var(--jana-leveys);
  justify-content: space-between;
  margin-top: 0.12rem;
  font-size: 0.66rem;
  line-height: 1.2;
}

/* Päätylukemat keskitetään janan päihin, jotta ne osuvat viivan kohdalle. */
.fokus-jana-nolla { transform: translateX(-50%); }
.fokus-jana-maksimi { transform: translateX(50%); }

/*
 * ALANURKKA ON AINA VAPAA — MITAT EIVÄT PINOUDU (omistajan
 * pelitestitilaus 26.8.2026).
 *
 * Tässä oli mediakysely (max-width: 1140px), joka nosti kartuutsin ja
 * janan alanappirivin YLÄPUOLELLE pinoon. Sen syy oli rivi itse:
 * 560 pikselin kortti täytti kapean ruudun alalaidan, eikä kartuutsi
 * mahtunut sen viereen. Fokusnäkymässä rivi on nyt yksi pieni neliö
 * kartuutsin rinnalla, joten estettä ei ole ja mitat pysyvät siellä,
 * minne ne kuuluvat: kartuutsi vasemmassa, jana oikeassa alanurkassa.
 *
 * Turva-alue lasketaan mukaan samalla kaavalla kuin alanappirivillä
 * (body[data-mode] .turn-card, max-width: 640px), jotta neliö ja
 * kartuutsi ovat iPhonella samalla viivalla eivätkä kotipalkin alla.
 */
@media (max-width: 640px) {
  .fokusmitat { bottom: calc(0.9rem + env(safe-area-inset-bottom, 0px)); }
}

/*
 * Puhelimessa pienemmällä: kartuutsi ei saa viedä puolta kartasta —
 * eikä varsinkaan tunkea neliönappia mittajanan päälle, koska kaikki
 * kolme ovat nyt samassa alalaidassa. Mitattu 390 px:n ruudulla.
 */
@media (max-width: 700px) {
  .fokus-kartuutsi-nimi { font-size: 1.05rem; letter-spacing: 0.18em; }
  .fokus-kartuutsi-paikallinen { font-size: 0.7rem; }
  .fokus-kartuutsi-aika { font-size: 0.6rem; }
  .fokus-kartuutsi-viiva { max-width: 11rem; }
  .fokus-jana-luvut { font-size: 0.6rem; }
}

/*
 * KAPEIMMALLA PUHELIMELLA ALALAITAAN MAHTUU KOLME ASIAA VAIN NIUKASTI:
 * kartuutsi, Liiku-neliö ja mittajana. Mitattu 320 px:n ruudulla
 * (iPhone SE): täysimittainen kartuutsi työnsi neliön janan päälle.
 *
 * AIKAKAUDEN VALTIOMUOTO JÄÄ POIS, EI MITÄÄN MUUTA. Se on kartuutsin
 * alarivin pisin ja vähäarvoisin pala ("· kuningaskunta v. 1873"); maan
 * oma nimi (ΕΛΛΑΣ · Hellas) ja suomenkielinen nimi jäävät. Rivi ei siis
 * typisty kesken sanan — pala jätetään pois kokonaisena, kuten se
 * jätettäisiin pois datastakin (js/packs/fokus-grc.js).
 */
@media (max-width: 460px) {
  .fokus-kartuutsi-nimi { font-size: 0.92rem; letter-spacing: 0.14em; }
  .fokus-kartuutsi-paikallinen { font-size: 0.6rem; letter-spacing: 0.04em; }
  .fokus-kartuutsi-aika { font-size: 0.52rem; }
  .fokus-kartuutsi-viiva { max-width: 8.5rem; }
}

/*
 * Raja on mitattu eikä arvattu: 430 px:n puhelimella kartuutsi (217 px)
 * ja neliö mahtuivat janan viereen 34 pikselin raolla, 390 px:llä rako
 * oli nolla ja 320 px:llä neliö nousi janan päälle. Valtiomuoto jää
 * siis pois vasta siitä alaspäin.
 */
@media (max-width: 415px) {
  .fokus-kartuutsi-aika { display: none; }
}

/* ===========================================================================
   FOKUSNÄKYMÄN ALANAPPIRIVI — LIIKU ON KESKITETTY TEKSTINAPPI
   ---------------------------------------------------------------------------
   Omistajan pelitestitilaus 25.8.2026 (KUMOAA AIEMMIN TILATUN NELIÖN):
   *"Liiku-nappi: nykyinen alareunan neliö (kompassi-ikoni) muutetaan
   TEKSTINAPIKSI (LIIKU) ja keskitetään sivusuunnassa ruudun alareunaan."*

   Neliö oli kartuutsin rinnalla vasemmassa alanurkassa, ja siellä se luki
   kuin kartuutsin osa — kompassi ilman sanaa ei kerro, että se on pelin
   ainoa tapa lähteä liikkeelle. Keskitetty sana LIIKU on ruudun
   alareunan oma kaluste eikä kartuutsin liite.

   NAPIN OMA ULKOASU (sana, mitat, keskitys) ON YHDEN NAPIN RIVIN
   YLEISSÄÄNNÖISSÄ (.toimintorivi.rivi-yksi, ks. "FOKUSNÄKYMÄN YHDEN
   NAPIN RIVI"): se ei riipu siitä, onko maalle esirenderöityä lehteä.
   Täällä ratkaistaan vain se, mitä kartuutsin ja mittajanan naapuruus
   vaatii — ja nämä säännöt on siksi rajattu body.fokuspohjaan eli
   täsmälleen siihen tilaan, jossa kartuutsi on ruudulla (js/ui.js
   paivitaFokusPohja).

     1. KORTTI LAIDASTA LAITAAN. .turn-card on muualla keskitetty
        560 pikselin kortti; täällä se venyy laidasta laitaan ilman omaa
        pehmustetta, jotta keskitys on RUUDUN keskitys eikä kortin.
        Rivin vanha vasen pehmuste (--fokus-nappipaikka, mitattu
        kartuutsin leveydestä js/fokusmitat.js:ssä) jää käyttämättä: se
        oli olemassa vain siksi, että neliö väisti kartuutsin
        sivusuunnassa.
     2. EI TÖRMÄYSTÄ KARTUUTSIIN. Kartuutsi on vasemmassa ja mittajana
        oikeassa alanurkassa; leveällä ruudulla keskelle jää tilaa, mutta
        kapealla ei. Kapealla nappi nousee siksi kartuutsin YLÄPUOLELLE
        (mediakysely alempana) — ei sivuun, koska keskitys on juuri se,
        mikä tilattiin.

   MATKANAPPIEN LIUKU EI KUTISTU. Se peittää rivin entiseen tapaan ja
   saa keskitetyn enimmäisleveyden, jotta kolme nappia eivät veny
   työpöydällä laidasta laitaan.
   =========================================================================== */

body.fokuspohja[data-mode] .turn-card {
  left: 0.7rem;
  right: 0.7rem;
  width: auto;
  margin-inline: 0;
  padding: 0;
}

/*
 * Kahden napin rivi (Liiku + Tutki) on fokusnäkymässä käytännössä
 * tavoittamaton — Tutki on siellä kaupungin laatassa — mutta jos se
 * joskus piirtyy, se pysyy keskitettynä ja entisen levyisenä eikä veny
 * laidasta laitaan sen myötä, että kortti leveni.
 */
body.fokuspohja .toimintorivi { width: min(100%, 20rem); margin-inline: auto; }

body.fokuspohja .toimintorivi.rivi-yksi { width: 100%; margin-inline: 0; }

/*
 * Napin oma ulkoasu (sana, keskitys, mitat) on yhden napin rivin
 * yleissäännöissä ylempänä — se ei riipu siitä, onko maalle
 * esirenderöityä lehteä. Täällä ratkaistaan enää se, mitä kartuutsin ja
 * mittajanan naapuruus vaatii.
 */
body.fokuspohja .toimintorivi-liuku {
  left: 0;
  right: 0;
  width: min(100%, 21rem);
  margin-inline: auto;
}

/* ---------------------------------------------------------------------------
   KAPEALLA RUUDULLA NAPPI NOUSEE KARTUUTSIN YLÄPUOLELLE.

   Alalaidassa on kolme kalustetta: kartuutsi vasemmalla (maan nimestä
   riippuen noin 220 px), mittajana oikealla (noin 230 px) ja nyt keskellä
   LIIKU. Mitattuna ne mahtuvat samalle viivalle vasta noin 700 pikselin
   levyisellä ruudulla; sitä kapeammalla keskitetty nappi menisi
   kartuutsin päälle. Nousu on napin oma eikä kartuutsin: maan nimi ja
   mittajana kuuluvat lehden alalaitaan, nappi on pelin kaluste.

   Maataulu väistää mukana ilman muutoksia — se mittaa napin yläreunan
   ruudulta (js/fokusmitat.js paivitaTaulunPohja).
   --------------------------------------------------------------------------- */
@media (max-width: 700px) {
  body.fokuspohja[data-mode] .turn-card {
    /* Kaksi riviä: jälkimmäinen ohittaa ensimmäisen siellä, missä
       turva-alue on olemassa (iPhonen kotipalkki, ks. 640 px:n sääntö
       ylempänä); vanhassa selaimessa jää voimaan ensimmäinen. */
    bottom: calc(0.9rem + 3.4rem);
    bottom: calc(0.9rem + 3.4rem + env(safe-area-inset-bottom, 0px));
  }
}

/* ===========================================================================
   MAATAULU — kartuutsin päältä nouseva maan perustietotaulu
   (js/fokusmitat.js)
   ---------------------------------------------------------------------------
   Omistajan tilaus 25.8.2026: kartuutsin kertapainallus nostaa
   läpikuultavan taulun, jossa maan perustiedot uuden atlaskartan tyyliin
   ja plus-nappi varsinaiseen maalehteen. Luvut ovat SAMASTA lähteestä
   kuin maalehdessä (MAATIEDOT).

   VIIMEISTELY PELITESTISSÄ 26.8.2026 — kolme muutosta:

     1. TAULU NOUSEE KARTUUTSIN KOHDALTA, ei ruudun levyisenä alalevynä.
        Se on ankkuroitu samaan vasempaan laitaan (left: 0.7rem, sama
        kuin .fokusmitat) ja sen alareuna on heti kartuutsin yläpuolella,
        joten se näyttää nousevan KREIKKA-sanan takaa. Enimmäisleveys on
        maltillinen: taulu ei saa peittää kartan oikeaa laitaa.
     2. LÄPINÄKYVÄMPI. Tausta oli 0.86; kartta kuulsi läpi vain
        aavistuksen. Nyt 0.58, ja luettavuus tulee musteesta ja ohuesta
        kehyksestä eikä paperin peittävyydestä.
     3. EI OTSIKKOA EIKÄ SULKUNAPPIA. Maan nimi lukee kartuutsissa
        taulun alla, ja taulu sulkeutuu kartasta, kartuutsista tai
        Escistä (js/fokusmitat.js). Jäljelle jää yksi kaluste: plus
        oikeassa yläkulmassa.

   ALAREUNA ON ALANAPPIRIVIN YLÄPUOLELLA: Liiku-neliö jää kokonaan
   näkyviin ja käyttöön.

   LIIKE ON TRANSFORM + OPACITY, ei suodatin (iOS-sääntö), ja
   prefers-reduced-motion sammuttaa sen kokonaan.

   --- LOPPU PAPERILAATASTA (omistajan pelitestitilaus 27.8.2026) ------

   *"Taulu kokonaan läpinäkyvälle pohjalle ja lähemmäs KREIKKA-plakaattia
   niin että ne muodostavat yhtenäisen kokonaisuuden."* Kaksi seurausta:

     A. EI TAUSTAA, EI KEHYSTÄ, EI VARJOA. Kohdan 2 vaalea laatta (0.58)
        oli viimeinen jäänne "sivusta" kartan päällä; nyt taulu on samaa
        lajia kuin kartuutsi eli MUSTETTA PAPERILLA. Luettavuus tulee
        yksinomaan halosta — kolme kerrosta kuten kartuutsin alarivillä,
        koska taulun pienin teksti (lähdeviite 0,64rem) on vielä
        alariviäkin hennompi. Halo on text-shadow eikä suodatin
        (tests/rules.test.mjs).
     B. ALAREUNA MITATAAN KARTUUTSISTA eikä arvata rem-luvuilla. Vanha
        `4.9rem + turva-alue` ei ollut sama viiva kuin kartuutsin oma
        `0.9rem` ilman turva-aluetta, joten iPadilla väliin jäi
        turva-alueen verran tyhjää — juuri se rako, jonka takia taulu ja
        plakaatti näyttivät kahdelta eri kalusteelta. Nyt js/fokusmitat.js
        mittaa kartuutsin (ja Liiku-neliön) yläreunan ja kirjoittaa sen
        muuttujaan --fokus-taulupohja; rem-arvo jää varalle siltä
        varalta, ettei mittaus ole vielä ehtinyt.
   =========================================================================== */

.fokus-maataulu {
  position: absolute;
  left: 0.7rem;
  /*
   * ALAREUNA ON SEKÄ KARTUUTSIN ETTÄ LIIKU-NELIÖN YLÄPUOLELLA — mitattuna
   * niistä itsestään (js/fokusmitat.js paivitaTaulunPohja). Varalla oleva
   * rem-arvo on entinen: kartuutsi alkaa 0.9rem korkeudelta ja on noin
   * 3rem korkea, mutta neliö on ylempänä, koska alanappirivi asuu
   * .rail-kerroksessa, joka on itse --gapin verran irti reunasta.
   */
  bottom: var(--fokus-taulupohja, calc(4.9rem + env(safe-area-inset-bottom, 0px)));
  z-index: 5;
  width: min(26rem, calc(100% - 1.4rem));
  max-height: min(46%, 22rem);
  overflow-y: auto;
  /*
   * VASEN PEHMUSTE ON SAMA KUIN KARTUUTSILLA (0.35rem), jotta lukurivit
   * ja KREIKKA alkavat täsmälleen samasta pystyviivasta — se on se yksi
   * asia, joka tekee kahdesta kalusteesta yhden. Oikea pehmuste pitää
   * rivit poissa plus-napin alta.
   */
  /* Plus on taulun ensimmäinen VIRRASSA OLEVA rivi (omistaja 26.8.2026:
     absoluuttinen ankkurointi ei pysynyt keskellä kaikilla ruuduilla),
     joten yläpehmuste on taas tavallinen. */
  padding: 0.5rem 0.35rem 0.5rem;
  border: 0;
  background: none;
  box-shadow: none;
  color: rgba(52, 36, 21, 0.95);
  font-family: var(--font-type);
  /* Ilman paperilaattaa muste on suoraan maaston päällä: halo on siis
     taulun ainoa luettavuuden lähde, ja siksi kolmikerroksinen. */
  text-shadow:
    0 0 3px rgba(244, 232, 205, 0.98),
    0 0 6px rgba(244, 232, 205, 0.92),
    0 0 12px rgba(244, 232, 205, 0.8);
  /* Pystyvieritys sormella; kartan panorointi ei saa käynnistyä
     (js/fokusmitat.js pysäyttää tapahtumat, tämä sallii vierityksen). */
  touch-action: pan-y;
  opacity: 0;
  /* Nousee kartuutsin takaa, ei ruudun alalaidasta: matka on taulun
     oma korkeus, joten se on piilossa kartuutsin kohdalla. */
  transform: translateY(18%) scaleY(0.94);
  transform-origin: bottom left;
  visibility: hidden;
  transition: transform 0.26s ease, opacity 0.2s ease, visibility 0s linear 0.26s;
}

.fokus-maataulu.auki {
  opacity: 1;
  transform: translateY(0) scaleY(1);
  visibility: visible;
  transition: transform 0.26s ease, opacity 0.2s ease, visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .fokus-maataulu,
  .fokus-maataulu.auki { transition: none; }
}

/*
 * PALJAS PAKSU PLUS LUKURIVIEN VIERESSÄ (omistaja 25.8.2026: "enemmän
 * vasemmalla lähempänä tekstiä... pelkästään paksummaksi plus merkiksi
 * ilman pyöreää ympyrää"). Ympyrälaatta ja reunaviiva ovat poissa —
 * merkki piirretään kahdella currentColor-palkilla, jotta se on aidosti
 * paksu eikä kirjasimen faux-boldin varassa. Nappi SYKKII hitaasti,
 * jotta se erottuu kutsuna eikä jää koristeeksi.
 *
 * SYKE ON TRANSFORM JA OPACITY. Sama iOS-sääntö kuin kaikella muullakin
 * (tests/rules.test.mjs): ei suodattimia, ei box-shadow-animaatiota.
 * prefers-reduced-motion sammuttaa sen ja jättää napin täyteen
 * peittävyyteen, jottei se jää pysyvästi haaleaksi.
 *
 * Kosketusala on 44 px, vaikka piirretty merkki on pienempi. Vasen
 * mitta on rivien tyypillisen leveyden mukaan; kapealla ruudulla nappi
 * pysyy taulun sisällä calc-varalla.
 */
.fokus-maataulu-lehti {
  /* Oma rivi taulun yläreunassa, AIDOSTI keskellä (omistaja 26.8.2026):
     virrassa oleva lohko + auto-marginaalit eivät riipu taulun
     leveydestä eivätkä ruudun koosta, toisin kuin entinen
     absoluuttinen left:50%-ankkurointi. */
  display: grid;
  place-items: center;
  /* Vaakapaikan (margin-left) asettaa js/fokusmitat.js taytaMaataulu:
     plus istuu otsikko- ja arvopalstan rajalle. */
  margin: 0 0 0.15rem;
  width: 2.1rem;
  height: 2.1rem;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  color: rgba(58, 40, 25, 0.95);
  /* Merkin piirtävät palkit; tekstisolmun '+' ei saa näkyä niiden alla. */
  font-size: 0;
  line-height: 0;
  cursor: pointer;
}

/*
 * Animaatiot vain kun taulu on AUKI, jotta ne käynnistyvät alusta joka
 * avauksella: ensin yksi reilu pehmeä sykäys huomion herättäjäksi
 * (omistaja 26.8.2026), sitten entinen hidas syke.
 */
.fokus-maataulu.auki .fokus-maataulu-lehti {
  /* Sykäys vasta reilun sekunnin päästä avauksesta (omistaja 26.8.):
     taulu ehtii asettua ennen kuin plus vetää huomion. */
  animation:
    fokus-plus-alku 0.9s cubic-bezier(0.34, 1.3, 0.5, 1) 1.25s backwards,
    fokus-plus-syke 3.2s ease-in-out 2.15s infinite;
}

@keyframes fokus-plus-alku {
  0% { transform: scale(0.3); opacity: 0; }
  55% { transform: scale(1.55); opacity: 1; }
  100% { transform: scale(1); opacity: 0.72; }
}

.fokus-maataulu-lehti::before,
.fokus-maataulu-lehti::after {
  content: '';
  grid-area: 1 / 1;
  background: currentColor;
  border-radius: 2px;
}

.fokus-maataulu-lehti::before { width: 1.15rem; height: 3px; }
.fokus-maataulu-lehti::after { width: 3px; height: 1.15rem; }

@keyframes fokus-plus-syke {
  0%, 100% { transform: scale(1); opacity: 0.72; }
  50% { transform: scale(1.12); opacity: 1; }
}

.fokus-maataulu-lehti:hover,
.fokus-maataulu-lehti:focus-visible {
  color: #16130f;
  animation-play-state: paused;
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .fokus-maataulu-lehti { animation: none; opacity: 1; }
}

.fokus-maataulu-rivit {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.28rem 0.8rem;
  margin: 0;
  font-size: 0.84rem;
}

.fokus-maataulu-otsikko {
  margin: 0;
  color: rgba(74, 52, 33, 0.75);
  font-size: 0.72rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  align-self: baseline;
}

.fokus-maataulu-arvo {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0;
}

.fokus-maataulu-sija { color: rgba(74, 52, 33, 0.6); font-size: 0.7rem; }

/*
 * KIELIRIVI: maalehden omat .tervehdys-tyylit hoitavat tervehdyksen,
 * lipun ja kielen nimen (js/fokusmitat.js kieliOsat), joten tässä
 * säädetään vain rivin ladonta. Rivi saa kietoutua: kolmen kielen maa
 * ei mahdu kapealle ruudulle yhdelle riville.
 */
.fokus-maataulu-kielet {
  flex-wrap: wrap;
  gap: 0.25rem 0.7rem;
  font-size: 0.78rem;
}

/*
 * KIELEN TARKENNE ("· Länsi-Traakia") kielen nimen perässä. Se on
 * väitteen ehto eikä lisätieto (js/fokusmitat.js kieliOsat), joten se
 * on luettavissa — mutta selvästi kevyempi kuin kielen nimi, jottei
 * lyhyt rivi näytä kahdelta rinnakkaiselta kieleltä. Sama sävy ja
 * kokosuhde kuin lukurivien sijaluvulla (.fokus-maataulu-sija).
 */
.fokus-kieli-tarkenne {
  color: rgba(74, 52, 33, 0.6);
  font-size: 0.78em;
  white-space: nowrap;
}

/* Lähderivi (.fokus-maataulu-lahde) poistui 26.8.2026 — omistaja:
 * "ota se koko rivi pois joka alkoi samat luvut tekstillä". */

/* ---------------------------------------------------------------------------
   TAULUN JA MAAN NIMEN ALLA OLEVA KARTTA SUMENEE (omistajan tilaus #102:
   *"tekstin alla olevat kohdat saisi blurrautua"*, ja pelitestipalaute
   27.8.2026 iltapäivä: *"blurin pitää levitä myös maan nimen alle ...
   reunan pitää häivyttyä pehmeästi ... blur saa olla aavistuksen
   kevyempi"*).

   MIKSI SUMENNUS. Taulu on 27.8.2026 alkaen pohjaton — pelkkää mustetta
   maaston päällä (ks. "LOPPU PAPERILAATASTA" yllä) — ja luettavuus oli
   kolmen kerroksen halon varassa. Halo kantaa yksittäisen sanan, muttei
   kokonaista lukutaulukkoa vuoristokartan päällä. Sumennus rauhoittaa
   PINNAN eikä lisää yhtään paperia takaisin.

   BACKDROP-FILTER, EI KARTAN OMA SUODATIN. Sama sääntö kuin Tutki-arkilla
   (.dialog.arkki::backdrop) ja lehden alapalkilla: suodatettu SVG-kerros
   pudottaa iOS:llä piirtopuskurinsa ja katoaa, mutta backdrop-filter ei
   koske karttaan lainkaan — se sumentaa vain sen, mikä on TÄMÄN kerroksen
   takana.

   OMA ELEMENTTI, EI TAULUN PSEUDO. Sumennus oli taulun ::before-pseudossa
   ja saattoi siksi kattaa vain taulun: KREIKKA-kartuutsi on eri
   elementissä (.fokusmitat), joten maan nimi jäi terävän vuoriston päälle
   ja sumennuksen alareuna piirsi ruudun poikki suoran viivan. Pseudoa ei
   voi venyttää kartuutsin yli, koska taulu on vierityssäiliö
   (overflow-y: auto) ja laitojen yli venyvä lapsi kasvattaisi sen
   vieritysaluetta. Huntu on siksi karttaruudun oma lapsi kuten taulukin,
   ja js/fokusmitat.js (paivitaMaatauluHuntu) mittaa sen molemmista
   kalusteista.

   MITAT TULEVAT JS:STÄ, EI TÄÄLTÄ. Taulun korkeus riippuu maan riveistä
   ja kielirivin kietoutumisesta, kartuutsin korkeus ruudun leveydestä:
   kumpaakaan ei voi kirjoittaa remeinä. CSS antaa vain ankkurin (vasen
   alanurkka) ja häivytyksen.

   HÄIVYTYS VAIN SINNE, MISSÄ NAAPURINA ON TERÄVÄ KARTTA. Huntu on
   ankkuroitu karttaruudun vasempaan alanurkkaan, joten vasen ja ala
   rajautuvat kartan KEHYKSEEN — siellä häivytys jättäisi vain ohuen
   terävän kaistan kehyksen viereen. Ylhäällä ja oikealla naapurina on
   kartta, ja siellä maski liudentaa sumennuksen olemattomiin
   --fokus-haive-matkalla. Kapealla puhelimella huntu yltää kartan oikeaan
   laitaan asti, ja silloin JS nollaa oikean häivytyksen
   (--fokus-haive-oikea) — muuten se söisi sumennuksen kielirivin
   viimeisiltä sanoilta.

   KAKSI GRADIENTTIA JA LEIKKAUS, EI YHTÄ SÄTEITTÄISTÄ. Säteittäinen
   maski (entinen ratkaisu) häivyttää eri matkalla joka suunnassa, ja
   laatikon laidoilla sen liukuma jäi niin lyhyeksi, että raja näkyi
   suorana. Kaksi lineaarista gradienttia leikattuna (mask-composite)
   antaa saman, mitatun liukuman jokaisessa reunassa.

   VAIN AUKI OLLESSA: suljettuna huntu on visibility: hidden, koska
   suodatinkerros on muuten turhaa työtä joka kehyksellä.
   --------------------------------------------------------------------------- */
.fokus-maatauluhuntu {
  position: absolute;
  left: 0;
  bottom: 0;
  /* Kartan päällä (.kartta-kuori on z-indeksitön), mutta kartuutsin
     (.fokusmitat, z-index: 3) ja taulun (z-index: 5) ALLA — muuten
     sumennus söisi oman tekstinsä. */
  z-index: 2;
  pointer-events: none;
  /* Mitat: js/fokusmitat.js paivitaMaatauluHuntu. Nollasta lähtevä
     laatikko ei sumenna mitään ennen ensimmäistä mittausta. */
  width: 0;
  height: 0;
  /*
   * SUMENNUS ON KEVENNETTY 5 px → 3.6 px (omistajan pelitestipalaute
   * 27.8.2026: *"blur saa olla myös aavistuksen kevyempi"*). Sama noin
   * kolmanneksen kevennys kylläisyydessä: 0.82 → 0.88.
   */
  -webkit-backdrop-filter: blur(3.6px) saturate(0.88);
  backdrop-filter: blur(3.6px) saturate(0.88);
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0, #000 var(--fokus-haive, 34px)),
    linear-gradient(to left, transparent 0, #000 var(--fokus-haive-oikea, 34px));
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to bottom, transparent 0, #000 var(--fokus-haive, 34px)),
    linear-gradient(to left, transparent 0, #000 var(--fokus-haive-oikea, 34px));
  mask-composite: intersect;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s ease, visibility 0s linear 0.26s;
}

.fokus-maatauluhuntu.auki {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.2s ease, visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .fokus-maatauluhuntu,
  .fokus-maatauluhuntu.auki { transition: none; }
}

/*
 * FALLBACK ilman backdrop-filteriä (vanhat WebKitit): sumennusta ei saa,
 * joten pinta rauhoitetaan hennolla pergamenttihunnulla — sama kaava kuin
 * avausnäkymän verholla (.intro-verho). Maski häivyttää senkin reunat.
 */
@supports not ((backdrop-filter: blur(5px)) or (-webkit-backdrop-filter: blur(5px))) {
  .fokus-maatauluhuntu { background: rgba(244, 232, 205, 0.5); }
}

/* ---------------------------------------------------------------------------
   MATKUSTA-NAPPI VÄISTYY TAULUN AJAKSI (#102: *"se voisi piilottaa
   matkusta-napin väliaikaisesti, jos se on laudalla"*).

   Taulu nousee kartuutsin takaa aivan alanappirivin yläpuolelle, ja
   fokusnäkymässä rivissä on vain tämä yksi neliö — se jäi taulun alareunan
   viereen kilpailemaan huomiosta juuri silloin, kun pelaaja lukee maan
   lukuja.

   VISIBILITY, EI DISPLAY. Rivin ruudukko pitää paikkansa, joten kartuutsi
   ja mittajana eivät hyppää sivusuunnassa napin kadotessa ja palatessa.
   Peittävyys tuo pehmeän häivytyksen, ja pointer-events estää sen, että
   näkymätöntä nappia voisi napauttaa vahingossa.

   AUKI OLEVA MATKUSTUSLIUKU EI TARVITSE OMAA SÄÄNTÖÄ: taulu avataan
   kartuutsista eli rivin ULKOPUOLELTA, ja sama napautus sulkee liu'un
   (js/ui.js kytkeLiukuSulku).

   SÄÄNTÖ EI RAJAA ITSEÄÄN FOKUSNÄKYMÄÄN, koska maataulu on olemassa vain
   siellä — tilauksen ehto ("jos se on laudalla") toteutuu siis itsestään.
   --------------------------------------------------------------------------- */
body.maataulu-auki .toimintorivi .monitoimi-nappi {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}

@media (prefers-reduced-motion: reduce) {
  body.maataulu-auki .toimintorivi .monitoimi-nappi { transition: none; }
}

/* ===========================================================================
   KARTAN REUNAVIIVAIMET — dynaamiset asteviivat (js/fokusmitat.js)
   ---------------------------------------------------------------------------
   Omistajan pelitestitilaus 26.8.2026: *"ohuet viivainmerkinnät
   (asteviivat + lukemat) reunoihin atlas-tyyliin, laskettuna näkyvästä
   alueesta samalla projektiokaavalla kuin mittajana"*.

   HIENOVARAISUUS ON SÄÄNTÖ, EI TYYLIVALINTA. Merkit ovat kartan päällä,
   jossa on jo kaupunkien laatat, fokusvirran kortit ja alanapit. Siksi:
   nauha on kapea (reunan ohut kaista), muste on haalea, lukema on pieni
   ja koko kerros on napautuksille läpinäkyvä (pointer-events: none).
   z-index on 2 eli mittojen (3), taulun (5) ja alanappien alla — jos
   jokin niistä osuu päälle, viivain jää alle eikä toisin päin.

   PAIKAT: pituusasteet ylä- JA alareunaan, leveysasteet vasempaan JA
   oikeaan (omistajan pelitestitilaus 25.8.2026: neljä sivua). Alalaidan
   kartuutsi, neliönappi ja mittajana sekä oikean reunan kelluva pöllö ja
   zoomiportaat eivät väisty — viivain jättää merkin latomatta niiden
   kohdalta (js/fokusmitat.js KALUSTEET).
   =========================================================================== */

.fokus-viivaimet {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  font-family: var(--font-type);
  color: rgba(74, 52, 33, 0.62);
}

.fokus-viivaimet[hidden] { display: none; }

/* NAUHA ON SE, JOKA LIIKKUU (js/fokusmitat.js paivitaNauha): panoroinnissa
   koko nauha liu'utetaan yhdellä muunnoksella, ja merkkien omat muunnokset
   kirjoitetaan vain uudelleenladonnassa. Siksi vihje kuuluu nauhalle —
   ja samalla kompositorin kerroksia on kaksi eikä kahdeksantoista. */
.fokus-viivain { position: absolute; will-change: transform; }
.fokus-viivain-yla { top: 0; left: 0; right: 0; height: 1.4rem; }
.fokus-viivain-ala { bottom: 0; left: 0; right: 0; height: 1.4rem; }
.fokus-viivain-vasen { top: 0; bottom: 0; left: 0; width: 2.6rem; }
.fokus-viivain-oikea { top: 0; bottom: 0; right: 0; width: 2.6rem; }

/* Merkin paikka nauhassa tulee TRANSFORMISTA eikä left/top-arvosta
   (js/fokusmitat.js ladoNauha): lukemat päivittyvät kartan liikkuessa
   joka kehyksellä, ja `left` pakottaisi uudelleenasettelun jokaisesta
   merkistä. Siksi nauhan omat ankkurit ovat nollassa ja kaikki liike
   on yhdessä muunnoksessa — myös keskitys, joka oli ennen tässä. */
.fokus-viivain-merkki {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

.fokus-viivain-viiva {
  display: block;
  background: rgba(74, 52, 33, 0.5);
}

.fokus-viivain-luku {
  font-size: 0.58rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  white-space: nowrap;
  /* Sama vaalea halo kuin kartuutsilla: lukema pysyy luettavana sekä
     maaston että ulapan päällä. Ei suodatin. */
  text-shadow: 0 0 4px rgba(244, 232, 205, 0.95), 0 0 8px rgba(244, 232, 205, 0.7);
}

/* Yläviivain: pystyviiva reunasta alas, lukema sen alla ja keskitettynä
   viivan kohdalle (kuten mittajanan päätylukemat). */
.fokus-viivain-yla .fokus-viivain-merkki {
  top: 0;
  left: 0;
  flex-direction: column;
  align-items: center;
  transform: translateX(-50%);
}

.fokus-viivain-yla .fokus-viivain-viiva { width: 1px; height: 6px; }

/* Alaviivain on yläviivaimen peilikuva: viiva alareunassa kiinni ja
   lukema sen YLÄPUOLELLA (column-reverse), jottei lukema jää ruudun
   alalaidan taakse. */
.fokus-viivain-ala .fokus-viivain-merkki {
  bottom: 0;
  left: 0;
  flex-direction: column-reverse;
  align-items: center;
  transform: translateX(-50%);
}

.fokus-viivain-ala .fokus-viivain-viiva { width: 1px; height: 6px; }

/* Vasen viivain: vaakaviiva reunasta oikealle, lukema sen perässä. */
.fokus-viivain-vasen .fokus-viivain-merkki {
  left: 0;
  top: 0;
  transform: translateY(-50%);
}

.fokus-viivain-vasen .fokus-viivain-viiva { width: 6px; height: 1px; }

/* Oikea viivain: sama peilattuna — viiva kiinni oikeassa reunassa ja
   lukema sen vasemmalla puolella (row-reverse). */
.fokus-viivain-oikea .fokus-viivain-merkki {
  right: 0;
  top: 0;
  flex-direction: row-reverse;
  transform: translateY(-50%);
}

.fokus-viivain-oikea .fokus-viivain-viiva { width: 6px; height: 1px; }

/* ---------------------------------------------------------------------------
   VIIVAIMET SEURAAVAT KARTTAA (omistajan tilaus 28.8.2026)

   Ennen nauha liukui kokonaan reunansa yli kartan liikkeen ajaksi, koska
   lukemat laskettiin vasta liikkeen päätteeksi eivätkä ne siihen asti
   voineet olla oikeassa. Nyt ne lasketaan joka kehyksellä (js/fokusmitat.js
   piirraViivaimet), joten nauha pysyy paikallaan ja lukemat elävät.

   MERKIN OMA LIUKU ON POIS TARKOITUKSELLA. Merkkiä siirretään joka
   kehyksellä uuteen kohtaan; siirtymä tarkoittaisi, että se olisi aina
   matkalla edelliseen paikkaan eli aina väärässä kohdassa. Kartan liike
   on jo pelaajan sormen liikettä — viivain vain seuraa sitä.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   KARTTASYMBOLIT — täkysymbolien ja kohdemerkkien yhteinen kirjasto
   ---------------------------------------------------------------------------
   Raamattu, SYMBOLITAKSONOMIA (omistaja 26.8.2026 ilta): kaksitoista
   kategoriaa, joilla jokaisella oma koodilla piirretty symboli
   (js/fokusnosto-symbolit.js piirraNostosymboli) ja VAIMEA HERALDINEN
   VÄRI. MUOTO RATKAISEE, väri on toissijainen vihje — sävyt on
   taitettu seepiaan ja pergamenttiin, ei puhtaita perusvärejä.

   TYYLIT OVAT TÄSSÄ TIEDOSTOSSA EIVÄTKÄ css/fokusnosto.css:ssä, koska
   samat luokat piirtyvät kahdessa kerroksessa: täkysymboleissa
   (js/fokusnosto-symbolit.js) ja kartan kohdemerkeissä
   (js/fokuskohteet.js) — ja kohdekerros ei lataa fokusnosto.css:ää.
   styles.css on ainoa tyylitiedosto, joka on aina paikalla.

   LÄPINÄKYVÄ MUSTETYYLI (omistajan valinta 27.8.2026, montaasin C):
   merkillä EI OLE aluslaattaa eikä kehysympyrää — glyyfi piirtyy
   suoraan pergamenttikartalle, ja sen perään ladotaan lyhyt nimiö
   (.nostosym-nimio). --sym-laatta jäi silti käyttöön niissä kohdissa,
   joissa muoto tarvitsee paperinvaalean sisäosan: portin holvi, silmän
   valkuainen ja pyörän napa.

   EI SUODATTIMIA (tests/rules.test.mjs): kaikki on pelkkää täyttöä,
   viivaa ja tekstiä.
   =========================================================================== */

:root {
  /* Muste ja paperi — koko perheen runko. */
  --sym-muste: #4b3a1c;
  --sym-laatta: rgba(243, 234, 210, 0.88);
  /* Kategoriat (Raamattu, SYMBOLITAKSONOMIA). */
  --sym-huuto: #dda42c;        /* keltainen — skandaalit ja hurjat tarinat */
  --sym-elain: #b98d54;        /* ruskea — eläimet (pöllönpoikanen) */
  --sym-silma: #5f7f9e;        /* sininen — nähtävyydet ja multimedia */
  --sym-historia: #a05c3f;     /* punaruskea — historia ja rauniot */
  --sym-luonto: #4f7d6f;       /* sinivihreä — luonnon kategoriaväri (kortin ylärivi) */
  /*
   * Luonnon merkki on perheen ainoa KOLMIVÄRINEN (omistaja 27.8.2026:
   * "sininen meri ja ruskea vuori, jossa vihreä puu"). Sävyt ovat yhtä
   * vaimeita kuin muidenkin aksentit — pergamentti ei kestä kirkasta.
   */
  --sym-luonto-vuori: #8a6849;  /* ruskea — kallio */
  --sym-luonto-puu: #4a6b3d;    /* vihreä — havupuu */
  --sym-luonto-vesi: #4a7690;   /* sininen — meri ja järvi */
  --sym-ruoka: #8e4550;        /* viininpunainen — ruoka ja juoma */
  --sym-kulttuuri: #7b5a8c;    /* violetti — musiikki, teatteri, taide */
  --sym-tekniikka: #6f7278;    /* teräksenharmaa — tekniikka ja keksinnöt */
  --sym-kauppa: #7d7840;       /* oliivi — kauppa ja raha */
  --sym-sana: #47597f;         /* tummansininen — kieli, kirjallisuus, legendat */
  --sym-merenkulku: #34566d;   /* meren tummansininen — merenkulku ja satamat */
  --sym-urheilu: #93893c;      /* kullanvihreä — urheilu ja kisat */
  --sym-kaupunki: #8a6d4a;  /* muurinruskea — kaupungit (porttitorni) */
  --sym-ihme: #b8862b;      /* vanha kulta — Matkakirjan kadonneet ihmeet (tähti) */
  /*
   * Tiimalasi — Historian hetket (2.9.2026). Sävy on tumma purppura:
   * perheen kaksitoista muuta väriä ovat okrasta oliiviin ja sinestä
   * viininpunaiseen, eikä yksikään ole purppura, joten rivi erottuu
   * selitevalikossa myös väristä. Vaimennettu kuten muutkin —
   * pergamentti ei kestä kirkasta.
   */
  --sym-hetki: #6e4a63;
  --sym-hetki-hiekka: #c9a86a; /* hiekan kellertävä kasa lasin pohjalla */
}

/* TÄHTI — Matkakirjan ihme, kohde jota ei enää ole (Raamattu, osio
 * "Matkakirjan ihmeet"). Kompassiruusun sakarat kullassa. Musteinen
 * ääriviiva on läpinäkyvässä mustetyylissä (27.8.2026) tähden ainoa
 * kontrasti pergamenttia vasten, ja siksi se on hiukan paksumpi kuin
 * perheen muilla koodipiirroksilla. */
.nostosym-tahti {
  fill: var(--sym-ihme);
  stroke: var(--sym-muste);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

/* Täkysymbolien oma osuma-alue (.nostosym-osuma) poistui 26.8.2026:
 * yksi kuplatäky per maa, muut aiheet ovat kartan tavallisia
 * kohteita (js/fokusnosto-symbolit.js). */

/* ---------------------------------------------------------------------------
   MERKIN NIMIÖ — symbolin perään ladottu lyhyt nimi.
   ---------------------------------------------------------------------------
   Omistajan valinta 27.8.2026 (montaasin C): merkki piirretään suoraan
   pergamentille ilman laattaa, ja sen perään tulee lyhyt teksti kartan
   nimiötypografialla. Peräkkäin eikä alle, koska lehteen poltettu
   atlaskerros latoo omat nimensä merkkiensä ALLE — perusteet
   js/fokusnosto-symbolit.js:n osiossa NIMIÖ. Asu on siis .fokus-nimen (fokusnäkymän
   suomenkieliset lisänimet) asu: sama kaunokirjasin, vaimea muste ja
   ohut pergamenttihalo, joka pitää nimen luettavana myös vuoren ruskean
   ja meren harmaan päältä.

   HALO ON STROKE JA PAINT-ORDER, EI SUODATIN (tests/rules.test.mjs):
   suodatettu kerros palaa iOS:n taustalta tyhjänä.

   NIMIÖN RASTERI EI OTA NAPAUTUKSIA VASTAAN — mutta nimiöllä on oma
   napautusalue (omistaja 1.9.2026 ilta: tekstit kokonaan
   klikattaviksi). Rasteri pysyy mykkänä, koska SVG antaisi
   napautuksen päällimmäiselle kuvalle; tekstin alueen hoitaa merkin
   ryhmän suorakaide (.fokuskohde-tekstiosuma), joka kilpailee
   naapureiden kanssa keskipiste-etäisyydellä (js/fokuskohteet.js
   lahinKohde) eikä siis peitä naapurimerkin osuma-aluetta.
   --------------------------------------------------------------------------- */
/*
 * NIMIÖ ON LEHDEN OMAA LADONTAA (27.8.2026 ilta, omistajan palaute laitteelta
 * v1211: nimiö *"pitää muuttaa täsmälleen samaan tyyliin ja kokoon
 * kuin karttaan poltetut nimet olivat (esim. poistettu Smólikas:
 * pieni kursiivi antiikva)"*).
 *
 * Luvut ovat suoraan tools/fokuskartta/piirto.js:n kohdasta 8e
 * (poltettu vuorennimi): kursiivi antiikva ja muste rgba(74,52,33,0.92).
 * Kaunokäsiala (--font-kauno) oli tässä 27.8.2026 asti, ja juuri se
 * erotti pelin nimiöt lehden omista nimistä yhdellä silmäyksellä.
 *
 * PERGAMENTTIHALO POISTUI 1.9.2026 (omistaja, kuvakaappaus Bulgarian
 * lehtinäkymästä, sanatarkasti: *"otetaan pois karttanostojen
 * teksteistä valkoinen ääriviiva, eli tekstit pelkällä tummalla"*).
 * Halo on poltetun VUORENNIMEN keino: siellä nimi kirjoitetaan keskelle
 * kirjavaa rinnettä. Karttanoston nimiö on merkkinsä vieressä oleva
 * lippu, ja merkillä on jo oma laattansa — kolmas vaalea reunus teki
 * nimistä sumeita. `paint-order` jää pois samalla: ilman strokea sillä
 * ei ole mitään järjestettävää.
 *
 * SAMA LUKU ON CANVASILLA (js/fokusnosto-symbolit.js
 * NOSTOSYM_NIMIO_ASUT `haloLeveys: 0`), koska poltettu ladonta ei voi
 * odottaa CSS:ää. Kaupunkien ja maaston nimet (.karttanimi) eivät kuulu
 * tähän sääntöön eivätkä muutu.
 */
.nostosym-nimio {
  font-family: var(--font-atlas);
  font-style: italic;
  fill: rgba(74, 52, 33, 0.92);
  stroke: none;
  pointer-events: none;
}

/*
 * MEREN NIMI ON HARVENNETTU KAPITEELI ILMAN HALOA — piirto.js kohta
 * 8b. Meren nimi jää paperiin eikä nouse sen päälle, joten sillä ei
 * ole pergamenttivedosta; harvennuksen hoitaa canvasilla merkeittäin
 * ladonta (js/fokusnosto-symbolit.js), ja tämä sääntö on elävän
 * varapolun ja tyylin lukemisen tähden.
 */
.nostosym-nimio-meri {
  fill: rgba(120, 108, 84, 0.72);
  stroke: none;
  letter-spacing: 0.28em;
}

/* ---------------------------------------------------------------------------
   KARTAN VIIVAMERKKI (js/fokusnosto-symbolit.js NOSTOSYM_MINI)

   Omistajan palaute laitteelta v1211: generoidut mustepiirrokset ovat
   *"aivan liian raskaita"* — kartalle kuuluu *"superyksinkertainen,
   minimalistinen, vanhan ajan kartan fiilis — kuten karttaan alunperin
   poltettu yksinkertainen vuorisymboli (pieni kolmio
   hachure-viivoituksella)"*.

   Muste ja viivanleveydet ovat poltetun vuorimerkin omat (piirto.js
   kohta 8e): ääriviiva rgba(58,40,25,0.8) leveydellä 1,15 ja hachure
   rgba(58,40,25,0.4) leveydellä 0,75. Kartalla merkki piirretään
   canvasille, joka LUKEE NÄMÄ ARVOT täältä — sävy ei siis ole
   kahdessa paikassa.

   VIIVAMERKEILLÄ EI OLE KATEGORIAVÄRIÄ, ja se koskee 2.9.2026 alkaen
   niitä viittä, joilla on yhä oma muoto (vuori, vesi, huutomerkki,
   tassu, kompassiruusu): kartalla ne ovat samaa seepiaa kuin lehden
   oma painojälki, ja kategorian kertoo muoto. Loput yksitoista ovat
   samannäköinen piste, jolla kategorian kertoo väri — ks.
   .nostosym-mini-taytto alempana. Heraldiset aksentit (--sym-*)
   elävät sen lisäksi kortin ylärivillä, jossa merkki on 1,5 em.
   --------------------------------------------------------------------------- */
/* VETO ON TÄYTETTY MUOTO, EI VIIVA (omistaja 31.8.2026: viivat eivät
   saa olla tasapaksuja eivätkä päättyä pyöreään). Merkki piirretään
   leveän terän jälkenä, jonka paksuus seuraa kulkusuuntaa ja jonka
   pääte on viisto — koko muoto lasketaan js/fokusnosto-symbolit.js:ssä
   (osio LEVEÄTERÄINEN KYNÄ). Tänne jää siis vain MUSTE: viivanleveys
   ja päätetyyli eivät enää koske näitä merkkejä, koska viivaa ei ole. */
.nostosym-mini {
  fill: rgba(58, 40, 25, 0.86);
  stroke: none;
}

.nostosym-mini-ohut {
  fill: rgba(58, 40, 25, 0.52);
  stroke: none;
}

/* PISTEMERKIN KIEKKO (omistaja 2.9.2026: *"Kaikista muista
   kategorioista voisi tehdä yksinkertaisesti vain pisteen, paitsi
   jätetään vuori ja vesi ja skandaali ja söpöysmerkki ennalleen"*).

   Yksitoista kategoriaa jakaa saman kiekon, joten kartalla kategorian
   kertoo enää VÄRI — ja se on sama --sym-muuttuja, jolla selitevalikon
   väripallo palaa (js/karttavalot.js karttavaloVari). Peitto on 0,86
   eli merkin oman musteen paino: pergamentilla täysi kylläisyys olisi
   liikennemerkki. Canvas lukee kummankin luvun täältä
   (js/fokusnosto-symbolit.js nostosymMustelajit), joten sävy on
   yhdessä paikassa.

   VIISI SÄILYNYTTÄ MERKKIÄ (vuori, vesi, huutomerkki, tassu,
   kompassiruusu) ovat yhä pelkkää seepiaa: niillä muoto kertoo. */
.nostosym-mini-taytto {
  stroke: none;
  opacity: 0.86;
}

.nostosym-mini-silma { fill: var(--sym-silma); }
.nostosym-mini-historia { fill: var(--sym-historia); }
.nostosym-mini-ruoka { fill: var(--sym-ruoka); }
.nostosym-mini-kulttuuri { fill: var(--sym-kulttuuri); }
.nostosym-mini-tekniikka { fill: var(--sym-tekniikka); }
.nostosym-mini-kauppa { fill: var(--sym-kauppa); }
.nostosym-mini-sana { fill: var(--sym-sana); }
.nostosym-mini-merenkulku { fill: var(--sym-merenkulku); }
.nostosym-mini-urheilu { fill: var(--sym-urheilu); }
.nostosym-mini-kaupunki { fill: var(--sym-kaupunki); }
.nostosym-mini-hetki { fill: var(--sym-hetki); }

/*
 * RASTEROITU MERKKI — glyyfi ja nimiö yhtenä valmiina kuvana
 * (js/fokusnosto-symbolit.js piirraNostosymKartalle). Kartalla merkki
 * on tavallisesti tämä; elävä <text> yllä jää varapolulle ja antaa
 * samalla rasterille sen värit ja kirjasimen, jotka canvas lukee
 * .nostosym-nimiön lasketusta tyylistä.
 *
 * EI NAPAUTUKSIA: kuva ulottuu nimiön verran merkin oikealle puolelle
 * ja peittäisi naapurin osuma-alueen. Sormen ottaa merkin oma 44 px:n
 * ympyrä (.fokuskohde-osuma).
 */
.nostosym-rasteri { pointer-events: none; }

.nostosym-kaupunki {
  fill: var(--sym-kaupunki);
  stroke: var(--sym-muste);
  stroke-width: 0.9;
  stroke-linejoin: round;
}

/* Porttiaukko on laatan väriä: portti näyttää avoimelta. */
.nostosym-portinaukko { fill: var(--sym-laatta); stroke: var(--sym-muste); stroke-width: 0.7; }

/* Tornin viiri: sama muurinruskea, mutta ohuempi kynä. */
.nostosym-viiri {
  fill: var(--sym-kaupunki);
  stroke: var(--sym-muste);
  stroke-width: 0.6;
  stroke-linejoin: round;
}


/* Kaiverruksen apuviivat: höyry, uurteet, kielet, ripustimet, varpaat. */
.nostosym-viiva {
  fill: none;
  stroke: var(--sym-muste);
  stroke-width: 1;
  stroke-linecap: round;
}

/* Huutomerkki: okrankeltainen täyttö, musteviiva ympärillä. */
.nostosym-huuto {
  fill: var(--sym-huuto);
  stroke: var(--sym-muste);
  stroke-width: 0.9;
  stroke-linejoin: round;
}

/* Pöllövauva: untuvainen kroppa on vaaleaa ruskeaa (kategorian sävy
   pehmennettynä — tumma täyttö söisi silmät), muoto on viivassa. */
.nostosym-pollo {
  fill: #ecd9b4;
  stroke: var(--sym-muste);
  stroke-width: 1.1;
  stroke-linejoin: round;
}

.nostosym-silma {
  fill: #fbf6e8;
  stroke: var(--sym-muste);
  stroke-width: 0.9;
}

.nostosym-tera { fill: var(--sym-muste); }

/* Silmäsymbolin kehä: kategorian sininen (SYMBOLITAKSONOMIA muutti
   v1119:n okran — silmä on nähtävyyksien kategoria, ei "avautuu
   jotakin" -väri). */
.nostosym-silmakaari {
  fill: var(--sym-silma);
  stroke: var(--sym-muste);
  stroke-width: 0.9;
  stroke-linejoin: round;
}

/* Terän kiilto: yksi vaalea piste, ettei silmä ole musta läiskä. */
.nostosym-kiilto { fill: rgba(251, 246, 232, 0.9); }

.nostosym-nokka {
  fill: var(--sym-elain);
  stroke: var(--sym-muste);
  stroke-width: 0.7;
  stroke-linejoin: round;
}

/* Tiimalasi — Historian hetket. Kehys (laipiot ja pylväät) on
   musteessa kuten kaikki puuosat perheessä, lasi kategoriansa
   purppurassa ja hiekka kellertävänä kasana pohjalla. */
.nostosym-hetkikehys {
  fill: var(--sym-muste);
  stroke: none;
}

.nostosym-hetki {
  fill: var(--sym-hetki);
  stroke: var(--sym-muste);
  stroke-width: 0.8;
  stroke-linejoin: round;
}

.nostosym-hiekka {
  fill: var(--sym-hetki-hiekka);
  stroke: none;
}

/* Murtunut pylväs — historia ja rauniot. */
.nostosym-pylvas {
  fill: var(--sym-historia);
  stroke: var(--sym-muste);
  stroke-width: 0.8;
  stroke-linejoin: round;
}

/* Vuori, havupuu ja aalto — luonto; kolme osaa, kolme sävyä. */
.nostosym-vuoristo {
  fill: var(--sym-luonto-vuori);
  stroke: var(--sym-muste);
  stroke-width: 0.9;
  stroke-linejoin: round;
}

.nostosym-havu {
  fill: var(--sym-luonto-puu);
  stroke: var(--sym-muste);
  stroke-width: 0.7;
  stroke-linejoin: round;
}

.nostosym-aalto {
  fill: none;
  stroke: var(--sym-luonto-vesi);
  stroke-width: 1.4;
  stroke-linecap: round;
}

/* Höyryävä malja — ruoka ja juoma. */
.nostosym-malja {
  fill: var(--sym-ruoka);
  stroke: var(--sym-muste);
  stroke-width: 0.8;
  stroke-linejoin: round;
}

/* Lyyra — kulttuuri: käsivarret ja kaikupohja kantavat värin. */
.nostosym-lyyrakaari {
  fill: none;
  stroke: var(--sym-kulttuuri);
  stroke-width: 1.7;
  stroke-linecap: round;
}

.nostosym-lyyrapohja {
  fill: var(--sym-kulttuuri);
  stroke: var(--sym-muste);
  stroke-width: 0.7;
}

/*
 * Höyryveturi — tekniikka. Hammasratas poistui 27.8.2026 (asetusnapin
 * konnotaatio, ks. js/fokusnosto-symbolit.js piirraNostosymVeturi).
 */
.nostosym-veturi {
  fill: var(--sym-tekniikka);
  stroke: var(--sym-muste);
  stroke-width: 0.8;
  stroke-linejoin: round;
}

.nostosym-veturipyora {
  fill: var(--sym-tekniikka);
  stroke: var(--sym-muste);
  stroke-width: 0.8;
}

/* Vetopyörän napa on paperia: reikä erottaa pyörän umpikiekosta. */
.nostosym-veturinapa {
  fill: var(--sym-laatta);
  stroke: var(--sym-muste);
  stroke-width: 0.6;
}

/* Höyry on vaaleaa kuin paperi, ohut musteviiva reunana. */
.nostosym-hoyry {
  fill: var(--sym-laatta);
  stroke: var(--sym-muste);
  stroke-width: 0.6;
}

/* Vaaka — kauppa: kupit ja jalusta täyttöinä, varsi musteviivana. */
.nostosym-vaakakuppi {
  fill: var(--sym-kauppa);
  stroke: var(--sym-muste);
  stroke-width: 0.7;
  stroke-linejoin: round;
}

/* Sulkakynä — kieli, kirjallisuus ja legendat. */
.nostosym-sulka {
  fill: var(--sym-sana);
  stroke: var(--sym-muste);
  stroke-width: 0.8;
  stroke-linejoin: round;
}

/* Ankkuri — merenkulku: rauta kantaa värin paksumpana viivana. */
.nostosym-ankkurirauta {
  fill: none;
  stroke: var(--sym-merenkulku);
  stroke-width: 1.7;
  stroke-linecap: round;
}

.nostosym-ankkurikoura {
  fill: var(--sym-merenkulku);
  stroke: var(--sym-muste);
  stroke-width: 0.5;
  stroke-linejoin: round;
}

.nostosym-ankkurirengas {
  fill: none;
  stroke: var(--sym-muste);
  stroke-width: 1;
}

/* Laakeriseppele — urheilu: oksat kullanvihreällä, lehdet musteella.
   Oksa on perheen paksuin viiva: ilman sitä seppele haalistui
   katkoympyräksi 21 pikselissä. */
.nostosym-seppele {
  fill: none;
  stroke: var(--sym-urheilu);
  stroke-width: 2.1;
  stroke-linecap: round;
}

.nostosym-lehva {
  fill: none;
  stroke: var(--sym-muste);
  stroke-width: 0.9;
  stroke-linecap: round;
}

/* ===========================================================================
   KARTTASELITEVALIKKO JA AIHEVALOT
   (js/karttaselite.js, js/karttavalot.js)
   ---------------------------------------------------------------------------
   Omistajan tilaus 29.8.2026: kartan oikeaan yläkulmaan popup-valikko,
   josta rullautuu alas karttaselitteet, ja jokaisen rivin väripallo
   sytyttää valon kaikkiin sen aiheen kohteisiin kartalla.

   --- AIHEVALOT ------------------------------------------------------------

   Valo on piirretty jokaisen merkin alle aina, ja NÄKYVYYS ON YKSI
   LUOKKA BODYSSÄ. Siksi sytytys ja sammutus ovat luokanvaihto eivätkä
   DOM-kierros, eikä merkkikerroksen uudelleenrakennus voi hukata
   valotilaa: uusi merkki syntyy valoineen ja tämä sääntö päättää,
   näkyykö se.

   Aihe–luokka-parit on pakko luetella: CSS ei osaa yhdistää bodyn
   luokkaa ja lapsen luokkaa muuten kuin kirjoittamalla pari näkyviin.
   Pareja on kahdeksan eikä neljätoista, koska valikon rivi on
   symbolien SUKUKUNTA (js/fokusnosto-symbolit.js
   NOSTOSYM_PAAKATEGORIAT): merkin oma luokka on jo ryhmitelty siellä,
   kun valo piirretään, joten tänne riittää yksi pari ryhmää kohti.
   Lista on sama ja samassa järjestyksessä kuin KARTTAVALO_AIHEET.
   =========================================================================== */

.karttavalo { display: none; }

body.valot-kaupungit .karttavalo-kaupungit,
body.valot-luonto .karttavalo-luonto,
body.valot-elaimet .karttavalo-elaimet,
body.valot-historia .karttavalo-historia,
body.valot-ihmeet .karttavalo-ihmeet,
body.valot-kulttuuri .karttavalo-kulttuuri,
body.valot-kauppa .karttavalo-kauppa,
body.valot-skandaalit .karttavalo-skandaalit { display: block; }

/* ---------------------------------------------------------------- valikko */

/*
 * KOTELO KIINNI OIKEAAN YLÄKULMAAN (omistajan pelitesti 30.8.2026:
 * *"Selite ikoni pitää olla neliön mallinen ja kiinnitetty yläkulmaan
 * (nyt liikaa irti ylhäältä)"*).
 *
 * MIKSI SE ROIKKUI IRRALLAAN. Nappi väisti maakylttiä (.maa-pilleri,
 * top 0.4rem, korkeus 1.2rem), joka asui kartan oikeassa yläkulmassa
 * — 2rem jätti kyltin alle 0,4rem raon. Kylttiä ei enää LUODA
 * pelinäkymässä (js/ui.js paivitaMaaPilleri, 30.8.2026: maan nimen
 * kertoo kartuutsi vasemmassa alanurkassa), joten nappi väisti tyhjää
 * ja jäi kellumaan keskelle kartan ylälaitaa. Nyt sama 0,4rem
 * molemmilta reunoilta, eli nappi istuu nurkassa symmetrisesti.
 */
.karttaselite {
  position: absolute;
  top: 0.4rem;
  right: 0.4rem;
  z-index: 6;
}

/*
 * NAPPI ON KARTAN NAPPIEN PERHETTÄ: sama pergamenttilaatta ja sama
 * sormimitta kuin muilla ikoninapeilla — pehmuste nollassa ja keskitys
 * gridillä, koska 20 px:n kuvake ei mahdu 40 px:n napin pehmustettuun
 * sisältöalueeseen.
 */
.karttaselite-nappi {
  display: grid;
  width: 2.15rem;
  height: 2.15rem;
  min-width: 40px;
  min-height: 40px;
  padding: 0;
  place-items: center;
  border: 1px solid var(--line);
  /*
   * NELIÖ EIKÄ YMPYRÄ (omistaja 30.8.2026). var(--radius) on 12px eli
   * sama pyöristys kuin pelin muilla ikoninapeilla, jolloin selite on
   * samaa perhettä ratas- ja valikkonapin kanssa eikä yksinäinen
   * pyörylä kartan päällä.
   */
  border-radius: var(--radius);
  background: rgba(239, 220, 180, 0.9);
  color: var(--map-ink);
  cursor: pointer;
}

.karttaselite-nappi svg { display: block; }

/*
 * HOVER-SÄÄNNÖT TARVITSEVAT `:not(:disabled)`-LISÄN, eivät koristeeksi
 * vaan painoksi: pelin oma yleissääntö on `button:hover:not(:disabled)
 * { background: #43331f; }` (tumma muste), ja sen painoarvo on kaksi
 * pseudoluokkaa + elementti. Pelkkä `.karttaselite-rivi:hover` häviää
 * sille, jolloin sormen alla oleva rivi maalautuu tummaksi ja sen oma
 * tumma teksti katoaa kokonaan — juuri se näkyi kaappauksessa
 * ensimmäisellä savukeajolla. Sama lisä nostaa nämä säännöt yleisen
 * yläpuolelle ilman !importantia.
 */
.karttaselite-nappi:hover:not(:disabled) { background: rgba(245, 231, 200, 0.95); }

.karttaselite-nappi[aria-expanded='true'] {
  background: var(--map-ink);
  color: rgba(245, 231, 200, 0.95);
}

/*
 * LEVY LIUKUU YLÖS PIILOON (omistaja: *"Popup LIUKUU YLÖS PIILOON kun
 * karttaa klikataan"*), joten sitä ei poisteta DOM:sta — poistettu
 * solmu ei voi liukua mihinkään. Suljettuna se on `visibility:
 * hidden`, jolloin se on poissa myös näppäimistöltä ja
 * ruudunlukijalta; näkyvyyden siirtymä viivästetään liu'un loppuun,
 * jotta liuku ehtii näkyä ennen katoamista.
 *
 * Origo on YLHÄÄLLÄ: levy rullautuu napin alta esiin ja vetäytyy
 * takaisin sen alle.
 */
.karttaselite-levy {
  position: absolute;
  top: calc(100% + 0.35rem);
  right: 0;
  display: flex;
  flex-direction: column;
  width: max-content;
  max-width: min(78vw, 20rem);
  max-height: min(60vh, 26rem);
  overflow-y: auto;
  padding: 0.35rem;
  transform: translateY(-0.6rem) scaleY(0.86);
  transform-origin: top right;
  opacity: 0;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 8px;
  background: #f5f0e2;
  box-shadow: 0 8px 24px rgba(20, 14, 6, 0.35);
  visibility: hidden;
  transition: transform 220ms ease, opacity 180ms ease, visibility 0s linear 220ms;
}

.karttaselite-levy.auki {
  transform: none;
  opacity: 1;
  visibility: visible;
  transition: transform 220ms ease, opacity 180ms ease, visibility 0s;
}

@media (prefers-reduced-motion: reduce) {
  .karttaselite-levy { transition: opacity 1ms linear, visibility 0s linear 1ms; }
  .karttaselite-levy.auki { transition: opacity 1ms linear, visibility 0s; }
}

/* Otsikkorivi: nimi vasemmalle, OFF ja ALL oikeaan laitaan. */
.karttaselite-ylarivi {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.15rem 0.35rem 0.4rem;
  border-bottom: 1px solid rgba(70, 51, 31, 0.18);
}

.karttaselite-otsikko {
  flex: 1 1 auto;
  color: rgba(70, 51, 31, 0.92);
  font-family: var(--font-type);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.karttaselite-kaikki {
  min-height: 0;
  padding: 0.2rem 0.45rem;
  border: 1px solid rgba(70, 51, 31, 0.3);
  border-radius: 5px;
  background: rgba(255, 252, 242, 0.7);
  color: rgba(70, 51, 31, 0.85);
  font-family: var(--font-type);
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  cursor: pointer;
}

.karttaselite-kaikki:hover:not(:disabled) {
  background: rgba(255, 252, 242, 1);
  color: rgba(70, 51, 31, 1);
}

.karttaselite-lista {
  display: flex;
  flex-direction: column;
  padding-top: 0.2rem;
}

/* Neljä saraketta: pallo, symboli, selite, luku. Selite venyy, joten
   luku asettuu joka rivillä samaan kohtaan oikeaan laitaan. */
.karttaselite-rivi {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center;
  gap: 0.45rem;
  min-height: 0;
  padding: 0.3rem 0.4rem;
  border: 0;
  border-radius: 6px;
  background: none;
  color: rgba(70, 51, 31, 0.92);
  font: inherit;
  font-size: 0.86rem;
  text-align: left;
  cursor: pointer;
}

.karttaselite-rivi:hover:not(:disabled) {
  background: rgba(70, 51, 31, 0.07);
  color: rgba(70, 51, 31, 0.92);
}

/*
 * VÄRIPALLO ON KYTKIN JA TILANÄYTTÖ (omistajan täsmennys 29.8.2026:
 * *"päälle kytketyn aiheen väripallo syttyy myös valikon
 * seliterivillä — valikko näyttää aina mitkä valot ovat päällä"*).
 *
 * Sammuneena pallo on pelkkä ääriviiva aiheen omassa värissä; syttyneenä
 * se on täytetty ja saa ympärilleen saman himmeän kehän kuin kartan
 * valotäplä.
 *
 * KEHÄ ON PSEUDOELEMENTTI EIKÄ color-mix-varjo: läpinäkyvyys pitäisi
 * silloin laskea CSS:n omalla funktiolla, jota vanhempi WebKit ei
 * tunne — ja peliä pelataan iOS:n kotivalikkosovelluksessa. Sama väri
 * `opacity`lla on sama jälki ilman uutta funktiota.
 */
.karttaselite-pallo {
  position: relative;
  width: 0.85rem;
  height: 0.85rem;
  border: 2px solid var(--valo, #8a6d4a);
  border-radius: 50%;
  background: transparent;
}

.karttaselite-rivi[aria-pressed='true'] .karttaselite-pallo {
  background: var(--valo, #8a6d4a);
}

.karttaselite-rivi[aria-pressed='true'] .karttaselite-pallo::after {
  content: '';
  position: absolute;
  inset: -0.3rem;
  border-radius: 50%;
  background: var(--valo, #8a6d4a);
  opacity: 0.24;
}

.karttaselite-rivi[aria-pressed='true'],
.karttaselite-rivi[aria-pressed='true']:hover:not(:disabled) {
  background: rgba(70, 51, 31, 0.06);
}

.karttaselite-symboli {
  width: 1.35rem;
  height: 1.35rem;
  display: block;
}

.karttaselite-nimi { line-height: 1.25; }

/* Kappalemäärä (omistajan lisätilaus 29.8.2026): montako tämän aiheen
   merkkiä kartalla juuri nyt on. Numerot ladotaan tabulaarisina, jotta
   sarake ei heilu rivien välillä. */
.karttaselite-luku {
  color: rgba(70, 51, 31, 0.6);
  font-family: var(--font-type);
  font-size: 0.74rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.04em;
}

/* Aihe, jota tällä kartalla ei ole: rivi jää selitteeksi mutta
   himmenee — selitelista ei saa vaihtua maan mukana, sillä se on
   kartan selite eikä sisällysluettelo. */
.karttaselite-tyhja { opacity: 0.45; }

.karttaselite-vihje {
  margin: 0.35rem 0.4rem 0.1rem;
  color: rgba(70, 51, 31, 0.62);
  font-size: 0.7rem;
  line-height: 1.35;
}

/* ==================== KARTTAPALLO (js/pallo.js) ==================== */
/*
 * Omistaja 4.9.2026: Google Earth -tyylinen maailmanvalikko Globe.gl:llä.
 * Kuori peittää koko ruudun linssin tummalla asulla; kirjasto piirtää
 * palloon koteloon. z-index 45: pulun kuplapinon (40) yllä, dialogien
 * (50) alla.
 */
.pallo-kuori {
  position: fixed;
  inset: 0;
  z-index: 45;
  display: flex;
  flex-direction: column;
  background: radial-gradient(ellipse at 50% 55%, #241c15 0%, #120e0b 70%);
  color: #e6d5ac;
  opacity: 0;
  transition: opacity 420ms ease;
}
.pallo-kuori.esilla { opacity: 1; }
/* Otsikkorivi poistui 4.9.2026 (omistaja: menee logon kanssa
 * päällekkäin, ei tarvita); kuori alkaa ylärivin alta (js/pallo.js
 * asettaa top) ja Sulje kelluu oikeassa yläkulmassa. */
.pallo-sulje {
  position: absolute;
  top: 0.7rem;
  right: 0.8rem;
  z-index: 2;
  min-height: 0;
  width: 2.2rem;
  height: 2.2rem;
  padding: 0;
  border-radius: 999px;
  border: 1px solid rgba(217, 161, 59, 0.55);
  background: rgba(217, 161, 59, 0.12);
  color: #f3e4bf;
  font-size: 1rem;
  cursor: pointer;
}
.pallo-sulje:hover, .pallo-sulje:focus-visible { background: rgba(217, 161, 59, 0.3); }
.pallo-kotelo { flex: 1 1 auto; min-height: 0; position: relative; }
.pallo-kotelo > div { position: absolute; inset: 0; }
.pallo-tila {
  position: absolute;
  left: 0; right: 0; top: 50%;
  margin: 0;
  text-align: center;
  color: #a8987a;
  font-family: var(--font-ui, system-ui, sans-serif);
  font-size: 0.9rem;
  pointer-events: none;
}
.pallo-tila[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .pallo-kuori { transition: none; }
}

/* ============ PALLOLAUTA (js/pallolauta/lauta.js, vaihe 1) ============ */
/*
 * Omistaja 5.9.2026 (Raamattu KARTTAPALLO ON PELILAUTA): pallo on pelin
 * lauta, ei ikkuna. Kuori asuu KARTTARUUDUSSA tasokartan paikalla:
 * ei kiinteää sijaintia, ei tummaa pohjaa (karttaruudun oma pohja
 * riittää), ei Sulje-nappia. Pinontatasoa ei anneta: kuori on
 * DOM-järjestyksessä kartan siirtokuoren jälkeen ja ennen kuplia ja
 * nappeja, jotka kelluvat kartan päällä (event-toast, maalehti-nappi
 * z-index 3), joten ne jäävät pallon päälle täsmälleen kuten kartan.
 */
.pallo-kuori.pallolauta {
  position: absolute;
  inset: 0;
  z-index: auto;
  background: transparent;
  /* Ruudun oma pohja on tummaa nahkaa (.map-pane); pallo kelluu siinä. */
  /* Linssikartan häivytys (vaihe 4): pallo häipyy heränneen kartan
     päältä ja häivyttyy takaisin sen päälle 250 ms:ssa. */
  transition: opacity 250ms ease;
}
.pallo-kuori.pallolauta[hidden] { display: none; }
/* Linssin alla pallo on läpinäkyvä eikä ota kosketuksia. */
.pallo-kuori.pallolauta.linssin-alla { opacity: 0; pointer-events: none; }
/*
 * LINSSIKARTAN KEHYS (js/pallolauta/linssikartta.js, vaihe 4): ohut
 * kehys tasokartan päällä linssin ajaksi — otsikkorivi vasemmalla
 * (maalehti-napin oikealla puolella) ja Sulje samassa kulmassa, jossa
 * vaiheen 1 "Palaa pallolle" oli. Kehys ei ota kosketuksia; vain nappi.
 * Radiotilassa ja aikajanalla kehys on piilossa: niillä on oma
 * sulkemisensa (radion OFF, aikajanan ✕), ja kumpikin päättää linssin.
 */
.linssikartta-kehys {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  transition: opacity 250ms ease;
}
.linssikartta-kehys.esilla { opacity: 1; }
.linssikartta-otsikko {
  position: absolute;
  left: 3rem;
  top: 0.7rem;
  /* Vasemmalla maalehti-nappi (0,5 + 2,15 rem), oikealla Sulje (~4 rem)
     ja selitenappi (2,15 + 0,5 rem): selite katkaistaan, ei rivitetä. */
  max-width: calc(100% - 11.5rem);
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  padding: 0.3rem 0.8rem;
  border-radius: 1rem;
  border: 1px solid rgba(217, 161, 59, 0.55);
  background: rgba(36, 26, 18, 0.82);
  color: #f3e4bf;
  font-family: var(--font-ui, system-ui, sans-serif);
}
.linssikartta-nimi { font-size: 0.82rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.linssikartta-selite { font-size: 0.7rem; color: #d9c8a0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.linssikartta-sulje {
  position: absolute;
  /* Selitenapin (js/karttaselite.js, oikea yläkulma) vasemmalla puolella
     — vaiheen 1 "Palaa pallolle" jäi sen alle (kaappaus 5.9.2026). */
  right: 3.3rem;
  top: 0.7rem;
  pointer-events: auto;
  min-height: 0;
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
  border: 1px solid rgba(217, 161, 59, 0.55);
  background: rgba(36, 26, 18, 0.82);
  color: #f3e4bf;
  font-family: var(--font-ui, system-ui, sans-serif);
  font-size: 0.8rem;
  cursor: pointer;
}
.linssikartta-sulje:hover, .linssikartta-sulje:focus-visible { background: rgba(217, 161, 59, 0.3); }
body.radio-tila .linssikartta-kehys, body.aikajana-paalla .linssikartta-kehys { display: none; }
@media (prefers-reduced-motion: reduce) {
  .pallo-kuori.pallolauta, .linssikartta-kehys { transition: none; }
}
/*
 * Nappula pallolla (htmlElementsData): CSS2D-elementti kaupungin
 * kohdalla, jalka pisteessä. Ei ota napautuksia — kaupungin piste
 * ja pallon oma osumatesti hoitavat ne. Näkyvyys pallon takana
 * vaihdetaan opacityllä (js/pallolauta/lauta.js), joten siirtymä
 * pehmentää horisontin ylityksen.
 */
.pallolauta-nappula {
  pointer-events: none;
  transform: translate(-50%, -100%);
  transition: opacity 250ms ease;
}
.pallolauta-nappula svg { display: block; overflow: visible; }
@media (prefers-reduced-motion: reduce) {
  .pallolauta-nappula { transition: none; }
}

/* ============ PALLOLAUTA, VAIHE 2: SIIRROT PALLOLLA ============ */
/*
 * Nopanheiton kohde pallolla (js/pallolauta/merkit.js, htmlElementsData):
 * halo, piste ja nimi samoilla luokilla kuin tasokartan fokusKohdeMerkki
 * (.target-halo.fokus, .target-piste, .target-nimi yllä), joten väri ja
 * hengitys tulevat samasta säännöstä. Ei ota napautuksia — osuma on
 * pallon oma (lähin kohde 44 px, js/pallolauta/lauta.js).
 */
.pallolauta-kohde {
  pointer-events: none;
  transform: translate(-50%, -50%);
  transition: opacity 250ms ease;
}
.pallolauta-kohde svg { display: block; overflow: visible; }
/*
 * Liikkuva nappula ja lentokone (js/pallolauta/siirto.js) ovat pelin
 * omaa DOMia kotelon päällä: paikka kirjoitetaan joka kehys pallon
 * pinnan pisteestä. Kotelon yleissääntö (.pallo-kotelo > div, inset 0)
 * ei saa venyttää niitä koko ruudun kokoisiksi — siksi tarkempi
 * valitsin ja oma laatikko. CSS2D-kerroksen (kirjaston div) jälkeen
 * DOMissa, joten ne piirtyvät paikallaan olevien merkkien päälle.
 */
.pallo-kotelo > .pallolauta-liikkuva,
/*
 * KONE ON HETI LENTOSUUNNASSA — ASENTO EI ANIMOIDU (omistaja 5.9.2026
 * klo 00.35: *"lentokoneen ei tarvitse kääntyä alussa vaan voi lehtää
 * heti oikeaan suuntaa"*).
 *
 * Kaksi lukua tulee js/pallolauta/siirto.js:stä elementin omina
 * muuttujina, jotta vakio ja tyyli eivät voi erkaantua:
 * KONEEN_KAANNOKSEN_MS (0 ms) on transformin — siis myös kiertokulman —
 * siirtymä, ja KONEEN_ILMESTYS_MS on se peittävyyden liuku, jolla kone
 * häivyttyy näkyviin JO OIKEASSA ASENNOSSA. Kulma itse luetaan joka
 * kehys kaaresta (siirto.js koneenKulma), joten lähdössä ei ole
 * kaartoa eikä nykäystä.
 */
.pallo-kotelo > .pallolauta-kone {
  position: absolute;
  inset: auto;
  left: 0;
  top: 0;
  width: auto;
  height: auto;
  pointer-events: none;
  will-change: transform, opacity;
  transform-origin: 50% 50%;
  opacity: 0;
  transition: transform var(--koneen-kaannos-ms, 0ms) linear,
    opacity var(--koneen-ilmestys-ms, 420ms) ease;
}
.pallo-kotelo > .pallolauta-kone.nakyy { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .pallo-kotelo > .pallolauta-kone { transition: none; }
}
.pallo-kotelo > .pallolauta-liikkuva { transition: none; }
.pallolauta-kone svg { display: block; overflow: visible; }
/* Noppa kuoressa pallon päällä laudan ajaksi (js/pallolauta/lauta.js
   noppaKuoreen): sama kerros kuin kartan siirtokuoressa, ruudun px. */
.pallo-kuori.pallolauta > .die-layer { position: absolute; inset: 0; z-index: 3; }
@media (prefers-reduced-motion: reduce) {
  .pallolauta-kohde { transition: none; }
}

/* ====== PALLOLAUTA, VAIHE 5b: AVAUSLENTO ILMAN SUMENNUSTA ====== */
/*
 * KARTTA NÄKYY TERÄVÄNÄ LENNON AIKANA (omistaja 5.9.2026 klo 00.35,
 * sanatarkasti: *"lentokonekohtauksessa kartta voi näkyä ilman
 * sumennusta"*).
 *
 * TÄSSÄ OLI HARSO. Vaihe 5b laski kotelon päälle pergamentin värisen
 * kalvon (.pallolauta-harso, rgba(238, 225, 196, 0.62)), joka
 * jäljitteli tasokartan lentoharsoa (.fokus-sumu-harso, js/kartta.js
 * aloituslennonNiukkuus). Pallolla se peitti juuri sen, mitä
 * avauksessa katsotaan: laattakartan maapallon. Kalvo on poistettu
 * kokonaan, ja niukkuus on nyt vain kaksi nimeä ja pelitilan
 * poissaolo (js/pallolauta/lauta.js aloitaLentotila). Vanha kartta
 * (?lauta=kartta) pitää oman harsonsa: se on kartan oman
 * lentokerroksen asia eikä tämän laudan.
 */
/*
 * MERKIT PELIN PÄÄLLÄ LENNON AJAN. Pinontataso jäi, vaikka harso
 * lähti: kone ja kaksi nimeä piirtyvät pelin muiden kerrosten päälle,
 * jottei mikään myöhemmin lisätty kerros peitä niitä. Kotelo ei ole
 * oma pinontakontekstinsa (position: relative ilman z-indexiä), joten
 * merkin oma z-index riittää — ja sääntö on voimassa vain lennon ajan,
 * jottei muu peli muuta pinoaan.
 */
.pallo-kuori.pallolauta.pallolauta-lennossa .pallolauta-nimi,
.pallo-kuori.pallolauta.pallolauta-lennossa .pallolauta-kone { z-index: 3; }
/*
 * LENNON KAKSI NIMEÄ LUKEUTUVAT MYÖS TERÄVÄN KARTAN PÄÄLLÄ. Asu on
 * sama kuin tasokartan lentonimillä (.aloituslento-nimi) — täysi muste
 * ja pergamenttihalo — ja se pysyy, vaikka harso poistui: laattakartta
 * on paikoin tumma ja paikoin vaalea, ja halo on se, joka pitää nimen
 * luettavana molempien päällä. Halon leveys on ruutuvakio, koska pallon
 * nimi on ruutuvakio (js/pallolauta/nimet.js).
 */
.pallo-kuori.pallolauta.pallolauta-lennossa .pallolauta-nimi text {
  fill: rgba(52, 36, 22, 0.98);
  paint-order: stroke;
  stroke: rgba(240, 228, 200, 0.9);
  stroke-width: 4.2;
  stroke-linejoin: round;
}
/*
 * Kohtaus väistyy saapumiskortin alla: kone häipyy samassa tahdissa
 * kuin tasokartan lentokerros (.lento-poistuu, 280 ms).
 */
.pallo-kuori.pallolauta.pallolauta-lento-poistuu .pallolauta-kone {
  opacity: 0;
  transition: opacity 280ms ease;
}

/* ==================================================================   ILMEPAKETTI (js/ilme.js; omistaja 5.9.2026, kartoituksen TOP 6 kohta 6)
   -------------------------------------------------------------------------
   Vivus piirtää reitin musteviivana, Rough.js piirtää pienen koristeen
   kehyksen käsin piirretyn näköisenä, rough-notation vetää kynällä
   alleviivauksen tai ympyrän. Nämä säännöt astuvat voimaan VAIN, kun
   kirjasto on ladattu ja js/ilme.js on merkinnyt elementin — ilman
   kirjastoa yksikään valitsin ei osu ja peli näyttää entiseltä.
   ------------------------------------------------------------------------- */

/*
 * Musteviivan aikana pelin omat reittipolut ja askelpisteet odottavat
 * näkymättöminä ja kynä piirtää kopioon (g.ilme-muste). Kun kynä on
 * perillä, alkuperäiset häivytetään esiin ja kopio pois — yksi
 * kertaluonteinen 260 ms:n ristihäivytys, sama laji kuin card-in, ei
 * jatkuva animaatio kartalla. Lapsivalitsin (>) jättää kopion rauhaan.
 */
.matkareitit[data-musteviiva] > .matkareitti,
.matkareitit[data-musteviiva] > .matkareitti-piste { transition: opacity 260ms ease-out; }
.matkareitit[data-musteviiva='piirtyy'] > .matkareitti,
.matkareitit[data-musteviiva='piirtyy'] > .matkareitti-piste { opacity: 0; }
.matkareitit > .ilme-muste { transition: opacity 260ms ease-out; }
.matkareitit > .ilme-muste.ilme-muste-pois { opacity: 0; }

/*
 * Karhea kehys asuu isäntänsä ensimmäisenä lapsena nollakorkuisena
 * svg:nä, joka piirtää reunaviivan ulos omasta laatikostaan (overflow
 * visible, ei viewBoxia = ei skaalausta). Sticky pitää sen paikallaan
 * myös silloin, kun isäntä vierittää sisältöään. Isännän oma reunaviiva
 * väistyy, mutta sen leveys jää, jottei sisältö liikahda.
 */
svg.ilme-karhea {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 1;
  display: block;
  flex: none;
  width: 100%;
  /* Ei nolla: Chromium jättää tyhjäkokoisen svg-juuren kokonaan
     piirtämättä. Yksi pikseli, jonka negatiivinen marginaali syö. */
  height: 1px;
  margin-bottom: -1px;
  overflow: visible;
  pointer-events: none;
}

.ilme-karhea-kehys { border-color: transparent; }

/* rough-notationin piirros ei saa napata napautuksia eikä viedä tilaa. */
svg.rough-annotation { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .matkareitit[data-musteviiva] > .matkareitti,
  .matkareitit[data-musteviiva] > .matkareitti-piste,
  .matkareitit > .ilme-muste { transition: none; }
}

/* ============ PALLOLAUTA, VAIHE 3: NIMET JA NOSTOT PALLOLLA ============ */
/*
 * Kaupunkien nimet, elävät nostot, eläintäyt ja kohtaamispiste ovat
 * CSS2D-elementtejä (js/pallolauta/{merkit,nimet,nostot}.js). Omistajan
 * kortin vastaus 5.9.2026: nimet *"ELAVINA tekstielementteina laattojen
 * paalla (kuten Google Earth)"*. Elementit eivät ota napautuksia —
 * osuma on pallon oma (lähin merkki 44 px, js/pallolauta/lauta.js).
 *
 * KAIKKI LIIKE ANIMOIDAAN (Raamattu): sisääntulo pehmeällä
 * häivytyksellä (pallolauta-ilmesty), poistuminen häivytyksellä
 * (.pallolauta-poistuu), pallon taakse kiertyvä merkki häivyttää
 * (.pallolauta-takana) ja nimen siirtymä pisteestä uuteen paikkaan
 * liukuu (.pallolauta-nimi-siirto). Reduced motion: ei siirtymiä.
 */
.pallolauta-merkki {
  pointer-events: none;
  transition: opacity 250ms ease-in-out;
  animation: pallolauta-ilmesty 250ms ease-out;
}
.pallolauta-merkki.pallolauta-takana,
.pallolauta-merkki.pallolauta-poistuu { opacity: 0; }
@keyframes pallolauta-ilmesty {
  from { opacity: 0; }
  to { opacity: 1; }
}
.pallolauta-nimi,
.pallolauta-nosto,
.pallolauta-piste {
  pointer-events: none;
  transform: translate(-50%, -50%);
}
.pallolauta-nimi svg,
.pallolauta-nosto svg,
.pallolauta-piste svg { display: block; overflow: visible; }
.pallolauta-nimi-siirto { transition: transform 250ms ease-in-out; }
/* Nimen muste ja kirjasin tulevat .karttanimi-luokasta (tasokartan sama
   sääntö); svg:n sisällä teksti asettuu keskilinjaan kuten kartalla. */
.pallolauta-nimi text { dominant-baseline: middle; }
/*
 * VESISTÖLINSSIN JOKINIMET PALLOLLA (js/linssit/vesistot.js pallolle).
 *
 * Tasokartalla nimet tulevat maastonimikerroksesta (.maastonimi-joki);
 * pallolla kerrosta ei ole, joten linssi tuo omat merkkinsä. Asu on sama
 * kuin kartalla — kaunokirjoitus kursiivina, meren muste — ja koko on
 * ruutuvakio kuten kaikilla pallon merkeillä (karttapallo.md luku 6).
 */
.pallolauta-vesinimi {
  pointer-events: none;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-family: var(--font-kauno);
  font-style: italic;
  font-size: 13px;
  letter-spacing: 0.06em;
  color: rgba(20, 44, 68, 0.98);
  text-shadow: 0 0 3px rgba(247, 241, 226, 0.85);
}

/*
 * MAAN NIMI PALLOLLA (vertailutila, js/vertailu.js aalto 1C). Sama
 * käsiala ja muste kuin tasokartan .vertailu-maa-nimi, mutta koko on
 * ruutuvakio: CSS2D-elementti ei skaalaudu pallon mukana, joten
 * tasokartan leveydestä laskettua kirjasinkokoa ei ole mistä ottaa.
 * Vaalea ääriviiva erottaa nimen laatan mereltä ja maalta.
 */
.pallolauta-maanimi {
  font-family: var(--font-hand);
  font-size: 13px;
  color: rgba(70, 51, 31, 0.85);
  white-space: nowrap;
  pointer-events: none;
  transform: translate(-50%, -50%);
  text-shadow:
    0 0 3px rgba(247, 237, 216, 0.85),
    0 0 3px rgba(247, 237, 216, 0.85);
}

/*
 * MAAT EDELLÄ, PELI VÄISTÄÄ — sama sääntö kuin tasokartalla
 * (body.vertailu-tila .cities/.tokens/.targets/.pawns): kun vertailu
 * tai maaselain on auki, pallon omat merkit väistyvät maakerroksen
 * tieltä. HUOM: kaupunkien PISTEET ovat Globe.gl:n pointsData eivätkä
 * DOM-elementtejä, joten ne eivät katoa css:llä — se on laudan oma
 * ehto (js/pallolauta/lauta.js pisteNakyy, kirjattu aallon 1C
 * raporttiin).
 */
body.vertailu-tila .pallolauta-nimi,
body.vertailu-tila .pallolauta-nosto,
body.vertailu-tila .pallolauta-piste,
body.vertailu-tila .pallolauta-kohde,
body.vertailu-tila .pallolauta-nappula,
body.maatiedot-tila .pallolauta-nimi,
body.maatiedot-tila .pallolauta-nosto,
body.maatiedot-tila .pallolauta-piste,
body.maatiedot-tila .pallolauta-kohde,
body.maatiedot-tila .pallolauta-nappula { display: none; }

/* Lunastettu eläintäky haalistuu kuten kartalla (js/elaintaky.js). */
.pallolauta-nosto.lunastettu { opacity: 0.55; }
.pallolauta-nosto.lunastettu.pallolauta-takana,
.pallolauta-nosto.lunastettu.pallolauta-poistuu { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .pallolauta-merkki { transition: none; animation: none; }
  .pallolauta-nimi-siirto { transition: none; }
}

/* ==========================================================================
   KEHITTÄJÄN KOHTAAMISLISTA (js/kohtaamistesti.js, omistajan tilaus
   5.9.2026: "Tarvitaan joku kehittäjätila missä pääsen testaamaan kaikki
   aarre kohtaamiset ja niiden tehtävä pelit listasta valitsemalla.
   Lajittele listat maanosien mukaan.").

   Lehti on kehittäjän työkalu, joten se pysyy pelin paperissa mutta
   tiiviinä: rivi kertoo kaupungin, henkilön, aiheen ja merkit yhdellä
   silmäyksellä. Kaikki liike animoidaan — dialogin avaus 250 ms.
   ========================================================================== */
.kohtaamistesti-kortti {
  width: min(680px, 94vw);
  animation: kohtaamistesti-auki 250ms ease-out;
}
@keyframes kohtaamistesti-auki {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
.kohtaamistesti-ylarivi {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
}
.kohtaamistesti-ylarivi h2 { margin-bottom: 0.2rem; }
.kohtaamistesti-selite {
  margin: 0 0 0.5rem;
  font-size: 0.85rem;
  opacity: 0.75;
}
.kohtaamistesti-tyokalut { margin-bottom: 0.6rem; }
.kohtaamistesti-vipu[aria-pressed="true"] {
  color: var(--accent);
  border-color: currentColor;
}
.kohtaamistesti-sisalto { display: flex; flex-direction: column; gap: 0.5rem; }

.kt-ryhma { display: flex; flex-direction: column; }
.kt-ryhma-otsikko {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6rem;
  width: 100%;
  padding: 0.4rem 0.2rem;
  background: none;
  border: 0;
  border-bottom: 1px solid rgba(70, 51, 31, 0.35);
  font-family: var(--font-type);
  font-size: 1rem;
  letter-spacing: 0.05em;
  color: inherit;
  cursor: pointer;
  text-align: left;
}
.kt-ryhma-otsikko[aria-expanded="true"] .kt-ryhma-nimi { color: var(--accent); }
.kt-ryhma-luku { font-size: 0.75rem; opacity: 0.7; }
.kt-rivit { display: flex; flex-direction: column; gap: 0.3rem; padding: 0.35rem 0 0.6rem; }
.kt-rivit.kt-avautuu { animation: kohtaamistesti-auki 250ms ease-out; }

.kt-rivi {
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
  width: 100%;
  padding: 0.4rem 0.5rem;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(70, 51, 31, 0.25);
  border-radius: var(--sketch-radius, 6px);
  color: inherit;
  cursor: pointer;
  text-align: left;
  transition: background 160ms ease-out, transform 160ms ease-out;
}
.kt-rivi:hover, .kt-rivi:focus-visible {
  background: rgba(255, 255, 255, 0.34);
  transform: translateX(2px);
}
.kt-rivi-yla { display: flex; align-items: baseline; gap: 0.45rem; }
.kt-kaupunki { font-family: var(--font-type); letter-spacing: 0.04em; }
.kt-henkilo { font-size: 0.8rem; opacity: 0.75; }
.kt-aihe { font-size: 0.82rem; opacity: 0.85; }
.kt-merkit { display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.2rem; }
.kt-merkki {
  padding: 0.05rem 0.36rem;
  border: 1px solid rgba(70, 51, 31, 0.35);
  border-radius: 999px;
  font-size: 0.68rem;
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.kt-merkki.on { border-color: rgba(60, 110, 60, 0.6); }
.kt-merkki.ei { border-color: rgba(150, 60, 40, 0.6); opacity: 0.85; }
.kt-merkki.kt-laji { background: rgba(70, 51, 31, 0.12); }
.kt-tyhja { margin: 0.2rem 0.2rem 0; font-size: 0.82rem; opacity: 0.7; }

.kt-kohde { display: flex; flex-direction: column; gap: 0.45rem; animation: kohtaamistesti-auki 250ms ease-out; }
.kt-osa-nimi {
  margin: 0.3rem 0 0;
  font-family: var(--font-type);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.75;
}
.kt-teksti { margin: 0; line-height: 1.5; }
.kt-huomio { margin: 0; font-size: 0.8rem; opacity: 0.8; }
.kt-napit { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.3rem; }

@media (prefers-reduced-motion: reduce) {
  .kohtaamistesti-kortti,
  .kt-kohde,
  .kt-rivit.kt-avautuu { animation: none; }
  .kt-rivi { transition: none; }
}
