/* Levydivarin avustin — mobiili edellä, ei riippuvuuksia. */

:root {
  --tausta: #14110f;
  --pinta: #1f1b19;
  --pinta2: #2a2422;
  --teksti: #ece7e3;
  --himmea: #a49a92;
  --korosto: #d97a3c;
  --vihrea: #5ea172;
  --punainen: #d1584f;
  --keltainen: #d8a33c;
  --reuna: #3a322e;
  --pyoristys: 10px;

  /* Tekstivärit värillisille pinnoille. Valkoinen teksti näiden päällä jää
     3,1:1 kontrastiin eli alle AA:n — ja juuri nämä ovat päänappi ja ainoa
     tallennusvahvistus. Käyttöpaikka on puhelin divarin valaistuksessa,
     joten kontrastissa ei ole varaa oikaista. Tumma teksti nostaa saman
     brändivärin päällä ~5,9:1:een. */
  --korosto-teksti: #241202;
  --vihrea-teksti: #06180d;
  --punainen-teksti: #2a0906;

  /* Toinen suunta: VÄRILLINEN teksti tummalla pinnalla. `--punainen` ja
     `--keltainen` ovat pintavärejä, eivät tekstivärejä — `--punainen`
     tekstinä jää `--pinta`lla 4,25:1 ja `--pinta2`lla 3,80:1 eli alle AA:n,
     ja `--pinta2` on juuri VALITUN ehdokkaan tausta. Painosvaroitus siis
     himmeni sillä hetkellä kun valinta tehtiin, ja se on se varoitus joka
     estää 10–50-kertaisen hintavirheen. Vaaleammat sävyt nousevat samoilla
     pinnoilla: punainen 8,48:1 / 7,59:1, keltainen 9,28:1 / 8,30:1.

     Älä sekoita `--punainen-teksti`in: se on TUMMA teksti punaisen PÄÄLLÄ,
     tämä on PUNAINEN teksti tumman päällä. Arvot ovat muuttujia siksi että
     ne olivat ennen hardkoodattuina neljässä säännössä — seuraava
     samankaltainen tapaus perii korjauksen vain jos se on muuttujassa. */
  --punainen-tummalla: #ff9c92;
  --keltainen-tummalla: #e5b955;

  /* Pienin sallittu kosketuskohde. */
  --kosketus: 44px;

  /* Kerrotaan selaimelle että paletti on tumma. Tämä EI ole kosmetiikkaa:
     ilman sitä selaimen oma tyylitaulu piirtää `select`-valikot,
     päivämääräkalenterin ja kirjoitusmerkin VAALEAN teeman arvoilla, eli
     valkoinen pudotusvalikko keskellä tummaa lomaketta. Vaikuttaa myös
     UA:n linkkiväreihin — mutta niihin ei jätetä nojaamaan, ks. `a` alla. */
  color-scheme: dark;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--tausta);
  color: var(--teksti);
  padding-bottom: env(safe-area-inset-bottom);
}

/* Vaakainsetit: maisematilassa iPhonen lovi ja pyoristetyt kulmat syovat
   ruudun reunoja, ja `viewport-fit=cover` (base.html) vie sisallon niiden
   alle. `max()` siksi etta puhelimessa jossa insettia ei ole padding pysyy
   ennallaan 1rem:issa — ilman sita korjaus kaventaisi 320 px:n ruutua. */
main {
  max-width: 640px; margin: 0 auto;
  padding: 1rem max(1rem, env(safe-area-inset-right))
           1rem max(1rem, env(safe-area-inset-left));
}

/* Paljas linkki. Tätä sääntöä EI ollut, ja se on eri vika kuin väärä väri:
   selaimen oma taulu asettaa `a:link { color: -webkit-link }`, joka osuu
   ELEMENTTIIN SUORAAN ja voittaa siksi periytymisen. `.banneri { color:
   var(--keltainen) }` ei siis värittänyt bannerin linkkiä lainkaan — se
   renderöityi oletussinisenä #0000EE, ja mock-varoituksen ainoa ulospääsy
   oli 1,38:1 (vierailtuna 1,18:1) eli käytännössä näkymätön. Pelkkä
   `color-scheme: dark` ei riitä: se jättää sävyn selaimen päätettäväksi.

   Kontrastit `--korosto`lle (AA-raja normaalille tekstille 4,5:1):
   --tausta 6,09:1 · --pinta 5,53:1 · --pinta2 4,95:1 · .varoitus 4,88:1.
   Savutesti laskee nämä eikä luota siihen että sääntö on olemassa. */
a { color: var(--korosto); }

/* Värillisillä paneeleilla `--korosto` jää 4,21:1:een eli ALLE AA:n, joten
   linkki perii lohkon oman tekstivärin joka on siellä jo todennettu:
   .banneri --keltainen 5,71:1 · .huomio peritty --teksti 10,59:1 ·
   .varoitus 12,27:1. Alleviivaus kantaa linkkimerkityksen kun väri ei erotu.

   `.tyhja` ja `.vihje` EIVÄT ole tässä listassa tarkoituksella: ne ovat
   `--tausta`lla jossa `--korosto` on 6,09:1, ja tyhjän tilan linkki on
   näkymän ainoa toiminto — sen himmentäminen veisi korostuksen juuri siltä
   mitä pitäisi napauttaa.

   Huomaa että `<a class="huomio linkkilaatikko">` on itse paneeli eikä sen
   jälkeläinen, joten tämä sääntö ei osu siihen — sen hoitaa
   `.linkkilaatikko`n oma `color: inherit`. */
.huomio a, .varoitus a, .banneri a {
  color: inherit; text-decoration: underline;
}

/* Kirjoitusvihje. Selaimen oletus on harmaa joka on viritetty VAALEALLE
   pohjalle; tummalla se jää lukukelvottomaksi. `opacity: 1` on pakollinen:
   Firefox himmentää placeholderin erikseen läpinäkyvyydellä, joten pelkkä
   väri ei riitä. `--himmea` on 6,82:1 `--tausta`lla ja 6,20:1 `--pinta`lla. */
::placeholder { color: var(--himmea); opacity: 1; }

/* Navigaatio — puhelin edella.
   Rivilla pysyvat vain Skannaa ja Tunnista; muu on valikkonapin takana,
   koska koko rivi ei mahtunut 360px:n leveyteen. Leveasta 700px:sta
   ylospain nappi katoaa ja valikon sisalto asettuu riville. */
/* Ylainsetti tahan eika bodyyn: navi on `position: sticky; top: 0`, joten se
   liimautuu ruudun ylareunaan — `viewport-fit=cover`illa se on tilapalkin ja
   loven ALLA, eli valikko jaa niiden peittoon. Bodyn padding ei auta koska
   sticky irtoaa siita vierittaessa. Alareuna on hoidettu bodyssa.
   Kauppiaan laite on iPhone (`iPhone OS 18_7`, 320x553) — mitattu palautteen
   #58 kontekstista 9.9.2026, ja se on vastaus auditoinnin K2-css-4:aan joka
   oli auki nelja kierrosta muodossa "onko kaverilla iPhone". */
.navi {
  display: flex; gap: .5rem; align-items: center;
  background: var(--pinta); border-bottom: 1px solid var(--reuna);
  padding: max(.5rem, env(safe-area-inset-top))
           max(1rem, env(safe-area-inset-right))
           .5rem max(1rem, env(safe-area-inset-left));
  position: sticky; top: 0; z-index: 10;
}
.navi a {
  display: inline-flex; align-items: center;
  min-height: var(--kosketus);   /* peukalolle, myos valikon sisalla */
  color: var(--himmea); text-decoration: none;
  padding: .5rem .9rem; border-radius: var(--pyoristys); font-weight: 500;
}
.navi a.aktiivinen { background: var(--pinta2); color: var(--teksti); }

/* Valikkonappi. Ikonin rinnalla on sana: kolme viivaa yksin ei kerro
   ruudunlukijalle eika kiireiselle mitaan. */
.navi-nappi {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: .4rem;
  min-height: var(--kosketus); padding: .5rem .8rem;
  background: none; border: 1px solid var(--reuna);
  border-radius: var(--pyoristys);
  color: var(--teksti); font: inherit; cursor: pointer;
}
.navi-nappi.aktiivinen,
.navi-nappi[aria-expanded="true"] { background: var(--pinta2); }

/* Valikko kelluu navin alla eika tyonna sisaltoa: sivu jaa normaalisti
   vieritettavaksi eika sticky-palkki kasva puolen ruudun korkuiseksi.
   Sijoittelun ankkuri on `.navi` (position: sticky). */
.navi-valikko {
  display: none;
  position: absolute; top: 100%; right: .5rem;
  flex-direction: column; gap: .25rem;
  min-width: 11rem; padding: .5rem;
  background: var(--pinta); border: 1px solid var(--reuna);
  border-radius: var(--pyoristys); box-shadow: 0 8px 24px rgba(0, 0, 0, .5);
}
.navi-valikko.auki { display: flex; }
/* Lomake tarvitaan koska uloskirjautuminen on POST — GET-linkki
   uloskirjaisi kuvan latauksesta. */
.navi-valikko form { margin: 0; }
.navi-ulos {
  display: inline-flex; align-items: center; width: 100%;
  min-height: var(--kosketus);
  background: none; border: none; cursor: pointer; font: inherit;
  color: var(--himmea); padding: .5rem .9rem; border-radius: var(--pyoristys);
}
.navi-ulos:active { background: var(--pinta2); }

@media (min-width: 700px) {
  .navi-nappi { display: none; }
  .navi-valikko {
    display: flex; flex-direction: row; align-items: center;
    position: static; margin-left: auto;
    min-width: 0; padding: 0;
    background: none; border: none; box-shadow: none;
  }
  .navi-ulos { width: auto; padding: .5rem .6rem; }
}

.banneri {
  background: #3d2f14; color: var(--keltainen);
  padding: .6rem 1rem; font-size: .875rem; text-align: center;
}
.banneri code { background: rgba(0,0,0,.3); padding: .1rem .35rem; border-radius: 4px; }

/* Kuvapaikat — vakiojärjestys: kansi, takakansi, sisälehti, keskiötarra,
   runout */
.kuvapaikat {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: .5rem; margin-bottom: .5rem;
}
.kuvapaikka {
  position: relative; aspect-ratio: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .15rem;
  background: var(--pinta) center/cover no-repeat;
  border: 2px dashed var(--reuna); border-radius: var(--pyoristys);
  cursor: pointer; font-size: .75rem; color: var(--himmea);
  text-align: center; padding: .3rem; overflow: hidden;
}
.kuvapaikka:active { border-color: var(--korosto); }
.kuvapaikka .numero {
  position: absolute; top: .3rem; left: .4rem;
  font-size: .6875rem; font-weight: 700; color: var(--himmea);
}
.kuvapaikka .tila { font-size: 1.5rem; line-height: 1; }
.kuvapaikka.taytetty {
  border-style: solid; border-color: var(--vihrea); color: transparent;
}
.kuvapaikka.taytetty::after {
  content: ""; position: absolute; inset: 0; background: rgba(0,0,0,.35);
}
.kuvapaikka.taytetty .paikkanimi, .kuvapaikka.taytetty .numero {
  position: relative; z-index: 1; color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.9);
}
.kuvapaikka.taytetty .tila {
  position: relative; z-index: 1; color: var(--vihrea);
  text-shadow: 0 1px 3px rgba(0,0,0,.9);
}

/* Poistonappi: nakyy vain taytetylle paikalle. Kosketuskohde on 44 px
   (min-width/height), vaikka merkki on pienempi — sormella osuminen ei saa
   vaatia tahtaamista. Ylakulmassa siksi etta paikan keskiosa jaa vapaaksi
   kuvan vaihtamiselle, joka on yleisempi tarve kuin poisto. */
.kuvapaikka .poista { display: none; }
.kuvapaikka.taytetty .poista {
  display: flex; align-items: center; justify-content: center;
  position: absolute; top: 0; right: 0; z-index: 2;
  min-width: 44px; min-height: 44px; padding: 0;
  border: 0; background: none; cursor: pointer;
  font-size: 1.125rem; line-height: 1; color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.9);
}
.kuvapaikka.taytetty .poista:active { color: var(--punainen); }

/* Kuvagalleria */
.kuvagalleria {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  gap: .5rem; margin-bottom: 1rem;
}
.kuvagalleria figure { margin: 0; }
.kuvagalleria img {
  width: 100%; aspect-ratio: 1; object-fit: cover;
  border-radius: 8px; background: var(--pinta); display: block;
}
.kuvagalleria figcaption {
  font-size: .6875rem; color: var(--himmea);
  text-align: center; margin-top: .2rem;
}

/* Kuvan hallinta levynäkymässä: rooli ja poisto kuvan alla.
   Molemmat ovat peukalokohteita, joten kumpikaan ei kutistu alle 44 px:n —
   kuvat katsotaan ja järjestetään puhelimella hyllyjen välissä. */
.kuvaohjaus {
  display: flex; flex-direction: column; gap: .3rem; margin-top: .3rem;
}
.kuvaohjaus .kuvarooli {
  min-height: var(--kosketus); font-size: .8125rem; padding: .4rem .5rem;
}
.kuvaohjaus .nappi { width: 100%; text-align: center; align-self: stretch; }

/* Lisää kuvia -lohko. Suljettunakin näkyvä otsikko: juuri tämän
   puuttuminen oli alkuperäinen vika, joten sitä ei piiloteta. */
.lisakuvat {
  background: var(--pinta); border: 1px solid var(--reuna);
  border-radius: var(--pyoristys); padding: .75rem; margin-bottom: 1rem;
}
.lisakuvat > summary {
  cursor: pointer; font-weight: 600; list-style-position: inside;
  min-height: var(--kosketus); display: flex; align-items: center;
}
.lisakuvat[open] > summary { margin-bottom: .5rem; }
.lisakuvat .vihje { margin-bottom: .5rem; }

/* Kytkimet ja liput */
.tilavalinta { margin-bottom: .75rem; }
.kytkin {
  flex-direction: row; align-items: center; gap: .5rem;
  cursor: pointer; color: var(--teksti); font-size: .875rem;
  min-height: var(--kosketus);   /* työnkulun tärkein valinta, oli 21px */
}
.kytkin input { width: auto; flex-shrink: 0; }
.lippurivi { display: flex; gap: 1.25rem; flex-wrap: wrap; }

/* Otsikko + lippu yhtenä flex-itemina. `label` on pystyflex, joten
   irrallinen lippu-span putoaisi omalle rivilleen kentän otsikon alle —
   juuri siinä merkinnässä joka kertoo päätyykö teksti myynti-ilmoitukseen. */
.kentta-otsikko {
  display: flex; align-items: center; gap: .4rem; flex-wrap: wrap;
}

/* `.lippu` = JULKISUUSMERKINTÄ, eikä mitään muuta. Kaksi arvoa: menee
   ostajalle (`julkinen`) tai ei mene (`sisainen`). Profiilin `tila-*`
   -variantit ovat saman merkin laajennus samaan kysymykseen — ne kertovat
   pääseekö avain ulos palvelusta.

   Rajaus on kirjoitettu tähän koska merkki laimeni kerran yleismerkiksi:
   se tarkoitti yhtä aikaa tietosuojaa, tarkistamattomuutta, keksittyä
   mock-dataa, hintalähdettä ja avaimen tilaa. Jokainen lisäys oli
   perusteltu yksinään, ja lopputulos oli merkki joka ei varoita mistään —
   ja juuri tämä merkki vartioi periaatetta 2b (oma arvio ei päädy
   myynti-ilmoitukseen). Merkin arvo on ainutlaatuisuudessa, ei värissä.

   Tilatieto ja metatieto kuuluvat `.merkki`in, eivät tänne. */
.lippu {
  display: inline-block; padding: .1rem .45rem; border-radius: 4px;
  font-size: .6875rem; font-weight: 700; text-transform: uppercase;
  vertical-align: middle; letter-spacing: .02em;
}
/* Kontrasti oli 4,0:1 — alle AA:n, ja tämä on pienin teksti sivulla. */
.lippu.julkinen { background: #16301f; color: #86d3a0; }
.lippu.sisainen { background: #3a1613; color: var(--punainen-tummalla); }

/* Avaimen tila profiilissa. Neljä eri asiaa, joita kaksi väriä ei erota:
   avainta ei ole / avain on mutta sitä ei ole kokeiltu / kokeiltu ja toimii
   / avain on tallessa mutta ei aukea. Aiemmin kaikki näkyivät samana
   punaisena `sisainen`-lippuna, ja tallennettu avain näytti siltä kuin
   jotain olisi vialla (palaute #4). Väri on toisto, sana kertoo tilan. */
.lippu.tila-puuttuu  { background: var(--pinta2); color: var(--himmea); }
.lippu.tila-asetettu { background: #3d2f14; color: var(--keltainen-tummalla); }
.lippu.tila-toimii   { background: #16301f; color: #86d3a0; }
.lippu.tila-rikki    { background: #3a1613; color: var(--punainen-tummalla); }
.sisainen-teksti {
  background: var(--pinta); border-left: 3px solid var(--punainen);
  padding: .6rem .8rem; border-radius: 0 8px 8px 0; font-style: italic;
}

/* Sanelu */
.sanelu-lohko { display: flex; flex-direction: column; gap: .5rem; }
.vihje { color: var(--himmea); font-size: .8125rem; margin: 0; }

/* Napit */
.nappi {
  padding: .8rem 1.1rem; border: none; border-radius: var(--pyoristys);
  font-size: 1rem; font-weight: 600; cursor: pointer; font-family: inherit;
}
/* Nappi joka on linkki. Viisi käyttöpaikkaa kantaa saman inline-merkkijonon
   kopiona (`havainnot.html`in YouTube-▶ näkyvimpänä), ja kaikki saivat UA:n
   alleviivauksen: nuolen alla oli viiva. Alleviivaus pois `.nappi`sta eikä
   `a`:sta — nappi ei ole navigointivihje vaan toiminto.

   `display` on tässä JAETTU KAHTIA tarkoituksella. `.nappi` ei saa asettaa
   sitä: author-tason `display` voittaa selaimen `[hidden] { display: none }`
   -säännön, ja «Aloita alusta» on `<button class="nappi …" hidden>` eli se
   olisi näkyvissä aina. Linkkiä ei koskaan piiloteta `hidden`illä, joten
   `a.nappi` saa sen turvallisesti — ja tarvitseekin, koska pystypadding ei
   vaikuta inline-elementin korkeuteen. Savutestin vahti on rajattu niin
   että se päästää tämän läpi mutta ei paljasta `.nappi`a. */
.nappi { text-decoration: none; }
a.nappi { display: inline-block; }

.nappi.ensisijainen { background: var(--korosto); color: var(--korosto-teksti); flex: 1; }
.nappi.toissijainen {
  background: var(--pinta2); color: var(--teksti);
  border: 1px solid var(--reuna);
}
/* `pieni` on hierarkiamerkki, ei kosketuskohteen koko: sitä käytetään myös
   sivun päätoiminnossa. Korkeus pysyy peukalolle riittävänä. */
.nappi.pieni {
  padding: .6rem .9rem; font-size: .875rem; align-self: flex-start;
  min-height: var(--kosketus);
}
.nappi:disabled { opacity: .5; cursor: not-allowed; }

/* Kauppiaan omat genresanat napautettaviksi genrekentän alla.
   `flex-wrap` on se mikä tekee tästä käytettävän: laite on 320 px leveä,
   ja rivittymätön lista työntäisi lomakkeen ulos ruudusta vaakasuunnassa.
   Sanat ovat lyhyitä (`italodisco`, `swing`), joten kahdeksan mahtuu
   kahdelle riville. */
.genresanat {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .4rem; margin: -.25rem 0 .75rem;
}
.genresanat .vihje { margin: 0; }
/* Peruuttamaton toiminto. Väri on varoitus, ei koriste — tämä on ainoa nappi
   sovelluksessa joka hävittää dataa lopullisesti. */
.nappi.vaarallinen {
  background: var(--punainen); color: var(--punainen-teksti);
}
/* Viritetty vahvistusnappi: seuraava painallus tekee sen mitä nappi sanoo.
   Sama väri kuin `vaarallinen`, koska seuraus on sama — ero on siinä että
   tähän tilaan päädytään yhdellä painalluksella ja siitä pääsee pois
   odottamalla. Myös teksti vaihtuu, joten merkitys ei jää värin varaan. */
.nappi.varmistus {
  background: var(--punainen); color: var(--punainen-teksti);
  border-color: var(--punainen);
}

/* Nappi joka näyttää linkiltä: "valitse kaikki" on toiminto eikä navigointi,
   joten se on <button>, mutta se ei saa kilpailla varsinaisten nappien
   kanssa huomiosta. */
.linkkinappi {
  background: none; border: none; padding: 0; font: inherit;
  color: var(--korosto); text-decoration: underline; cursor: pointer;
}
#sanelunappi.nauhoittaa {
  background: var(--punainen); color: var(--punainen-teksti);
  animation: syke 1.2s ease-in-out infinite;
}
@keyframes syke { 50% { opacity: .6; } }
/* Täydennyksen sanelunappi sykkii samalla tavalla (task 084): kahdesta
   sanelusta vain yksi on kerrallaan päällä, ja sen pitää näkyä kummasta. */
#taydenna-sanele.nauhoittaa {
  background: var(--punainen); color: var(--punainen-teksti);
  animation: syke 1.2s ease-in-out infinite;
}
/* Sanelun välitulos kentän alla (task 084). Harmaa ja kursiivi: se ei ole
   vielä kentän arvo eikä päädy tallennukseen. */
.sanelu-valitila {
  flex-basis: 100%; color: var(--himmea); font-style: italic;
  font-size: .9rem;
}

/* Lomake */
input, select, textarea {
  width: 100%; padding: .65rem .75rem;
  background: var(--pinta); color: var(--teksti);
  border: 1px solid var(--reuna); border-radius: 8px;
  font-size: 1rem; font-family: inherit;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--korosto); outline-offset: -1px;
}
label {
  display: flex; flex-direction: column; gap: .25rem;
  font-size: .8125rem; color: var(--himmea); font-weight: 500;
}
.lomake { display: flex; flex-direction: column; gap: .85rem; margin-top: 1rem; }
/* `minmax(0, 1fr)` eika `1fr`: `1fr` on lyhenne `minmax(auto, 1fr)`:sta, ja
   se `auto` on sarakkeen POHJA jota ei voi alittaa. Kentan oma vahimmaisleveys
   johtuu `size`-attribuutista (oletus 20 merkkia) eika `width: 100%`:sta,
   joten kaksi kenttaa vierekkain voi vaatia enemman kuin ruutu antaa — ja
   silloin ruudukko ei kavenna vaan tyontaa sivun vaakavieritykselle. Nolla
   pohjaksi paastaa sarakkeen kutistumaan; leveilla ruuduilla mikaan ei muutu,
   koska `1fr` jakaa tilan samoin. Kauppiaan ruutu on 320 px leve, ja
   tyylitiedosto on kirjoitettu 360 px:n oletukselle. */
.rivi { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: .75rem; }
.rivi.kolme { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 480px) {
  .rivi, .rivi.kolme { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* Kentta joka odottaa ihmisen arviota. Tyhja kunto ei ole virhe eika
   puute vaan tunnistuksen oikea tulos: kone ei nae kannen kuntoa kuvasta,
   ja kauppias arvioi sen levy kadessa. Siksi tama on korostus (--korosto)
   eika hylkays (--punainen) — punainen kehottaisi korjaamaan jotain
   rikkinaista, tama kehottaa tekemaan tyon jota kone ei voi tehda. */
.lomake select.kysytaan { border-color: var(--korosto); }
/* Sama korostus catno-kentalle (task 083): numero jota kannattaa katsoa
   keskiotarraa vasten. Ei punainen samasta syysta — kone ei tieda kumpi on
   oikein, kauppias ratkaisee. */
.lomake input.kysytaan { border-color: var(--korosto); }

.toiminnot { display: flex; gap: .75rem; margin-top: .5rem; }

/* Ehdokkaat */
#ehdokkaat h3 { font-size: .9375rem; margin: 1.25rem 0 .5rem; color: var(--himmea); }
.ehdokas {
  display: flex; flex-direction: column; gap: .2rem; width: 100%;
  text-align: left; padding: .75rem; margin-bottom: .5rem;
  background: var(--pinta); color: var(--teksti);
  border: 1px solid var(--reuna); border-radius: 8px;
  cursor: pointer; font-family: inherit;
}
/* Painallus ja valinta eivät saa näyttää samalta. Ennen `:active` antoi
   täsmälleen valitun taustan, joten valitsemattoman ehdokkaan painaminen
   näytti hetken valinnalta — ja jos sormi liukui pois, mitään ei valittu
   mutta kauppias luuli. Painallus on nyt liike, valinta väri ja merkki. */
.ehdokas:active { transform: scale(.99); }

/* Valinta on sovelluksen kalleimman virheen paikka: valittu painos määrää
   release_id:n ja sen kautta hinnan, ja sama albumi eri painoksina eroaa
   arvoltaan 10–50-kertaisesti. Siksi signaali ei ole 1 px reunaväri vaan
   paksu palkki, tausta ja ✓ — palkki ja merkki näkyvät myös silloin kun
   väri ei erotu: hämärä divari, heijastava ruutu, värisokeus.
   Sama tila kahdessa näkymässä (skannaus `.ehdokas`, tunnistus
   `.ehdokaslista li`), koska valinta tarkoittaa molemmissa samaa. */
.ehdokas.valittu, .ehdokaslista li.valittu {
  border-color: var(--korosto);
  background: var(--pinta2);
  box-shadow: inset 4px 0 0 var(--korosto);
}
.valittu > .ehdokas-nimi::after {
  content: " ✓"; color: var(--korosto); font-weight: 700;
}

/* «Vastaa kannen tietoja» EI OLE VALINTA vaan huomio siitä mihin katse
   kannattaa kohdistaa. Ero valintaan on tehty tarkoituksella isoksi: jos
   merkintä näyttäisi valinnalta, kauppias ei napauttaisi — ja juuri napautus
   on se ainoa asia joka tekee `painos_vahvistettu`sta totta, eli ilman sitä
   `release_id` jäisi sitomatta.

   Katkoviiva ilman taustaa ja ilman ✓:ta, eli kolme eroa yhtä aikaa: valinnan
   signaali on yhtenäinen palkki + tausta + ✓. Sama teema vaaleampana olisi
   juuri se virhe jota vältetään — himmeämpi versio samasta merkistä luetaan
   "melkein valittuna", ei eri asiana. Vihreä eikä `--korosto`: valinnan väri
   on varattu valinnalle. */
.ehdokaslista li.ehdotettu {
  border-left: 4px dashed var(--vihrea);
  padding-left: calc(.75rem - 3px);
}
/* Perustelu omalle rivilleen ja himmeänä: se kertoo MIKSI merkki on siinä,
   eikä saa kilpailla ehdokkaan omien tietojen kanssa. */
.ehdokas-vastaavuus {
  flex-basis: 100%; font-size: .8125rem; color: var(--himmea);
}
/* Kehotus katoaa kun se on tehty, perustelu jää. Valitulla rivillä luki
   ✓:n vieressä yhä "valitse jos tämä on oikea painos" — jo tehdyn asian
   pyytäminen toista kertaa näyttää siltä ettei edellistä huomattu (todettu
   selaimessa tuotannossa 11.8.2026). Perustelu on hyödyllinen myös valinnan
   jälkeen: se kertoo miksi juuri tämä rivi on se oikea.

   CSS eikä JS: `Ehdokkaat.korosta` ei piirrä listaa uudelleen, joten teksti
   säilyisi sellaisenaan — mutta luokka on jo rivillä, joten mitään ei tarvitse
   kertoa kahdesti. */
.ehdokaslista li.valittu .ehdokas-kehotus { display: none; }
.ehdokas-nimi { font-weight: 600; }
.ehdokas-meta { font-size: .8125rem; color: var(--himmea); }

/* Painoserottelu. Määre erottuu himmeästä metarivistä, koska se on usein
   ainoa ero kahden muuten identtisen ehdokkaan välillä — ja se ero on se
   jossa raha on. Varoitus on eri väri: se ei ole levyn ominaisuus vaan
   kertoo ettei valintaa voi tehdä näkyvän tiedon perusteella. */
.ehdokas-painos { display: block; margin-top: .3rem; font-size: .8125rem; }
.painosmerkki {
  display: inline-block; padding: .1rem .45rem; border-radius: 4px;
  background: var(--pinta2); color: var(--teksti); font-weight: 600;
}
/* Tekstiväri, ei pintaväri: `--punainen` jäi tässä 4,25:1 / 3,80:1:een, ja
   nimenomaan `--pinta2` eli valitun rivin tausta oli se huonompi. */
.painosvaroitus {
  display: block; margin-top: .25rem; color: var(--punainen-tummalla);
}
/* Painosmerkin tausta oli sama kuin valitun rivin tausta, eli juuri se tieto
   joka ratkaisee hinnan katosi sillä hetkellä kun rivi valittiin. */
.valittu .painosmerkki { background: var(--tausta); }
.ehdokaslista .ehdokas-painos { flex-basis: 100%; }

/* Varoitukset */
.varoitus, .huomio {
  padding: .75rem 1rem; border-radius: 8px;
  margin-bottom: 1rem; font-size: .875rem;
}
.varoitus { background: #3a1f1d; border-left: 3px solid var(--punainen); }
.huomio { background: #3d2f14; border-left: 3px solid var(--keltainen); }
.varoitus ul { margin: .5rem 0 0; padding-left: 1.1rem; }
.varoitus li { margin-bottom: .25rem; }

/* Lataus */
.lataus { text-align: center; padding: 4rem 1rem; color: var(--himmea); }
.pyoriva {
  width: 36px; height: 36px; margin: 0 auto 1rem;
  border: 3px solid var(--reuna); border-top-color: var(--korosto);
  border-radius: 50%; animation: pyori .8s linear infinite;
}
@keyframes pyori { to { transform: rotate(360deg); } }

/* Ilmoitus */
.ilmoitus {
  position: fixed; left: 1rem; right: 1rem;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  max-width: 608px; margin: 0 auto;
  background: var(--vihrea); color: var(--vihrea-teksti);
  padding: .85rem 1rem; border-radius: var(--pyoristys);
  font-weight: 600; text-align: center; z-index: 20;
}
.ilmoitus.virhe { background: var(--punainen); color: var(--punainen-teksti); }
/* Linkki ilmoituksessa (esim. juuri tallennettu levy). Oma kosketuskorkeus:
   ilmoitus on ruudun alalaidassa ja linkkiin osutaan peukalolla. */
.ilmoitus a {
  color: inherit; font-weight: 700; text-decoration: underline;
  display: inline-block; padding: .35rem .5rem; min-height: var(--kosketus);
}

/* Varastolista.

   Tilastolaatikoita on seitsemän, ja `minmax(110px)` mahtui 360 px:n
   puhelimella vain kahteen sarakkeeseen: neljä riviä à ~76 px eli ~353 px
   ennen kuin hakukenttää näkyi lainkaan — ja huomiolaatikoiden kanssa
   ensimmäinen levy oli ~660 px alaspäin. Varasto on listanäkymä, joten
   listan pitää näkyä.

   96 px on laskettu eikä valittu: 3 × 96 + 2 × 9,6 (gap) = 307 px mahtuu
   siihen 328 px:ään joka jää `main`in 1rem-paddingin jälkeen. Kolme
   saraketta ja matalampi laatikko vievät korkeuden ~353 px:stä ~226 px:ään.
   Savutesti laskee saman rajan uudelleen, joten arvoa ei voi nostaa
   huomaamatta takaisin. Yhtään laatikkoa ei poistettu — mitä mitataan on
   sisältöpäätös, ei tyylikysymys. */
.tilastot {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: .6rem; margin-bottom: 1.25rem;
}
.tilasto {
  background: var(--pinta); border: 1px solid var(--reuna);
  border-radius: 8px; padding: .5rem;
}
/* `overflow-wrap`, koska luku voi olla «12345 €»: kapeassa laatikossa se
   vuoti ulos reunan yli sen sijaan että olisi katkennut. */
.tilasto .luku {
  font-size: 1.1rem; font-weight: 700; display: block;
  overflow-wrap: anywhere;
}
.tilasto .selite { font-size: .75rem; color: var(--himmea); }

.hakupalkki { display: flex; gap: .5rem; margin-bottom: 1rem; }

.levylista { display: flex; flex-direction: column; gap: .5rem; }

/* Siivous: valintaruutu rivin vieressä. Kehys on aina paikallaan mutta ruutu
   piilossa, jotta listan asettelu ei hyppää kun siivous kytketään päälle. */
.levyrivi-kehys { display: flex; align-items: center; gap: .5rem; }
.levyrivi-kehys > .levyrivi { flex: 1; min-width: 0; }
.valintaruutu { display: none; }
body.siivous .valintaruutu {
  display: flex; align-items: center; justify-content: center;
  min-width: var(--kosketus); min-height: var(--kosketus);
  flex: none; cursor: pointer;
}
.valintaruutu input { width: 22px; height: 22px; cursor: pointer; }
/* Poisto levynäkymässä: kiinni kunnes avataan. Sama ajatus kuin siivoustilassa
   — peruuttamaton toiminto ei ole yhden osuman päässä. */
.poistolohko summary {
  cursor: pointer; color: var(--himmea); font-size: .875rem;
  min-height: var(--kosketus); display: flex; align-items: center;
}
.poistolohko .vihje { margin: .5rem 0 .75rem; }
.siivousrivi {
  display: flex; align-items: center; gap: .75rem;
  flex-wrap: wrap; margin-bottom: 1rem;
}
.levyrivi {
  display: flex; gap: .75rem; align-items: center;
  background: var(--pinta); border: 1px solid var(--reuna);
  border-radius: 8px; padding: .6rem; text-decoration: none; color: inherit;
}
.levyrivi img {
  width: 52px; height: 52px; object-fit: cover;
  border-radius: 6px; background: var(--pinta2); flex-shrink: 0;
}
.levyrivi .tiedot { flex: 1; min-width: 0; }
.levyrivi .nimi {
  font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis;
}
.levyrivi .meta { font-size: .8125rem; color: var(--himmea); }
.levyrivi .hinta { font-weight: 700; color: var(--korosto); white-space: nowrap; }

.merkki {
  display: inline-block; padding: .1rem .45rem; border-radius: 4px;
  font-size: .6875rem; font-weight: 600; text-transform: uppercase;
  background: var(--pinta2); color: var(--himmea);
}
/* `--vihrea` on PINTAvari eika tekstivari — sama ansa joka on kirjoitettu
   auki `--punainen-tummalla`n kohdalla ylla. Vihrealla merkkitaustalla se
   jai 4,02:1:een eli alle AA:n, ja tama on varastolistan yleisin merkki.
   Vika oli olemassa ennen tata tehtavaa; se paljastui vasta kun merkkien
   kontrastit alettiin LASKEA testissa. Vaaleampi savy nostaa saman vihrean
   5,99:1:een. Literaali eika muuttuja, koska kayttopaikkoja on yksi —
   sama ratkaisu kuin `.merkki.valmis`illa. */
.merkki.varasto { background: #1f3a2a; color: #7cc492; }
.merkki.myynnissa { background: #3d2f14; color: var(--keltainen); }

/* «Myyty» oli tavu tavulta sama kuin paljas `.merkki`, ja `varasto.html`
   renderöi SAMALLE RIVILLE «myyty» ja «ei myytävä» — levyn elinkaaren
   päätepiste ja kauppiaan asettama lippu pikselintarkasti identtisinä.

   Täyttö pois, ei tummempi täyttö: mitattuna merkkien taustat eivät tällä
   luminanssialueella erotu toisistaan lainkaan — `--pinta2` erottuu
   `--pinta`-kortista 1,12:1 ja `--tausta` 1,10:1. «Himmeämpi pilleri» olisi
   siis taas se virhe josta tämä tiedosto varoittaa kahdessa muussa
   kommentissa: ainoa ero olisi 11 px:n versaalisana. Ilman täyttöä `myyty`
   on omassa perheessään (ei täyttöä, ei ääriviivaa = vähiten painoarvoa),
   ja se on lopputilalle oikein: myyty levy ei enää odota mitään.

   Ääriviiva olisi väärä: `.merkki.epavarma` ja `.merkki.ehdotettu` ovat jo
   ääriviivamerkkejä ja kertovat tiedon luotettavuudesta, eivät tilasta.
   Teksti `--himmea` 6,20:1 `--pinta`-kortilla ja 6,82:1 levysivun
   `--tausta`lla — kumpi pinta osuu, riippuu näkymästä. */
.merkki.myyty { background: none; color: var(--himmea); }

/* Havainto = kirppiksellä nähty levy jota EI omisteta. Sitä ei ollut
   lainkaan, joten havaintolevyn tila renderöityi `.merkki`n oletusharmaana
   eli samana kuin «ei myytävä».

   Sininen siksi että omistettujen tilojen sävyt ovat varattuja (vihreä
   varasto, keltainen myynnissä, oranssi triage) ja koska `.merkki.oma`
   (#2a2440, lavendeli) renderöityy SAMALLE RIVILLE tilamerkin kanssa —
   sävyero 211° vs 253° pitää ne erillään myös 11 px:n koossa. Sininen
   sanoo «tuolla jossain», mikä on havainnon koko merkitys.
   Teksti 7,91:1. */
.merkki.havainto { background: #1b2c3e; color: #9cc6ea; }

/* Tiedon luotettavuus, ei levyn tila: «tarkistamatta» ja «KEKSITTY (mock)».
   Nämä olivat ennen `.lippu.sisainen`ia eli hälytyspunaisia — sama merkki
   kuin tietosuojavaroitus, vaikka kyse on aivan eri asiasta.

   Ääriviiva täytön sijaan on tarkoituksellinen: `.merkki.myynnissa` ja
   `.merkki.triage` ovat jo täytettyjä keltaisia, ja niiden kanssa
   pikselintarkasti sama ulkoasu on virhe joka on tehty tässä tiedostossa
   kertaalleen ennenkin. Kehys erottaa varauksen tilamerkeistä vilkaisulla.
   Teksti 9,28:1 pinnalla, kehys 3,22:1 (ei-tekstille riittää 3:1). */
.merkki.epavarma {
  background: var(--pinta); color: var(--keltainen-tummalla);
  box-shadow: inset 0 0 0 1px #8a6520;
}

/* «VASTAA KANTTA» kertoo tiedon luotettavuudesta samoin kuin `epavarma`, joten
   se on samaa perhettä: ääriviiva, ei täyttö. Ero on sävy — keltainen sanoo
   "tätä ei ole varmistettu", vihreä "tämä vastaa sitä mitä kannesta luettiin".

   Täyttö olisi tässä nimenomaan väärä: `.merkki.varasto` on jo TÄYTETTY
   vihreä, ja se on levyn TILA eikä väite tiedon osuvuudesta. Kaksi eri asiaa
   samannäköisenä on virhe joka on tässä tiedostossa tehty kertaalleen jo
   ennenkin. Teksti 5,62:1 pinnalla, kehys 3,68:1 (ei-tekstille riittää 3:1). */
.merkki.ehdotettu {
  background: var(--pinta); color: var(--vihrea);
  box-shadow: inset 0 0 0 1px #4a7f5b;
}

.tyhja { text-align: center; padding: 3rem 1rem; color: var(--himmea); }

/* Hintahaku levynäkymässä: nappi ja sen tulos omana lohkonaan tietojen
   alla, ei korjauslomakkeen sisällä. Hinta on katselutietoa — lomakkeen
   sisällä se jäi fold-rajan alle eikä sitä löytynyt. */
.hintalohko { margin: 1rem 0 1.25rem; }
.hintalohko .vihje { margin-top: .4rem; }

/* Kaikki vierityksen kohteet vieritetään näkyviin napautuksesta (osat.js,
   `Markkina.vierita`). Navi on `position: sticky; top: 0` ja mitattuna 61 px
   korkea, ja `scrollIntoView({block:"start"})` vie kohteen yläreunan
   viewportin yläreunaan — eli suoraan navin alle piiloon. Ilman tätä varaa
   kauppias näkisi vieritetyn lohkon otsikon puolittain palkin takaa, mikä
   näyttää siltä että ruutu pysähtyi väärään kohtaan.

   `#hintarivi` on paluusuunnan kohde: hintataulun "Käytä" vie kauppiaan
   takaisin siihen riviin johon hinta juuri kirjoittui. Ilman varaa navi
   peittäisi juuri myyntihintakentän eli sen mitä hän tuli katsomaan. */
.hintalohko, #markkina, #hintarivi { scroll-margin-top: 4.5rem; }
/* Levysivun myyntiosio on ankkurilinkin kohde (`#myyntiin`, task 080):
   sama navi peittäisi sen otsikon. */
#myyntiin { scroll-margin-top: 4.5rem; }

/* Tulosvaiheessa navin alla on lisäksi tarttuva palkki (task 080), joten
   varaa tarvitaan molempien verran. Korkeudet mittaa `skannaa.js`
   (`--navi-korkeus`, `--palkki-korkeus`): navi kasvaa puhelimen loven
   verran ja palkki rivittyy kapealla ruudulla, joten kiinteä luku olisi
   väärin jossain laitteessa. Varaluvut ovat 360 px:n mitat. `#t-nimi` on
   automaattivierityksen kohde (speksi K5). */
#vaihe-tulos #markkina, #vaihe-tulos #hintarivi, #t-nimi {
  scroll-margin-top: calc(var(--navi-korkeus, 61px)
                          + var(--palkki-korkeus, 61px) + .5rem);
}

/* ── Tarttuva palkki tulosvaiheessa (task 080, palaute #63) ─────────────
   Levyn nimi + ▶ + "Skannaa uusi", tai lomakkeen ollessa näkyvissä nimi +
   ▶ + tallennusnapit (samat napit siirrettyinä, `skannaa.js` Palkki).
   Liimautuu navin alle. Nimi saa kutistua tyhjään asti (`min-width: 0`):
   napit ovat palkin tehtävä, nimi muistutus. Kapealla ruudulla kaksi
   tallennusnappia rivittyy omalle rivilleen eikä työnny ruudun yli. */
.tulospalkki {
  position: sticky; top: var(--navi-korkeus, 61px); z-index: 9;
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .5rem;
  margin: 0 0 .75rem; padding: .5rem 0;
  background: var(--tausta); border-bottom: 1px solid var(--reuna);
}
.palkki-nimi {
  flex: 1 1 0; min-width: 0; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Ei `display`-sääntöä: flex-lapsena linkki on jo lohko, ja oma `display`
   voittaisi `hidden`in (sama ansa kuin `.nappi`lla). */
.palkki-video {
  min-width: var(--kosketus); min-height: var(--kosketus);
  line-height: var(--kosketus); text-align: center;
  color: var(--korosto); text-decoration: none; font-size: 1.25rem;
  border: 1px solid var(--reuna); border-radius: var(--pyoristys);
}
.tulospalkki .nappi { align-self: center; white-space: nowrap; }
.palkki-tallennus:empty { display: none; }
.palkki-tallennus .toiminnot { margin-top: 0; gap: .4rem; }
.palkki-tallennus .nappi {
  flex: none; padding: .5rem .7rem; font-size: .875rem;
  min-height: var(--kosketus);
}

/* Levyn tiedot */
.levykortti img { width: 100%; border-radius: var(--pyoristys); margin-bottom: 1rem; }
.kentat { display: grid; grid-template-columns: auto 1fr; gap: .5rem 1rem; }
.kentat dt { color: var(--himmea); font-size: .875rem; }
.kentat dd { margin: 0; }

/* Täydennys */
.taydennys {
  display: flex; flex-wrap: wrap; gap: .5rem;
  background: var(--pinta); border: 1px solid var(--reuna);
  border-radius: var(--pyoristys); padding: .75rem; margin: 1rem 0;
}
.taydennys textarea { flex-basis: 100%; }
.taydennys .vihje { flex-basis: 100%; }
/* Jäsennyksen muutoslista (task 084). `display` ei tässä: `[hidden]` saa
   piilottaa lohkon (ks. `.nappi`-kommentti yllä). */
.jasennysmuutokset { flex-basis: 100%; font-size: .9rem; }
.jasennysmuutokset p { margin: 0 0 .25rem; font-weight: 600; }
.jasennysmuutokset ul { margin: 0 0 .5rem; padding-left: 1.2rem; }
.jasennysmuutokset li { overflow-wrap: anywhere; }

/* Ryhmitelty hakutulos */
.ryhmaotsikko {
  font-size: .875rem; color: var(--himmea); font-weight: 600;
  margin: 1.5rem 0 .5rem; display: flex; align-items: center; gap: .5rem;
}
.ryhmaotsikko .maara {
  background: var(--pinta2); color: var(--himmea);
  padding: .05rem .45rem; border-radius: 10px; font-size: .75rem;
}
.levyrivi .genret { font-style: italic; }
.kuvatyhja {
  width: 52px; height: 52px; flex-shrink: 0; border-radius: 6px;
  background: var(--pinta2); display: flex;
  align-items: center; justify-content: center; color: var(--himmea);
}
/* Spesifisyys, ei lähdejärjestys: tämä voitti `.levyrivi .hinta`:n vain
   koska se sattui olemaan tiedoston lopussa. Siivous olisi vaihtanut
   myytyjen hinnan värin huomaamatta. */
.levyrivi .hinta.myyty { color: var(--vihrea); }
.merkki.oma { background: #2a2440; color: #a99ad9; }

/* Triage vaatii toimenpiteen — se on koko pikatilan tuotos. Aiemmin tämä
   oli pikselintarkasti sama kuin `.merkki.myynnissa`, eli ainoa ero oli
   11px versaalisana. Kehys erottaa sen listasta vilkaisulla. */
.merkki.triage {
  background: #402a10; color: #ffc663;
  box-shadow: inset 0 0 0 1px #8a6520;
}

/* Jonon tilat. Näitä ei ollut lainkaan, joten epäonnistunut tunnistus
   näytti jonolistassa täsmälleen samalta kuin valmis: molemmat saivat
   `.merkki`n oletusharmaan, ja ainoa ero oli 11 px:n versaalisana.
   Jono renderöi `odottaa`n `triage`na (yllä), muut suoraan tilan nimellä.
   Kontrastit: virhe 7,99:1, valmis 8,02:1, käsittelyssä 12,45:1. */
.merkki.virhe { background: #3a1613; color: var(--punainen-tummalla); }
.merkki.valmis { background: #16301f; color: #86d3a0; }
/* Käsittely on ohimenevä välitila eikä vaadi mitään: oletustausta, mutta
   kirkas teksti erottaa sen valmiista ja virheestä. */
.merkki.kasittelyssa { background: var(--pinta2); color: var(--teksti); }

/* Selaimessa tehdyn skannauksen tilat. Erotettu eräajon tiloista värillä
   eikä pelkällä sanalla: samassa listassa on kahdenlaista työtä, ja niitä
   koskevat eri odotukset — eräajo purkautuu itsestään, skannaus odottaa
   ihmistä. `kesken` on sininen (käynnissä), `tunnistettu` vihertävä mutta
   eri sävy kuin eräajon `valmis` (analyysi on tehty, levyä ei ole viety
   kirjastoon), `tunnistamaton` lämmin mutta ei virheen punainen — malli ei
   osannut, mikään ei rikkoutunut. */
.merkki.kesken { background: #1c2740; color: #9db4e8; }
.merkki.tunnistettu { background: #143029; color: #7fd0b6; }
.merkki.tunnistamaton { background: #3a2418; color: #e5a97f; }

/* Ehdokaslista triage-korjauksessa.
   `.selauslista` (Discogsin selaus käsin) jakaa asettelun mutta on ERI
   LUOKKA: sen rivi on artisti tai albumi eikä painos, eikä sillä ole
   catnoa eikä maata. Yhteinen luokka houkuttelisi ajamaan myös nämä rivit
   `Ehdokkaat`in läpi, ja silloin riville tulostuisi `? · ?` juuri niihin
   kohtiin joissa lukee painoksen ratkaisevat tiedot. Asettelu on sama,
   koska rivi luetaan samalla tavalla — merkitys on eri. */
.ehdokaslista, .selauslista { list-style: none; padding: 0; margin: .5rem 0 1rem; }
.ehdokaslista li, .selauslista li {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  background: var(--pinta); border: 1px solid var(--reuna);
  border-radius: var(--pyoristys); padding: .6rem .75rem;
  margin-bottom: .5rem;
}
.ehdokaslista .vihje, .selauslista .vihje { flex-basis: 100%; }
.selaus-nimi { font-weight: 600; }

/* Discogs-linkit (`osat.js`, DiscogsLinkki).

   OMA RIVI JA OMA VALI, EI VIIMEISTELYA VAAN VAATIMUS. Ehdokasrivin
   napautus SITOO PAINOKSEN, ja väärä painos on tämän sovelluksen kallein
   virhe (hintaero 10–50-kertainen). 320 px:llä sormella painettuna
   valintanapin viereen ahdettu linkki on vahinkopainallus odottamassa,
   joten linkeille annetaan kokorivi, oma yläväli ja täysi kosketuskorkeus.

   `flex-basis: 100%` sama kuvio kuin `.ehdokas-vastaavuus`illa: listan rivi
   on `flex-wrap`iva, ja tämä pakottaa rivinvaihdon ilman erillistä
   asettelusääntöä. `flex-wrap` myös kääreessä itsessään — kaksi linkkiä
   vierekkäin ei mahdu 320 px:iin, eikä vaakarullausta saa syntyä. */
.discogs-linkit {
  flex-basis: 100%; display: flex; flex-wrap: wrap; gap: .25rem 1rem;
  margin-top: .35rem;
}
/* EI OMAA VARIA. Linkki perii `a { color: var(--korosto) }`:n, jonka
   kontrasti `--pinta`-pinnalla (= listan rivin tausta) on jo mitattu
   savutestissa (`_LINKKIPINNAT`, `.levyrivi-kortti`). Oma varimaarittely
   olisi neljas paikka jossa sama savy elaa — ja se olisi mittaamaton. */
.discogs-linkki {
  display: inline-flex; align-items: center; min-height: var(--kosketus);
  font-size: .8125rem; text-decoration: underline; overflow-wrap: anywhere;
}

/* Selauspaneeli. Hakukenttä ja nappi samalle riville, murupolku sen alle:
   kolmivaiheisessa selauksessa (artisti → levy → painos) on tiedettävä
   missä ollaan ja päästävä takaisin ilman uutta hakua. */
.selaus { margin: .5rem 0 1rem; }
.selaus-rivi { display: flex; align-items: flex-end; gap: .5rem; }
.selaus-haku { flex: 1 1 auto; }
.selaus-polku {
  display: flex; align-items: center; gap: .5rem; margin: .5rem 0;
}

/* Klikattava tilalaatikko: kun jono ei purkaudu, ensimmäinen kysymys on
   mitkä levyt siellä ovat. */
.linkkilaatikko {
  display: block; text-decoration: none; color: inherit;
  min-height: var(--kosketus);
}
.linkkilaatikko:hover { filter: brightness(1.12); }
.virheteksti { color: var(--punainen-tummalla); }
/* Spesifisyys, ei lähdejärjestys — sama ansa kuin `.levyrivi .hinta.myyty`
   yllä. Jonorivin virhe on `<div class="meta virheteksti">`, ja
   `.levyrivi .meta` (0,2,0) voittaa paljaan `.virheteksti`n (0,1,0)
   riippumatta siitä kumpi on tiedostossa alempana. Sääntö oli siis
   toimimaton koko olemassaolonsa ajan: epäonnistuneen tunnistuksen syy
   renderöityi samana harmaana kuin päivämäärä. Savutesti laskee nyt
   spesifisyydet eikä luota siihen että tämän muistaa. */
.levyrivi .meta.virheteksti { color: var(--punainen-tummalla); }

/* Kirppis */
.hintataulu { width: 100%; border-collapse: collapse; margin: .5rem 0; }
.hintataulu td {
  padding: .45rem .2rem; border-bottom: 1px solid var(--reuna);
  font-size: .9375rem;
}
.hintataulu .hinta { text-align: right; font-weight: 700; color: var(--korosto); }
.videolista { list-style: none; padding: 0; margin: .5rem 0; }
.videolista li { margin-bottom: .35rem; }
.videolista a {
  color: var(--teksti); text-decoration: none; display: inline-block;
  padding: .35rem 0; min-height: var(--kosketus); line-height: 1.9;
}

.havaintorivi { flex-wrap: wrap; }
.havaintolinkki {
  display: flex; align-items: center; gap: .75rem;
  flex: 1 1 240px; text-decoration: none; color: inherit; min-width: 0;
}
.havaintotoiminnot { display: flex; gap: .5rem; align-items: center; }

/* Historia (task 081): rivin toiminnot rivittyvät kapealla ruudulla levyn
   tietojen alle, samalla säännöllä kuin `.havaintorivi`. */
.historiasuodatin { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1rem; }
.historiasuodatin a { display: inline-flex; align-items: center; text-decoration: none; }
.historialista .levyrivi-kehys { flex-wrap: wrap; }
.historialista .levyrivi-kehys > .levyrivi { flex: 1 1 240px; }
.historiatoiminnot { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
/* Päätelty paikka on ehdotus eikä tieto: kursiivi + kysymysmerkki. */
.paikka.paatelty { font-style: italic; }

/* Valintaruutu omalla rivillään lomakkeessa — `label` on pystyflex, joten
   ruutu ja teksti erkanisivat ilman tätä. */
.valintarivi {
  flex-direction: row; align-items: center; gap: .5rem;
  min-height: var(--kosketus);
}
.valintarivi input { width: auto; flex-shrink: 0; }

/* Valintaruudut omana lohkonaan lomakeruudukon ulkopuolella. Ruudukon
   sarake on 360 px:n ruudulla noin 150 px, ja siihen valinnan teksti
   katkesi kahdelle riville ruudun viereen. Perusleveys 12rem: valinnat
   asettuvat rinnakkain vain kun ne mahtuvat, muuten kumpikin saa oman
   rivin koko leveydeltä. Kosketuskorkeus tulee `.valintarivi`stä eikä
   muutu tässä. */
.valinnat {
  display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; margin-top: .25rem;
}
.valinnat .valintarivi { flex: 1 1 12rem; }

/* Palaute — kelluva nappi joka näkymässä.
   Sijainti ilmoituspalkin yläpuolella (.ilmoitus on kiinni alareunassa),
   jottei kuittaus peitä nappia juuri kun sitä painetaan uudelleen. */
.palautenappi {
  position: fixed; right: 1rem;
  bottom: calc(4.5rem + env(safe-area-inset-bottom));
  width: var(--kosketus); height: var(--kosketus);
  border-radius: 50%; border: 1px solid var(--reuna);
  background: var(--pinta2); color: var(--teksti);
  font-size: 1.25rem; line-height: 1; cursor: pointer;
  z-index: 15; opacity: .75;
}
.palautenappi:hover, .palautenappi:focus-visible { opacity: 1; }

.palauteikkuna {
  border: 1px solid var(--reuna); border-radius: var(--pyoristys);
  background: var(--pinta); color: var(--teksti);
  width: min(30rem, calc(100vw - 2rem)); padding: 1.25rem;
}
.palauteikkuna::backdrop { background: rgba(0, 0, 0, .6); }
.palauteikkuna h3 { margin: 0 0 .25rem; }
.palauteikkuna textarea {
  width: 100%; margin-top: .5rem;
  background: var(--tausta); color: var(--teksti);
  border: 1px solid var(--reuna); border-radius: var(--pyoristys);
  padding: .6rem; font: inherit;
}
.palautelajit { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .75rem; }
.palautelajit .valittu {
  border-color: var(--korosto); background: var(--pinta2);
}
.palaute-sivu { word-break: break-all; }

/* Mihin painokseen hinnat perustuvat (palaute #28). Oma sääntö eikä pelkkä
   `.vihje`, jolla marginaali on nolla: rivi on lukujen perustelu ja se
   luetaan ennen lukuja, joten se ei saa liimautua otsikkoon eikä
   taulukkoon. Tyhjänä se ei vie tilaa. */
.hintaperuste { margin: .3rem 0 .6rem; }
.hintaperuste:empty { display: none; }

/* Hintataso myyntihintakentän vieressä (palaute #36). Kiinni edellisessä
   rivissä eikä omana lohkonaan: se on juuri sen kentän selite, ja väljyys
   irrottaisi sen siitä kentästä jota se koskee. Nappi omalle rivilleen —
   kosketuskohde ei saa jäädä tekstin sekaan kapealla ruudulla. */
.markkinavihje { margin: -.25rem 0 .75rem; }
.markkinavihje .vihje { margin: 0 0 .4rem; }
.hintatiivistelma strong { color: var(--korosto); }

/* Levyn oma kunto korostettuna hintataulussa: se rivi on se joka koskee
   tätä kappaletta, muut ovat vertailukohtia. */
.hintataulu tr.valittu td {
  background: var(--pinta2);
  border-left: 3px solid var(--korosto);
}

/* ── Myyntikanavat ──────────────────────────────────────────────────────
   Kolme uutta näkymää (kanavat, kanavan asetukset, myyntiinvienti) käyttävät
   samoja osia. Omat säännöt eivätkä olemassa olevien uudelleenkäyttö, koska
   ne ovat listoja ja lomakkeita eivätkä levykortteja — `.ehdokas` olisi
   näyttänyt oikealta mutta tarkoittanut eri asiaa. */
.lista { width: 100%; border-collapse: collapse; margin: .5rem 0 1.25rem; }
table.lista th, table.lista td {
  text-align: left; padding: .5rem .6rem; vertical-align: top;
  border-bottom: 1px solid var(--reuna); font-size: .9375rem;
}
table.lista th { color: var(--himmea); font-weight: 600; }
ul.lista { list-style: none; padding: 0; }
ul.lista li {
  padding: .6rem .75rem; margin-bottom: .4rem;
  background: var(--pinta); border-radius: 8px;
}
/* Rivikohtainen virhe taulukossa: sama väri kuin muissa varoituksissa
   (`--punainen`), mutta ilman laatikkoa — se on osa riviä, ei oma lohkonsa. */
.varoitus-rivi { color: var(--punainen-tummalla); font-size: .875rem; }

/* Ilmoituksen esikatselu: teksti näytetään täsmälleen sellaisena kuin se
   menee kanavalle, rivinvaihdot mukaan lukien. Siksi `pre` eikä `p` — mutta
   `white-space: pre-wrap`, koska puhelimen leveys ei saa aiheuttaa
   vaakavieritystä. */
pre.esikatselu {
  white-space: pre-wrap; word-break: break-word; font: inherit;
  background: var(--pinta); padding: .75rem; border-radius: 8px;
  margin: .25rem 0 1rem;
}

/* Monivalinta asetuslomakkeessa. Rivitys pystyyn, koska vaihtoehtojen nimet
   ovat eri pituisia ja sarakkeisiin pakotettuna ne hyppivät. */
.lomake fieldset {
  border: 1px solid var(--reuna); border-radius: 8px; padding: .75rem;
}
.lomake fieldset legend { padding: 0 .4rem; color: var(--himmea); }
label.valinta {
  display: flex; align-items: center; gap: .5rem; margin: .35rem 0;
}
label.valinta input { width: auto; }
