Rebuild the site to the Claude Design drafts
Carries the 11 page drafts plus the shared SiteNav and SiteFooter onto the project's own design system: tier-2 tokens, the published type roles, logical properties throughout, and both locales. Surfaces - The page stands on #0B0B0A with #1D1D1B bands lifted off it, as the drafts do; the body previously painted the band colour, so every band was a step too light. - A card is drawn one step off whatever it stands on (#1D1D1B on the ground, #141413 inside a band). Components paint --surface-card and a band re-points it for its subtree, so a card can never come out the same colour as its band. Shell - Nav: translucent ground with a blur, chevrons on group triggers, an accent rule under the current section, the drafts' compact dropdown card, and an EN | AR toggle in place of the globe menu. - Footer: the drafts' four-column grid, one-line brand text, Facebook as a bordered button, the EU lockup, the implemented-by row and the funding disclaimer. Pages - Home: hero with counting figures, launch band, three areas of change, newsroom, FAQ accordion and the consortium band. - The nine interior pages rebuilt and then audited section by section against their drafts. - Applications: the three-step application form now posts real submissions to the Strapi `application` type, validated server-side and working without JavaScript. Motion - Every animation in the drafts, as classes in _page-kit/motion.css: staggered entrances, scroll-driven reveals, the drifting washes (each page carries its own geometry), the sheen, the counting figures and the accordion. The drafts' coloured hover glow is deliberately not shipped. CMS - New `faq` collection type behind the home page's accordion. - `role` added to the consortium member component so an editor can supply the chip and the deliverable separately. Content - No invented figure, date, name or commitment ships: the five-working-day reply, the placeholder email and Facebook handle, the sample news, events, publications and FAQs, the invented application rules and the TBD counters are all withheld pending real content. Figures that survived (3 consortium partners, 4 areas of work, 16 human security sub-projects, Dec 2025 - Dec 2027) are verified against docs/ and the bundled draft copy. Verified: pnpm typecheck (web + CMS) and pnpm --filter web build pass; all 20 page/locale URLs render 200 through the built SSR handler, including with the CMS unreachable; no raw hex or physical-direction utility in components or routes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
/* ============================================================================
|
||||
HOME MOTION - the reveals the redesigned home page runs
|
||||
----------------------------------------------------------------------------
|
||||
Every animation in the Claude Design draft ("SHARP-ER Home v2 Dark"), carried
|
||||
over as classes so the page modules stay free of inline keyframes and raw
|
||||
values. Durations and easings are the motion tokens from semantic.css; the
|
||||
few long, decorative loops are expressed as multiples of them rather than as
|
||||
bare seconds, so retiming the system retimes the page.
|
||||
|
||||
TWO KINDS OF MOTION LIVE HERE
|
||||
* entrance - time based, runs once from the server-rendered HTML
|
||||
(.sh-rise, .sh-bar-grow), staggered with .sh-rise--2..5
|
||||
* scroll - scroll-driven (`animation-timeline`), so a band reveals as
|
||||
it enters the viewport and the top progress bar tracks the
|
||||
document
|
||||
|
||||
WHY THE @supports GUARD: scroll-driven timelines ship in Chromium only. The
|
||||
from-state (opacity 0) is applied ONLY where `animation-timeline: view()` is
|
||||
understood, so Safari and Firefox render every band at rest, fully visible,
|
||||
instead of holding an invisible element forever.
|
||||
|
||||
REDUCED MOTION: app.css already collapses every animation to 0.01ms. The
|
||||
scroll block is additionally gated on `prefers-reduced-motion: no-preference`
|
||||
so a reduced-motion visitor never gets a timeline-driven opacity ramp at all.
|
||||
|
||||
DIRECTION: `transform-origin` and `linear-gradient()` have no logical
|
||||
keywords, so the progress bar and the brand stripe carry an explicit RTL
|
||||
override. These are the only physical directions in the file, and they exist
|
||||
because the property itself has no logical form - every box edge elsewhere is
|
||||
still ps-/pe-/start-/end-.
|
||||
========================================================================= */
|
||||
|
||||
@layer theme, base, components, utilities;
|
||||
|
||||
@layer components {
|
||||
/* -------------------------------------------------------------------------
|
||||
ENTRANCE - hero content, first paint
|
||||
---------------------------------------------------------------------- */
|
||||
.sh-rise {
|
||||
animation: sh-rise var(--motion-duration-reveal) var(--motion-ease-entrance)
|
||||
var(--sh-rise-delay, 0ms) both;
|
||||
}
|
||||
|
||||
/* The hero's cascade. The step is the system's fast duration, so the whole
|
||||
stagger retimes with the token instead of drifting on hard-coded ms. */
|
||||
.sh-rise--2 {
|
||||
--sh-rise-delay: calc(var(--motion-duration-fast) * 0.75);
|
||||
}
|
||||
|
||||
.sh-rise--3 {
|
||||
--sh-rise-delay: calc(var(--motion-duration-fast) * 1.5);
|
||||
}
|
||||
|
||||
.sh-rise--4 {
|
||||
--sh-rise-delay: calc(var(--motion-duration-fast) * 2.25);
|
||||
}
|
||||
|
||||
.sh-rise--5 {
|
||||
--sh-rise-delay: calc(var(--motion-duration-fast) * 3);
|
||||
}
|
||||
|
||||
/* The brand stripe under the hero picture, drawn on from the inline start. */
|
||||
.sh-bar-grow {
|
||||
transform-origin: left center;
|
||||
animation: sh-bar-grow var(--motion-duration-reveal)
|
||||
var(--motion-ease-entrance) calc(var(--motion-duration-fast) * 4) both;
|
||||
}
|
||||
|
||||
[dir="rtl"] .sh-bar-grow {
|
||||
transform-origin: right center;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
AMBIENT LOOPS - decorative, never carrying meaning
|
||||
---------------------------------------------------------------------- */
|
||||
|
||||
/* The two soft washes behind the hero. Long, slow drifts: 22.5x and 30x the
|
||||
reveal duration (18s / 24s at the shipped token). */
|
||||
.sh-glow {
|
||||
animation: sh-glow calc(var(--motion-duration-reveal) * 22.5) ease-in-out
|
||||
infinite;
|
||||
}
|
||||
|
||||
/* A highlight travelling across the hero picture. */
|
||||
.sh-sheen {
|
||||
background-size: 240% 100%;
|
||||
animation: sh-sheen calc(var(--motion-duration-reveal) * 8) linear infinite;
|
||||
}
|
||||
|
||||
/* The live dot in the hero status pill. */
|
||||
.sh-pulse {
|
||||
animation: sh-pulse calc(var(--motion-duration-reveal) * 2.75) ease-in-out
|
||||
infinite;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
INTERACTION
|
||||
---------------------------------------------------------------------- */
|
||||
|
||||
/* Tiles that rise a little under the pointer. No shadow: the draft's hover
|
||||
glow is deliberately left out. */
|
||||
.sh-lift {
|
||||
transition:
|
||||
transform var(--motion-duration-base) var(--motion-ease-standard),
|
||||
border-color var(--motion-duration-base) var(--motion-ease-standard),
|
||||
background-color var(--motion-duration-base) var(--motion-ease-standard);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.sh-lift:hover {
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
}
|
||||
|
||||
/* An FAQ answer opening under its question. */
|
||||
.sh-answer {
|
||||
animation: sh-answer var(--motion-duration-base) var(--motion-ease-entrance)
|
||||
both;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
SCROLL DRIVEN - Chromium today, inert and harmless elsewhere
|
||||
---------------------------------------------------------------------- */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
@supports (animation-timeline: view()) {
|
||||
.sh-reveal {
|
||||
animation: sh-rise linear both;
|
||||
animation-timeline: view();
|
||||
animation-range: entry 0% entry 70%;
|
||||
}
|
||||
|
||||
/* Cards and pictures: the same reveal with a touch of scale. */
|
||||
.sh-reveal--in {
|
||||
animation-name: sh-reveal-in;
|
||||
animation-range: entry 0% entry 80%;
|
||||
}
|
||||
}
|
||||
|
||||
@supports (animation-timeline: scroll()) {
|
||||
/* The reading-progress rule across the top of the page. It is painted
|
||||
ONLY inside this @supports block: without a scroll timeline the bar
|
||||
would sit there permanently at full width, which is a rule the design
|
||||
never asked for. */
|
||||
.sh-progress {
|
||||
background-image: linear-gradient(
|
||||
to right,
|
||||
var(--surface-accent),
|
||||
var(--text-accent) 55%,
|
||||
var(--surface-danger)
|
||||
);
|
||||
transform-origin: left center;
|
||||
animation: sh-bar-grow linear both;
|
||||
animation-timeline: scroll();
|
||||
}
|
||||
|
||||
[dir="rtl"] .sh-progress {
|
||||
background-image: linear-gradient(
|
||||
to left,
|
||||
var(--surface-accent),
|
||||
var(--text-accent) 55%,
|
||||
var(--surface-danger)
|
||||
);
|
||||
transform-origin: right center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-rise {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(26px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-reveal-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px) scale(0.985);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-bar-grow {
|
||||
from {
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scaleX(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-glow {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 0.5;
|
||||
transform: translate3d(-4%, 0, 0) scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.85;
|
||||
transform: translate3d(6%, -3%, 0) scale(1.12);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-sheen {
|
||||
from {
|
||||
background-position: -160% 0;
|
||||
}
|
||||
|
||||
to {
|
||||
background-position: 260% 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.35;
|
||||
transform: scale(0.72);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sh-answer {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-8px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user