Files
oki-foundation/src/lib/components/sections/Hero.svelte
T

270 lines
5.2 KiB
Svelte
Raw Normal View History

<script lang="ts">
import type { Bundle, Locale } from '$lib/i18n';
import { splitLeadingEmoji } from './pictos';
let { t }: { t: Bundle; locale?: Locale } = $props();
</script>
<section class="hero">
<div class="hero-bg" aria-hidden="true">
<div class="hero-watermark"></div>
<div class="hero-stripes s1"></div>
<div class="hero-stripes s2"></div>
</div>
<div class="hero-content container">
<h1 class="hero-title">
<span class="mask"><span class="w w1">ORGANISATION</span></span>
<span class="mask"><span class="w w2">KA</span></span>
</h1>
<h2 class="hero-subtitle">
<span class="mask"><span class="w w3">INTERNATIONALE</span></span>
</h2>
<p class="hero-tagline">{t.site.tagline}</p>
<div class="hero-tags">
{#each t.hero.tags as rawTag (rawTag)}
{@const tag = splitLeadingEmoji(rawTag)}
<span class="tag">
{#if tag.icon}
<svg class="icon" aria-hidden="true"><use href="/icons.svg#{tag.icon}" /></svg>
{/if}
{tag.text}
</span>
{/each}
</div>
<p class="hero-description">{t.site.description}</p>
<div class="cta-buttons">
<a href="#solutions" class="btn btn-solid">{t.hero.cta_primary}</a>
<a href="#mission" class="btn">{t.hero.cta_secondary}</a>
</div>
</div>
</section>
<style>
.hero {
padding: 9rem 0 5rem;
min-height: 100vh;
display: flex;
align-items: center;
position: relative;
overflow: hidden;
border-bottom: 1px solid var(--line);
}
.hero-bg {
position: absolute;
inset: 0;
pointer-events: none;
}
.hero-watermark {
position: absolute;
top: 0;
right: -5%;
width: 55%;
height: 100%;
background: url('/images/logo-512x512.png') center / contain no-repeat;
opacity: 0.05;
will-change: transform;
}
/* Filets drapeau en diagonale, très basse opacité (profondeur) */
.hero-stripes {
position: absolute;
left: -50%;
width: 200%;
background: linear-gradient(
to right,
transparent 0 10%,
var(--or-oki) 10% 40%,
var(--vert-oki) 40% 65%,
var(--rouge-oki) 65% 85%,
transparent 85% 100%
);
transform: rotate(-12deg);
will-change: transform;
}
.hero-stripes.s1 {
top: 22%;
height: 3px;
opacity: 0.1;
}
.hero-stripes.s2 {
bottom: 18%;
height: 2px;
opacity: 0.07;
}
.hero-content {
position: relative;
z-index: 2;
width: 100%;
will-change: transform, opacity;
}
h1 {
font-size: clamp(3rem, 9vw, 7rem);
font-weight: 900;
margin-bottom: 0.4rem;
line-height: 0.95;
}
.hero-subtitle {
font-size: clamp(1.6rem, 4.5vw, 3rem);
font-weight: 700;
margin-bottom: 1.25rem;
color: var(--or-oki);
}
/* Reveal masqué au chargement (pattern titrage des sites primés) :
uniquement si JS actif et motion autorisée — sinon texte visible */
.mask {
display: inline-block;
overflow: hidden;
vertical-align: bottom;
}
.w {
display: inline-block;
will-change: transform;
}
@media (prefers-reduced-motion: no-preference) {
:global(html.js) .w {
transform: translateY(110%);
animation: word-rise var(--dur-phrase) var(--ease-ka) forwards;
}
:global(html.js) .w1 {
animation-delay: 150ms;
}
:global(html.js) .w2 {
animation-delay: 270ms;
}
:global(html.js) .w3 {
animation-delay: 510ms;
}
/* Si la cérémonie d'intro joue, le titrage attend sa sortie */
:global(html.js.intro-pending) .w1 {
animation-delay: 1400ms;
}
:global(html.js.intro-pending) .w2 {
animation-delay: 1520ms;
}
:global(html.js.intro-pending) .w3 {
animation-delay: 1760ms;
}
}
@keyframes word-rise {
to {
transform: translateY(0);
}
}
.hero-tagline {
font-size: 1.4rem;
margin-bottom: 1.5rem;
color: var(--or-oki);
font-weight: 600;
}
.hero-description {
font-size: 1.2rem;
margin-bottom: 2rem;
color: var(--muted);
max-width: 680px;
}
.hero-tags {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
margin-bottom: 2rem;
}
.hero-tags .tag {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.cta-buttons {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
/* Parallaxe et sortie scrubée : scroll-driven animations natives,
enhancement progressif — sans support, le hero reste statique */
@supports (animation-timeline: scroll()) {
@media (prefers-reduced-motion: no-preference) {
.hero-watermark {
animation: wm-drift linear both;
animation-timeline: scroll(root);
animation-range: 0 100vh;
}
.hero-stripes.s1 {
animation: s1-drift linear both;
animation-timeline: scroll(root);
animation-range: 0 100vh;
}
.hero-stripes.s2 {
animation: s2-drift linear both;
animation-timeline: scroll(root);
animation-range: 0 100vh;
}
.hero-content {
animation: hero-exit linear both;
animation-timeline: scroll(root);
animation-range: 0 75vh;
}
}
}
@keyframes wm-drift {
to {
transform: translateY(14%) scale(1.06);
}
}
@keyframes s1-drift {
to {
transform: rotate(-12deg) translateX(-8%);
}
}
@keyframes s2-drift {
to {
transform: rotate(-12deg) translateX(6%);
}
}
@keyframes hero-exit {
to {
transform: translateY(-8vh);
opacity: 0.2;
}
}
@media (max-width: 768px) {
.cta-buttons {
flex-direction: column;
}
.cta-buttons .btn {
width: 100%;
text-align: center;
}
}
</style>