/* ============ Yhden miehen levyraati — pages ============ */

/* ----- Debug: posts missing an Image (.fi) link ----- */
function MissingImagesPage() {
  const missing = [...REVIEWS, ...CONCERTS].filter((p) => !p.cardImg);
  return (
    <main id="main" style={{ padding: "60px 24px", maxWidth: 760, margin: "0 auto" }}>
      <h1 className="h1" style={{ marginBottom: 24 }}>Puuttuvat kuvat ({missing.length})</h1>
      {missing.length === 0 ?
        <p>Kaikilla julkaistuilla artikkeleilla on Image (.fi) -kuva.</p> :
        <ul style={{ display: "flex", flexDirection: "column", gap: 12, padding: 0, listStyle: "none" }}>
          {missing.map((p) =>
            <li key={p.slug} style={{ padding: 16, border: "1px solid rgba(0,0,0,0.15)", borderRadius: 8 }}>
              <div style={{ fontWeight: 600 }}>{p.title}</div>
              <div style={{ fontSize: "0.85rem", color: "var(--charcoal)", marginBottom: 6 }}>
                {p.dateShort} · {p.type}
              </div>
              <a href={`https://www.notion.so/${p.notionPageId.replace(/-/g, "")}`} target="_blank" rel="noreferrer">
                Avaa Notionissa →
              </a>
            </li>
          )}
        </ul>
      }
    </main>);

}

/* ----- Home ----- */
function HomePage({ navigate }) {
  const latestReviews = REVIEWS.slice(0, 6);
  const latestConcerts = CONCERTS.slice(0, 6);

  return (
    <main id="main" data-screen-label="01 Home">
      <section className="hero">
        <div className="container">
          <h1 className="h1">Rakastatko musiikkia ilman rajoja? Tulit oikeaan paikkaan.</h1>
          <p>
            Yhden miehen levyraati on musiikkimedia sinulle, joka haluat tutustua musiikkiin
            monipuolisesti, ennakkoluulottomasti ja genrerajoista piittaamatta.
          </p>
        </div>
      </section>

      {/* Podcast */}
      <section className="section">
        <div className="container two-col">
          <div className="section-head">
            <h2 className="h2"><a onClick={() => navigate("podcast")}>Podcast</a></h2>
            <p>Pohdintaa ja keskustelua musiikin ajankohtaisista ja ajattomista aiheista. Mukana musiikintekijöitä ja meitä musiikista nauttijoita. Ja välillä ollaan ihan vain yhden miehen voimin.</p>
            <div style={{ marginTop: 24 }}>
              <a className="btn btn--secondary" onClick={() => navigate("podcast")}>Kuuntele jaksoja →</a>
            </div>
          </div>
          <SpotifyEmbed showId="3TcraLNC3FwD9Z3gta9bHZ" type="show" height={352} />
        </div>
      </section>

      {/* Levyarviot carousel */}
      <Carousel
        title="Levyarviot"
        tagline="Mietteitä uusimmista ja mielenkiintoisimmista julkaisuista. Klassikkoja unohtamatta!"
        ctaLabel="Selaa kaikki arviot →"
        onCta={() => navigate("levyarviot")}
        onTitle={() => navigate("levyarviot")}>
        {latestReviews.map((r) =>
        <div className="carousel__item" key={r.slug}>
            <ReviewCard review={r} navigate={navigate} />
          </div>
        )}
      </Carousel>

      {/* Keikkaraportit carousel */}
      <Carousel
        title="Keikkaraportit"
        tagline="Musiikki on parasta livenä! Tsekkaa Yhden miehen levyraadin tunnelmat kiinnostavimmilta keikoilta pikkuklubeista stadioneille."
        ctaLabel="Selaa kaikki keikat →"
        onCta={() => navigate("keikkaraportit")}
        onTitle={() => navigate("keikkaraportit")}>
        {latestConcerts.map((c) =>
        <div className="carousel__item" key={c.slug}>
            <ConcertCard concert={c} navigate={navigate} />
          </div>
        )}
      </Carousel>

      {/* Instagram */}
      <section className="section">
        <div className="container">
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 32, gap: 24, flexWrap: "wrap" }}>
            <h2 className="h2">
              <a href="https://www.instagram.com/yhdenmiehenlevyraati/" target="_blank" rel="noopener" style={{ textDecoration: "none" }}>
                Instagram
              </a>
            </h2>
            <a className="btn btn--tertiary" href="https://www.instagram.com/yhdenmiehenlevyraati/" target="_blank" rel="noopener">
              @yhdenmiehenlevyraati →
            </a>
          </div>
          <InstagramGrid />
        </div>
      </section>

      {/* Yhteys */}
      <ContactSection navigate={navigate} />
    </main>);

}

/* ----- Reusable: Carousel section (horizontal scroller w/ arrows) ----- */
function Carousel({ title, tagline, onTitle, onCta, ctaLabel, children }) {
  const trackRef = React.useRef(null);
  const scrollBy = (dir) => {
    const track = trackRef.current;
    if (!track) return;
    track.scrollBy({ left: dir * 320, behavior: "smooth" });
  };
  return (
    <section className="section">
      <div className="container">
        <div className="two-col" style={{ marginBottom: 48, alignItems: "end" }}>
          <div className="section-head">
            <h2 className="h2"><a onClick={onTitle}>{title}</a></h2>
            <p>{tagline}</p>
          </div>
          <div style={{ display: "flex", justifyContent: "flex-end", alignItems: "center", gap: 14, flexWrap: "wrap" }}>
            <a className="btn btn--tertiary" onClick={onCta}>{ctaLabel}</a>
            <div style={{ display: "flex", gap: 10, flexShrink: 0 }}>
              <button className="carousel__btn" aria-label="Edellinen" onClick={() => scrollBy(-1)}>
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2"><path d="M10 2l-6 6 6 6" /></svg>
              </button>
              <button className="carousel__btn" aria-label="Seuraava" onClick={() => scrollBy(1)}>
                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2"><path d="M6 2l6 6-6 6" /></svg>
              </button>
            </div>
          </div>
        </div>
        <div className="carousel">
          <div className="carousel__track" ref={trackRef}>
            {children}
          </div>
        </div>
      </div>
    </section>);

}

/* ----- Contact section (homepage + /yhteys) ----- */
function ContactSection({ navigate, fullPage = false }) {
  return (
    <section className="section" data-screen-label={fullPage ? "08 Yhteys" : null}>
      <div className="container two-col">
        <div>
          {fullPage ?
          <h1 className="h1">Yhteys</h1> :
          <h2 className="h2">Yhteys</h2>}
          <p style={{ marginTop: 24, fontSize: "1.1rem", maxWidth: "42ch" }}>
            Onko sinulla yhteistyökuvio mielessä, vinkki uudesta levystä, tai vain jotain sanottavaa? Lähetä viesti — vastaan aina.
          </p>
          <p style={{ marginTop: 8, fontFamily: "var(--font-heading)", fontSize: "1.4rem" }}>
            <a href="mailto:yhdenmiehenlevyraati@gmail.com" style={{ textDecoration: "underline", textUnderlineOffset: 4 }}>
              yhdenmiehenlevyraati@gmail.com
            </a>
          </p>
          <div style={{ marginTop: 32 }}>
            <ContactForm />
          </div>
        </div>
        <img
          src={fullPage ? "assets/valtteri-yhteys.jpg" : "assets/photos/img-0776.jpg"}
          alt="Valtteri Perämäki levyjen kanssa podcast-studiossa"
          style={{ width: "100%", aspectRatio: "4/5", objectFit: "cover", objectPosition: "center top", borderRadius: 16, border: "2px solid var(--black)", display: "block" }} data-comment-anchor="62ac4a862f-img-144-9" />
        
      </div>
    </section>);

}

/* ----- Shared pagination bar (used above and below result grids) ----- */
function Pagination({ page, pageCount, setPage }) {
  if (pageCount <= 1) return null;
  const goTo = (p) => {
    setPage(p);
    window.scrollTo({ top: 0, behavior: "auto" });
  };
  return (
    <div style={{ display: "flex", justifyContent: "space-between", margin: "32px 0", gap: 16, flexWrap: "wrap" }}>
      <button className="btn btn--secondary" disabled={page === 1} onClick={() => goTo(Math.max(1, page - 1))}>
        ← Uudemmat julkaisut
      </button>
      <span style={{ alignSelf: "center", color: "var(--charcoal)" }}>Sivu {page} / {pageCount}</span>
      <button className="btn btn--secondary" disabled={page === pageCount} onClick={() => goTo(Math.min(pageCount, page + 1))}>
        Vanhemmat julkaisut →
      </button>
    </div>);

}

/* ----- Levyarviot index ----- */
function LevyarviotPage({ navigate, tag = null }) {
  const [query, setQuery] = React.useState("");
  const [page, setPage] = React.useState(1);
  const perPage = 9;

  let items = REVIEWS;
  if (tag) items = items.filter((r) => r.tags.includes(tag));
  if (query.trim()) {
    const q = query.toLowerCase();
    items = items.filter((r) =>
    r.title.toLowerCase().includes(q) ||
    r.artist.toLowerCase().includes(q) ||
    r.work.toLowerCase().includes(q)
    );
  }

  const allTags = Array.from(new Set(REVIEWS.flatMap((r) => r.tags)));

  const pageCount = Math.max(1, Math.ceil(items.length / perPage));
  const shown = items.slice((page - 1) * perPage, page * perPage);

  return (
    <main id="main" data-screen-label="03 Levyarviot index">
      <section className="section" style={{ borderTop: "none" }}>
        <div className="container">
          <h1 className="h1" style={{ marginBottom: 32 }}>
            {tag ? <>Levyarviot: <em style={{ fontStyle: "italic" }}>{tag}</em></> : "Levyarviot"}
          </h1>
          <p style={{ fontSize: "1.2rem", maxWidth: "56ch", marginBottom: 40 }}>
            Albumiarvioita uusista julkaisuista sekä klassikoista. Selaa, etsi tai suodata aiheittain.
          </p>

          <div className="search" style={{ marginBottom: 24 }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></svg>
            <input
              type="text"
              placeholder="Etsi artistilta tai albumilta…"
              value={query}
              onChange={(e) => {setQuery(e.target.value);setPage(1);}} />
            
            {query &&
            <button onClick={() => setQuery("")} aria-label="Tyhjennä" style={{ background: "none", border: "none", cursor: "pointer" }}>✕</button>
            }
          </div>

          <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginBottom: 56 }}>
            <button className={"tag" + (!tag ? " is-active" : "")} onClick={() => navigate("levyarviot")}>Kaikki</button>
            {allTags.map((t) =>
            <button key={t}
            className={"tag" + (tag === t ? " is-active" : "")}
            onClick={() => navigate(`levyarviot/tag/${t}`)}>
                #{t}
              </button>
            )}
          </div>

          <Pagination page={page} pageCount={pageCount} setPage={setPage} />

          {shown.length === 0 ?
          <p style={{ fontSize: "1.1rem" }}>Ei tuloksia hakuehdoilla.</p> :

          <div className="grid">
              {shown.map((r) => <ReviewCard key={r.slug} review={r} navigate={navigate} />)}
            </div>
          }

          <Pagination page={page} pageCount={pageCount} setPage={setPage} />
        </div>
      </section>

      <section className="section">
        <div className="container">
          <BadRecordPromo />
        </div>
      </section>

      <section className="section">
        <div className="container">
          <h2 className="h2" style={{ marginBottom: 32 }}>Lisää sisältöä Instagramissa</h2>
          <InstagramGrid />
        </div>
      </section>
    </main>);

}

/* ----- Keikkaraportit index ----- */
function KeikkaraportitPage({ navigate, tag = null }) {
  const [query, setQuery] = React.useState("");
  const [page, setPage] = React.useState(1);
  const perPage = 9;

  let items = CONCERTS;
  if (tag) items = items.filter((c) => c.tags.includes(tag));
  if (query.trim()) {
    const q = query.toLowerCase();
    items = items.filter((c) =>
    c.title.toLowerCase().includes(q) ||
    c.artist.toLowerCase().includes(q) ||
    c.venue.toLowerCase().includes(q) ||
    c.city.toLowerCase().includes(q)
    );
  }

  const allTags = Array.from(new Set(CONCERTS.flatMap((c) => c.tags)));
  const pageCount = Math.max(1, Math.ceil(items.length / perPage));
  const shown = items.slice((page - 1) * perPage, page * perPage);

  return (
    <main id="main" data-screen-label="05 Keikkaraportit index">
      <section className="section" style={{ borderTop: "none" }}>
        <div className="container">
          <h1 className="h1" style={{ marginBottom: 32 }}>
            {tag ? <>Keikkaraportit: <em style={{ fontStyle: "italic" }}>{tag}</em></> : "Keikkaraportit"}
          </h1>
          <p style={{ fontSize: "1.2rem", maxWidth: "56ch", marginBottom: 40 }}>
            Musiikki on parasta livenä. Raportteja klubeilta, festareilta ja konserttisaleilta.
          </p>

          <div className="search" style={{ marginBottom: 24 }}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7" /><path d="m20 20-3.5-3.5" /></svg>
            <input
              type="text"
              placeholder="Etsi artistilta, paikalta tai kaupungilta…"
              value={query}
              onChange={(e) => {setQuery(e.target.value);setPage(1);}} />
            
            {query &&
            <button onClick={() => setQuery("")} aria-label="Tyhjennä" style={{ background: "none", border: "none", cursor: "pointer" }}>✕</button>
            }
          </div>

          <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginBottom: 56 }}>
            <button className={"tag" + (!tag ? " is-active" : "")} onClick={() => navigate("keikkaraportit")}>Kaikki</button>
            {allTags.map((t) =>
            <button key={t}
            className={"tag" + (tag === t ? " is-active" : "")}
            onClick={() => navigate(`keikkaraportit/tag/${t}`)}>
                #{t}
              </button>
            )}
          </div>

          <Pagination page={page} pageCount={pageCount} setPage={setPage} />

          {shown.length === 0 ?
          <p style={{ fontSize: "1.1rem" }}>Ei tuloksia hakuehdoilla.</p> :

          <div className="grid">
              {shown.map((c) => <ConcertCard key={c.slug} concert={c} navigate={navigate} />)}
            </div>
          }

          <Pagination page={page} pageCount={pageCount} setPage={setPage} />
        </div>
      </section>

      <section className="section">
        <div className="container">
          <h2 className="h2" style={{ marginBottom: 32 }}>Lisää sisältöä Instagramissa</h2>
          <InstagramGrid />
        </div>
      </section>
    </main>);

}

/* ----- Article: shared rich-text renderer ----- */
function RichText({ paragraphs }) {
  if (!paragraphs) return <div className="prose" style={{ color: "var(--charcoal)" }}>Ladataan…</div>;
  const render = (text) => {
    const nodes = [];
    let i = 0; let key = 0;
    const re = /(\*\*\*([^*]+)\*\*\*)|(\*\*([^*]+)\*\*)|(\*([^*]+)\*)/g;
    let m;
    while ((m = re.exec(text)) !== null) {
      if (m.index > i) nodes.push(text.slice(i, m.index));
      if (m[2]) nodes.push(<strong key={key++}><em>{m[2]}</em></strong>);
      else if (m[4]) nodes.push(<strong key={key++}>{m[4]}</strong>);
      else if (m[6]) nodes.push(<em key={key++}>{m[6]}</em>);
      i = m.index + m[0].length;
    }
    if (i < text.length) nodes.push(text.slice(i));
    return nodes;
  };
  return (
    <div className="prose">
      {paragraphs.map((p, i) => <p key={i}>{render(p)}</p>)}
    </div>);
}

/* ----- Individual album review ----- */
function LevyarvioArticle({ slug, navigate }) {
  const idx = REVIEWS.findIndex((r) => r.slug === slug);
  const r = REVIEWS[idx];
  if (!r) return <NotFound navigate={navigate} />;
  const prev = REVIEWS[idx - 1];
  const next = REVIEWS[idx + 1];

  const [body, setBody] = React.useState(r.body);
  React.useEffect(() => {
    if (r.body !== null) { setBody(r.body); return; }
    window.fetchPostBody(r.notionPageId).then(paragraphs => {
      r.body = paragraphs;
      setBody(paragraphs);
    });
  }, [r.notionPageId]);

  return (
    <main id="main" data-screen-label="04 Levyarvio article">
      <article>
        <div className="section" style={{ borderTop: "none" }}>
          <div className="container" style={{ maxWidth: 980 }}>
            <a className="btn btn--tertiary" onClick={() => navigate("levyarviot")} style={{ marginBottom: 24 }}>
              ← Kaikki levyarviot
            </a>
            <div style={{ fontSize: "0.9rem", color: "var(--charcoal)", marginBottom: 12, letterSpacing: "0.04em" }}>
              {r.dateShort} · {r.type === "klassikkoarvio" ? "Klassikkoarvio" : "Levyarvio"}
            </div>
            <h1 className="h1" style={{ marginBottom: 32, maxWidth: "22ch" }}>{r.title}</h1>

            {r.cardImg && (
              <img src={r.cardImg} alt={`${r.artist} – ${r.work}`}
                style={{ width: "100%", height: "auto", display: "block", marginBottom: 40 }} />
            )}

            <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginBottom: 40 }}>
              <Field label="Artisti" value={r.artist} inline />
              <Field label="Levy" value={<em>{r.work}</em>} inline />
              <Field label="Vuosi" value={r.year} inline />
              <Field label="Tyyppi" value={r.type === "klassikkoarvio" ? "Klassikkoarvio" : "Levyarvio"} inline />
            </div>

            <RichText paragraphs={body} />

            <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginTop: 48 }}>
              {r.tags.map((t) =>
                <button key={t} className="tag" onClick={() => navigate(`levyarviot/tag/${t}`)}>#{t}</button>
              )}
            </div>

            {r.spotifyEmbedUrl &&
            <div style={{ margin: "48px 0" }}>
                <SpotifyEmbed embedUrl={r.spotifyEmbedUrl} type="album" height={352} />
              </div>
            }

            <BadRecordPromo />

            <p style={{ marginTop: 32, fontSize: "0.95rem", color: "var(--charcoal)" }}>
              Kirjoittaja: <strong>Valtteri Perämäki</strong>
            </p>

            <div className="adjacent">
              <a className="adjacent__card" onClick={() => prev && navigate(`levyarviot/${prev.slug}`)} style={{ opacity: prev ? 1 : 0.3, pointerEvents: prev ? "auto" : "none" }}>
                <div className="eyebrow">← Edellinen arvio</div>
                <div style={{ fontFamily: "var(--font-heading)", fontSize: "1.3rem", lineHeight: 1.2 }}>{prev ? prev.title : "—"}</div>
              </a>
              <a className="adjacent__card adjacent__card--next" onClick={() => next && navigate(`levyarviot/${next.slug}`)} style={{ opacity: next ? 1 : 0.3, pointerEvents: next ? "auto" : "none" }}>
                <div className="eyebrow">Seuraava arvio →</div>
                <div style={{ fontFamily: "var(--font-heading)", fontSize: "1.3rem", lineHeight: 1.2 }}>{next ? next.title : "—"}</div>
              </a>
            </div>
          </div>
        </div>
      </article>
    </main>);

}

function Field({ label, value, inline }) {
  if (inline) return (
    <div style={{ display: "flex", flexDirection: "column", gap: 2, padding: "10px 16px", background: "rgba(0,0,0,0.06)", borderRadius: 8 }}>
      <div className="eyebrow" style={{ color: "var(--charcoal)", fontSize: "0.68rem" }}>{label}</div>
      <div style={{ fontSize: "1rem", fontWeight: 500 }}>{value}</div>
    </div>
  );
  return (
    <div style={{ display: "grid", gridTemplateColumns: "100px 1fr", gap: 16, paddingBottom: 12, borderBottom: "1px solid rgba(0,0,0,0.2)" }}>
      <div className="eyebrow" style={{ color: "var(--charcoal)" }}>{label}</div>
      <div style={{ fontSize: "1.05rem" }}>{value}</div>
    </div>);

}

/* ----- Individual concert report ----- */
function KeikkaraporttiArticle({ slug, navigate }) {
  const idx = CONCERTS.findIndex((c) => c.slug === slug);
  const c = CONCERTS[idx];
  if (!c) return <NotFound navigate={navigate} />;
  const prev = CONCERTS[idx - 1];
  const next = CONCERTS[idx + 1];

  const [body, setBody] = React.useState(c.body);
  React.useEffect(() => {
    if (c.body !== null) { setBody(c.body); return; }
    window.fetchPostBody(c.notionPageId).then(paragraphs => {
      c.body = paragraphs;
      setBody(paragraphs);
    });
  }, [c.notionPageId]);

  return (
    <main id="main" data-screen-label="06 Keikkaraportti article">
      <article>
        <div className="section" style={{ borderTop: "none" }}>
          <div className="container" style={{ maxWidth: 980 }}>
            <a className="btn btn--tertiary" onClick={() => navigate("keikkaraportit")} style={{ marginBottom: 24 }}>
              ← Kaikki keikkaraportit
            </a>
            <div style={{ fontSize: "0.9rem", color: "var(--charcoal)", marginBottom: 12, letterSpacing: "0.04em" }}>
              {c.dateShort} · Keikkaraportti
            </div>
            <h1 className="h1" style={{ marginBottom: 32, maxWidth: "22ch" }}>{c.title}</h1>

            {c.cardImg && (
              <img src={c.cardImg} alt={`${c.artist} @ ${c.venue}`}
                style={{ width: "100%", height: "auto", display: "block", marginBottom: 40 }} />
            )}

            <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginBottom: 40 }}>
              <Field label="Artisti" value={c.artist} inline />
              <Field label="Paikka" value={c.venue} inline />
              <Field label="Kaupunki" value={c.city} inline />
              <Field label="Keikkapäivä" value={c.concertDate} inline />
            </div>

            <RichText paragraphs={body} />

            <div style={{ display: "flex", flexWrap: "wrap", gap: 10, marginTop: 48 }}>
              {c.tags.map((t) =>
                <button key={t} className="tag" onClick={() => navigate(`keikkaraportit/tag/${t}`)}>#{t}</button>
              )}
            </div>

            <p style={{ marginTop: 32, fontSize: "0.95rem", color: "var(--charcoal)" }}>
              Kirjoittaja: <strong>Valtteri Perämäki</strong>
            </p>

            <div className="adjacent">
              <a className="adjacent__card" onClick={() => prev && navigate(`keikkaraportit/${prev.slug}`)} style={{ opacity: prev ? 1 : 0.3, pointerEvents: prev ? "auto" : "none" }}>
                <div className="eyebrow">← Edellinen raportti</div>
                <div style={{ fontFamily: "var(--font-heading)", fontSize: "1.3rem", lineHeight: 1.2 }}>
                  {prev ? prev.title : "—"}
                </div>
              </a>
              <a className="adjacent__card adjacent__card--next" onClick={() => next && navigate(`keikkaraportit/${next.slug}`)} style={{ opacity: next ? 1 : 0.3, pointerEvents: next ? "auto" : "none" }}>
                <div className="eyebrow">Seuraava raportti →</div>
                <div style={{ fontFamily: "var(--font-heading)", fontSize: "1.3rem", lineHeight: 1.2 }}>
                  {next ? next.title : "—"}
                </div>
              </a>
            </div>
          </div>
        </div>
      </article>
    </main>);

}

/* ----- Podcast page ----- */
function PodcastPage() {
  return (
    <main id="main" data-screen-label="02 Podcast">
      <section className="section" style={{ borderTop: "none", paddingTop: 96 }}>
        <div className="container" style={{ textAlign: "center" }}>
          <h1 className="h1" style={{ maxWidth: "20ch", margin: "0 auto 24px" }}>
            Kuuntele Yhden miehen levyraati -podcastia
          </h1>
          <p style={{ maxWidth: "52ch", margin: "0 auto 56px", fontSize: "1.15rem" }}>
            Valitse alustasi alta. Jaksot ilmestyvät kahdesti kuukaudessa.
          </p>
          <div className="podcast-buttons">
            <a className="btn btn--primary" href="https://podimo.com/s/yhdenmiehenlevyraati" target="_blank" rel="noopener">Podimo</a>
            <a className="btn btn--primary" href="https://open.spotify.com/show/3TcraLNC3FwD9Z3gta9bHZ" target="_blank" rel="noopener">Spotify</a>
            <a className="btn btn--primary" href="https://www.youtube.com/@yhdenmiehenlevyraati" target="_blank" rel="noopener">YouTube</a>
            <a className="btn btn--primary" href="https://podcasts.apple.com/us/podcast/yhden-miehen-levyraati/id1732901688" target="_blank" rel="noopener">Apple Podcasts</a>
          </div>

          <div className="podimo-block">
            <div className="podimo-block__logo">Podimo</div>
            <h3 className="h3" style={{ marginBottom: 8 }}>Kokeile 30 päivää ilmaiseksi</h3>
            <p style={{ maxWidth: "44ch", margin: "0 auto 24px" }}>
              Kuuntele Yhden miehen levyraati ja sadat muut suomenkieliset podcastit Podimossa.
              Yhteistyökoodillamme saat ensimmäisen kuukauden veloituksetta.
            </p>
            <a className="btn btn--primary" href="https://podimo.com/s/yhdenmiehenlevyraati" target="_blank" rel="noopener">Kokeile 30 päivää ilmaiseksi</a>
          </div>
        </div>
      </section>
    </main>);

}

/* ----- Info page ----- */
function InfoPage() {
  return (
    <main id="main" data-screen-label="07 Info">
      <section className="section" style={{ borderTop: "none" }}>
        <div className="container two-col">
          <div>
            <h1 className="h1" style={{ marginBottom: 32 }}>Info</h1>
            <div className="prose">
              <p>
                Yhden miehen levyraadin takaa löytyy innokas musiikkiharrastaja <strong>Valtteri Perämäki</strong>.
              </p>
              <p>
                Ahkerana elävän musiikin ystävänä Valtteri alkoi harrastuksena kirjoitella
                keikkaraportteja Instagramiin. Sittemmin homma laajeni myös julkaisujen arvioimiseen
                ja vuoden 2024 alusta starttasi vielä podcast.
              </p>
              <p>
                Yhden miehen levyraadin ydinfilosofiana on ennakkoluuloton suhtautuminen erilaiseen
                musiikkiin. Genrerajat on tehty rikottavaksi!
              </p>
            </div>
          </div>
          <img
            src="assets/photos/img-0717.jpg"
            alt="Valtteri Perämäki"
            style={{ width: "100%", aspectRatio: "4/5", objectFit: "cover", objectPosition: "center top", borderRadius: 16, border: "2px solid var(--black)", display: "block" }} data-comment-anchor="57ca76491e-div-572-11" />
        </div>
      </section>
    </main>);

}

/* ----- Yhteys page ----- */
function YhteysPage({ navigate }) {
  return <ContactSection navigate={navigate} fullPage />;
}

/* ----- Tietosuojaseloste ----- */
function TietosuojaselostePage() {
  return (
    <main id="main" data-screen-label="09 Tietosuojaseloste">
      <section className="section" style={{ borderTop: "none" }}>
        <div className="container" style={{ maxWidth: 820 }}>
          <h1 className="h1" style={{ marginBottom: 8 }}>Tietosuojaseloste</h1>
          <p style={{ color: "var(--charcoal)", marginBottom: 40 }}>
            Yhden miehen levyraati (yhdenmiehenlevyraati.fi) · Päivitetty 21.7.2026
          </p>

          <div className="prose">
            <p>
              Tässä tietosuojaselosteessa kerromme, mitä henkilötietoja keräämme verkkosivustollamme
              yhdenmiehenlevyraati.fi, mihin tarkoitukseen niitä käytetään ja mitä oikeuksia sinulla on
              rekisteröitynä. Seloste on laadittu EU:n yleisen tietosuoja-asetuksen (GDPR) ja Suomen
              tietosuojalain mukaisesti.
            </p>

            <h2>1. Rekisterinpitäjä</h2>
            <p>
              WBH Productions Oy<br />
              Y-tunnus: 3485324-7<br />
              Yhteystiedot tietosuoja-asioissa: <a href="mailto:yhdenmiehenlevyraati@gmail.com">yhdenmiehenlevyraati@gmail.com</a>
            </p>

            <h2>2. Mitä henkilötietoja keräämme ja mihin tarkoitukseen</h2>
            <p>
              Sivustomme ei edellytä käyttäjätilin luomista, kirjautumista eikä sisällä maksutoimintoja
              tai uutiskirjettä. Henkilötietoja kerätään käytännössä vain silloin, kun otat meihin yhteyttä.
            </p>
            <h3>Yhteydenottolomake</h3>
            <p>Kun lähetät viestin sivustomme yhteydenottolomakkeella, keräämme seuraavat tiedot:</p>
            <ul>
              <li>etunimi</li>
              <li>sukunimi</li>
              <li>sähköpostiosoite</li>
              <li>vapaamuotoinen viestisi sisältö</li>
            </ul>
            <p>
              Näiden tietojen käsittelyn tarkoitus on vastata yhteydenottoosi. Käsittelyn oikeusperusteena
              on oikeutettu etumme vastata meille osoitettuihin yhteydenottoihin ja hoitaa sivustomme
              viestintää.
            </p>
            <p>
              Lomakkeen tiedot lähetetään sähköpostilla Resend-nimisen palvelun kautta osoitteeseen
              yhdenmiehenlevyraati@gmail.com, ja lähettämäsi sähköpostiosoite asetetaan viestin
              vastausosoitteeksi (reply-to), jotta voimme vastata sinulle suoraan. Viestejä ei tallenneta
              erilliseen tietokantaan tai muuhun rekisteriin — ne päätyvät ainoastaan Gmail-sähköpostilaatikkoomme,
              jota rekisterinpitäjä hallinnoi itse.
            </p>

            <h2>3. Evästeet ja muut seurantateknologiat</h2>
            <p>
              Sivustollamme on käytössä evästeasetusten hallintajärjestelmä (evästebanneri sekä
              "Evästeasetukset"-linkki sivuston alatunnisteessa). Evästeet on jaettu neljään kategoriaan:
            </p>
            <ul>
              <li>
                <strong>Välttämättömät evästeet</strong> — Nämä ovat aina käytössä, sillä ne ovat tarpeen
                sivuston perustoimintojen, kuten evästesuostumuksesi muistamisen, toteuttamiseksi. Ne eivät
                vaadi suostumustasi.
              </li>
              <li>
                <strong>Analytiikka</strong> — Varattu mahdollista tulevaa käyttöä varten. Sivustolla ei
                tällä hetkellä ole käytössä analytiikkatyökaluja (kuten Google Analyticsia), eikä tämä
                kategoria tällä hetkellä aja mitään skriptejä tai kerää tietoa, vaikka hyväksyisit sen.
              </li>
              <li>
                <strong>Markkinointi</strong> — Varattu mahdollista tulevaa käyttöä varten. Sivustolla ei
                tällä hetkellä ole käytössä mainostageja tai muita markkinointiin liittyviä
                seurantatyökaluja, eikä tämä kategoria tällä hetkellä aja mitään skriptejä tai kerää
                tietoa, vaikka hyväksyisit sen.
              </li>
              <li>
                <strong>Upotukset</strong> — Jos hyväksyt tämän kategorian, sivusto näyttää Spotify-soittimia
                (iframe-upotuksia) esimerkiksi podcast-jaksojen ja albumien yhteydessä. Nämä upotukset
                voivat asettaa Spotifyn omia evästeitä selaimeesi. Jos et hyväksy tätä kategoriaa,
                Spotify-soittimia ei ladata.
              </li>
            </ul>
            <p>
              Tekemäsi evästevalinnat tallennetaan selaimesi localStorageen (ei siis perinteisenä
              HTTP-evästeenä). Valinta on voimassa 365 päivää, minkä jälkeen sinulta kysytään suostumusta
              uudelleen. Voit muuttaa valintaasi milloin tahansa sivuston alatunnisteen
              "Evästeasetukset"-linkistä.
            </p>
            <p>
              Välttämättömien evästeiden käsittelyn oikeusperusteena on oikeutettu etumme sivuston
              toiminnan mahdollistamiseksi. Analytiikka-, markkinointi- ja upotusevästeiden käsittely
              perustuu antamaasi suostumukseen, jonka voit peruuttaa milloin tahansa.
            </p>

            <h2>4. Kolmannet osapuolet ja henkilötietojen käsittelijät</h2>
            <p>
              Käytämme sivuston toteutuksessa seuraavia palveluntarjoajia, jotka voivat käsitellä tietoja
              puolestamme tai jotka sivustolle upotetun sisällön kautta saavat tietoa kävijästä:
            </p>
            <ul>
              <li>
                <strong>Vercel</strong> — Toimii sivustomme hosting-palveluna sekä palvelinfunktioiden ja
                kuvien (Vercel Blob) tallennuspalveluna. Voi kerätä tavanomaisia palvelinlokitietoja, kuten
                IP-osoitteita, osana palvelun toimintaa.
              </li>
              <li><strong>Resend</strong> — Välittää yhteydenottolomakkeen kautta lähetetyt sähköpostit meille.</li>
              <li>
                <strong>Notion</strong> — Toimii sisällönhallintajärjestelmänämme (CMS) blogitekstien
                ylläpitoon. Notion ei käsittele sivuston kävijöiden henkilötietoja.
              </li>
              <li>
                <strong>Meta / Instagram</strong> — Sivustomme etusivulla näytetään live-Instagram-syöte
                Instagram Graph API:n kautta. Kun vierailet sivustolla, selaimesi lataa kuvia suoraan
                Instagramin palvelimilta.
              </li>
              <li>
                <strong>Spotify</strong> — Sivustolle upotetut podcast- ja albumisoittimet ladataan vain,
                jos olet hyväksynyt evästeasetuksista "Upotukset"-kategorian.
              </li>
            </ul>
            <p>
              Kaikki edellä mainitut palveluntarjoajat ovat yhdysvaltalaisia yrityksiä, minkä vuoksi
              niiden käyttöön liittyy henkilötietojen siirtoa Euroopan unionin ja Euroopan talousalueen
              (EU/ETA) ulkopuolelle. Tällaisissa siirroissa palveluntarjoajien tulee noudattaa GDPR:n
              edellyttämiä asianmukaisia suojatoimia, kuten EU:n ja Yhdysvaltojen välistä
              tietosuojakehystä (Data Privacy Framework) tai Euroopan komission hyväksymiä
              vakiosopimuslausekkeita (Standard Contractual Clauses).
            </p>

            <h2>5. Henkilötietojen säilytysaika</h2>
            <p>
              Yhteydenottolomakkeen kautta lähetetyt viestit säilyvät rekisterinpitäjän
              Gmail-sähköpostilaatikossa niin kauan, kunnes rekisterinpitäjä poistaa ne itse. Viesteille
              ei ole määritelty erillistä automaattista poistoaikaa.
            </p>
            <p>
              Evästesuostumuksesi säilyy selaimesi localStoragessa 365 päivän ajan, minkä jälkeen
              suostumusta kysytään uudelleen.
            </p>

            <h2>6. Rekisteröidyn oikeudet</h2>
            <p>Sinulla on GDPR:n mukaisesti oikeus:</p>
            <ul>
              <li>tarkastaa, mitä sinua koskevia henkilötietoja käsittelemme</li>
              <li>oikaista virheelliset tai puutteelliset tietosi</li>
              <li>pyytää tietojesi poistamista</li>
              <li>rajoittaa tietojesi käsittelyä</li>
              <li>siirtää tietosi järjestelmästä toiseen (tietojen siirrettävyys)</li>
              <li>vastustaa tietojesi käsittelyä</li>
            </ul>
            <p>
              Voit käyttää näitä oikeuksia ottamalla meihin yhteyttä osoitteessa{" "}
              <a href="mailto:yhdenmiehenlevyraati@gmail.com">yhdenmiehenlevyraati@gmail.com</a>.
            </p>
            <p>
              Jos katsot, että henkilötietojesi käsittelyssä on rikottu tietosuojalainsäädäntöä, sinulla
              on oikeus tehdä valitus valvontaviranomaiselle. Suomessa valvontaviranomainen on
              tietosuojavaltuutetun toimisto (<a href="https://tietosuoja.fi" target="_blank" rel="noopener">tietosuoja.fi</a>).
            </p>

            <h2>7. Tietoturva</h2>
            <p>
              Pyrimme suojaamaan käsittelemämme henkilötiedot asianmukaisin teknisin ja organisatorisin
              toimenpitein. Yhteydenottolomakkeen tiedot välitetään suoraan sähköpostiin eikä niitä
              tallenneta erilliseen, itse ylläpidettyyn tietokantaan.
            </p>

            <h2>8. Muutokset tähän tietosuojaselosteeseen</h2>
            <p>
              Voimme päivittää tätä tietosuojaselostetta esimerkiksi sivuston toiminnallisuuden tai
              lainsäädännön muuttuessa. Suosittelemme tarkistamaan tämän sivun ajoittain. Selosteen
              alussa näkyy viimeisin päivityspäivä.
            </p>

            <h2>9. Yhteydenotot</h2>
            <p>
              Jos sinulla on kysyttävää tästä tietosuojaselosteesta tai henkilötietojesi käsittelystä,
              ota yhteyttä:<br />
              WBH Productions Oy<br />
              <a href="mailto:yhdenmiehenlevyraati@gmail.com">yhdenmiehenlevyraati@gmail.com</a>
            </p>
          </div>
        </div>
      </section>
    </main>);

}

/* ----- 404 ----- */
function NotFound({ navigate }) {
  return (
    <main id="main" className="section" style={{ textAlign: "center", borderTop: "none" }}>
      <div className="container">
        <h1 className="h1">404 — Ei löytynyt</h1>
        <p style={{ marginTop: 16, marginBottom: 32 }}>Sivua, jota etsit, ei ole olemassa.</p>
        <button className="btn btn--primary" onClick={() => navigate("home")}>Palaa etusivulle</button>
      </div>
    </main>);

}

Object.assign(window, {
  HomePage, LevyarviotPage, KeikkaraportitPage,
  LevyarvioArticle, KeikkaraporttiArticle,
  PodcastPage, InfoPage, YhteysPage, NotFound
});