String navItem(const String& href, const String& icon, const String& text) {
  String cls = (server.uri() == href || (href == "/" && server.uri() == "/")) ? "nav active" : "nav";
  String s = F("<a class='"); s += cls; s += F("' href='"); s += href; s += F("'><span>"); s += icon; s += F("</span>"); s += text; s += F("</a>");
  return s;
}

String flagButton(const String& code) {
  String cls = "flag f" + code;
  String label = code;
  String s = F("<a class='");
  s += cls;
  s += F("' href='/config?lang=");
  s += code;
  s += F("'><b>");
  s += label;
  s += F("</b><span></span></a>");
  return s;
}

String pageStart(const String& title) {
  String s;
  s.reserve(3500);
  s += F("<!doctype html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>");
  s += F("<title>"); s += title; s += F("</title><style>");
  s += F("*{box-sizing:border-box}body{font-family:Arial,Helvetica,sans-serif;background:#f3f6f9;margin:0;color:#10202c;font-size:16px}.layout{display:flex;min-height:100vh}.side{width:250px;background:linear-gradient(180deg,#0e2d38,#06212b);color:white;position:fixed;inset:0 auto 0 0}.brand{text-align:center;padding:22px 16px 14px}.logo{width:96px;height:96px;border-radius:14px;background:#fff;margin:0 auto 12px;box-shadow:0 4px 14px #0005;overflow:hidden}.logo img{width:96px;height:96px}.brand h1{font-size:28px;margin:8px 0 4px}.brand p{margin:0;color:#dce9ee}.flags{display:flex;justify-content:center;gap:18px;margin:22px 0 10px}.flag{color:#fff;text-decoration:none;font-size:12px;text-align:center;font-weight:bold}.flag span{display:block;width:42px;height:28px;border-radius:3px;margin-top:5px;box-shadow:0 2px 6px #0006;overflow:hidden;background-size:100% 100%}.fDK span{background:linear-gradient(90deg,transparent 0 31%,#fff 31% 43%,transparent 43%),linear-gradient(0deg,transparent 0 42%,#fff 42% 58%,transparent 58%),#c8102e}.fGB span{background:linear-gradient(146deg,transparent 0 43%,#fff 43% 48%,#c8102e 48% 54%,#fff 54% 59%,transparent 59%),linear-gradient(34deg,transparent 0 43%,#fff 43% 48%,#c8102e 48% 54%,#fff 54% 59%,transparent 59%),linear-gradient(90deg,transparent 0 39%,#fff 39% 45%,#c8102e 45% 55%,#fff 55% 61%,transparent 61%),linear-gradient(0deg,transparent 0 35%,#fff 35% 43%,#c8102e 43% 57%,#fff 57% 65%,transparent 65%),#012169}.fD span{background:linear-gradient(#000 0 33%,#dd0000 33% 66%,#ffce00 66%)}.nav{display:flex;align-items:center;gap:14px;padding:15px 22px;color:#fff;text-decoration:none;font-size:20px}.nav span{width:24px;text-align:center}.nav:hover,.nav.active{background:rgba(90,145,158,.65)}.foot{position:absolute;left:18px;right:18px;bottom:20px;font-size:13px;line-height:1.5;color:#eaf4f7}.foot a{color:#90d6ff}.main{margin-left:250px;flex:1}.topbar{height:64px;background:#fff;border-bottom:1px solid #d9e0e6;display:flex;align-items:center;justify-content:space-between;padding:0 28px;box-shadow:0 2px 8px #0001}.topbar b{font-size:28px}.content{padding:30px;max-width:1180px}.title{font-size:34px;margin:0 0 22px}.card{background:white;border-radius:8px;padding:22px;margin:0 0 22px;box-shadow:0 2px 16px #0001;border:1px solid #edf0f2}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:22px;margin-bottom:22px}.metric{text-align:left;min-height:132px}.metric h3{margin:0 0 14px;font-size:18px}.val{font-size:30px;font-weight:800}.red{color:#d40000}.blue{color:#006bd6}.green{color:#078b22}.purple{color:#6814b8}.small{font-size:13px;color:#61717b}.grid2{display:grid;grid-template-columns:1fr 1fr;gap:22px}.tbl{width:100%;border-collapse:collapse}.tbl th,.tbl td{border:1px solid #d9e0e6;padding:10px 14px;text-align:left}.tbl th{background:#eee;width:42%}.pill{display:inline-block;padding:6px 12px;border-radius:999px;margin:3px 6px 12px 0;font-weight:bold}.pill.ok{background:#dcf7df;color:#08751c}.pill.bad{background:#ffe1e1;color:#b22626}.pill.info{background:#e8f1ff;color:#0058b6}label{display:block;margin-top:14px;font-weight:bold}input,select{width:100%;padding:11px;border:1px solid #ccd4db;border-radius:7px;font-size:16px}button,.btn{background:#1f7890;color:white;border:0;border-radius:7px;padding:11px 18px;margin-top:16px;text-decoration:none;display:inline-block;font-weight:bold}.redbtn{background:#c32e32}.gray{background:#6d737a}.bluebtn{background:#126fdd}.actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px}@media(max-width:850px){.side{position:relative;width:100%;height:auto}.layout{display:block}.main{margin-left:0}.foot{position:static;margin-top:20px}.topbar{display:none}.grid2{grid-template-columns:1fr}.content{padding:18px}.nav{font-size:18px}}");
  s += F("</style></head><body><div class='layout'><aside class='side'><div class='brand'><div class='logo'><img src='/icon.svg' alt='TempMQTT'></div><h1>TempMQTT</h1><p>NodeMCU + DHT + MQTT</p><div class='flags'>");
  s += flagButton("DK"); s += flagButton("GB"); s += flagButton("D");
  s += F("</div></div>");
  s += navItem("/", "⌂", txt("status"));
  s += navItem("/sensor", "♨", txt("sensor"));
  s += navItem("/wifi", "≋", txt("wifi"));
  s += navItem("/mqtt", "◇", txt("mqtt"));
  s += navItem("/config", "⚙", txt("system"));
  s += navItem("/firmware", "↥", txt("firmware"));
  s += navItem("/info", "ⓘ", txt("info"));
  s += F("<div class='foot'>NodeMCU TempMQTT v"); s += APP_VERSION; s += F("<br>© Jens Krogsgaard<br>Farum, Danmark<br><a href='https://www.krogsgaardsmodelbane.dk'>www.krogsgaardsmodelbane.dk</a></div></aside>");
  s += F("<main class='main'><div class='topbar'><b>"); s += htmlEscape(cfg.sensorName); s += F("</b><span>"); s += APP_NAME; s += F(" v"); s += APP_VERSION; s += F(" &nbsp; | &nbsp; Hostname: "); s += htmlEscape(cfg.hostname); s += F(" &nbsp; | &nbsp; "); s += txt("languageCode"); s += F(": "); s += htmlEscape(cfg.language); s += F("</span></div><div class='content'>");
  return s;
}
String pageEnd() { return F("</div></main></div></body></html>"); }

String rssiBars() {
  if (!WiFi.isConnected()) return "";
  int r = WiFi.RSSI();
  if (r > -60) return "▂▄▆█";
  if (r > -70) return "▂▄▆";
  if (r > -80) return "▂▄";
  return "▂";
}

