diff --git a/www/html/wordle/wordle.css b/www/html/wordle/wordle.css
index 19da514..b1c33d1 100644
--- a/www/html/wordle/wordle.css
+++ b/www/html/wordle/wordle.css
@@ -134,6 +134,28 @@ main.container { padding-top: 32px; padding-bottom: 64px; }
.site-nav a:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.site-nav a[aria-current="page"] { color: var(--text); background: var(--surface-3); }
+.header-search { position: relative; display: flex; align-items: center; }
+.header-search .icon { position: absolute; left: 12px; width: 18px; height: 18px; color: var(--faint); pointer-events: none; }
+.header-search input {
+ width: 190px;
+ height: 40px;
+ padding: 0 14px 0 38px;
+ border-radius: 999px;
+ border: 1px solid var(--border);
+ background: var(--surface);
+ color: var(--text);
+ font: inherit;
+ font-size: 0.92rem;
+ transition: width 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
+}
+.header-search input::placeholder { color: var(--faint); }
+.header-search input:focus { outline: none; width: 240px; border-color: var(--accent); box-shadow: 0 0 0 3px var(--glow); }
+.icon-btn.search-link { display: none; color: var(--text); }
+@media (max-width: 640px) {
+ .header-search { display: none; }
+ .icon-btn.search-link { display: inline-grid; }
+}
+
.logo { display: flex; gap: 4px; align-items: center; color: inherit; }
.logo:hover { text-decoration: none; }
.logo .tile {
diff --git a/www/html/wordle/wordle.js b/www/html/wordle/wordle.js
index abf3adc..87e9bf8 100644
--- a/www/html/wordle/wordle.js
+++ b/www/html/wordle/wordle.js
@@ -557,13 +557,42 @@ export function mountShell({ active = null } = {}) {
const link = (href, text, key, cls) =>
h("a", { href, class: cls, "aria-current": active === key ? "page" : null }, text);
+ const searchInput = h("input", {
+ id: "header-search",
+ type: "search",
+ placeholder: "Find a player",
+ autocomplete: "off",
+ autocapitalize: "none",
+ spellcheck: "false",
+ enterkeyhint: "go",
+ });
+ const search = h("form", { class: "header-search", role: "search" },
+ h("label", { class: "sr-only", for: "header-search" }, "Find a player"),
+ icon("search"),
+ searchInput);
+ search.addEventListener("submit", e => {
+ e.preventDefault();
+ const user = normalizeUser(searchInput.value);
+ if (!user) return;
+ addRecentSearch(user);
+ location.href = statsPage(user);
+ });
+ // "/" jumps to the search box, as on lots of sites
+ document.addEventListener("keydown", e => {
+ if (e.key !== "/" || e.target.closest?.("input, textarea") || !search.offsetParent) return;
+ e.preventDefault();
+ searchInput.focus();
+ });
+
document.body.prepend(h("header", { class: "site-header" },
h("div", { class: "container" },
logo(),
h("nav", { class: "site-nav", "aria-label": "Main" },
link("/wordle/", "Home", "home"),
- link("/wordle/#find", "Find a player", "find", "wide"),
link("/wordle/#how", "How to play", "how", "wide")),
+ search,
+ // Phones get a button that jumps to the search box on the home page instead
+ h("a", { class: "icon-btn search-link", href: "/wordle/#find", "aria-label": "Find a player" }, icon("search")),
h("button", {
class: "icon-btn",
type: "button",