// ─────────────────────────────────────────────────────────────────────────
// components.jsx — shared UI building blocks
// ─────────────────────────────────────────────────────────────────────────

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* ────────── Logo ────────── */
function KreditLogo({ size = 28 }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
      <svg width={size} height={size} viewBox="0 0 32 32" fill="none">
        <rect x="2" y="2" width="28" height="28" rx="8" fill="var(--accent)" />
        <path d="M10 8 L10 24 M10 16 L20 8 M10 16 L22 24" stroke="var(--bg)" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
      <div style={{ display: "flex", flexDirection: "column", lineHeight: 1 }}>
        <span style={{ fontSize: 16, fontWeight: 800, letterSpacing: "-0.02em", color: "var(--text)" }}>
          Kredit<span style={{ color: "var(--accent)" }}>EU</span>
        </span>
        <span style={{ fontSize: 9, fontWeight: 600, color: "var(--text-3)", letterSpacing: "0.12em", textTransform: "uppercase", marginTop: 2 }}>
          europe · 2026
        </span>
      </div>
    </div>
  );
}

/* ────────── Sparkline ────────── */
function Sparkline({ data, width = 90, height = 28, stroke = "var(--accent)", fillOpacity = 0.18, showDot = true }) {
  if (!data || data.length === 0) return null;
  const min = Math.min(...data);
  const max = Math.max(...data);
  const range = max - min || 1;
  const step = width / (data.length - 1 || 1);
  const pts = data.map((v, i) => {
    const x = i * step;
    const y = height - ((v - min) / range) * (height - 4) - 2;
    return [x, y];
  });
  const d = pts.map((p, i) => (i === 0 ? `M ${p[0]} ${p[1]}` : `L ${p[0]} ${p[1]}`)).join(" ");
  const area = d + ` L ${width} ${height} L 0 ${height} Z`;
  const last = pts[pts.length - 1];
  return (
    <svg width={width} height={height} style={{ overflow: "visible" }}>
      <path d={area} fill={stroke} opacity={fillOpacity} />
      <path d={d} fill="none" stroke={stroke} strokeWidth={1.8} strokeLinecap="round" strokeLinejoin="round" />
      {showDot && <circle cx={last[0]} cy={last[1]} r={2.4} fill={stroke} />}
    </svg>
  );
}

/* ────────── Animated number ────────── */
function AnimatedNumber({ value, digits = 0, duration = 600 }) {
  const [display, setDisplay] = useState(value);
  const prev = useRef(value);
  useEffect(() => {
    const from = prev.current;
    const to = value;
    if (from === to) return;
    const start = performance.now();
    let raf;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 3);
      setDisplay(from + (to - from) * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
      else prev.current = to;
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [value, duration]);
  return <span className="num-mono">{display.toLocaleString("pl-PL", { minimumFractionDigits: digits, maximumFractionDigits: digits })}</span>;
}

/* ────────── Live ticker ────────── */
function Ticker() {
  const items = [...window.FX, ...window.REFERENCE_RATES.slice(0, 3).map(r => ({ pair: r.name, value: r.value, d24: r.change, source: "—", isRate: true }))];
  const all = [...items, ...items]; // duplicate for seamless loop
  return (
    <div style={{
      background: "var(--bg-2)",
      borderTop: "1px solid var(--border-soft)",
      borderBottom: "1px solid var(--border-soft)",
      overflow: "hidden",
      position: "relative",
    }}>
      <div className="ticker-track" style={{ padding: "10px 0" }}>
        {all.map((it, i) => {
          const up = it.d24 > 0;
          const flat = Math.abs(it.d24) < 0.005;
          return (
            <div key={i} style={{ display: "flex", alignItems: "center", gap: 10, fontSize: 12, fontWeight: 600, color: "var(--text-2)" }}>
              <span style={{ color: "var(--text-3)", letterSpacing: "0.04em" }}>{it.pair}</span>
              <span className="num-mono" style={{ color: "var(--text)" }}>{it.isRate ? it.value.toFixed(2) + "%" : it.value.toFixed(4)}</span>
              <span style={{ color: flat ? "var(--text-3)" : (up ? "var(--good)" : "var(--bad)"), display: "flex", alignItems: "center", gap: 4 }}>
                {flat ? "→" : (up ? "▲" : "▼")} {Math.abs(it.d24).toFixed(2)}%
              </span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ────────── Header ────────── */
function Header({ route, navigate, lang, setLang, country, setCountry, mode, setMode, theme, setTheme, openSearch }) {
  const [navOpen, setNavOpen] = useState(false);
  const [langOpen, setLangOpen] = useState(false);
  const [countryOpen, setCountryOpen] = useState(false);
  const t = window.I18N[lang]?.nav || window.I18N.pl.nav;
  const cta = window.I18N[lang]?.cta || window.I18N.pl.cta;
  const current = window.COUNTRIES.find(c => c.code === country) || window.COUNTRIES[0];

  const items = [
    { key: "home",     label: t.home },
    { key: "banks",    label: t.banks },
    { key: "markets",  label: t.markets },
    { key: "programs", label: t.programs },
    { key: "articles", label: t.articles },
    { key: "faq",      label: t.faq },
    { key: "contact",  label: t.contact },
  ];

  useEffect(() => {
    const close = () => { setLangOpen(false); setCountryOpen(false); };
    if (langOpen || countryOpen) {
      document.addEventListener("click", close);
      return () => document.removeEventListener("click", close);
    }
  }, [langOpen, countryOpen]);

  return (
    <header style={{
      position: "sticky", top: 0, zIndex: 50,
      background: "color-mix(in oklch, var(--bg) 85%, transparent)",
      backdropFilter: "blur(18px) saturate(160%)",
      WebkitBackdropFilter: "blur(18px) saturate(160%)",
      borderBottom: "1px solid var(--border-soft)",
    }}>
      <div className="container" style={{
        display: "flex", alignItems: "center", gap: 24,
        padding: "14px 24px", justifyContent: "space-between",
      }}>
        <button onClick={() => navigate("home")} style={{ background: "none", border: "none", padding: 0, cursor: "pointer" }} aria-label="KreditEU home">
          <KreditLogo />
        </button>

        {/* Desktop nav */}
        <nav style={{ display: "flex", alignItems: "center", gap: 4 }} className="kr-nav-desktop">
          {items.map(it => (
            <button key={it.key}
              onClick={() => navigate(it.key)}
              style={{
                background: route === it.key ? "var(--surface)" : "transparent",
                color: route === it.key ? "var(--text)" : "var(--text-2)",
                border: "none",
                padding: "8px 12px",
                borderRadius: 8,
                fontSize: 13,
                fontWeight: 600,
                cursor: "pointer",
                transition: "all 0.16s var(--ease)",
                position: "relative",
              }}
              onMouseEnter={e => e.currentTarget.style.color = "var(--text)"}
              onMouseLeave={e => e.currentTarget.style.color = route === it.key ? "var(--text)" : "var(--text-2)"}
            >
              {it.label}
              {route === it.key && (
                <span style={{ position: "absolute", left: "20%", right: "20%", bottom: -2, height: 2, background: "var(--accent)", borderRadius: 2 }} />
              )}
            </button>
          ))}
        </nav>

        {/* Right controls */}
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <button onClick={openSearch} aria-label="search" style={iconBtn()}>
            <SearchIcon />
          </button>

          {/* Country */}
          <div style={{ position: "relative" }}>
            <button onClick={(e) => { e.stopPropagation(); setCountryOpen(o => !o); setLangOpen(false); }} style={chipBtn()}>
              <span style={{ fontSize: 16 }}>{current.flag}</span>
              <span className="kr-hide-mobile" style={{ fontWeight: 600 }}>{current.currency}</span>
              <ChevronDown size={12} />
            </button>
            {countryOpen && (
              <div style={dropdown(320)}>
                <div style={{ padding: 12, borderBottom: "1px solid var(--border-soft)", fontSize: 11, fontWeight: 700, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: "0.08em" }}>
                  {window.t(lang, "common.creditCountry", "Credit Country")}
                </div>
                <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", padding: 6, maxHeight: 360, overflowY: "auto" }}>
                  {window.COUNTRIES.map(c => (
                    <button key={c.code} onClick={() => { setCountry(c.code); setCountryOpen(false); }}
                      style={{
                        ...rowBtn(),
                        background: country === c.code ? "var(--surface-2)" : "transparent",
                      }}>
                      <span style={{ fontSize: 18 }}>{c.flag}</span>
                      <span style={{ flex: 1, textAlign: "left" }}>{c.name}</span>
                      <span style={{ fontSize: 10, color: "var(--text-3)", fontWeight: 700 }}>{c.currency}</span>
                    </button>
                  ))}
                </div>
              </div>
            )}
          </div>

          {/* Lang */}
          <div style={{ position: "relative" }}>
            <button onClick={(e) => { e.stopPropagation(); setLangOpen(o => !o); setCountryOpen(false); }} style={chipBtn()}>
              <span style={{ fontSize: 16 }}>{window.LANGS.find(l => l.code === lang)?.flag}</span>
              <span className="kr-hide-mobile" style={{ fontWeight: 700, textTransform: "uppercase" }}>{lang}</span>
              <ChevronDown size={12} />
            </button>
            {langOpen && (
              <div style={dropdown(200)}>
                {window.LANGS.map(l => (
                  <button key={l.code} onClick={() => { setLang(l.code); setLangOpen(false); }}
                    style={{ ...rowBtn(), background: lang === l.code ? "var(--surface-2)" : "transparent" }}>
                    <span style={{ fontSize: 18 }}>{l.flag}</span>
                    <span style={{ flex: 1, textAlign: "left" }}>{l.name}</span>
                    {lang === l.code && <CheckIcon />}
                  </button>
                ))}
              </div>
            )}
          </div>

          {/* Mode toggle */}
          <button onClick={() => setMode(mode === "dark" ? "light" : "dark")} aria-label="theme mode" style={iconBtn()}>
            {mode === "dark" ? <SunIcon /> : <MoonIcon />}
          </button>

          {/* CTA */}
          <button className="btn btn-primary kr-hide-mobile" onClick={() => navigate("home")}>
            {cta.calculate}
            <span style={{ marginLeft: 4 }}>→</span>
          </button>

          {/* Mobile nav burger */}
          <button onClick={() => setNavOpen(o => !o)} aria-label="menu" className="kr-show-mobile" style={iconBtn()}>
            <BurgerIcon open={navOpen} />
          </button>
        </div>
      </div>

      {/* Mobile nav drawer */}
      {navOpen && (
        <div className="kr-show-mobile" style={{
          borderTop: "1px solid var(--border-soft)",
          background: "var(--bg)",
          padding: "8px 16px 16px",
        }}>
          {items.map(it => (
            <button key={it.key} onClick={() => { navigate(it.key); setNavOpen(false); }}
              style={{
                display: "block", width: "100%", textAlign: "left",
                padding: "12px 8px",
                background: "transparent", border: "none",
                color: route === it.key ? "var(--accent)" : "var(--text)",
                fontSize: 16, fontWeight: 600, cursor: "pointer",
                borderBottom: "1px solid var(--border-soft)",
              }}>
              {it.label}
            </button>
          ))}
          <button className="btn btn-primary" onClick={() => { navigate("home"); setNavOpen(false); }} style={{ width: "100%", justifyContent: "center", marginTop: 16 }}>
            {cta.calculate} →
          </button>
        </div>
      )}
    </header>
  );
}

function iconBtn() {
  return {
    width: 36, height: 36,
    display: "inline-flex", alignItems: "center", justifyContent: "center",
    background: "var(--surface)",
    border: "1px solid var(--border-soft)",
    borderRadius: 10,
    color: "var(--text-2)",
    cursor: "pointer",
    transition: "all 0.16s var(--ease)",
  };
}
function chipBtn() {
  return {
    display: "inline-flex", alignItems: "center", gap: 6,
    padding: "8px 10px",
    background: "var(--surface)",
    border: "1px solid var(--border-soft)",
    borderRadius: 10,
    color: "var(--text)",
    fontSize: 12, fontWeight: 600,
    cursor: "pointer",
    transition: "all 0.16s var(--ease)",
  };
}
function dropdown(width) {
  return {
    position: "absolute", top: "calc(100% + 8px)", right: 0,
    width, background: "var(--surface)",
    border: "1px solid var(--border)",
    borderRadius: 12,
    boxShadow: "var(--shadow-lg)",
    overflow: "hidden",
    zIndex: 60,
  };
}
function rowBtn() {
  return {
    display: "flex", alignItems: "center", gap: 10,
    padding: "10px 12px",
    background: "transparent", border: "none",
    color: "var(--text)",
    fontSize: 13, fontWeight: 500,
    cursor: "pointer",
    borderRadius: 8,
    transition: "background 0.14s",
    textAlign: "left",
  };
}

/* ────────── Footer ────────── */
function Footer({ lang, navigate }) {
  const t = window.I18N[lang]?.footer || window.I18N.pl.footer;
  const nav = window.I18N[lang]?.nav || window.I18N.pl.nav;
  return (
    <footer style={{
      marginTop: 80,
      borderTop: "1px solid var(--border-soft)",
      background: "var(--bg-2)",
      paddingTop: 32,
      paddingBottom: 32,
    }}>
      {/* Bigger ad strip before footer */}
      <div className="container" style={{ marginBottom: 48 }}>
        <AdSlot size="billboard" label="Billboard 970×250" hint="reklama w stopce — zaprojektowana" />
      </div>

      <div className="container">
        <div style={{
          display: "grid",
          gridTemplateColumns: "minmax(220px, 2fr) repeat(3, 1fr)",
          gap: 48,
          marginBottom: 48,
        }} className="kr-footer-grid">
          <div>
            <KreditLogo />
            <p style={{ marginTop: 16, fontSize: 13, lineHeight: 1.6, color: "var(--text-2)", maxWidth: 320 }}>
              {t.brand}
            </p>
            <div style={{ marginTop: 20, display: "flex", gap: 8, flexWrap: "wrap" }}>
              {window.LANGS.slice(0, 7).map(l => (
                <span key={l.code} className="chip" style={{ padding: "4px 10px", fontSize: 11 }}>{l.flag} {l.code.toUpperCase()}</span>
              ))}
            </div>
          </div>

          <FooterCol title={t.tools} items={[
            { label: window.t(lang, "calc.typeMortgage", "Mortgage"), route: "mortgage" },
            { label: window.t(lang, "calc.typeCash", "Cash Loan"), route: "cash" },
            { label: nav.banks, route: "banks" },
            { label: nav.markets, route: "markets" },
            { label: nav.programs, route: "programs" },
          ]} navigate={navigate} />

          <FooterCol title={t.knowledge} items={[
            { label: nav.articles, route: "articles" },
            { label: window.t(lang, "common.glossary", "Glossary"), route: "articles" },
            { label: nav.faq, route: "faq" },
            { label: window.t(lang, "common.bankNews", "Bank News"), route: "articles" },
          ]} navigate={navigate} />

          <FooterCol title={t.info} items={[
            { label: t.privacy, route: "privacy" },
            { label: t.terms, route: "terms" },
            { label: t.cookies, route: "cookies" },
            { label: `⚙ ${window.t(lang, "common.cookieSettings", "Cookie Settings")}`, onClick: () => window.openCookieSettings && window.openCookieSettings() },
            { label: nav.contact, route: "contact" },
            { label: t.admin, route: "admin" },
          ]} navigate={navigate} />
        </div>

        {/* Contact strip */}
        <div style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
          gap: 16,
          padding: "20px 0",
          borderTop: "1px solid var(--border-soft)",
          borderBottom: "1px solid var(--border-soft)",
          fontSize: 13,
        }}>
          <div>
            <div style={{ color: "var(--text-3)", fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4 }}>{t.emailLabel || "Email"}</div>
            <a href="mailto:kontakt@krediteu.com" style={{ color: "var(--text)" }}>kontakt@krediteu.com</a>
            <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 2 }}>{window.t(lang, "common.singleInbox", "One inbox for all topics")}</div>
          </div>
          <div>
            <div style={{ color: "var(--text-3)", fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4 }}>{window.t(lang, "common.form", "Form")}</div>
            <button onClick={() => navigate("contact")} style={{ background: "none", border: "none", padding: 0, color: "var(--text)", fontSize: 13, fontWeight: 500, cursor: "pointer", textAlign: "left" }}>
              {window.t(lang, "common.openForm", "Open form")} →
            </button>
            <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 2 }}>{window.t(lang, "common.internalInbox", "Internal inbox, no mail client needed")}</div>
          </div>
          <div>
            <div style={{ color: "var(--text-3)", fontSize: 11, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.08em", marginBottom: 4 }}>{t.statusLabel || "Data Status"}</div>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
              <span className="live-dot" />
              <span style={{ color: "var(--text)" }}>{t.statusValue || "Up to date · 2026-05-12"}</span>
            </span>
            <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 2 }}>{window.t(lang, "common.nextUpdate", "Next update: Mon 06:00")}</div>
          </div>
        </div>

        <p style={{ marginTop: 20, fontSize: 11, lineHeight: 1.7, color: "var(--text-3)" }}>
          ⚠️ {t.legal}
        </p>

        <div style={{ marginTop: 24, display: "flex", flexWrap: "wrap", justifyContent: "space-between", gap: 12, fontSize: 11, color: "var(--text-3)" }}>
          <span>{t.copyright}</span>
          <span>{window.t(lang, "common.buildInfo", "Made in EU · Build 2026.05")}</span>
        </div>
      </div>
    </footer>
  );
}

function FooterCol({ title, items, navigate }) {
  const currentLang = (document.documentElement.lang || "pl").slice(0, 2).toLowerCase();
  return (
    <div>
      <h4 style={{ margin: 0, fontSize: 11, fontWeight: 800, textTransform: "uppercase", letterSpacing: "0.08em", color: "var(--text-3)", marginBottom: 16 }}>
        {title}
      </h4>
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {items.map((it, i) => (
          <a key={i}
            href={it.route ? buildInternalHref(it.route, currentLang) : "#"}
            onClick={(e) => {
              e.preventDefault();
              if (it.onClick) it.onClick();
              else navigate(it.route);
            }}
            style={{
            background: "transparent", border: "none", padding: 0, textDecoration: "none",
            color: "var(--text-2)", textAlign: "left",
            fontSize: 13, fontWeight: 500, cursor: "pointer",
            transition: "color 0.14s",
          }} onMouseEnter={e => e.currentTarget.style.color = "var(--accent)"}
             onMouseLeave={e => e.currentTarget.style.color = "var(--text-2)"}>
            {it.label}
          </a>
        ))}
      </div>
    </div>
  );
}

/* ────────── Ad Slot ────────── */
function AdSlot({ size = "leaderboard", label, hint }) {
  const sizes = {
    leaderboard: { width: "100%", height: 90, max: 728 },
    billboard:   { width: "100%", height: 250, max: 970 },
    banner:      { width: "100%", height: 180, max: 1200 },
    rect:        { width: "100%", height: 250, max: 300 },
    skyscraper:  { width: 160, height: 600 },
    mobile:      { width: "100%", height: 50, max: 320 },
    in_grid:     { width: "100%", height: "100%", min: 200 },
    sidebar:     { width: "100%", height: 600 },
  };
  const s = sizes[size] || sizes.leaderboard;
  return (
    <div style={{
      width: s.width,
      maxWidth: s.max || "100%",
      height: s.height,
      minHeight: s.min || s.height,
      margin: "0 auto",
      background: "repeating-linear-gradient(135deg, var(--surface) 0 10px, var(--surface-2) 10px 20px)",
      border: "1px dashed var(--border)",
      borderRadius: 12,
      display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center",
      color: "var(--text-3)",
      gap: 4,
      position: "relative",
      overflow: "hidden",
    }}>
      <span style={{ position: "absolute", top: 8, left: 12, fontSize: 9, fontWeight: 700, textTransform: "uppercase", letterSpacing: "0.12em", color: "var(--text-3)", background: "var(--bg)", padding: "2px 8px", borderRadius: 999, border: "1px solid var(--border-soft)" }}>
        Reklama
      </span>
      <div style={{ fontSize: 12, fontWeight: 700, color: "var(--text-2)" }}>{label || "AdSense"}</div>
      <div style={{ fontSize: 10, color: "var(--text-3)", fontFamily: "var(--font-mono)" }}>{hint || size}</div>
    </div>
  );
}

/* ────────── Breadcrumbs ────────── */
function Breadcrumbs({ items, navigate }) {
  const currentLang = (document.documentElement.lang || "pl").slice(0, 2).toLowerCase();
  return (
    <nav aria-label="breadcrumb" style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 12, color: "var(--text-3)", padding: "16px 0" }}>
      {items.map((it, i) => (
        <React.Fragment key={i}>
          {i > 0 && <span style={{ opacity: 0.5 }}>/</span>}
          {it.route ? (
            <a href={buildInternalHref(it.route, currentLang)}
              onClick={(e) => { e.preventDefault(); navigate(it.route); }}
              style={{ background: "none", border: "none", padding: 0, color: "var(--text-2)", fontSize: 12, fontWeight: 500, cursor: "pointer", textDecoration: "none" }}
              onMouseEnter={e => e.currentTarget.style.color = "var(--accent)"}
              onMouseLeave={e => e.currentTarget.style.color = "var(--text-2)"}>
              {it.label}
            </a>
          ) : (
            <span style={{ color: "var(--text)", fontWeight: 600 }}>{it.label}</span>
          )}
        </React.Fragment>
      ))}
    </nav>
  );
}

function buildInternalHref(route, lang = "pl") {
  const safeLang = (lang || "pl").slice(0, 2).toLowerCase();
  if (!route) return `/?lang=${safeLang}`;
  if (typeof route === "object") {
    const name = route.name || "home";
    if (name === "article") return `/?lang=${safeLang}&page=article&id=${route.id || 1}`;
    return name === "home" ? `/?lang=${safeLang}` : `/?lang=${safeLang}&page=${name}`;
  }
  return route === "home" ? `/?lang=${safeLang}` : `/?lang=${safeLang}&page=${route}`;
}

function InternalLinksCard({ title, links = [], navigate, lang = "pl" }) {
  return (
    <div className="card" style={{ padding: 20, marginTop: 28 }}>
      <h3 style={{ margin: 0, fontSize: 12, color: "var(--text-3)", fontWeight: 800, textTransform: "uppercase", letterSpacing: "0.08em" }}>
        {title}
      </h3>
      <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginTop: 12 }}>
        {links.map((item, idx) => (
          <a
            key={`${item.route || item.label}-${idx}`}
            href={buildInternalHref(item.route, lang)}
            onClick={(e) => { e.preventDefault(); navigate(item.route); }}
            className="chip"
            style={{ textDecoration: "none", cursor: "pointer" }}
          >
            {item.label}
          </a>
        ))}
      </div>
    </div>
  );
}

/* ────────── Page header ────────── */
function PageHeader({ kicker, title, sub, actions }) {
  return (
    <div style={{ padding: "32px 0 24px" }} className="fade-up">
      {kicker && <div style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", letterSpacing: "0.12em", textTransform: "uppercase", marginBottom: 12 }}>{kicker}</div>}
      <div style={{ display: "flex", alignItems: "flex-end", justifyContent: "space-between", flexWrap: "wrap", gap: 16 }}>
        <div style={{ flex: 1, minWidth: 280 }}>
          <h1 style={{ margin: 0, fontSize: "clamp(28px, 4vw, 44px)", fontWeight: 800, letterSpacing: "-0.025em", textWrap: "balance", lineHeight: 1.1 }}>
            {title}
          </h1>
          {sub && <p style={{ marginTop: 12, fontSize: 15, color: "var(--text-2)", maxWidth: 640, lineHeight: 1.6 }}>{sub}</p>}
        </div>
        {actions}
      </div>
    </div>
  );
}

/* ────────── Search modal ────────── */
function SearchModal({ open, onClose, navigate, lang = "pl" }) {
  const [q, setQ] = useState("");
  const inputRef = useRef(null);
  const T = (k, fb) => window.t(lang, `common.${k}`, fb);
  const nav = window.I18N[lang]?.nav || window.I18N.pl.nav;
  useEffect(() => {
    if (open) setTimeout(() => inputRef.current?.focus(), 50);
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    if (open) window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose]);

  if (!open) return null;

  const ql = q.toLowerCase().trim();
  const articleHits = ql ? window.ARTICLES.filter(a => a.title.toLowerCase().includes(ql) || a.excerpt.toLowerCase().includes(ql)).slice(0, 5) : [];
  const bankHits = ql ? window.BANKS.filter(b => b.name.toLowerCase().includes(ql)).slice(0, 4) : [];
  const navHits = ql ? [
    ["home", nav.home], ["banks", nav.banks], ["markets", nav.markets], ["programs", nav.programs],
    ["articles", nav.articles], ["faq", nav.faq], ["contact", nav.contact], ["admin", window.t(lang, "footer.admin", "Admin")]
  ].filter(([_, l]) => l.toLowerCase().includes(ql)) : [];

  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, zIndex: 100,
      background: "color-mix(in oklch, var(--bg) 70%, transparent)",
      backdropFilter: "blur(8px)",
      display: "flex", alignItems: "flex-start", justifyContent: "center",
      padding: "10vh 16px 16px",
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: "min(640px, 100%)",
        background: "var(--surface)",
        border: "1px solid var(--border)",
        borderRadius: 16,
        boxShadow: "var(--shadow-lg)",
        overflow: "hidden",
      }}>
        <div style={{ display: "flex", alignItems: "center", padding: "16px 20px", gap: 12, borderBottom: "1px solid var(--border-soft)" }}>
          <SearchIcon />
          <input ref={inputRef} value={q} onChange={e => setQ(e.target.value)}
            placeholder={T("searchPlaceholder", "Search articles, banks, tools...")}
            style={{ flex: 1, background: "none", border: "none", outline: "none", color: "var(--text)", fontSize: 16, fontFamily: "inherit" }} />
          <button onClick={onClose} style={{ ...chipBtn(), fontSize: 11 }}>ESC</button>
        </div>
        <div style={{ maxHeight: "60vh", overflowY: "auto", padding: 8 }}>
          {!ql && (
            <div style={{ padding: "24px 16px", textAlign: "center", color: "var(--text-3)", fontSize: 13 }}>
              {T("startTyping", "Start typing to search articles, banks and sections.")}
            </div>
          )}
          {ql && navHits.length > 0 && (
            <SearchGroup title={T("sections", "Sections")}>
              {navHits.map(([r, l]) => (
                <button key={r} onClick={() => { navigate(r); onClose(); }} style={{ ...rowBtn(), width: "100%" }}>
                  <span style={{ color: "var(--accent)" }}>→</span>{l}
                </button>
              ))}
            </SearchGroup>
          )}
          {ql && articleHits.length > 0 && (
            <SearchGroup title={T("articles", "Articles")}>
              {articleHits.map(a => (
                <button key={a.id} onClick={() => { navigate({ name: "article", id: a.id }); onClose(); }} style={{ ...rowBtn(), width: "100%", flexDirection: "column", alignItems: "flex-start", gap: 2 }}>
                  <span style={{ fontWeight: 600 }}>{a.title}</span>
                  <span style={{ fontSize: 11, color: "var(--text-3)" }}>{a.cat} · {a.read} {T("minutes", "min read")}</span>
                </button>
              ))}
            </SearchGroup>
          )}
          {ql && bankHits.length > 0 && (
            <SearchGroup title={T("banks", "Banks")}>
              {bankHits.map(b => {
                const c = window.COUNTRIES.find(c => c.code === b.country);
                return (
                  <button key={b.id} onClick={() => { navigate("banks"); onClose(); }} style={{ ...rowBtn(), width: "100%" }}>
                    <span>{c?.flag}</span>
                    <span style={{ flex: 1, textAlign: "left" }}>{b.name}</span>
                    <span style={{ fontSize: 11, color: "var(--text-3)", fontFamily: "var(--font-mono)" }}>{b.mortgage}%</span>
                  </button>
                );
              })}
            </SearchGroup>
          )}
          {ql && navHits.length + articleHits.length + bankHits.length === 0 && (
            <div style={{ padding: "24px 16px", textAlign: "center", color: "var(--text-3)", fontSize: 13 }}>
              {T("noResults", "No results for")} "{q}"
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
function SearchGroup({ title, children }) {
  return (
    <div style={{ padding: 8 }}>
      <div style={{ fontSize: 10, fontWeight: 700, color: "var(--text-3)", textTransform: "uppercase", letterSpacing: "0.1em", padding: "6px 12px" }}>{title}</div>
      {children}
    </div>
  );
}

/* ────────── Icons ────────── */
function SearchIcon({ size = 16 }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>;
}
function SunIcon({ size = 16 }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M5 5l1.5 1.5M17.5 17.5 19 19M2 12h2M20 12h2M5 19l1.5-1.5M17.5 6.5 19 5"/></svg>;
}
function MoonIcon({ size = 16 }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>;
}
function ChevronDown({ size = 14 }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"><polyline points="6 9 12 15 18 9"/></svg>;
}
function CheckIcon({ size = 14 }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12"/></svg>;
}
function BurgerIcon({ open, size = 18 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
      <line x1="3" y1="6" x2="21" y2="6" style={{ transform: open ? "rotate(45deg) translate(3px, 3px)" : "", transformOrigin: "center", transition: "transform 0.2s" }} />
      <line x1="3" y1="12" x2="21" y2="12" style={{ opacity: open ? 0 : 1, transition: "opacity 0.2s" }} />
      <line x1="3" y1="18" x2="21" y2="18" style={{ transform: open ? "rotate(-45deg) translate(3px, -3px)" : "", transformOrigin: "center", transition: "transform 0.2s" }} />
    </svg>
  );
}
function ArrowRight({ size = 14 }) {
  return <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>;
}

/* ────────── Progress bar ────────── */
function ProgressBar({ value, label }) {
  return (
    <div>
      {label && <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, color: "var(--text-3)", marginBottom: 6 }}>
        <span>{label}</span>
        <span className="num-mono" style={{ color: "var(--text)" }}>{Math.round(value)}%</span>
      </div>}
      <div style={{ width: "100%", height: 6, background: "var(--surface-2)", borderRadius: 999, overflow: "hidden" }}>
        <div style={{ width: `${Math.max(0, Math.min(100, value))}%`, height: "100%", background: "var(--accent)", borderRadius: 999, transition: "width 0.6s var(--ease)" }} />
      </div>
    </div>
  );
}

/* ────────── Trend pill ────────── */
function TrendPill({ value, suffix = "%" }) {
  const up = value > 0;
  const flat = Math.abs(value) < 0.005;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 4,
      padding: "2px 8px",
      borderRadius: 999,
      background: flat ? "var(--surface-2)" : (up ? "color-mix(in oklch, var(--bad) 18%, transparent)" : "color-mix(in oklch, var(--good) 18%, transparent)"),
      color: flat ? "var(--text-3)" : (up ? "var(--bad)" : "var(--good)"),
      fontSize: 11,
      fontWeight: 700,
      fontFamily: "var(--font-mono)",
    }}>
      {flat ? "→" : (up ? "▲" : "▼")} {Math.abs(value).toFixed(2)}{suffix}
    </span>
  );
}

/* ────────── useInView (one-shot intersection observer) ────────── */
function useInView(threshold = 0.2) {
  const ref = useRef(null);
  const [inView, setInView] = useState(false);
  useEffect(() => {
    if (!ref.current || inView) return;
    const obs = new IntersectionObserver(
      ([entry]) => { if (entry.isIntersecting) { setInView(true); obs.disconnect(); } },
      { threshold }
    );
    obs.observe(ref.current);
    return () => obs.disconnect();
  }, [inView, threshold]);
  return [ref, inView];
}

/* ────────── CountUp (animates 0 → target when in view) ────────── */
function CountUp({ to, duration = 1800, digits = 0, suffix = "", prefix = "" }) {
  const [ref, inView] = useInView(0.3);
  const [val, setVal] = useState(0);
  useEffect(() => {
    if (!inView) return;
    const start = performance.now();
    let raf;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / duration);
      const eased = 1 - Math.pow(1 - p, 4);
      setVal(to * eased);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [inView, to, duration]);
  return (
    <span ref={ref} className="num-mono">
      {prefix}{val.toLocaleString("pl-PL", { minimumFractionDigits: digits, maximumFractionDigits: digits })}{suffix}
    </span>
  );
}

/* ────────── ImpactStrip — animated stats above footer ────────── */
function ImpactStrip({ visits, lang = "pl" }) {
  const T = (k, fb) => window.t(lang, `impact.${k}`, fb);
  const flagsRow = [...window.COUNTRIES, ...window.COUNTRIES]; // duplicate for seamless loop
  const chips = window.t(lang, "impact.chips", []);
  return (
    <section style={{
      marginTop: 64,
      borderTop: "1px solid var(--border-soft)",
      borderBottom: "1px solid var(--border-soft)",
      background: "linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%)",
      paddingTop: 64, paddingBottom: 48,
      position: "relative", overflow: "hidden",
    }}>
      {/* Decorative blobs */}
      <div style={{ position: "absolute", top: -100, left: -100, width: 400, height: 400, background: "radial-gradient(closest-side, var(--accent-soft), transparent)", filter: "blur(40px)", pointerEvents: "none" }} />
      <div style={{ position: "absolute", bottom: -100, right: -100, width: 400, height: 400, background: "radial-gradient(closest-side, var(--accent-soft), transparent)", filter: "blur(40px)", pointerEvents: "none", opacity: 0.5 }} />

      <div className="container" style={{ position: "relative" }}>
        <div style={{ textAlign: "center", marginBottom: 40 }}>
          <span className="chip" style={{ marginBottom: 16 }}>
            <span className="live-dot" /> {T("kicker", "KreditEU Snapshot")}
          </span>
          <h2 style={{
            margin: 0,
            fontSize: "clamp(28px, 4vw, 44px)",
            fontWeight: 800, letterSpacing: "-0.025em",
            textWrap: "balance",
          }}>
            {T("title1", "Already")} <span style={{ color: "var(--accent)" }}><CountUp to={visits} /></span> {T("title2", "people")}<br />
            {T("title3", "have calculated their loan with us.")}
          </h2>
          <p style={{ marginTop: 12, fontSize: 14, color: "var(--text-2)", maxWidth: 560, margin: "12px auto 0" }}>
            {T("sub", "Free, no sign-up required, with live-updated numbers.")}
          </p>
        </div>

        {/* Big stats */}
        <div style={{
          display: "grid",
          gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))",
          gap: 16,
          marginBottom: 48,
        }}>
          <ImpactCard kicker={T("countries", "🌍 European Countries")} value={<CountUp to={window.COUNTRIES.length} duration={1400} />} sub={T("subCountries", "Poland, Germany, France +27 others")} />
          <ImpactCard kicker={T("banks", "🏦 Banks in Database")} value={<CountUp to={window.BANKS.length} duration={1800} suffix="+" />} sub={T("subBanks", "Updated weekly")} />
          <ImpactCard kicker={T("languages", "🌐 Languages")} value={<CountUp to={window.LANGS.length} duration={1200} />} sub={T("subLanguages", "PL · EN · DE · FR · CZ · HU · NL")} />
          <ImpactCard kicker={T("calculations", "📈 Calculations")} value={<CountUp to={Math.round(visits * 4.2)} duration={2200} />} sub={T("subCalculations", "Completed in calculator")} />
          <ImpactCard kicker={T("programs", "🏛️ Subsidy Programs")} value={<CountUp to={window.PROGRAMS.length} duration={1600} suffix="+" />} sub={T("subPrograms", "Across 7 European countries")} />
          <ImpactCard kicker={T("visits", "👁 Visits")} value={<CountUp to={visits} duration={2400} />} sub={T("subVisits", "Since launch")} featured />
        </div>

        {/* Moving flags strip */}
        <div style={{
          padding: "20px 0",
          background: "var(--surface)",
          border: "1px solid var(--border-soft)",
          borderRadius: 16,
          overflow: "hidden",
          position: "relative",
        }}>
          <div style={{ position: "absolute", left: 0, top: 0, bottom: 0, width: 60, background: "linear-gradient(90deg, var(--surface), transparent)", zIndex: 2, pointerEvents: "none" }} />
          <div style={{ position: "absolute", right: 0, top: 0, bottom: 0, width: 60, background: "linear-gradient(-90deg, var(--surface), transparent)", zIndex: 2, pointerEvents: "none" }} />
          <div className="ticker-track" style={{ animationDuration: "60s" }}>
            {flagsRow.map((c, i) => (
              <div key={i} style={{
                display: "flex", alignItems: "center", gap: 10,
                padding: "8px 18px",
                fontSize: 14, color: "var(--text-2)",
              }}>
                <span style={{ fontSize: 28 }}>{c.flag}</span>
                <div>
                  <div style={{ fontSize: 13, fontWeight: 700, color: "var(--text)" }}>{c.name}</div>
                  <div style={{ fontSize: 10, color: "var(--text-3)", fontFamily: "var(--font-mono)" }}>{c.currency} · {c.rate.toFixed(2)}%</div>
                </div>
              </div>
            ))}
          </div>
        </div>

        {/* Mini-stats row */}
        <div style={{
          marginTop: 32,
          display: "flex", justifyContent: "center", flexWrap: "wrap", gap: 8,
        }}>
          {(Array.isArray(chips) ? chips : ["🇪🇺 30 European Countries", "💯 100% Free", "🚫 No Signup", "🤖 AI Analysis", "⚡ Live WIBOR & EURIBOR", "📱 Responsive", "🔄 Weekly Updates"]).map((label, i) => (
            <span key={i} className="chip" style={{ fontSize: 11 }}>{label}</span>
          ))}
        </div>
      </div>
    </section>
  );
}

function ImpactCard({ kicker, value, sub, featured }) {
  return (
    <div style={{
      padding: 24,
      background: featured ? "linear-gradient(155deg, var(--accent-soft), transparent 70%), var(--surface)" : "var(--surface)",
      border: "1px solid " + (featured ? "var(--accent)" : "var(--border-soft)"),
      borderRadius: 16,
      textAlign: "center",
    }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: "var(--text-3)", letterSpacing: "0.06em", textTransform: "uppercase", marginBottom: 10 }}>{kicker}</div>
      <div style={{
        fontSize: "clamp(28px, 3.4vw, 42px)",
        fontWeight: 800,
        letterSpacing: "-0.03em",
        color: featured ? "var(--accent)" : "var(--text)",
        lineHeight: 1,
      }}>
        {value}
      </div>
      <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 8 }}>{sub}</div>
    </div>
  );
}

/* ────────── Visitor counter chip (small, in header area) ────────── */
function VisitorChip({ visits, lang = "pl" }) {
  return (
    <span className="chip" style={{
      background: "color-mix(in oklch, var(--good) 12%, var(--surface))",
      borderColor: "color-mix(in oklch, var(--good) 30%, var(--border-soft))",
      fontSize: 11,
    }}>
      <span className="live-dot" />
      <span style={{ color: "var(--text-2)" }}>{window.t(lang, "visitor.already", "Already")}</span>
      <span className="num-mono" style={{ color: "var(--text)", fontWeight: 800 }}>{visits.toLocaleString("pl-PL")}</span>
      <span style={{ color: "var(--text-2)" }}>{window.t(lang, "visitor.visits", "visits")}</span>
    </span>
  );
}

Object.assign(window, {
  KreditLogo, Sparkline, AnimatedNumber, Ticker, Header, Footer, AdSlot,
  Breadcrumbs, PageHeader, SearchModal, ProgressBar, TrendPill,
  InternalLinksCard, buildInternalHref,
  SearchIcon, SunIcon, MoonIcon, ChevronDown, CheckIcon, BurgerIcon, ArrowRight,
  CountUp, useInView, ImpactStrip, VisitorChip,
});
