feat: Apple-grade pass — scale, type, photographic hero, de-noise, single-signal chrome, lighter header
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012jWfn3RwPfFGTtBddm36Uy
This commit is contained in:
+270
-212
@@ -1,7 +1,8 @@
|
||||
/* ==========================================================================
|
||||
CTAO Science Portal — design tokens per the official CTAO Brand Guidelines
|
||||
(April 2024): colors D.2, typography D.3 (Inter body / Space Grotesk display),
|
||||
flash D.4. All look-and-feel lives in the tokens below; WCAG 2.1 AA contrast.
|
||||
(April 2024): colors D.2, typography D.3 (Inter body / Space Grotesk display
|
||||
at medium weight per D.3.4), flash D.4. All look-and-feel lives in the tokens
|
||||
below; WCAG 2.1 AA contrast (photo-hero worst cases computed — see DESIGN.md).
|
||||
Light theme only (brand is light-first; navy bands carry the dark identity).
|
||||
System rules (spacing / elevation / surfaces / motion): see DESIGN.md.
|
||||
========================================================================== */
|
||||
@@ -9,9 +10,9 @@
|
||||
color-scheme: light;
|
||||
/* Brand palette — hex values straight from the brand book */
|
||||
--galaxy: #00004a; /* Galaxy Blue — headings, header/footer bands */
|
||||
--cherenkov: #00e4d8; /* Cherenkov Blue — accents, flash, CTAs; NOT for small text on light */
|
||||
--cherenkov: #00e4d8; /* Cherenkov Blue — primary CTA, flash, hero subtitle, logo cluster ONLY */
|
||||
--moon: #f5f5f5; /* Moon Gray — surfaces */
|
||||
--azure: #007aff; /* Cosmic Azure — brand hyperlink hue (large/UI only on light) */
|
||||
--azure: #007aff; /* Cosmic Azure — focus rings (UI only on light) */
|
||||
--indigo: #00009c; /* Interestellar Indigo — gradient depth */
|
||||
/* Derived, WCAG-adjusted */
|
||||
--text: #101228; /* near-Galaxy body ink */
|
||||
@@ -19,35 +20,58 @@
|
||||
--border: #e2e5ee;
|
||||
--link: #0057c2; /* Cosmic Azure darkened to pass AA (4.5:1) for body links */
|
||||
--on-galaxy-muted: #c7cde9;
|
||||
--tint-cherenkov: color-mix(in srgb, var(--cherenkov) 16%, transparent); /* chip/badge fill */
|
||||
--tint-cherenkov: color-mix(in srgb, var(--cherenkov) 16%, transparent); /* <mark> 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');
|
||||
/* Type & layout */
|
||||
--font-body: "Inter", "Inter Fallback", Arial, system-ui, sans-serif; /* BRAND D.3.1 */
|
||||
--font-display: "Space Grotesk", var(--font-body); /* BRAND D.3.2 — headlines only */
|
||||
/* 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 */
|
||||
--fs-xs: 0.8125rem; /* chips, meta, badges, labels */
|
||||
--fs-s: 0.9rem; /* secondary text, nav, forms, footer */
|
||||
--fs-l: 1.125rem; /* card titles, standfirst, panel titles */
|
||||
--fs-xl: 1.5rem; /* prose h2, featured title, auth h1 */
|
||||
--fs-h2: clamp(1.75rem, 3.5vw, 2.5rem); /* section heads */
|
||||
--fs-h1: clamp(2.25rem, 5vw, 3.5rem); /* page/article headlines */
|
||||
--fs-display: clamp(2.5rem, 7vw, 4.75rem); /* home hero only */
|
||||
/* ctao.org uses generous rounding (15/30/60px tokens) and pill buttons */
|
||||
--radius: 16px;
|
||||
--radius-pill: 999px;
|
||||
--maxw: 1120px;
|
||||
/* Fluid spacing scale (ctao.org rhythm: sections breathe, mobile stays compact).
|
||||
/* Fluid spacing scale (Apple-scale rhythm: sections breathe, mobile stays compact).
|
||||
Every section / container / card padding sits on this scale — no ad-hoc values. */
|
||||
--gutter: clamp(18px, 4vw, 28px); /* page side padding */
|
||||
--space-s: 12px;
|
||||
--space-m: 20px;
|
||||
--space-m: 24px;
|
||||
--space-l: clamp(24px, 2vw + 16px, 40px);
|
||||
--space-xl: clamp(40px, 3vw + 24px, 72px); /* section rhythm */
|
||||
--space-band: clamp(48px, 5vw + 28px, 96px); /* hero / auth band padding */
|
||||
/* Elevation — navy-tinted; the ONLY two shadows allowed in this codebase */
|
||||
--shadow-ambient: 0 1px 2px rgba(0, 0, 74, 0.05), 0 4px 14px rgba(0, 0, 74, 0.07);
|
||||
--shadow-lifted: 0 4px 10px rgba(0, 0, 74, 0.08), 0 18px 44px rgba(0, 0, 74, 0.18);
|
||||
/* Nebula glow (BRAND D.5) — one stack for hero + auth bands, static AND animated.
|
||||
Alphas are contrast ceilings (DESIGN.md): Cherenkov ≤.38, Azure ≤.35 keep the
|
||||
Cherenkov subtitle/eyebrow ≥4.5:1 even with a blob core right under the text.
|
||||
Cherenkov and Azure cores sit in opposite corners — cores never meet. */
|
||||
--space-xl: clamp(56px, 7vw, 120px); /* section rhythm */
|
||||
--space-band: clamp(72px, 10vw, 160px); /* hero / auth / landing-head padding */
|
||||
/* Elevation — navy-tinted, soft/large/low-alpha; the ONLY two shadows allowed */
|
||||
--shadow-ambient: 0 1px 2px rgba(0, 0, 74, 0.04), 0 8px 24px rgba(0, 0, 74, 0.06);
|
||||
--shadow-lifted: 0 2px 6px rgba(0, 0, 74, 0.05), 0 24px 48px rgba(0, 0, 74, 0.14);
|
||||
/* Motion — ONE hover language everywhere (ctao.org: quiet .25s fades) */
|
||||
--dur: 0.25s;
|
||||
--ease: ease-out;
|
||||
/* Nebula glow (BRAND D.5) — auth band, static AND animated. Alphas are
|
||||
contrast ceilings (DESIGN.md): Cherenkov ≤.38 / Azure ≤.35; cores sit in
|
||||
opposite corners — cores never meet. */
|
||||
--nebula:
|
||||
radial-gradient(52% 58% at 78% 76%, rgba(0, 228, 216, 0.38), transparent 66%),
|
||||
radial-gradient(46% 52% at 12% 18%, rgba(0, 122, 255, 0.33), transparent 64%),
|
||||
radial-gradient(75% 85% at 40% 55%, rgba(0, 0, 156, 0.8), transparent 72%);
|
||||
/* Photo-hero variant: no indigo depth blob over photography, Cherenkov ≤.30
|
||||
with its core pinned ≥80% band width (only ~.15 fringe reaches text). */
|
||||
--nebula-glow:
|
||||
radial-gradient(52% 58% at 82% 80%, rgba(0, 228, 216, 0.3), transparent 66%),
|
||||
radial-gradient(46% 52% at 10% 15%, rgba(0, 122, 255, 0.28), transparent 64%);
|
||||
/* Hero scrim over the photo — worst-case AA computed in DESIGN.md:
|
||||
small text lives left of 52% band width (α ≥ .76 there). */
|
||||
--hero-scrim: linear-gradient(to right,
|
||||
rgba(0, 0, 74, 0.84), rgba(0, 0, 74, 0.76) 52%,
|
||||
rgba(0, 0, 74, 0.44) 78%, rgba(0, 0, 74, 0.26));
|
||||
}
|
||||
/* ≤640px the hero text spans the full width — flat scrim, computed ≥5.28:1 */
|
||||
@media (max-width: 640px) {
|
||||
:root { --hero-scrim: linear-gradient(rgba(0, 0, 74, 0.8), rgba(0, 0, 74, 0.8)); }
|
||||
}
|
||||
|
||||
/* Self-hosted brand fonts — latin subset, variable weight, swap + metric-matched fallback */
|
||||
@@ -73,7 +97,7 @@
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 84px; /* sticky header + anchor jumps */ }
|
||||
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 76px; /* 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
|
||||
@@ -84,11 +108,14 @@ body {
|
||||
font-family: var(--font-body);
|
||||
background: #fff;
|
||||
color: var(--text);
|
||||
line-height: 1.65;
|
||||
line-height: 1.5;
|
||||
min-height: 100dvh;
|
||||
}
|
||||
|
||||
h1, h2 { font-family: var(--font-display); letter-spacing: -0.01em; }
|
||||
/* Display type: Space Grotesk at medium weight (BRAND D.3.4 — regular/medium),
|
||||
tight tracking at display sizes, compact leading. Hierarchy comes from size. */
|
||||
h1, h2 { font-family: var(--font-display); font-weight: 500; letter-spacing: -0.025em; line-height: 1.1; }
|
||||
h3 { font-weight: 600; }
|
||||
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; }
|
||||
@@ -97,6 +124,10 @@ h1, h2, h3 { overflow-wrap: break-word; }
|
||||
/* Inline SVG icons — stroke inherits currentColor */
|
||||
.ico { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; flex: none; }
|
||||
|
||||
/* All <summary> disclosures (menu, search, TOC) share the plain-button look */
|
||||
summary { cursor: pointer; list-style: none; }
|
||||
summary::-webkit-details-marker { display: none; }
|
||||
|
||||
a { color: var(--link); text-decoration: underline; text-underline-offset: 3px; }
|
||||
a:hover { color: var(--indigo); }
|
||||
/* Placeholder links (<a> without href) don't pretend to be clickable */
|
||||
@@ -120,7 +151,8 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
}
|
||||
|
||||
.container { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
|
||||
/* Surface rhythm: white (editorial) → Moon Gray (service/utility bands) → Galaxy (hero/footer) */
|
||||
/* Surface rhythm: white (editorial + landing heads) → Moon Gray (service/utility
|
||||
bands) → Galaxy (home hero, auth, footer) */
|
||||
.band--moon { background: var(--moon); }
|
||||
|
||||
/* Flash — the REAL brand star (BRAND D.4): inline SVG path lifted from the
|
||||
@@ -128,69 +160,99 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
.flash { width: 12px; height: 12px; color: var(--cherenkov); flex: none; }
|
||||
|
||||
|
||||
/* Header — Galaxy Blue band, reverse (white) logo per BRAND B.1.2 */
|
||||
/* Header — Galaxy Blue band, reverse (white) logo per BRAND B.1.2; translucent
|
||||
over content where backdrop blur is supported (AA computed: worst underlying
|
||||
white → bar (31,31,96), muted nav text 9.4:1). Solid Galaxy fallback. */
|
||||
.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; }
|
||||
@supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
|
||||
.site-header {
|
||||
background: color-mix(in srgb, var(--galaxy) 88%, transparent);
|
||||
-webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
|
||||
}
|
||||
}
|
||||
.nav { display: flex; align-items: center; gap: 4px; min-height: 56px; flex-wrap: nowrap; }
|
||||
.nav > nav { display: flex; align-items: center; gap: 4px; }
|
||||
/* 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) */
|
||||
/* One-row guarantee: everything keeps its natural size except the spacer
|
||||
(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; } }
|
||||
/* Header tiers, one row always: ≥1025px full nav · ≤1024px disclosure menu ·
|
||||
≤640px sub-brand hidden · ≤480px icon-only menu, smaller logo · ≤360px compact.
|
||||
Search is the same icon-reveal at every width (one pattern, no width math). */
|
||||
.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 { display: flex; align-items: center; gap: 10px; margin-right: 10px; text-decoration: none; }
|
||||
.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;
|
||||
color: var(--cherenkov); font-size: var(--fs-xs); 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;
|
||||
color: var(--on-galaxy-muted); font-weight: 500; font-size: var(--fs-s);
|
||||
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 a.navlink[aria-current="page"] { color: #fff; border-bottom-color: #fff; }
|
||||
/* AAI sign-in entry — ghost/outline: Cherenkov fill is reserved for the page's
|
||||
primary CTA, the header only whispers. */
|
||||
.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;
|
||||
color: #fff; background: transparent; font: inherit; font-weight: 600; font-size: var(--fs-s);
|
||||
border: 1px solid rgba(255, 255, 255, 0.55); border-radius: var(--radius-pill);
|
||||
padding: 7px 18px; margin-left: 6px; text-decoration: none; white-space: nowrap;
|
||||
}
|
||||
.nav .login-mock:hover { background: var(--cherenkov-hover); color: var(--galaxy); }
|
||||
.nav .login-mock:hover { background: rgba(255, 255, 255, 0.12); color: #fff; border-color: #fff; }
|
||||
/* 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; }
|
||||
/* Site search. Desktop ≥1025px: VISIBLE quiet field — NN/g magnifying-glass-
|
||||
icon research: icon-only search reduces discoverability/usage; a visible
|
||||
input is recommended when search is an important task (content-heavy portal,
|
||||
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); }
|
||||
.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;
|
||||
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 */
|
||||
border-radius: var(--radius-pill); padding: 7px 14px 7px 32px;
|
||||
}
|
||||
.nav-search input:focus { border-color: var(--azure); }
|
||||
.nav-search input::placeholder { color: rgba(255, 255, 255, 0.65); } /* 6.9:1 */
|
||||
.nav-search input:focus { border-color: #fff; }
|
||||
.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 */
|
||||
/* ≤1024px replacement: a 44px magnifier <details> reveals a search row under
|
||||
the header (NN/g mobile-search pattern) — see the menu media block. */
|
||||
.search-pop { display: none; }
|
||||
.search-pop summary {
|
||||
display: inline-flex; align-items: center; justify-content: center;
|
||||
min-width: 44px; min-height: 44px; color: #fff;
|
||||
}
|
||||
.search-pop form {
|
||||
position: absolute; left: 0; right: 0; top: 100%;
|
||||
display: flex; justify-content: center; gap: 8px; padding: 12px var(--gutter) 16px;
|
||||
background: var(--galaxy); border-top: 1px solid rgba(255, 255, 255, 0.15);
|
||||
box-shadow: var(--shadow-lifted);
|
||||
}
|
||||
.search-pop input {
|
||||
flex: 0 1 560px; min-width: 0; font: inherit; color: var(--text);
|
||||
background: #fff; border: 1px solid transparent; 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: max(var(--gutter), 50vw - 330px); right: max(var(--gutter), 50vw - 330px);
|
||||
top: calc(100% + 4px);
|
||||
}
|
||||
@media (max-width: 1024px) {
|
||||
.nav > nav { display: none; }
|
||||
.menu { display: block; }
|
||||
.menu summary {
|
||||
display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
|
||||
padding: 0 10px; margin-left: 6px; color: #fff; font-weight: 500;
|
||||
cursor: pointer; list-style: none; white-space: nowrap;
|
||||
padding: 0 10px; margin-left: 6px; color: #fff; font-weight: 500; white-space: nowrap;
|
||||
}
|
||||
.menu summary::-webkit-details-marker { display: none; }
|
||||
.menu nav {
|
||||
position: absolute; left: 0; right: 0; top: 100%;
|
||||
display: flex; flex-direction: column; padding: 6px var(--gutter) 14px;
|
||||
@@ -203,32 +265,9 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
.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); }
|
||||
.menu nav a[aria-current="page"] { font-weight: 700; }
|
||||
}
|
||||
@media (max-width: 640px) { .brand .brand-sub { display: none; } }
|
||||
@media (max-width: 480px) {
|
||||
.brand img { height: 22px; }
|
||||
.menu summary .menu-label { display: none; }
|
||||
@@ -237,8 +276,8 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
@media (max-width: 360px) {
|
||||
.nav { padding: 0 14px; gap: 2px; }
|
||||
.brand { margin-right: 4px; }
|
||||
.brand img { height: 20px; }
|
||||
.nav .login-mock { padding: 8px 12px; }
|
||||
/* logo stays 22px — 22px tall ≈ 105px wide, brand minimum is 100px digital */
|
||||
.nav .login-mock { padding: 7px 12px; }
|
||||
}
|
||||
/* External-link marker — SVG arrow via mask, inherits currentColor */
|
||||
.external::after {
|
||||
@@ -248,34 +287,37 @@ img { max-width: 100%; height: auto; display: block; }
|
||||
mask: var(--ico-ext) center / contain no-repeat;
|
||||
}
|
||||
|
||||
/* Hero — navy band with a nebula glow (BRAND D.5). The static gradient below is
|
||||
the reduced-motion fallback; with motion allowed, the glow moves to an animated
|
||||
pseudo-layer (see the motion block at the end of this file). */
|
||||
/* Hero (home only) — image-led: LST-1 under the night sky, full-bleed beneath a
|
||||
Galaxy scrim (--hero-scrim; worst-case AA computed in DESIGN.md). With motion
|
||||
allowed a Cherenkov/Azure glow layer drifts above the photo (see motion block). */
|
||||
.hero-band {
|
||||
background: var(--nebula), var(--galaxy);
|
||||
background: var(--hero-scrim), url("/brand/hero.jpg") center / cover, var(--galaxy);
|
||||
color: #fff; padding: var(--space-band) 0; position: relative;
|
||||
/* NO overflow:hidden here — it would clip the search-suggest dropdown.
|
||||
The animated nebula is clipped by its own .band-bg frame instead. */
|
||||
The animated glow is clipped by its own .band-bg frame instead. */
|
||||
}
|
||||
.band-bg { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
|
||||
.hero { position: relative; } /* content above the animated nebula layer */
|
||||
.hero h1 { font-size: clamp(2rem, 6vw, 3.6rem); margin: 0 0 10px; line-height: 1.12; font-weight: 700; }
|
||||
.hero p { color: var(--cherenkov); font-size: 1.08rem; max-width: 62ch; margin: 0; } /* subtitle per BRAND D.3.4 */
|
||||
.hero { position: relative; } /* content above the animated glow layer */
|
||||
.hero h1 { font-size: var(--fs-display); margin: 0 0 12px; }
|
||||
.hero p { color: var(--cherenkov); font-size: var(--fs-l); max-width: 62ch; margin: 0; } /* subtitle per BRAND D.3.4 */
|
||||
.eyebrow {
|
||||
color: var(--on-galaxy-muted); font-weight: 600; text-transform: uppercase;
|
||||
letter-spacing: 0.14em; font-size: 0.72rem; margin-bottom: 8px;
|
||||
letter-spacing: 0.14em; font-size: var(--fs-xs); margin-bottom: 8px;
|
||||
}
|
||||
|
||||
/* 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); }
|
||||
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--space-s); margin-top: var(--space-l); }
|
||||
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); }
|
||||
.btn--ghost:hover { background: rgba(255, 255, 255, 0.12); color: #fff; border-color: #fff; }
|
||||
|
||||
/* Section-landing head (news/search/proposals/dashboard/support) — white page,
|
||||
display-scale Galaxy h1 + standfirst; the navy band is reserved for / and /login. */
|
||||
.page-head { padding: var(--space-band) 0 var(--space-l); }
|
||||
.page-head h1 { color: var(--galaxy); font-size: var(--fs-h1); margin: 0 0 10px; }
|
||||
.page-head .standfirst { margin: 0; max-width: 62ch; }
|
||||
.page-head + .page { padding-top: 0; } /* white-on-white: head already spaces */
|
||||
|
||||
/* Search field (/search page) — large pill input with inline magnifier; real GET form */
|
||||
.search-form { position: relative; display: flex; gap: 8px; max-width: 560px; }
|
||||
@@ -286,7 +328,7 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
|
||||
border-radius: var(--radius-pill); padding: 13px 18px 13px 44px;
|
||||
}
|
||||
.search-form input:focus { border-color: var(--azure); }
|
||||
/* Live suggestions under the hero search — plain links, Tab-accessible */
|
||||
/* Live suggestions — plain links, Tab-accessible */
|
||||
.suggest {
|
||||
position: absolute; top: calc(100% + 8px); left: 0; right: 0;
|
||||
z-index: 11; /* above the sticky header (10) — never slides under it on scroll */
|
||||
@@ -303,14 +345,14 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
|
||||
stop titles from wrapping). ≥44px target comes from the block padding. */
|
||||
.suggest a {
|
||||
flex: 1; min-width: 0; display: block; padding-block: 10px;
|
||||
color: var(--text); font-weight: 500; font-size: 0.94rem; text-decoration: none;
|
||||
color: var(--text); font-weight: 500; font-size: var(--fs-s); text-decoration: none;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
.suggest small { margin-top: 12px; } /* date chip tracks the first title line */
|
||||
.suggest small { margin-top: 12px; } /* 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);
|
||||
color: var(--muted); font-size: 0.78rem;
|
||||
color: var(--muted); font-size: var(--fs-xs);
|
||||
}
|
||||
|
||||
/* Section header row (h2 + optional "All news →" link) */
|
||||
@@ -319,7 +361,7 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
|
||||
gap: var(--space-s); margin: var(--space-l) 0 var(--space-m);
|
||||
}
|
||||
.section-head:first-child { margin-top: 0; }
|
||||
.section-head h2 { margin: 0; color: var(--galaxy); font-size: clamp(1.3rem, 2.5vw, 1.6rem); }
|
||||
.section-head h2 { margin: 0; color: var(--galaxy); font-size: var(--fs-h2); }
|
||||
.more { font-weight: 600; text-decoration: none; white-space: nowrap; }
|
||||
.more:hover { text-decoration: underline; }
|
||||
|
||||
@@ -333,28 +375,22 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
|
||||
.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;
|
||||
whole card clickable via stretched link (research: NN/g & card-UI guides 2025). */
|
||||
/* News cards — image + clamped title/description + <time> meta; whole card
|
||||
clickable via stretched link. Chrome is single-signal: hairline on white,
|
||||
borderless on Moon (white-on-moon separates); hover = one elevate gesture. */
|
||||
.card {
|
||||
position: relative; background: #fff; border: 1px solid var(--border);
|
||||
border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow-ambient);
|
||||
display: flex; flex-direction: column;
|
||||
display: flex; flex-direction: column; line-height: 1.45;
|
||||
}
|
||||
.card:hover, .card:focus-within { border-color: var(--azure); box-shadow: var(--shadow-lifted); }
|
||||
.band--moon :is(.card, .panel) { border-color: transparent; }
|
||||
.card:hover, .card:focus-within { box-shadow: var(--shadow-lifted); }
|
||||
/* Visible focus ring for the whole-card stretched link (WCAG 2.4.7) */
|
||||
.card:focus-within { box-shadow: 0 0 0 2px var(--azure), var(--shadow-lifted); }
|
||||
.card .cover { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
|
||||
.card .body { padding: var(--space-m); display: flex; flex-direction: column; gap: 10px; flex: 1; }
|
||||
/* Cover-less cards get a Cherenkov top accent instead of an image */
|
||||
.card:not(:has(.cover)) .body { border-top: 3px solid var(--cherenkov); }
|
||||
.cat {
|
||||
display: inline-block; align-self: flex-start; font-size: 0.72rem; text-transform: uppercase;
|
||||
letter-spacing: 0.08em; font-weight: 600;
|
||||
color: var(--galaxy); background: var(--tint-cherenkov);
|
||||
padding: 4px 10px; border-radius: var(--radius-pill);
|
||||
}
|
||||
.card h3 {
|
||||
margin: 2px 0 0; font-size: 1.1rem; line-height: 1.35; font-family: var(--font-body), sans-serif;
|
||||
margin: 2px 0 0; font-size: var(--fs-l); line-height: 1.3; font-family: var(--font-body), sans-serif;
|
||||
display: -webkit-box; -webkit-line-clamp: 3; line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
|
||||
}
|
||||
.card h3 a { color: var(--galaxy); text-decoration: none; }
|
||||
@@ -363,21 +399,20 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
|
||||
.card h3 a::before { content: ""; position: absolute; inset: 0; }
|
||||
.card h3 a:hover { color: var(--link); }
|
||||
.card .desc {
|
||||
margin: 0; color: var(--muted); font-size: 0.94rem;
|
||||
margin: 0; color: var(--muted); font-size: var(--fs-s);
|
||||
display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||||
}
|
||||
.card .meta { margin-top: auto; color: var(--muted); font-size: 0.8rem; }
|
||||
.card .meta { margin-top: auto; color: var(--muted); font-size: var(--fs-xs); }
|
||||
/* Lead story — larger, splits when the grid itself is wide enough (container query) */
|
||||
@container (min-width: 640px) {
|
||||
.card--featured { grid-column: 1 / -1; display: grid; grid-template-columns: 3fr 2fr; }
|
||||
.card--featured .cover { height: 100%; aspect-ratio: auto; }
|
||||
.card--featured .body { padding: var(--space-l); justify-content: center; }
|
||||
.card--featured h3 { font-size: 1.6rem; font-family: var(--font-display), sans-serif; -webkit-line-clamp: 3; line-clamp: 3; }
|
||||
.card--featured h3 { font-size: var(--fs-xl); font-family: var(--font-display), sans-serif; font-weight: 500; -webkit-line-clamp: 3; line-clamp: 3; }
|
||||
.card--featured .desc { -webkit-line-clamp: 3; line-clamp: 3; }
|
||||
}
|
||||
|
||||
/* Pagination (news archive) — prev/next + windowed page numbers; ≥44px targets.
|
||||
Pattern mined from AstroPaper/Astro blog templates, numbers added for 9 pages. */
|
||||
/* Pagination (news archive) — prev/next + windowed page numbers; ≥44px targets. */
|
||||
.pagination {
|
||||
display: flex; align-items: center; justify-content: center; flex-wrap: wrap;
|
||||
gap: 4px var(--space-s); margin-top: var(--space-xl);
|
||||
@@ -388,7 +423,7 @@ a.btn { display: inline-flex; align-items: center; gap: 6px; text-decoration: no
|
||||
min-width: 44px; min-height: 44px; padding: 0 12px;
|
||||
border-radius: var(--radius-pill); text-decoration: none; font-weight: 500; color: var(--text);
|
||||
}
|
||||
a.page-link:hover { background: var(--moon); color: var(--indigo); }
|
||||
a.page-link:hover { background: var(--moon); }
|
||||
.page-link[aria-current="page"] { background: var(--galaxy); color: #fff; }
|
||||
.page-step { font-weight: 600; }
|
||||
a.page-step { color: var(--link); }
|
||||
@@ -396,80 +431,96 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
.page-gap { display: inline-flex; align-items: center; justify-content: center; min-width: 24px; min-height: 44px; color: var(--muted); }
|
||||
|
||||
/* Service tiles — card tokens; stroke glyph above an always-visible label
|
||||
(NN/g: icons differentiate and speed scanning only when labelled) */
|
||||
(NN/g: icons differentiate and speed scanning only when labelled).
|
||||
Planned (not-yet-available) tiles are subdued: muted, no link, no chrome —
|
||||
availability lives in the description text ("— planned"). */
|
||||
.tile { padding: var(--space-m); gap: 8px; }
|
||||
.tile .ico { width: 26px; height: 26px; stroke-width: 1.75; stroke-linejoin: round; color: var(--galaxy); }
|
||||
.tile h3 { margin: 0; }
|
||||
.tile .badge-mock, .tile .badge-ext { margin: auto 0 0; align-self: flex-start; }
|
||||
.tile--planned :is(h3, .ico) { color: var(--muted); }
|
||||
|
||||
/* Article — 70ch column; on ≥1200px a sticky "On this page" rail sits to the right */
|
||||
.article-layout { display: grid; grid-template-columns: minmax(0, 70ch); }
|
||||
.article { padding: var(--space-l) 0 var(--space-xl); max-width: 70ch; }
|
||||
.article .back { color: var(--muted); font-size: 0.9rem; }
|
||||
.article h1 {
|
||||
color: var(--galaxy); font-size: clamp(2rem, 5vw, 3rem);
|
||||
margin: 14px 0 10px; line-height: 1.12;
|
||||
}
|
||||
.article .back { color: var(--muted); font-size: var(--fs-s); }
|
||||
.article h1 { color: var(--galaxy); font-size: var(--fs-h1); margin: 14px 0 10px; }
|
||||
.article .meta {
|
||||
display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
|
||||
color: var(--muted); font-size: 0.9rem; margin-bottom: var(--space-l);
|
||||
color: var(--muted); font-size: var(--fs-s); margin-bottom: var(--space-l);
|
||||
}
|
||||
/* Lead image — borderless, breaking slightly out of the text column on wide
|
||||
screens (editorial breakout; the column stays 70ch for reading) */
|
||||
.article .cover { border-radius: var(--radius); margin-bottom: var(--space-l); }
|
||||
@media (min-width: 900px) {
|
||||
.article .cover { margin-inline: -40px; width: calc(100% + 80px); max-width: none; }
|
||||
}
|
||||
.article .cover { border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: var(--space-l); }
|
||||
/* Standfirst — the description shown as the visible lead under the headline
|
||||
(Guardian/BBC anatomy). Replaces the old first-prose-paragraph lead styling
|
||||
so an article never shows two competing leads. */
|
||||
.article .standfirst { margin: 0 0 var(--space-s); font-size: 1.12rem; line-height: 1.55; color: var(--muted); }
|
||||
/* Article TOC (MDN/Stripe pattern, rendered only when ≥3 h2/h3): sticky right rail
|
||||
on wide screens, collapsed <details> under the title otherwise. */
|
||||
.toc {
|
||||
background: var(--moon); border: 1px solid var(--border); border-radius: var(--radius);
|
||||
padding: var(--space-s) var(--space-m); font-size: 0.92rem;
|
||||
}
|
||||
(Guardian/BBC anatomy); also the intro line under section-landing h1s. */
|
||||
.standfirst { margin: 0 0 var(--space-s); font-size: var(--fs-l); line-height: 1.55; color: var(--muted); }
|
||||
/* Article TOC (Stripe/Apple-docs pattern, rendered only when ≥3 h2/h3):
|
||||
quiet "On this page" — sticky hairline-rule rail on wide screens, a light
|
||||
disclosure row otherwise. Links are muted, Galaxy on hover; the scrollspy
|
||||
active state (Galaxy text + Cherenkov rule segment) is navigation state,
|
||||
not decoration — it sits outside the one-accent budget. */
|
||||
.toc { font-size: var(--fs-s); }
|
||||
.toc strong, .toc summary {
|
||||
font-size: 0.72rem; text-transform: uppercase; font-weight: 600;
|
||||
font-size: var(--fs-xs); text-transform: uppercase; font-weight: 600;
|
||||
letter-spacing: 0.08em; color: var(--muted);
|
||||
}
|
||||
.toc strong { display: block; margin-bottom: 4px; }
|
||||
.toc summary { cursor: pointer; padding: 6px 0; }
|
||||
.toc strong { display: block; margin-bottom: 10px; }
|
||||
.toc ol { list-style: none; margin: 0; padding: 0; }
|
||||
.toc li { margin: 8px 0; }
|
||||
.toc li { margin: 6px 0; }
|
||||
.toc .d3 { padding-left: var(--space-s); }
|
||||
.toc a { text-decoration: none; display: inline-flex; align-items: center; min-height: 24px; }
|
||||
.toc a:hover { text-decoration: underline; }
|
||||
.toc a {
|
||||
color: var(--muted); text-decoration: none;
|
||||
display: inline-flex; align-items: center; min-height: 24px; position: relative;
|
||||
}
|
||||
.toc a:hover { color: var(--galaxy); }
|
||||
/* Scrollspy state (set by the [slug].astro script) — functional, not motion */
|
||||
.toc a[aria-current="true"] { color: var(--galaxy); font-weight: 600; }
|
||||
.toc--inline { margin-bottom: var(--space-l); }
|
||||
/* 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[open] summary .ico { transform: rotate(180deg); }
|
||||
.toc--inline ol { padding-bottom: var(--space-s); }
|
||||
.toc--rail { display: none; }
|
||||
@media (min-width: 1200px) {
|
||||
.article-layout { grid-template-columns: minmax(0, 70ch) 15rem; column-gap: var(--space-xl); justify-content: space-between; }
|
||||
.toc--inline { display: none; }
|
||||
.toc--rail {
|
||||
display: block; position: sticky; top: 88px; align-self: start;
|
||||
display: block; position: sticky; top: 80px; align-self: start;
|
||||
margin-top: calc(var(--space-l) + 44px); /* aligns with the article h1 */
|
||||
max-height: calc(100dvh - 112px); overflow: auto;
|
||||
max-height: calc(100dvh - 104px); overflow: auto;
|
||||
border-left: 1px solid var(--border); padding-left: var(--space-m);
|
||||
}
|
||||
/* Active rule segment: 2px Cherenkov over the hairline, tracking the link */
|
||||
.toc--rail a[aria-current="true"]::before {
|
||||
content: ""; position: absolute; left: calc(-1 * var(--space-m) - 1px);
|
||||
top: 3px; bottom: 3px; width: 2px; background: var(--cherenkov);
|
||||
}
|
||||
}
|
||||
|
||||
/* Long unbroken strings (URLs, identifiers) wrap instead of forcing page overflow */
|
||||
.prose { overflow-wrap: break-word; }
|
||||
.prose { line-height: 1.65; 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 h2 { color: var(--galaxy); margin: 44px 0 12px; font-size: var(--fs-xl); }
|
||||
.prose h3 { color: var(--galaxy); margin: 30px 0 8px; font-size: var(--fs-l); }
|
||||
.prose p { margin: 0 0 16px; }
|
||||
.prose ul, .prose ol { margin: 0 0 16px; padding-left: 22px; }
|
||||
.prose li { margin: 6px 0; }
|
||||
.prose blockquote {
|
||||
margin: 22px 0; padding: 12px 20px; border-left: 3px solid var(--cherenkov);
|
||||
margin: 22px 0; padding: 12px 20px; border-left: 3px solid var(--galaxy);
|
||||
background: var(--moon); color: var(--text);
|
||||
}
|
||||
.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 img + em, .prose p > em:only-child { color: var(--muted); font-size: var(--fs-s); }
|
||||
.prose hr { border: 0; border-top: 1px solid var(--border); margin: 32px 0; }
|
||||
/* 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 table { display: block; width: 100%; overflow-x: auto; border-collapse: collapse; margin: 0 0 16px; font-size: var(--fs-s); }
|
||||
.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); }
|
||||
.prose thead th { border-bottom: 2px solid var(--galaxy); }
|
||||
|
||||
/* Prev/next article links — sequential nav from the date-sorted collection */
|
||||
.post-nav {
|
||||
@@ -480,7 +531,7 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
.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;
|
||||
display: block; color: var(--muted); font-size: var(--fs-xs); font-weight: 600;
|
||||
text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 4px;
|
||||
}
|
||||
.post-nav .post-nav-title {
|
||||
@@ -497,7 +548,7 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
}
|
||||
.panel--narrow { max-width: 640px; }
|
||||
.form-row { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
|
||||
.form-row label { font-size: 0.88rem; font-weight: 500; }
|
||||
.form-row label { font-size: var(--fs-s); font-weight: 500; }
|
||||
.form-row input, .form-row select, .form-row textarea {
|
||||
background: #fff; border: 1px solid var(--border); border-radius: calc(var(--radius) - 4px);
|
||||
color: var(--text); padding: 11px 12px; font: inherit;
|
||||
@@ -509,35 +560,33 @@ span.page-step { color: var(--muted); } /* disabled end stop — non-interactive
|
||||
font: inherit; font-weight: 600; cursor: pointer;
|
||||
}
|
||||
.btn:hover { background: var(--cherenkov-hover); }
|
||||
.notice { color: var(--muted); font-size: 0.85rem; margin-top: 10px; }
|
||||
.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 */
|
||||
/* 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); }
|
||||
.search-results li {
|
||||
display: flex; align-items: flex-start; gap: var(--space-s);
|
||||
background: #fff; border: 1px solid var(--border); border-radius: var(--radius);
|
||||
background: #fff; 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 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; }
|
||||
/* 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 */
|
||||
/* 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 */
|
||||
/* Matched-term highlight in results/suggestions (Starlight search pattern) —
|
||||
brand tint only, no new hues */
|
||||
functional state, brand tint, no new hues */
|
||||
mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(var(--radius) - 12px); padding: 0 2px; }
|
||||
|
||||
/* 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. */
|
||||
/* Mock/status badges — whisper-quiet hairline pill, ONLY where a mock
|
||||
interaction actually happens (/proposals, /dashboard, /login, /support head);
|
||||
REQUIREMENTS §5 honesty lives at the interaction point, not on every tile. */
|
||||
.badge-mock, .badge-ext {
|
||||
display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
|
||||
font-size: 0.75rem; font-weight: 500; color: var(--muted);
|
||||
font-size: var(--fs-xs); 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;
|
||||
}
|
||||
@@ -546,43 +595,49 @@ mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(va
|
||||
/* Dashboard mock — aggregation panels with status pills */
|
||||
.dash-grid { display: grid; gap: var(--space-m); grid-template-columns: 1fr; margin-top: var(--space-s); }
|
||||
@media (min-width: 940px) { .dash-grid { grid-template-columns: repeat(2, 1fr); } }
|
||||
.panel-title { color: var(--galaxy); font-size: 1.1rem; margin: 0 0 var(--space-s); font-family: var(--font-body), sans-serif; font-weight: 600; }
|
||||
.panel-title { color: var(--galaxy); font-size: var(--fs-l); margin: 0 0 var(--space-s); font-family: var(--font-body), sans-serif; font-weight: 600; }
|
||||
.rows { list-style: none; margin: 0; padding: 0; }
|
||||
.rows li {
|
||||
display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
|
||||
padding: 10px 0; border-bottom: 1px solid var(--border); font-size: 0.92rem;
|
||||
padding: 10px 0; border-bottom: 1px solid var(--border); font-size: var(--fs-s);
|
||||
}
|
||||
.rows li:last-child { border-bottom: 0; }
|
||||
.row-id { color: var(--muted); font-size: 0.8rem; min-width: 7.5em; }
|
||||
.row-id { color: var(--muted); font-size: var(--fs-xs); min-width: 7.5em; }
|
||||
.row-main { flex: 1; min-width: 12em; }
|
||||
.row-date { color: var(--muted); font-size: 0.8rem; }
|
||||
.row-date { color: var(--muted); font-size: var(--fs-xs); }
|
||||
/* Status pills — neutral chrome; the label text carries the state */
|
||||
.pill {
|
||||
font-size: 0.72rem; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
|
||||
font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
|
||||
padding: 3px 10px; border-radius: var(--radius-pill); border: 1px solid var(--border);
|
||||
}
|
||||
.pill--ok { color: var(--galaxy); background: var(--tint-cherenkov); }
|
||||
.pill--review { color: var(--galaxy); background: var(--moon); }
|
||||
.pill--ok { color: var(--galaxy); background: var(--moon); }
|
||||
.pill--review { color: var(--text); background: #fff; }
|
||||
.pill--draft { color: var(--muted); background: #fff; }
|
||||
|
||||
/* Auth (login mock) — nebula backdrop + floating card, modern auth pattern */
|
||||
/* Auth (login mock) — nebula backdrop + floating card; the ONLY navy band
|
||||
besides the home hero */
|
||||
.auth-band {
|
||||
min-height: calc(100dvh - 64px); position: relative;
|
||||
min-height: calc(100dvh - 56px); position: relative;
|
||||
display: grid; place-items: center; padding: var(--space-band) var(--gutter);
|
||||
background: var(--nebula), var(--galaxy);
|
||||
}
|
||||
.auth-card {
|
||||
position: relative; background: #fff; border-radius: calc(var(--radius) + 8px);
|
||||
padding: clamp(24px, 5vw, 40px) clamp(20px, 4.5vw, 36px); max-width: 440px; width: 100%;
|
||||
padding: var(--space-l); max-width: 440px; width: 100%;
|
||||
box-shadow: var(--shadow-lifted);
|
||||
}
|
||||
.auth-logo { height: 24px; width: auto; margin-bottom: var(--space-m); }
|
||||
.auth-card h1 { color: var(--galaxy); margin: 6px 0 10px; font-size: 1.8rem; }
|
||||
.auth-card .muted { color: var(--muted); font-size: 0.95rem; }
|
||||
/* Whisper badge sits top-right, off the reading flow (back in flow ≤480px
|
||||
where it would collide with the logo) */
|
||||
.auth-card .badge-mock { position: absolute; top: var(--space-l); right: var(--space-l); margin: 0; }
|
||||
@media (max-width: 480px) { .auth-card .badge-mock { position: static; margin-bottom: 14px; } }
|
||||
.auth-card h1 { color: var(--galaxy); margin: 6px 0 10px; font-size: var(--fs-xl); }
|
||||
.auth-card .muted { color: var(--muted); font-size: var(--fs-s); }
|
||||
.btn-wide { width: 100%; margin-top: var(--space-s); }
|
||||
|
||||
/* Footer — brand band: logo + descriptor / spec links (§3.3.1) / demo note + flash.
|
||||
No top margin: Moon/Galaxy bands meet it flush; white pages pad via .page/.article. */
|
||||
.footer { background: var(--galaxy); color: var(--on-galaxy-muted); font-size: 0.85rem; }
|
||||
.footer { background: var(--galaxy); color: var(--on-galaxy-muted); font-size: var(--fs-s); line-height: 1.45; }
|
||||
.footer .container { display: grid; gap: var(--space-m); padding-top: var(--space-xl); padding-bottom: var(--space-l); }
|
||||
.foot-top { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-s) var(--space-m); }
|
||||
.foot-top img { height: 30px; width: auto; }
|
||||
@@ -593,11 +648,11 @@ mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(va
|
||||
.foot-links a:not([href]) { color: var(--on-galaxy-muted); }
|
||||
.foot-note { display: flex; align-items: center; gap: var(--space-s); border-top: 1px solid rgba(255, 255, 255, 0.15); padding-top: var(--space-m); }
|
||||
|
||||
/* Whole-page ambient (2026 pattern) — a fixed brand-hue wash behind everything,
|
||||
opt-in per page via <Base ambient> (home only). Clearly visible pastel fields
|
||||
(alphas .16/.12/.10 — ceilings: links on the worst blob overlap stay ≥ 5.3:1);
|
||||
all reading surfaces (cards, panels, bands) are solid and cover it. Static
|
||||
when motion is reduced. */
|
||||
/* Whole-page ambient — a fixed brand-hue wash behind everything, opt-in per
|
||||
page via <Base ambient> (home only). Clearly visible pastel fields (alphas
|
||||
.16/.12/.10 — ceilings: links on the worst blob overlap stay ≥ 5.3:1); all
|
||||
reading surfaces (cards, panels, bands) are solid and cover it. Static when
|
||||
motion is reduced. */
|
||||
.has-ambient::before {
|
||||
content: ""; position: fixed; inset: -30%; z-index: -1; pointer-events: none;
|
||||
background:
|
||||
@@ -608,44 +663,47 @@ mark { background: var(--tint-cherenkov); color: inherit; border-radius: calc(va
|
||||
|
||||
/* ==========================================================================
|
||||
Motion — ALL animation/transition lives in this block (WCAG 2.3.3; the
|
||||
reduce block above is a second safety net). Nebula translation of ctao.org:
|
||||
they drift looping videos under Galaxy-Blue vignettes; here an oversized
|
||||
gradient layer drifts via transform only (compositor-friendly, no repaints).
|
||||
Worst-case blob-over-text contrast verified ≥4.5:1 (see DESIGN.md).
|
||||
reduce block above is a second safety net). One hover language: every
|
||||
interactive element fades color/background/border/shadow on the SAME two
|
||||
tokens (--dur/--ease — ctao.org's quiet-fade feel); cards elevate as one
|
||||
gesture (shadow + 2px lift). Nebula/ambient drift is transform-only and
|
||||
sized to be clearly perceptible within ~10s of looking.
|
||||
========================================================================== */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
@view-transition { navigation: auto; }
|
||||
html { scroll-behavior: smooth; }
|
||||
/* Bands hand their glow to a slowly roaming layer inside the .band-bg clip
|
||||
frame (same --nebula stack) — the band itself never clips its overlays */
|
||||
.hero-band, .auth-band { background: var(--galaxy); }
|
||||
/* The auth band hands its glow to a roaming layer inside the .band-bg clip
|
||||
frame (same --nebula stack); the photo hero keeps its scrimmed photo and
|
||||
gets the lighter --nebula-glow drifting above it. */
|
||||
.auth-band { background: var(--galaxy); }
|
||||
.band-bg::before {
|
||||
content: ""; position: absolute; inset: -45% -30%;
|
||||
background: var(--nebula);
|
||||
animation: nebula 22s ease-in-out infinite alternate;
|
||||
animation: nebula 16s ease-in-out infinite alternate;
|
||||
}
|
||||
/* Whole-page wash — slow drift, clearly alive within ~15s of looking */
|
||||
.has-ambient::before { animation: ambient 60s ease-in-out infinite alternate; }
|
||||
.hero-band .band-bg::before { background: var(--nebula-glow); }
|
||||
/* Whole-page wash — slow drift, clearly alive */
|
||||
.has-ambient::before { animation: ambient 36s ease-in-out infinite alternate; }
|
||||
/* Hero content rises in once, gently staggered */
|
||||
.hero > * { animation: rise 0.5s ease-out backwards; }
|
||||
.hero > * { animation: rise 0.5s var(--ease) backwards; }
|
||||
.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); }
|
||||
/* Editorial cover micro-zoom on card hover (AstroWind pattern; card clips it) */
|
||||
.card .cover { transition: transform 0.3s ease; }
|
||||
.card:hover .cover, .card:focus-within .cover { transform: scale(1.03); }
|
||||
.btn, .login-mock, .navlink { transition: background-color 0.15s ease, color 0.15s ease; }
|
||||
/* Unified hover feedback — single-property fades, shared tokens */
|
||||
a, .btn, .post-nav-title {
|
||||
transition: color var(--dur) var(--ease), background-color var(--dur) var(--ease),
|
||||
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) */
|
||||
}
|
||||
@keyframes nebula { /* inert unless applied inside the block above */
|
||||
from { transform: translate3d(-6%, -4%, 0) rotate(-5deg) scale(1); }
|
||||
to { transform: translate3d(6%, 5%, 0) rotate(5deg) scale(1.22); }
|
||||
from { transform: translate3d(-8%, -5%, 0) rotate(-6deg) scale(1); }
|
||||
to { transform: translate3d(8%, 6%, 0) rotate(6deg) scale(1.3); }
|
||||
}
|
||||
@keyframes ambient {
|
||||
from { transform: translate3d(-4%, -3%, 0) rotate(-9deg) scale(1); opacity: 0.85; }
|
||||
to { transform: translate3d(4%, 4%, 0) rotate(9deg) scale(1.14); opacity: 1; }
|
||||
from { transform: translate3d(-5%, -4%, 0) rotate(-10deg) scale(1); opacity: 0.85; }
|
||||
to { transform: translate3d(5%, 5%, 0) rotate(10deg) scale(1.16); opacity: 1; }
|
||||
}
|
||||
@keyframes rise { from { opacity: 0; transform: translateY(14px); } }
|
||||
|
||||
Reference in New Issue
Block a user