/*
 * Livesuomi – TV-opas
 *
 * Samat muuttujat ja sama matala spesifisyys kuin live-näkymässä, jotta
 * teema voi ylikirjoittaa ilman !importantia.
 */

.ls-tv {
  --ls-accent: #0f4c5c;
  /* Linkkiväri tekstille. --ls-accent on tumma petroli, joka toimii
     napin taustana mutta ei tummalla taustalla olevana tekstinä. */
  --ls-accent-text: #6bb6c8;
  --ls-live: #e23744;
  --ls-bg: #14181b;
  --ls-card: #1c2126;
  --ls-card-hover: #242b31;
  --ls-text: #eef1f2;
  --ls-muted: #9aa3aa;
  --ls-border: #2a3238;
  --ls-radius: 10px;

  color: var(--ls-text);
  font-size: 15px;
  line-height: 1.45;
}

/*
 * Väripaletti seuraa TEEMAA, ei käyttöjärjestelmää.
 *
 * Tämä oli aiemmin @media (prefers-color-scheme: dark), ja se tuotti juuri
 * sen vian jonka Kim näki: teema on tummasävyinen aina, mutta selaimen
 * ollessa vaaleassa tilassa tämä lohko latasi vaalean palettinsa. Silloin
 * --ls-text oli lähes musta ja sivun tausta tumma, eli päivänapit olivat
 * mustaa mustalla. Vika ei näkynyt kehittäjän koneella lainkaan, koska se
 * riippui katsojan käyttöjärjestelmän asetuksesta.
 *
 * Oletus on siis tumma, sama kuin teemalla. Vaalea kytketään samalla
 * kytkimellä kuin teemassa (<html data-theme="light">), jolloin kumpikin
 * vaihtuu yhdessä eikä kumpikaan voi olla eri mieltä.
 */
:root[data-theme="light"] .ls-tv {
  --ls-accent-text: #0f4c5c;
  --ls-bg: #ffffff;
  --ls-card: #f7f8f9;
  --ls-card-hover: #eef1f2;
  --ls-text: #1b1f22;
  --ls-muted: #697076;
  --ls-border: #e2e6e8;
}

/* ------------------------------------------------------------------ pää */

.ls-tv__head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.ls-tv__title {
  margin: 0;
  font-size: 1.5rem;
  line-height: 1.2;
}

.ls-tv__meta {
  margin: 0;
  color: var(--ls-muted);
  font-size: 0.875rem;
}

/* -------------------------------------------------------------- päivät */

.ls-tv__days {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

/*
 * Elokuvat-välilehti päivien jatkona.
 *
 * Erottuu päivistä, koska se ei ole päivä: se on suodatin koko ikkunan
 * yli. Ilman eroa se näyttäisi kahdeksannelta vuorokaudelta.
 */
.ls-tv__day--films {
  margin-left: 6px;
  border-left: 1px solid var(--ls-tv-line, #2a3037);
  padding-left: 14px;
}


/*
 * Valitsematon päivä oli aiemmin pelkkä läpinäkyvä laatikko, jonka ainoa
 * erottuva osa oli ohut reunaviiva. Tummalla taustalla siitä tuli musta
 * laatikko mustalla — nappi jota ei näe on nappi jota ei paineta. Nyt
 * jokaisella napilla on oma taustansa, ja ero valittuun tehdään värillä
 * eikä sillä että toinen on olemassa ja toinen ei.
 */
.ls-tv__day {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 8px 14px;
  background: var(--ls-card);
  border: 1px solid var(--ls-border);
  border-radius: 8px;
  text-decoration: none;
  color: var(--ls-text);
  min-width: 78px;
  transition: border-color 0.15s, background-color 0.15s;
}

.ls-tv__day:hover {
  background: var(--ls-card-hover);
  border-color: var(--ls-muted);
}

.ls-tv__day:focus-visible {
  outline: 2px solid var(--ls-accent);
  outline-offset: 2px;
}

.ls-tv__day.is-on {
  background: var(--ls-accent);
  border-color: var(--ls-accent);
  color: #fff;
}

.ls-tv__dayname {
  font-weight: 600;
  font-size: 0.875rem;
}

.ls-tv__daydate {
  font-size: 0.75rem;
  color: var(--ls-muted);
  font-variant-numeric: tabular-nums;
}

.ls-tv__day.is-on .ls-tv__daydate {
  color: rgba(255, 255, 255, 0.82);
}

/* ------------------------------------------------------------- ryhmät */

/*
 * Ilmaiset ja maksulliset kanavat ovat eri asia katsojalle: toisen voi
 * avata heti, toinen vaatii tilauksen. Ryhmä on siis oma osionsa eikä
 * rivi kanavan nimessä.
 */
.ls-tv__group {
  margin: 0 0 28px;
}

.ls-tv__grouptitle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
  font-size: 1rem;
  letter-spacing: 0.01em;
}

.ls-tv__groupcount {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--ls-muted);
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid var(--ls-border);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- kanavat */

/*
 * Sarakkeet ovat kapeat, koska ruudukon tehtävä on näyttää monta kanavaa
 * rinnakkain — sama idea kuin Iltapulussa. 320 px riitti kolmeen
 * sarakkeeseen täydelläkin näytöllä; 232 px riittää kahdeksaan.
 *
 * Tiiviys maksaa kuvaukset: rivillä on aika, nimi ja kategorian ikoni.
 * Kuvaukset eivät katoa palvelusta vaan siirtyvät kanavan omalle sivulle,
 * jossa niille on pystysuunnassa tilaa.
 */
.ls-tv__channels {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 12px;
  align-items: start;
}

.ls-tv__channel {
  border: 1px solid var(--ls-border);
  border-radius: var(--ls-radius);
  overflow: hidden;
  background: var(--ls-bg);
  min-width: 0;
}

.ls-tv__chhead {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: var(--ls-card);
  border-bottom: 1px solid var(--ls-border);
  position: sticky;
  top: 0;
  z-index: 1;
  text-decoration: none;
  color: var(--ls-text);
}

/* Otsikko on linkki kanavan omaan listaukseen. Se näyttää linkiltä vasta
   osuessa, koska koko palkki on klikattava eikä vain sen teksti. */
.ls-tv__chhead:hover {
  background: var(--ls-card-hover);
}

.ls-tv__chhead:hover .ls-tv__chname {
  text-decoration: underline;
}

.ls-tv__chhead:focus-visible {
  outline: 2px solid var(--ls-accent-text);
  outline-offset: -2px;
}

.ls-tv__chlogo {
  width: 28px;
  height: 28px;
  object-fit: contain;
  flex: 0 0 auto;
  border-radius: 6px;
  background: #fff;
}

.ls-tv__chname {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ls-tv__chcount {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--ls-muted);
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--ls-border);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------ ohjelmat */

/*
 * Lista ei rullaa itsekseen.
 *
 * Aiemmin jokainen kanava oli 520 px korkea rullalaatikko. Puhelimessa
 * sellainen on lähes mahdoton käyttää: sormi rullaa sivua, laatikko jää
 * paikalleen, ja kesken olevan päivän loppu on tavoittamattomissa. Nyt
 * rullaa vain sivu, ja koko päivä on sivulla.
 */
.ls-tv__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.ls-tv__item {
  display: flex;
  gap: 8px;
  padding: 5px 10px;
  border-bottom: 1px solid var(--ls-border);
  font-size: 0.875rem;
}

/* Kanavasivun rivi saa hengittää: siinä on kaikki tiedot. */
.ls-tv__list--full .ls-tv__item {
  gap: 12px;
  padding: 12px 0;
  font-size: 0.9375rem;
}

.ls-tv__item:last-child {
  border-bottom: 0;
}

.ls-tv__item.is-now {
  background: var(--ls-card);
  box-shadow: inset 3px 0 0 var(--ls-live);
}

.ls-tv__time {
  flex: 0 0 auto;
  width: 38px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--ls-muted);
  padding-top: 1px;
}

.ls-tv__item.is-now .ls-tv__time {
  color: var(--ls-live);
}

.ls-tv__body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.ls-tv__name {
  font-weight: 600;
  font-size: 0.875rem;
}

.ls-tv__list--full .ls-tv__name {
  font-size: 1rem;
}

.ls-tv__sub {
  font-weight: 400;
  color: var(--ls-muted);
}

.ls-tv__sub::before {
  content: " — ";
}

/*
 * Kuvaus näkyy KOKONAAN siellä missä se ylipäätään näkyy.
 *
 * Aiemmin teksti rajattiin kahteen riviin ja loppu avattiin napista.
 * Rajaus ja nappi ovat nyt tarpeettomia, koska ruudukossa kuvausta ei ole
 * lainkaan (paitsi käynnissä olevassa ohjelmassa) ja kanavasivulla on
 * tilaa näyttää se kokonaan. Katkaistua tekstiä ei siis ole missään.
 */
.ls-tv__desc {
  display: block;
  color: var(--ls-muted);
  font-size: 0.8125rem;
  margin-top: 2px;
}

.ls-tv__list--full .ls-tv__desc {
  font-size: 0.875rem;
  line-height: 1.5;
  margin-top: 4px;
  max-width: 78ch;
}

/* Tiiviin rivin kategoriaikoni: pelkkä merkki, ei tekstiä. */
.ls-tv__caticon {
  display: inline-flex;
  align-items: center;
  color: var(--ls-muted);
  margin-top: 1px;
}

.ls-tv__caticon svg {
  width: 13px;
  height: 13px;
}

.ls-tv__facts {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  align-items: center;
  font-size: 0.75rem;
  color: var(--ls-muted);
  margin-top: 1px;
}

.ls-tv__badge {
  color: #fff;
  background: var(--ls-live);
  padding: 1px 7px;
  border-radius: 4px;
  font-weight: 700;
  letter-spacing: 0.04em;
}

.ls-tv__cat,
.ls-tv__ep,
.ls-tv__year {
  padding: 1px 7px;
  border-radius: 4px;
  background: var(--ls-card-hover);
}

.ls-tv__len {
  font-variant-numeric: tabular-nums;
}

.ls-tv__empty {
  color: var(--ls-muted);
  padding: 20px 0;
}

/* ------------------------------------------------------------ mobiili */

@media (max-width: 640px) {
  .ls-tv__channels {
    grid-template-columns: 1fr;
  }

  .ls-tv__day {
    min-width: 0;
    flex: 1 1 auto;
  }

  .ls-tv__chpage {
    gap: 10px;
  }
}

/*
 * Katkaisuvaroitus. Hiljainen katkaisu oli tämän näkymän ensimmäinen vika:
 * rivimäärän raja pudotti kokonaisia kanavia, eikä mikään kertonut siitä.
 */
.ls-tv__warn {
  margin: 0 0 16px;
  padding: 10px 14px;
  border-left: 3px solid var(--ls-live);
  background: var(--ls-card);
  border-radius: 4px;
  font-size: 0.875rem;
}

/* --------------------------------------------------------- kanavan sivu */

/*
 * Kanavan oma listaus. Sama lyhytkoodi, eri näkymä: yksi kanava, koko
 * päivä allekkain ja kaikki tiedot näkyvissä. Tämä on se paikka johon
 * ruudukon tiiviys siirtää kuvaukset.
 */
.ls-tv__back {
  margin: 0 0 12px;
  font-size: 0.875rem;
}

.ls-tv__back a {
  color: var(--ls-accent-text);
  text-decoration: none;
}

.ls-tv__back a:hover {
  text-decoration: underline;
}

.ls-tv__chpage {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 16px;
}

/*
 * Kanavan oma esittely.
 *
 * Leveys rajataan lukurivin mittaan eikä palstan mittaan: ohjelmalista
 * on taulukkomaista silmäiltävää, tämä on luettavaa tekstiä, ja
 * luettava teksti täydellä leveydellä on se jota kukaan ei lue.
 */
.ls-tv__intro {
  max-width: 62ch;
  margin: 0 0 18px;
  line-height: 1.6;
}

.ls-tv__intro p {
  margin: 0 0 0.75em;
}

.ls-tv__intro p:last-child {
  margin-bottom: 0;
}

.ls-tv__intro a {
  color: var(--ls-accent-text);
}

.ls-tv__chpagelogo {
  width: 56px;
  height: 56px;
  object-fit: contain;
  border-radius: 8px;
  background: #fff;
  flex: 0 0 auto;
}

.ls-tv__chpagetext {
  min-width: 0;
}

.ls-tv__chpagetext .ls-tv__meta {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 4px;
}

.ls-tv__access {
  padding: 2px 8px;
  border-radius: 999px;
  border: 1px solid var(--ls-border);
  background: var(--ls-card);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ls-text);
}

.ls-tv__access--paid {
  border-color: var(--ls-accent-text);
  color: var(--ls-accent-text);
}

/* Kanavasivulla rivi ei ole kortissa vaan sivulla, joten sen sisennys
   tulee reunaviivasta eikä laatikon täytteestä. */
.ls-tv__list--full .ls-tv__item.is-now {
  background: var(--ls-card);
  border-radius: 6px;
  padding-left: 10px;
  padding-right: 10px;
}

/* ------------------------------------------------------------ aikajaksot */

/*
 * Lista alkaa oletuksena nykyhetkestä, mikä on illalla oikein mutta
 * tarkoittaa että päivän ohjelmisto on yhtenä pitkänä pötkönä. Jaksot
 * siirtävät alkukohtaa, jolloin ilta löytyy ilman rullaamista.
 */
.ls-tv__bands {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin: -8px 0 20px;
}

.ls-tv__band {
  padding: 5px 12px;
  border: 1px solid var(--ls-border);
  border-radius: 999px;
  background: var(--ls-card);
  color: var(--ls-muted);
  text-decoration: none;
  font-size: 0.8125rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.ls-tv__band:hover {
  background: var(--ls-card-hover);
  color: var(--ls-text);
}

.ls-tv__band.is-on {
  background: var(--ls-accent);
  border-color: var(--ls-accent);
  color: #fff;
}

/* ------------------------------------------------------------ ohjelmanimi */

/*
 * Nimi on nappi, mutta se ei saa näyttää napilta: rivin on pysyttävä
 * listariviltä. Napin oletustyylit nollataan ja jäljelle jää teksti,
 * joka alleviivautuu osuessa.
 */
.ls-tv__open {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
}

.ls-tv__open:hover {
  text-decoration: underline;
}

.ls-tv__open:focus-visible {
  outline: 2px solid var(--ls-accent-text);
  outline-offset: 2px;
  border-radius: 3px;
}

/* --------------------------------------------------------- tietoikkuna */

/*
 * Vihjelaatikko: ohjelman tiedot hiiren alle.
 *
 * Sama sisältö kuin modaalissa, sama piirtofunktio — eri säiliö. Kaksi
 * eri toteutusta samasta sisällöstä olisi kaksi paikkaa jotka ajautuvat
 * erilleen, ja juuri se on tässä projektissa jo maksanut kolme vikaa.
 *
 * pointer-events: none on olennainen eikä koriste. Laatikko ilmestyy
 * osoittimen viereen, ja jos se ottaisi osoittimen vastaan, se
 * laukaisisi oman mouseoutinsa ja vilkkuisi — tai jäisi seuraavan
 * ohjelman päälle estäen sen katsomisen.
 */
.ls-tv__tip {
  position: fixed;
  z-index: 70;
  pointer-events: none;

  width: min(460px, calc(100vw - 24px));

  /*
   * Koko teksti näkyviin. Kuvaus oli katkaistu kuuteen riviin, ja
   * useimmat mahtuivat siihen — mutta juuri ne pisimmät, joissa lukemista
   * olisi eniten, eivät. Vihjeestä tuli silloin lupaus jota se ei
   * lunasta.
   *
   * Yläraja on ikkunan korkeus: sitä pidempää ei voi näyttää millään, ja
   * silloin klikkaus ja modaali ovat yhä olemassa. Vieritystä ei ole,
   * koska laatikko ei ota osoitinta vastaan eikä sitä siis voisi vierittää.
   */
  max-height: calc(100vh - 24px);
  overflow: hidden;

  padding: 14px 16px;
  border: 1px solid var(--ls-border);
  border-radius: 10px;
  background: var(--ls-bg);
  color: var(--ls-fg);
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.55);
}

.ls-tv__tip[hidden] { display: none; }

/* Laatikossa ei ole sulkuruksia, joten otsikko alkaa ylhäältä. */
.ls-tv__tip .ls-tv__modaltitle { margin-top: 0; }

/*
 * Kosketusnäytöillä vihjettä ei ole lainkaan.
 *
 * JS ei sido kuuntelijoita ilman osoitinlaitetta, mutta sääntö on tässä
 * varmuuden vuoksi: hybridilaitteella (kosketusnäyttö ja hiiri) selain
 * voi silti laukaista mouseoverin sormesta, ja silloin laatikko jäisi
 * roikkumaan ilman mitään joka sulkisi sen.
 */
@media (hover: none) {
  .ls-tv__tip { display: none !important; }
}

.ls-tv__modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.72);
}

.ls-tv__modal[hidden] { display: none; }

.ls-tv__modalbox {
  position: relative;
  width: min(560px, 100%);
  max-height: min(82vh, 640px);
  overflow-y: auto;
  padding: 22px;
  border: 1px solid var(--ls-border);
  border-radius: 12px;
  background: var(--ls-bg);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.5);
}

.ls-tv__modalclose {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 32px;
  height: 32px;
  border: 1px solid var(--ls-border);
  border-radius: 8px;
  background: var(--ls-card);
  color: var(--ls-text);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.ls-tv__modalclose:hover { background: var(--ls-card-hover); }

.ls-tv__modalhead {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  padding-right: 40px;
}

.ls-tv__modallogo {
  width: 40px;
  height: 40px;
  object-fit: contain;
  border-radius: 6px;
  background: #fff;
  flex: 0 0 auto;
}

.ls-tv__modalchannel {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ls-tv__modalchname {
  font-weight: 650;
  font-size: 0.875rem;
}

.ls-tv__modaltime {
  font-size: 0.8125rem;
  color: var(--ls-muted);
  font-variant-numeric: tabular-nums;
}

.ls-tv__modaltitle {
  margin: 0 0 8px;
  font-size: 1.25rem;
  line-height: 1.25;
  padding-right: 40px;
}

.ls-tv__modaldesc {
  margin: 12px 0 0;
  line-height: 1.55;
  color: var(--ls-text);
}

.ls-tv__modalwait {
  margin: 12px 0 0;
  color: var(--ls-muted);
}

/* ----------------------------------------------------------- kaistat */

/*
 * Kaista on kanavan ohjelmat yhdeltä aikaväliltä. Korkeus tulee JS:stä:
 * kaikkien kanavien sama kaista venytetään täydeimmän mittaiseksi, jolloin
 * seuraava kaista alkaa kaikilla samalta korkeudelta.
 *
 * Tyhjä kaista ei ole virhe vaan tieto: kanavalla ei ole tuolla välillä
 * mitään. Katkoviiva erottaa sen niin ettei se näytä rikkinäiseltä.
 */
.ls-tv__bandrow {
  position: relative;
}

.ls-tv__bandrow + .ls-tv__bandrow {
  border-top: 1px dashed var(--ls-border);
}

.ls-tv__bandrow .ls-tv__list {
  height: 100%;
}

/* Viimeisen rivin viiva pois: kaistan raja hoitaa erottelun. */
.ls-tv__bandrow .ls-tv__item:last-child {
  border-bottom: 0;
}

.ls-tv__band--now {
  border-color: var(--ls-live);
  color: var(--ls-live);
}

.ls-tv__band--now.is-on {
  background: var(--ls-live);
  border-color: var(--ls-live);
  color: #fff;
}
