feat: content-UX — header search, metadata de-noise, icon/microcopy coherence, article composition
This commit is contained in:
+159
-56
@@ -74,6 +74,11 @@
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 84px; /* sticky header + anchor jumps */ }
|
||||
/* Guard, not a solution (DESIGN.md): every wide element is contained at its own
|
||||
level (tables scroll in their box, long words wrap); clip only catches
|
||||
regressions so one offender can never remove the page gutters. `clip`, unlike
|
||||
`hidden`, creates no scroll container — sticky header keeps working. */
|
||||
html, body { overflow-x: clip; }
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: var(--font-body);
|
||||
@@ -85,6 +90,8 @@ body {
|
||||
|
||||
h1, h2 { font-family: var(--font-display); letter-spacing: -0.01em; }
|
||||
h1, h2, h3, .hero p { text-wrap: balance; }
|
||||
/* Overlong unbroken words (slugs, codes) may break rather than overflow the page */
|
||||
h1, h2, h3 { overflow-wrap: break-word; }
|
||||
.prose p, .desc { text-wrap: pretty; }
|
||||
|
||||
/* Inline SVG icons — stroke inherits currentColor */
|
||||
@@ -120,24 +127,72 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
official logo, never a CSS approximation. Budget: one accent per view; static. */
|
||||
.flash { width: 12px; height: 12px; color: var(--cherenkov); flex: none; }
|
||||
|
||||
/* Demo disclosure — GOV.UK phase-banner pattern: slim Moon bar above the
|
||||
header (scrolls away; the header sticks below it). Galaxy-on-tint pairs
|
||||
computed ≥16:1 (same pairing as .cat chips). */
|
||||
.phase-banner { background: var(--moon); border-bottom: 1px solid var(--border); font-size: 0.8rem; }
|
||||
.phase-banner .container { display: flex; align-items: center; gap: 10px; padding-top: 6px; padding-bottom: 6px; }
|
||||
.phase-tag {
|
||||
flex: none; font-size: 0.68rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em;
|
||||
color: var(--galaxy); background: var(--tint-cherenkov); border-radius: var(--radius-pill); padding: 2px 10px;
|
||||
}
|
||||
|
||||
/* Header — Galaxy Blue band, reverse (white) logo per BRAND B.1.2 */
|
||||
.site-header { background: var(--galaxy); position: sticky; top: 0; z-index: 10; }
|
||||
.nav { display: flex; align-items: center; gap: 4px; min-height: 64px; flex-wrap: nowrap; }
|
||||
.nav > nav { display: flex; align-items: center; gap: 4px; }
|
||||
/* Header tiers (one row, always): full nav >1024px; sub-brand only >1100px;
|
||||
disclosure menu (native <details>/<summary>, CSS-only) at ≤1024px */
|
||||
@media (max-width: 1100px) { .brand .brand-sub { display: none; } }
|
||||
@media (max-width: 360px) {
|
||||
.nav { padding: 0 14px; }
|
||||
.brand img { height: 20px; }
|
||||
.nav .login-mock { padding: 8px 14px; }
|
||||
}
|
||||
/* One-row guarantee: only the search field and the spacer flex — everything
|
||||
else keeps its natural size (links are single words, they can never wrap) */
|
||||
.nav > * { flex: none; }
|
||||
/* Header tiers (one row, always — width math in DESIGN.md):
|
||||
≥1100px full nav + inline search + sub-brand · 1025–1099px sub-brand hidden ·
|
||||
≤1024px disclosure menu + magnifier reveal (both native <details>, CSS-only) ·
|
||||
≤480px icon-only menu button, smaller logo · ≤360px compact paddings */
|
||||
@media (max-width: 1099px) { .brand .brand-sub { display: none; } }
|
||||
.menu { display: none; }
|
||||
.menu .i-close { display: none; }
|
||||
.menu[open] .i-menu { display: none; }
|
||||
.menu[open] .i-close { display: block; }
|
||||
.brand { display: flex; align-items: center; gap: 10px; margin-right: 10px; }
|
||||
.brand img { height: 26px; width: auto; }
|
||||
.brand .brand-sub {
|
||||
color: var(--cherenkov); font-size: 0.78rem; font-weight: 500;
|
||||
border-left: 1px solid rgba(255,255,255,0.25); padding-left: 10px;
|
||||
}
|
||||
.nav .spacer { flex: 1; }
|
||||
.nav a.navlink {
|
||||
color: var(--on-galaxy-muted); font-weight: 500; font-size: 0.95rem;
|
||||
padding: 10px 10px; text-decoration: none; border-bottom: 2px solid transparent;
|
||||
}
|
||||
.nav a.navlink:hover { color: #fff; }
|
||||
.nav a.navlink[aria-current="page"] { color: #fff; border-bottom-color: var(--cherenkov); }
|
||||
/* AAI sign-in entry — leads to the /login mock page */
|
||||
.nav .login-mock {
|
||||
color: var(--galaxy); background: var(--cherenkov); font: inherit; font-weight: 600;
|
||||
border: 0; border-radius: var(--radius-pill); padding: 8px 18px; margin-left: 6px;
|
||||
text-decoration: none; white-space: nowrap;
|
||||
}
|
||||
.nav .login-mock:hover { background: var(--cherenkov-hover); color: var(--galaxy); }
|
||||
/* Tap targets ≥44px (WCAG 2.5.5); inline-flex keeps the active bottom border */
|
||||
.nav a.navlink, .nav .login-mock {
|
||||
display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
|
||||
}
|
||||
/* Header search (desktop) — compact pill in the utility cluster; a plain GET
|
||||
form to /search (works without JS), suggestions reuse the shared .suggest
|
||||
dropdown. Flexes 130–180px so the row can never overflow (width math: DESIGN.md). */
|
||||
.nav-search { position: relative; display: flex; align-items: center; flex: 0 1 180px; min-width: 130px; margin-left: 6px; }
|
||||
.nav-search .search-ico { left: 12px; width: 15px; height: 15px; }
|
||||
.nav-search input {
|
||||
width: 100%; min-width: 0; font: inherit; font-size: 0.9rem; color: var(--text);
|
||||
background: #fff; border: 1px solid transparent; border-radius: var(--radius-pill);
|
||||
padding: 8px 14px 8px 34px;
|
||||
}
|
||||
.nav-search input:focus { border-color: var(--azure); }
|
||||
.nav-search .suggest { left: auto; right: 0; width: min(380px, 92vw); top: calc(100% + 10px); }
|
||||
/* ≤1024px replacement: magnifier <details> reveal — see the menu media block */
|
||||
.search-pop { display: none; }
|
||||
@media (max-width: 1024px) {
|
||||
.nav > nav, .nav > a.navlink { display: none; }
|
||||
.nav > nav { display: none; }
|
||||
.menu { display: block; }
|
||||
.menu summary {
|
||||
display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
|
||||
@@ -158,37 +213,42 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
}
|
||||
.menu nav a:last-child { border-bottom: 0; }
|
||||
.menu nav a[aria-current="page"] { color: var(--cherenkov); }
|
||||
/* Magnifier icon-button reveals a full-width search row under the header
|
||||
(visible search beats search buried in the menu — NN/g mobile-search).
|
||||
Same native-<details> panel pattern as the menu. */
|
||||
.nav-search { display: none; }
|
||||
.search-pop { display: block; }
|
||||
.search-pop summary {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
min-width: 44px; min-height: 44px; color: #fff; cursor: pointer; list-style: none;
|
||||
}
|
||||
.search-pop summary::-webkit-details-marker { display: none; }
|
||||
.search-pop form {
|
||||
position: absolute; left: 0; right: 0; top: 100%;
|
||||
display: flex; gap: 8px; padding: 10px var(--gutter) 14px;
|
||||
background: var(--galaxy); border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
box-shadow: var(--shadow-lifted);
|
||||
}
|
||||
.search-pop input {
|
||||
flex: 1; min-width: 0; font: inherit; color: var(--text);
|
||||
background: #fff; border: 1px solid var(--border); border-radius: var(--radius-pill);
|
||||
padding: 10px 16px;
|
||||
}
|
||||
.search-pop input:focus { border-color: var(--azure); }
|
||||
.search-pop .btn { padding: 10px 18px; }
|
||||
.search-pop .suggest { left: 10px; right: 10px; top: calc(100% + 4px); }
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 10px; margin-right: 10px; }
|
||||
.brand img { height: 26px; width: auto; }
|
||||
.brand .brand-sub {
|
||||
color: var(--cherenkov); font-size: 0.78rem; font-weight: 500;
|
||||
border-left: 1px solid rgba(255,255,255,0.25); padding-left: 10px;
|
||||
@media (max-width: 480px) {
|
||||
.brand img { height: 22px; }
|
||||
.menu summary .menu-label { display: none; }
|
||||
.menu summary { min-width: 44px; justify-content: center; padding: 0; margin-left: 2px; }
|
||||
}
|
||||
.nav .spacer { flex: 1; }
|
||||
.nav a.navlink {
|
||||
color: var(--on-galaxy-muted); font-weight: 500; font-size: 0.95rem;
|
||||
padding: 10px 10px; text-decoration: none; border-bottom: 2px solid transparent;
|
||||
@media (max-width: 360px) {
|
||||
.nav { padding: 0 14px; gap: 2px; }
|
||||
.brand { margin-right: 4px; }
|
||||
.brand img { height: 20px; }
|
||||
.nav .login-mock { padding: 8px 12px; }
|
||||
}
|
||||
.nav a.navlink:hover { color: #fff; }
|
||||
.nav a.navlink[aria-current="page"] { color: #fff; border-bottom-color: var(--cherenkov); }
|
||||
.nav a.navlink--edit {
|
||||
color: #fff; border: 1px solid rgba(255,255,255,0.35); border-radius: var(--radius-pill);
|
||||
padding: 7px 16px; margin-left: 6px;
|
||||
}
|
||||
.nav a.navlink--edit:hover { border-color: var(--cherenkov); color: var(--cherenkov); }
|
||||
/* AAI sign-in entry — leads to the /login mock page */
|
||||
.nav .login-mock {
|
||||
color: var(--galaxy); background: var(--cherenkov); font: inherit; font-weight: 600;
|
||||
border: 0; border-radius: var(--radius-pill); padding: 8px 18px; margin-left: 6px;
|
||||
text-decoration: none; white-space: nowrap;
|
||||
}
|
||||
.nav .login-mock:hover { background: var(--cherenkov-hover); color: var(--galaxy); }
|
||||
/* Tap targets ≥44px (WCAG 2.5.5); inline-flex keeps the active bottom border */
|
||||
.nav a.navlink, .nav .login-mock, .nav a.navlink--edit {
|
||||
display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
|
||||
}
|
||||
.navlink--edit .ico { width: 15px; height: 15px; }
|
||||
/* External-link marker — SVG arrow via mask, inherits currentColor */
|
||||
.external::after {
|
||||
content: ""; display: inline-block; width: 0.72em; height: 0.72em; margin-left: 3px;
|
||||
@@ -215,16 +275,26 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
letter-spacing: 0.14em; font-size: 0.72rem; margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* Search fields — large pill input with inline magnifier; real GET form to /search */
|
||||
.hero-search, .search-form { position: relative; display: flex; gap: 8px; max-width: 560px; }
|
||||
.hero-search { margin-top: var(--space-m); }
|
||||
/* Hero CTAs — the two core scientist tasks (SPEC §3.1): one Cherenkov primary,
|
||||
one quiet ghost. Links styled as buttons because they navigate. */
|
||||
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--space-s); margin-top: var(--space-m); }
|
||||
a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
|
||||
.btn--ghost { background: transparent; color: #fff; border: 1px solid rgba(255, 255, 255, 0.55); }
|
||||
.btn--ghost:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
|
||||
/* One-line latest-news teaser under the CTAs (editorial touch, no widgets) */
|
||||
.hero .hero-teaser { margin-top: var(--space-m); font-size: 0.9rem; color: var(--on-galaxy-muted); max-width: none; }
|
||||
.hero .hero-teaser a { color: #fff; text-underline-offset: 3px; }
|
||||
.hero .hero-teaser a:hover { color: var(--cherenkov); }
|
||||
|
||||
/* Search field (/search page) — large pill input with inline magnifier; real GET form */
|
||||
.search-form { position: relative; display: flex; gap: 8px; max-width: 560px; }
|
||||
.search-ico { position: absolute; left: 16px; top: 50%; translate: 0 -50%; color: var(--muted); pointer-events: none; }
|
||||
.hero-search input, .search-form input {
|
||||
.search-form input {
|
||||
flex: 1; min-width: 0; font: inherit; color: var(--text);
|
||||
background: #fff; border: 1px solid var(--border);
|
||||
border-radius: var(--radius-pill); padding: 13px 18px 13px 44px;
|
||||
}
|
||||
.hero-search input:focus, .search-form input:focus { border-color: var(--azure); }
|
||||
.search-form input:focus { border-color: var(--azure); }
|
||||
/* Live suggestions under the hero search — plain links, Tab-accessible */
|
||||
.suggest {
|
||||
position: absolute; top: calc(100% + 8px); left: 0; right: 0;
|
||||
@@ -235,14 +305,19 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
max-height: min(60vh, 480px); overflow: auto; /* long lists scroll on mobile */
|
||||
}
|
||||
.suggest:empty { display: none; }
|
||||
.suggest li { display: flex; align-items: center; gap: var(--space-s); padding: 0 12px; border-radius: calc(var(--radius) - 8px); }
|
||||
.suggest li { display: flex; align-items: flex-start; gap: var(--space-s); padding: 0 12px; border-radius: calc(var(--radius) - 8px); }
|
||||
.suggest li:hover, .suggest li:focus-within { background: var(--moon); }
|
||||
/* The link holds <mark>-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; display: flex; align-items: center; min-height: 44px;
|
||||
flex: 1; min-width: 0; display: block; padding-block: 10px;
|
||||
color: var(--text); font-weight: 500; font-size: 0.94rem; text-decoration: none;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
.suggest small { margin-top: 12px; } /* date chip tracks the first title line */
|
||||
.suggest::after {
|
||||
content: "↵ Enter — all results"; display: block; margin-top: 4px;
|
||||
content: "Press Enter for all results"; display: block; margin-top: 4px;
|
||||
padding: 8px 12px 2px; border-top: 1px solid var(--border);
|
||||
color: var(--muted); font-size: 0.78rem;
|
||||
}
|
||||
@@ -261,10 +336,10 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
.grid { display: grid; gap: var(--space-m); grid-template-columns: 1fr; container-type: inline-size; }
|
||||
@media (min-width: 640px) { .grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (min-width: 940px) { .grid { grid-template-columns: repeat(3, 1fr); } }
|
||||
/* Subgrid: cover/cat/title/desc/meta rows align across each card row */
|
||||
/* Subgrid: cover/title/desc/meta rows align across each card row */
|
||||
@supports (grid-template-rows: subgrid) {
|
||||
.grid > .card:not(.card--featured, .tile) { display: grid; grid-template-rows: subgrid; grid-row: span 5; gap: 0; }
|
||||
.grid > .card:not(.card--featured, .tile) .body { display: grid; grid-template-rows: subgrid; grid-row: span 4; gap: 10px; }
|
||||
.grid > .card:not(.card--featured, .tile) { display: grid; grid-template-rows: subgrid; grid-row: span 4; gap: 0; }
|
||||
.grid > .card:not(.card--featured, .tile) .body { display: grid; grid-template-rows: subgrid; grid-row: span 3; gap: 10px; }
|
||||
}
|
||||
|
||||
/* News cards — image + category + clamped title/description + <time> meta;
|
||||
@@ -380,6 +455,9 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
}
|
||||
}
|
||||
|
||||
/* Long unbroken strings (URLs, identifiers) wrap instead of forcing page overflow */
|
||||
.prose { overflow-wrap: break-word; }
|
||||
.prose a { overflow-wrap: anywhere; }
|
||||
.prose h2 { color: var(--galaxy); margin: 34px 0 10px; font-size: clamp(1.25rem, 2.6vw, 1.45rem); }
|
||||
.prose h3 { color: var(--galaxy); margin: 26px 0 8px; font-size: 1.15rem; }
|
||||
.prose p { margin: 0 0 16px; }
|
||||
@@ -392,11 +470,30 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
.prose img { border: 1px solid var(--border); border-radius: var(--radius); }
|
||||
.prose img + em, .prose p > em:only-child { color: var(--muted); font-size: 0.85rem; }
|
||||
.prose hr { border: 0; border-top: 1px solid var(--border); margin: 32px 0; }
|
||||
.prose table { width: 100%; border-collapse: collapse; margin: 0 0 16px; font-size: 0.94rem; }
|
||||
/* Wide tables scroll inside their own box, never the page (mobile guard) */
|
||||
.prose table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; margin: 0 0 16px; font-size: 0.94rem; }
|
||||
.prose th { text-align: left; font-weight: 600; color: var(--galaxy); }
|
||||
.prose th, .prose td { padding: 10px 12px; border-bottom: 1px solid var(--border); }
|
||||
.prose thead th { border-bottom: 2px solid var(--cherenkov); }
|
||||
|
||||
/* Prev/next article links — sequential nav from the date-sorted collection */
|
||||
.post-nav {
|
||||
display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-m);
|
||||
border-top: 1px solid var(--border); margin-top: var(--space-xl); padding-top: var(--space-m);
|
||||
}
|
||||
.post-nav a { display: block; min-width: 0; text-decoration: none; }
|
||||
.post-nav .post-nav-prev { grid-column: 1; }
|
||||
.post-nav .post-nav-next { grid-column: 2; text-align: right; }
|
||||
.post-nav small {
|
||||
display: block; color: var(--muted); font-size: 0.72rem; font-weight: 600;
|
||||
text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 4px;
|
||||
}
|
||||
.post-nav .post-nav-title {
|
||||
color: var(--galaxy); font-weight: 500;
|
||||
display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||||
}
|
||||
.post-nav a:hover .post-nav-title { color: var(--link); }
|
||||
|
||||
/* Generic page section — one rhythm token for all pages */
|
||||
.page { padding: var(--space-xl) 0; }
|
||||
.panel {
|
||||
@@ -422,29 +519,34 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
/* Search results (list built by the inline script on /search) — card-like rows */
|
||||
.search-results { list-style: none; margin: var(--space-m) 0 0; padding: 0; max-width: 720px; display: grid; gap: var(--space-s); }
|
||||
.search-results li {
|
||||
display: flex; justify-content: space-between; align-items: center; gap: var(--space-s);
|
||||
display: flex; align-items: flex-start; gap: var(--space-s);
|
||||
background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
|
||||
padding: 12px 18px; box-shadow: var(--shadow-ambient);
|
||||
}
|
||||
.search-results li:hover { border-color: var(--azure); box-shadow: var(--shadow-lifted); }
|
||||
.search-results a { text-decoration: none; font-weight: 500; }
|
||||
/* 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; }
|
||||
/* Date chips on results and suggestions */
|
||||
.search-results small, .suggest small {
|
||||
color: var(--muted); white-space: nowrap; font-size: 0.78rem;
|
||||
background: var(--moon); border-radius: var(--radius-pill); padding: 2px 10px;
|
||||
}
|
||||
.search-results small { margin-top: 3px; } /* optical align with the first title line */
|
||||
/* Matched-term highlight in results/suggestions (Starlight search pattern) —
|
||||
brand tint only, no new hues */
|
||||
mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(var(--radius) - 12px); padding: 0 2px; }
|
||||
|
||||
/* Mock/status badges — every mock must be labelled (REQUIREMENTS.md §5) */
|
||||
/* Mock/status badges — every mock stays labelled (REQUIREMENTS.md §5), but the
|
||||
Demo phase banner is loud once, so per-element badges only whisper: quiet
|
||||
hairline pill, muted text (7.1:1 on Moon), sentence case, Galaxy dot on mocks. */
|
||||
.badge-mock, .badge-ext {
|
||||
display: inline-block; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.06em;
|
||||
text-transform: uppercase; padding: 4px 10px; border-radius: var(--radius-pill); margin-bottom: 14px;
|
||||
display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
|
||||
font-size: 0.75rem; font-weight: 500; color: var(--muted);
|
||||
background: var(--moon); border: 1px solid var(--border);
|
||||
border-radius: var(--radius-pill); padding: 2px 10px; margin-bottom: 14px;
|
||||
}
|
||||
.badge-mock { color: #7a3d00; background: #fff3e0; border: 1px solid #f0cf9b; }
|
||||
.badge-ext { color: var(--galaxy); background: var(--moon); border: 1px solid var(--border); text-transform: none; letter-spacing: 0; }
|
||||
.badge-mock::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--galaxy); flex: none; }
|
||||
|
||||
/* Dashboard mock — aggregation panels with status pills */
|
||||
.dash-grid { display: grid; gap: var(--space-m); grid-template-columns: 1fr; margin-top: var(--space-s); }
|
||||
@@ -534,6 +636,7 @@ mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(va
|
||||
.hero > :nth-child(2) { animation-delay: 0.08s; }
|
||||
.hero > :nth-child(3) { animation-delay: 0.16s; }
|
||||
.hero > :nth-child(4) { animation-delay: 0.24s; }
|
||||
.hero > :nth-child(5) { animation-delay: 0.32s; }
|
||||
/* Hover feedback */
|
||||
.card, .search-results li { transition: border-color 0.15s ease, box-shadow 0.2s ease, transform 0.2s ease; }
|
||||
.card:hover { transform: translateY(-2px); }
|
||||
|
||||
Reference in New Issue
Block a user