diff --git a/public/search-client.js b/public/search-client.js
index b2655d1..d49dec8 100644
--- a/public/search-client.js
+++ b/public/search-client.js
@@ -104,6 +104,20 @@
const a = e.target.closest && e.target.closest('a');
remember((a && a.dataset.q) || input.value);
});
+ // Dropdown dismiss (opt-in — /search keeps its results list). A suggestion
+ // list is a NON-MODAL combobox popup (ARIA combobox pattern): interacting
+ // outside the field+list closes it but the interaction is NOT swallowed —
+ // unlike the modal header panels, which scrim-dismiss in Base.astro.
+ if (opts.dismiss) {
+ const box = input.closest('form') || input.parentElement;
+ const hide = () => { clearTimeout(timer); list.innerHTML = ''; status.textContent = ''; };
+ document.addEventListener('pointerdown', (e) => { if (list.firstChild && !box.contains(e.target)) hide(); });
+ // relatedTarget may be null mid-click on our own links — pointerdown covers that path
+ box.addEventListener('focusout', (e) => { if (e.relatedTarget && !box.contains(e.relatedTarget)) hide(); });
+ input.addEventListener('keydown', (e) => {
+ if (e.key === 'Escape' && list.firstChild) { hide(); e.stopPropagation(); } // panel Escape stays a second step
+ });
+ }
return run; // callers may run() immediately (e.g. /search?q=…)
};
})();
diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro
index ffac499..5dd7ff2 100644
--- a/src/layouts/Base.astro
+++ b/src/layouts/Base.astro
@@ -110,11 +110,35 @@ const links = [
diff --git a/src/styles/global.css b/src/styles/global.css
index 5f4270d..787f992 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -22,7 +22,8 @@
--on-galaxy-muted: #c7cde9;
--tint-cherenkov: color-mix(in srgb, var(--cherenkov) 16%, transparent); /* highlight only */
--cherenkov-hover: color-mix(in oklab, var(--cherenkov), var(--galaxy) 12%); /* CTA hover state */
- --ico-ext: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath d="M7 17 17 7M9 7h8v8" fill="none" stroke="black" stroke-width="2.5"/%3E%3C/svg%3E');
+ /* stroke 3: at ~0.72em rendering this matches the .ico family's ~1.5px optical weight */
+ --ico-ext: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"%3E%3Cpath d="M7 17 17 7M9 7h8v8" fill="none" stroke="black" stroke-width="3"/%3E%3C/svg%3E');
/* Type — fonts (BRAND D.3.1/D.3.2) and the ONLY font sizes in this codebase */
--font-body: "Inter", "Inter Fallback", Arial, system-ui, sans-serif;
--font-display: "Space Grotesk", var(--font-body); /* headlines only */
@@ -213,7 +214,8 @@ img { max-width: 100%; height: auto; display: block; }
spec-required search). Chrome stays whisper-quiet: hairline on navy.
Flexes 140-200px (only it and the spacer flex — one-row invariant). */
.nav-search { position: relative; display: flex; align-items: center; flex: 0 1 200px; min-width: 140px; margin-left: 6px; }
-.nav-search .search-ico { left: 11px; width: 14px; height: 14px; color: rgba(255, 255, 255, 0.7); }
+/* stroke 2.6 ≈ the family's 1.5px rendered weight at 14px (icons must not thin out when small) */
+.nav-search .search-ico { left: 11px; width: 14px; height: 14px; color: rgba(255, 255, 255, 0.7); stroke-width: 2.6; }
.nav-search input {
width: 100%; min-width: 0; font: inherit; font-size: var(--fs-s); color: #fff;
background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.45); /* 3.55:1 vs Galaxy — WCAG 1.4.11 */
@@ -345,6 +347,7 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
}
.suggest:empty { display: none; }
.suggest li { display: flex; align-items: flex-start; gap: var(--space-s); padding: 0 12px; border-radius: calc(var(--radius) - 8px); }
+.suggest li + li { margin-top: 2px; } /* rows breathe — hover fills read as discrete items */
.suggest li:hover, .suggest li:focus-within { background: var(--moon); }
/* Focused-empty state labels ("Recent" / "Latest news") — quiet, non-interactive */
li.suggest-label {
@@ -352,16 +355,20 @@ li.suggest-label {
text-transform: uppercase; letter-spacing: 0.08em; padding-top: 8px;
}
.suggest li.suggest-label:hover { background: none; }
+/* Each later group opens with a hairline — label + its rows read as one unit */
+.suggest li.suggest-label:not(:first-child) {
+ margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--border); border-radius: 0;
+}
.search-results li.suggest-label { background: none; border: 0; box-shadow: none; padding: 8px 0 0; }
/* The link holds -split text nodes — it must lay out as flowing text,
never as a flex row (flex would turn every fragment into its own item and
stop titles from wrapping). ≥44px target comes from the block padding. */
.suggest a {
- flex: 1; min-width: 0; display: block; padding-block: 10px;
+ flex: 1; min-width: 0; display: block; padding-block: 12px; /* row ≥44px — real tap target */
color: var(--text); font-weight: 500; font-size: var(--fs-s); text-decoration: none;
overflow-wrap: break-word;
}
-.suggest small { margin-top: 12px; } /* date tracks the first title line */
+.suggest small { margin-top: 14px; } /* date tracks the first title line */
.suggest::after {
content: "Press Enter for all results"; display: block; margin-top: 4px;
padding: 8px 12px 2px; border-top: 1px solid var(--border);
@@ -494,7 +501,7 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
/* Inline rendering (< 1200px): light disclosure row with a chevron */
.toc--inline { border: 1px solid var(--border); border-radius: var(--radius); padding: 4px var(--space-m); margin-bottom: var(--space-l); }
.toc--inline summary { display: flex; align-items: center; justify-content: space-between; gap: var(--space-s); min-height: 40px; }
-.toc--inline summary .ico { width: 14px; height: 14px; }
+.toc--inline summary .ico { width: 14px; height: 14px; stroke-width: 2.6; } /* optical weight match at 14px */
.toc--inline[open] summary .ico { transform: rotate(180deg); }
.toc--inline ol { padding-bottom: var(--space-s); }
.toc--rail { display: none; }
@@ -576,17 +583,24 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
.notice { color: var(--muted); font-size: var(--fs-s); margin-top: 10px; }
/* Search results (list built by the inline script on /search) — card-like rows;
- same single-signal chrome as cards (borderless on Moon, shadow hover) */
-.search-results { list-style: none; margin: var(--space-m) 0 0; padding: 0; max-width: 720px; display: grid; gap: var(--space-s); }
+ same single-signal chrome as cards (borderless on Moon, shadow hover).
+ Margins, not grid gap: idle-state group labels must hug their rows. */
+.search-results { list-style: none; margin: var(--space-m) 0 0; padding: 0; max-width: 720px; }
+.search-results li + li { margin-top: var(--space-m); } /* each article reads as its own card */
+.search-results li.suggest-label + li { margin-top: var(--space-s); } /* rows hug their group label */
.search-results li {
display: flex; align-items: flex-start; gap: var(--space-s);
background: #fff; border-radius: var(--radius);
- padding: 12px 18px; box-shadow: var(--shadow-ambient);
+ padding: var(--space-m); box-shadow: var(--shadow-ambient);
}
.search-results li:hover { box-shadow: var(--shadow-lifted); }
-/* Title flows as inline text (never display:flex — see .suggest a note) */
-.search-results a { flex: 1; min-width: 0; overflow-wrap: break-word; text-decoration: none; font-weight: 500; }
-.search-results a:hover { text-decoration: underline; }
+/* Title flows as inline text (never display:flex — see .suggest a note);
+ card-title treatment (fs-l Galaxy) so titles outweigh the muted meta */
+.search-results a {
+ flex: 1; min-width: 0; overflow-wrap: break-word; text-decoration: none;
+ font-weight: 600; font-size: var(--fs-l); line-height: 1.3; color: var(--galaxy);
+}
+.search-results a:hover { color: var(--link); text-decoration: underline; }
/* Dates on results and suggestions — plain muted text, no chip chrome */
.search-results small, .suggest small { color: var(--muted); white-space: nowrap; font-size: var(--fs-xs); }
.search-results small { margin-top: 5px; } /* optical align with the first title line */
@@ -709,7 +723,7 @@ mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(va
border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.card, .search-results li { transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease); }
- .card:hover { transform: translateY(-2px); } /* the one elevate gesture (no cover zoom) */
+ .card:hover, .search-results li:hover { transform: translateY(-2px); } /* the one elevate gesture (no cover zoom) */
}
@keyframes nebula { /* inert unless applied inside the block above */
from { transform: translate3d(-8%, -5%, 0) rotate(-6deg) scale(1); }