Refonte accueil : hero typo statique, axes icônes, menu italic, page numérique
- Hero : 5 lignes typographiques alternées (bold/light/accent/caps/italic), citations et axes dans un bloc discret dépliable - Icônes axes : Ğ1 custom, balance (éco don), graphe (WoT), marteau (décision), pictos plus lumineux (glow) - Menu : Autonomie en italique + grand, Événement majuscule - Page /autonomie renommée /numerique avec redirect 301 - Sceau hexagramme 益 Yì dans le layout, BookSection dans /modele-eco - Fonts Syne + Space Grotesk, dark theme éclairci - Popup GrateWizard agrandie (480×860) - Actions AxisBlock : primary côte à côte, secondary séparé dessous Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,8 @@
|
||||
>
|
||||
<!-- Item icon -->
|
||||
<div v-if="item.icon" class="axis-item-icon" :class="`axis-item-icon--${color}`">
|
||||
<div :class="iconClass(item.icon)" class="h-5 w-5" />
|
||||
<span v-if="item.icon === 'g1'" class="axis-item-icon-g1">Ğ1</span>
|
||||
<div v-else :class="iconClass(item.icon)" class="h-5 w-5" />
|
||||
</div>
|
||||
|
||||
<h3 class="font-display text-lg font-semibold text-white mb-1">
|
||||
@@ -40,15 +41,31 @@
|
||||
|
||||
<!-- Actions zone (separate from card link) -->
|
||||
<div v-if="item.actions?.length" class="axis-actions">
|
||||
<button
|
||||
v-for="action in item.actions"
|
||||
:key="action.id"
|
||||
class="axis-action-btn"
|
||||
@click.stop="handleAction(action.id)"
|
||||
>
|
||||
<div :class="iconClass(action.icon)" class="h-3.5 w-3.5" />
|
||||
{{ action.label }}
|
||||
</button>
|
||||
<!-- Primary row -->
|
||||
<div class="axis-actions-row">
|
||||
<button
|
||||
v-for="action in primaryActions(item.actions)"
|
||||
:key="action.id"
|
||||
class="axis-action-btn"
|
||||
:class="{ 'axis-action-btn--highlight': action.highlight }"
|
||||
@click.stop="handleAction(action.id)"
|
||||
>
|
||||
<div :class="iconClass(action.icon)" class="h-3.5 w-3.5" />
|
||||
{{ action.label }}
|
||||
</button>
|
||||
</div>
|
||||
<!-- Secondary row -->
|
||||
<div v-if="secondaryActions(item.actions).length" class="axis-actions-secondary">
|
||||
<button
|
||||
v-for="action in secondaryActions(item.actions)"
|
||||
:key="action.id"
|
||||
class="axis-action-btn axis-action-btn--secondary"
|
||||
@click.stop="handleAction(action.id)"
|
||||
>
|
||||
<div :class="iconClass(action.icon)" class="h-3.5 w-3.5" />
|
||||
{{ action.label }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,6 +77,8 @@ interface AxisAction {
|
||||
id: string
|
||||
label: string
|
||||
icon: string
|
||||
highlight?: boolean
|
||||
secondary?: boolean
|
||||
}
|
||||
|
||||
interface AxisItem {
|
||||
@@ -86,6 +105,14 @@ const emit = defineEmits<{
|
||||
'launch-gratewizard': []
|
||||
}>()
|
||||
|
||||
function primaryActions(actions: AxisAction[]) {
|
||||
return actions.filter(a => !a.secondary)
|
||||
}
|
||||
|
||||
function secondaryActions(actions: AxisAction[]) {
|
||||
return actions.filter(a => a.secondary)
|
||||
}
|
||||
|
||||
function handleAction(id: string) {
|
||||
if (id === 'open-player') emit('open-player')
|
||||
else if (id === 'open-pdf') emit('open-pdf')
|
||||
@@ -179,13 +206,22 @@ function itemAttrs(item: AxisItem) {
|
||||
}
|
||||
|
||||
.axis-item-icon--primary {
|
||||
background: hsl(var(--color-primary) / 0.1);
|
||||
background: hsl(var(--color-primary) / 0.18);
|
||||
color: hsl(var(--color-primary));
|
||||
box-shadow: 0 0 14px hsl(var(--color-primary) / 0.15);
|
||||
}
|
||||
|
||||
.axis-item-icon--accent {
|
||||
background: hsl(var(--color-accent) / 0.1);
|
||||
background: hsl(var(--color-accent) / 0.18);
|
||||
color: hsl(var(--color-accent));
|
||||
box-shadow: 0 0 14px hsl(var(--color-accent) / 0.15);
|
||||
}
|
||||
|
||||
.axis-item-icon-g1 {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.gestation-badge {
|
||||
@@ -204,12 +240,26 @@ function itemAttrs(item: AxisItem) {
|
||||
}
|
||||
|
||||
.axis-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
border-top: 1px solid hsl(var(--color-text) / 0.06);
|
||||
background: hsl(var(--color-bg) / 0.4);
|
||||
}
|
||||
|
||||
.axis-actions-row {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
padding: 0.75rem 1.25rem;
|
||||
border-top: 1px solid hsl(var(--color-text) / 0.06);
|
||||
background: hsl(var(--color-bg) / 0.4);
|
||||
}
|
||||
|
||||
.axis-actions-secondary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.375rem;
|
||||
padding: 0.5rem 1.25rem 0.75rem;
|
||||
border-top: 1px solid hsl(var(--color-text) / 0.04);
|
||||
}
|
||||
|
||||
.axis-action-btn {
|
||||
@@ -232,4 +282,28 @@ function itemAttrs(item: AxisItem) {
|
||||
background: hsl(var(--color-primary) / 0.12);
|
||||
border-color: hsl(var(--color-primary) / 0.3);
|
||||
}
|
||||
|
||||
.axis-action-btn--highlight {
|
||||
color: hsl(var(--color-primary));
|
||||
background: hsl(var(--color-primary) / 0.12);
|
||||
border-color: hsl(var(--color-primary) / 0.25);
|
||||
}
|
||||
|
||||
.axis-action-btn--highlight:hover {
|
||||
background: hsl(var(--color-primary) / 0.2);
|
||||
border-color: hsl(var(--color-primary) / 0.4);
|
||||
}
|
||||
|
||||
.axis-action-btn--secondary {
|
||||
color: hsl(var(--color-text) / 0.45);
|
||||
background: transparent;
|
||||
border-color: hsl(var(--color-text) / 0.06);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.axis-action-btn--secondary:hover {
|
||||
color: hsl(var(--color-accent));
|
||||
background: hsl(var(--color-accent) / 0.08);
|
||||
border-color: hsl(var(--color-accent) / 0.2);
|
||||
}
|
||||
</style>
|
||||
|
||||
135
app/components/home/BookSection.vue
Normal file
135
app/components/home/BookSection.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<section class="section-padding">
|
||||
<div class="container-content">
|
||||
<div class="grid items-center gap-12 md:grid-cols-2">
|
||||
<!-- Book cover -->
|
||||
<UiScrollReveal>
|
||||
<div class="book-cover-wrapper relative">
|
||||
<!-- Shadok pumper -->
|
||||
<svg class="shadok-pumper" viewBox="0 0 200 240" fill="none" aria-hidden="true">
|
||||
<ellipse cx="100" cy="130" rx="55" ry="65" fill="currentColor" opacity="0.9"/>
|
||||
<ellipse cx="100" cy="60" rx="30" ry="28" fill="currentColor" opacity="0.85"/>
|
||||
<circle cx="88" cy="54" r="6" fill="currentColor" opacity="0.2"/>
|
||||
<circle cx="112" cy="54" r="6" fill="currentColor" opacity="0.2"/>
|
||||
<circle cx="90" cy="53" r="2.5" fill="currentColor" opacity="0.5"/>
|
||||
<circle cx="114" cy="53" r="2.5" fill="currentColor" opacity="0.5"/>
|
||||
<polygon points="100,68 115,78 85,78" fill="currentColor" opacity="0.6"/>
|
||||
<line x1="80" y1="192" x2="70" y2="230" stroke="currentColor" stroke-width="4" stroke-linecap="round" opacity="0.7"/>
|
||||
<line x1="120" y1="192" x2="130" y2="230" stroke="currentColor" stroke-width="4" stroke-linecap="round" opacity="0.7"/>
|
||||
<line x1="70" y1="230" x2="55" y2="232" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.5"/>
|
||||
<line x1="130" y1="230" x2="145" y2="232" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.5"/>
|
||||
<line x1="155" y1="110" x2="190" y2="90" stroke="currentColor" stroke-width="4" stroke-linecap="round" opacity="0.6"/>
|
||||
<line x1="190" y1="90" x2="190" y2="120" stroke="currentColor" stroke-width="4" stroke-linecap="round" opacity="0.6"/>
|
||||
<rect x="180" y="118" width="18" height="40" rx="3" fill="currentColor" opacity="0.4"/>
|
||||
</svg>
|
||||
<div class="book-cover-3d">
|
||||
<img
|
||||
:src="content?.book.coverImage"
|
||||
:alt="content?.book.coverAlt"
|
||||
class="book-cover-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</UiScrollReveal>
|
||||
|
||||
<!-- Content + CTAs -->
|
||||
<div>
|
||||
<UiScrollReveal>
|
||||
<p class="mb-2 font-mono text-sm tracking-widest text-accent uppercase">{{ content?.book.kicker }}</p>
|
||||
<h2 class="heading-section font-display font-bold tracking-tight text-white">
|
||||
{{ content?.book.title }}
|
||||
</h2>
|
||||
</UiScrollReveal>
|
||||
|
||||
<UiScrollReveal :delay="100">
|
||||
<p class="mt-4 text-lg leading-relaxed text-white/60">
|
||||
{{ content?.book.description }}
|
||||
</p>
|
||||
</UiScrollReveal>
|
||||
|
||||
<UiScrollReveal :delay="200">
|
||||
<div class="mt-8 flex flex-col gap-3 sm:flex-row sm:gap-4">
|
||||
<UiBaseButton @click="$emit('open-player')">
|
||||
<div class="i-lucide-play mr-2 h-5 w-5" />
|
||||
{{ content?.book.cta.player }}
|
||||
</UiBaseButton>
|
||||
<UiBaseButton variant="accent" @click="$emit('open-pdf')">
|
||||
<div class="i-lucide-book-open mr-2 h-5 w-5" />
|
||||
{{ content?.book.cta.pdf }}
|
||||
</UiBaseButton>
|
||||
</div>
|
||||
</UiScrollReveal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineEmits<{
|
||||
'open-player': []
|
||||
'open-pdf': []
|
||||
}>()
|
||||
|
||||
const { data: content } = await usePageContent('home')
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.book-cover-wrapper {
|
||||
perspective: 800px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.book-cover-3d {
|
||||
aspect-ratio: 3 / 4;
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
border: 1px solid hsl(var(--color-text) / 0.1);
|
||||
box-shadow:
|
||||
0 12px 40px hsl(var(--color-text) / 0.15),
|
||||
0 0 0 1px hsl(var(--color-text) / 0.08);
|
||||
transition: transform 0.5s cubic-bezier(0.645, 0.045, 0.355, 1),
|
||||
box-shadow 0.5s ease;
|
||||
max-width: 360px;
|
||||
}
|
||||
|
||||
.book-cover-3d:hover {
|
||||
transform: rotateY(-8deg) rotateX(3deg) scale(1.02);
|
||||
box-shadow:
|
||||
12px 16px 48px hsl(var(--color-text) / 0.2),
|
||||
0 0 0 1px hsl(var(--color-primary) / 0.2);
|
||||
}
|
||||
|
||||
.book-cover-img {
|
||||
width: 200%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.heading-section {
|
||||
font-size: clamp(1.625rem, 4vw, 2.125rem);
|
||||
}
|
||||
|
||||
.shadok-pumper {
|
||||
position: absolute;
|
||||
right: 3%;
|
||||
bottom: 8%;
|
||||
width: clamp(90px, 12vw, 180px);
|
||||
opacity: 0.28;
|
||||
pointer-events: none;
|
||||
color: hsl(var(--color-primary));
|
||||
animation: shadok-float 10s ease-in-out infinite;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@keyframes shadok-float {
|
||||
0%, 100% { transform: translateY(0); }
|
||||
50% { transform: translateY(-10px); }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.shadok-pumper { display: none; }
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,7 @@
|
||||
<section class="relative overflow-hidden section-padding hero-section">
|
||||
<!-- Background gradient -->
|
||||
<div class="absolute inset-0 bg-gradient-to-b from-primary/10 via-transparent to-surface-bg" />
|
||||
<div class="absolute inset-0 bg-[radial-gradient(ellipse_at_top,hsl(12_76%_48%/0.15),transparent_70%)]" />
|
||||
<div class="absolute inset-0 bg-[radial-gradient(ellipse_at_top,hsl(12_76%_48%/0.12),transparent_70%)]" />
|
||||
|
||||
<!-- Shadok bird decoration -->
|
||||
<svg class="shadok-bird" viewBox="0 0 180 260" fill="none" aria-hidden="true">
|
||||
@@ -46,8 +46,8 @@
|
||||
<div class="container-content relative z-10 px-4">
|
||||
<div class="mx-auto max-w-2xl">
|
||||
<HomeTypewriterText
|
||||
v-if="sentences.length"
|
||||
:sentences="sentences"
|
||||
v-if="hero"
|
||||
:hero="hero"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -55,19 +55,17 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { TypewriterSentence } from '~/composables/useTypewriter'
|
||||
|
||||
const { data: content } = await usePageContent('home')
|
||||
|
||||
const sentences = computed<TypewriterSentence[]>(() => {
|
||||
const raw = (content.value as any)?.hero?.typewriter?.sentences
|
||||
if (!Array.isArray(raw)) return []
|
||||
return raw.map((s: any) => ({
|
||||
text: s.text,
|
||||
style: s.style || 'title',
|
||||
stays: !!s.stays,
|
||||
separator: !!s.separator,
|
||||
}))
|
||||
const hero = computed(() => {
|
||||
const raw = (content.value as any)?.hero
|
||||
if (!raw) return null
|
||||
return {
|
||||
heading: Array.isArray(raw.heading) ? raw.heading : [],
|
||||
citations: Array.isArray(raw.citations) ? raw.citations : [],
|
||||
approach: raw.approach || '',
|
||||
axes: Array.isArray(raw.axes) ? raw.axes : [],
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,171 +1,260 @@
|
||||
<template>
|
||||
<ClientOnly>
|
||||
<div class="hero-text" @click="handleClick">
|
||||
<!-- Locked sentences (stays: true, already revealed) -->
|
||||
<TransitionGroup name="lock">
|
||||
<div v-for="(item, i) in lockedSentences" :key="`lock-${i}`">
|
||||
<div v-if="item.separator" class="hero-separator" />
|
||||
<p v-else class="hero-line" :class="styleClass(item.style)">
|
||||
{{ item.text }}
|
||||
</p>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
|
||||
<!-- Active sentence — pure CSS opacity fade -->
|
||||
<div class="hero-active-zone">
|
||||
<p
|
||||
v-show="currentText"
|
||||
class="hero-line hero-active"
|
||||
:class="[styleClass(currentStyle), { 'is-visible': isVisible }]"
|
||||
>
|
||||
{{ currentText }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SEO / no-JS fallback -->
|
||||
<template #fallback>
|
||||
<div class="hero-text">
|
||||
<p
|
||||
v-for="(sentence, i) in stayingSentences"
|
||||
<div class="hero-content">
|
||||
<!-- 5-line heading with alternating typography -->
|
||||
<div class="hero-heading">
|
||||
<h1 v-if="hero.heading?.length" class="hero-lines">
|
||||
<span
|
||||
v-for="(line, i) in hero.heading"
|
||||
:key="i"
|
||||
class="hero-line"
|
||||
:class="styleClass(sentence.style)"
|
||||
>
|
||||
{{ sentence.text }}
|
||||
</p>
|
||||
:class="`hero-line--${i + 1}`"
|
||||
>{{ line }}</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<!-- Discrete aside block -->
|
||||
<details class="hero-aside">
|
||||
<summary class="hero-aside-toggle">En savoir plus</summary>
|
||||
|
||||
<div class="hero-aside-body">
|
||||
<!-- Citations -->
|
||||
<blockquote v-if="hero.citations?.length" class="hero-citations">
|
||||
<p v-for="(cite, i) in hero.citations" :key="i" class="hero-cite">
|
||||
{{ cite }}
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<!-- Approach + Axes -->
|
||||
<div v-if="hero.approach" class="hero-approach">
|
||||
<p class="hero-approach-text">{{ hero.approach }}</p>
|
||||
<dl v-if="hero.axes?.length" class="hero-axes">
|
||||
<div v-for="(axis, i) in hero.axes" :key="i" class="hero-axis">
|
||||
<dt>{{ axis.label }}</dt>
|
||||
<dd>{{ axis.value }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ClientOnly>
|
||||
</details>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { TypewriterSentence } from '~/composables/useTypewriter'
|
||||
interface HeroAxis {
|
||||
label: string
|
||||
value: string
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
sentences: TypewriterSentence[]
|
||||
interface HeroData {
|
||||
heading: string[]
|
||||
citations: string[]
|
||||
approach: string
|
||||
axes: HeroAxis[]
|
||||
}
|
||||
|
||||
defineProps<{
|
||||
hero: HeroData
|
||||
}>()
|
||||
|
||||
const stayingSentences = computed(() => props.sentences.filter(s => s.stays))
|
||||
|
||||
const {
|
||||
currentText,
|
||||
currentStyle,
|
||||
isVisible,
|
||||
lockedSentences,
|
||||
isComplete,
|
||||
start,
|
||||
skipToEnd,
|
||||
} = useTypewriter(props.sentences)
|
||||
|
||||
onMounted(() => {
|
||||
start()
|
||||
})
|
||||
|
||||
function handleClick() {
|
||||
if (!isComplete.value) {
|
||||
skipToEnd()
|
||||
}
|
||||
}
|
||||
|
||||
function styleClass(style?: string) {
|
||||
if (style === 'citation') return 'hero-line--citation'
|
||||
if (style === 'text') return 'hero-line--body'
|
||||
return 'hero-line--title'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hero-text {
|
||||
.hero-content {
|
||||
text-align: center;
|
||||
min-height: 16rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
/* ── Lines ── */
|
||||
/* ── Heading — 5 lines ── */
|
||||
|
||||
.hero-heading {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.hero-lines {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.1em;
|
||||
}
|
||||
|
||||
.hero-line {
|
||||
margin: 0;
|
||||
padding: 0.3em 0;
|
||||
display: block;
|
||||
font-family: var(--font-display);
|
||||
line-height: 1.4;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.hero-line--title {
|
||||
font-weight: 600;
|
||||
font-size: clamp(1.3rem, 3.5vw, 2.2rem);
|
||||
/* l1: Construire une autonomie collective. — bold, large */
|
||||
.hero-line--1 {
|
||||
font-weight: 700;
|
||||
font-size: clamp(1.45rem, 3.8vw, 2.5rem);
|
||||
color: hsl(var(--color-text) / 0.95);
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
/* l2: à l'échelle des bassins de vie — light, same size, softer */
|
||||
.hero-line--2 {
|
||||
font-weight: 300;
|
||||
font-size: clamp(1.3rem, 3.2vw, 2.1rem);
|
||||
color: hsl(var(--color-text) / 0.55);
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.hero-line--citation {
|
||||
/* l3: Pousser les curseurs — accent color, medium */
|
||||
.hero-line--3 {
|
||||
font-weight: 600;
|
||||
font-size: clamp(1.1rem, 2.6vw, 1.6rem);
|
||||
color: hsl(var(--color-accent));
|
||||
margin-top: 0.5em;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
/* l4: Autonomie numérique, économique, citoyenne. — small-caps feel */
|
||||
.hero-line--4 {
|
||||
font-family: var(--font-sans);
|
||||
font-weight: 500;
|
||||
font-size: clamp(0.9rem, 2vw, 1.15rem);
|
||||
color: hsl(var(--color-text) / 0.65);
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
margin-top: 0.15em;
|
||||
}
|
||||
|
||||
/* l5: — s'en donner les moyens — — italic, same tone as l4 */
|
||||
.hero-line--5 {
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-size: clamp(1.05rem, 2.8vw, 1.5rem);
|
||||
color: hsl(var(--color-text) / 0.7);
|
||||
max-width: 40ch;
|
||||
margin-inline: auto;
|
||||
font-size: clamp(0.95rem, 2.2vw, 1.2rem);
|
||||
color: hsl(var(--color-text) / 0.65);
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
|
||||
.hero-line--body {
|
||||
font-weight: 400;
|
||||
font-size: clamp(1rem, 2.5vw, 1.3rem);
|
||||
color: hsl(var(--color-text) / 0.6);
|
||||
max-width: 46ch;
|
||||
margin-inline: auto;
|
||||
/* ── Discrete aside block ── */
|
||||
|
||||
.hero-aside {
|
||||
width: 100%;
|
||||
max-width: 36em;
|
||||
}
|
||||
|
||||
/* ── Separator ── */
|
||||
|
||||
.hero-separator {
|
||||
width: 4rem;
|
||||
height: 2px;
|
||||
margin: 1.25rem auto;
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
transparent,
|
||||
hsl(var(--color-primary) / 0.45),
|
||||
transparent
|
||||
);
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
/* ── Active zone ── */
|
||||
|
||||
.hero-active-zone {
|
||||
min-height: 5rem;
|
||||
display: flex;
|
||||
.hero-aside-toggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
margin: 0 auto;
|
||||
padding: 0.35rem 0.85rem;
|
||||
border-radius: 9999px;
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 500;
|
||||
color: hsl(var(--color-text) / 0.35);
|
||||
border: 1px solid hsl(var(--color-text) / 0.08);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.hero-aside-toggle::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hero-aside-toggle::before {
|
||||
content: '▸';
|
||||
font-size: 0.65em;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.hero-aside[open] .hero-aside-toggle::before {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.hero-aside-toggle:hover {
|
||||
color: hsl(var(--color-text) / 0.55);
|
||||
border-color: hsl(var(--color-text) / 0.15);
|
||||
}
|
||||
|
||||
.hero-aside-body {
|
||||
margin-top: 1.25rem;
|
||||
animation: aside-reveal 0.3s ease;
|
||||
}
|
||||
|
||||
@keyframes aside-reveal {
|
||||
from { opacity: 0; transform: translateY(-6px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
/* ── Citations ── */
|
||||
|
||||
.hero-citations {
|
||||
margin: 0 0 1.25rem;
|
||||
padding: 0.6rem 0 0.6rem 1rem;
|
||||
border-left: 2px solid hsl(var(--color-accent) / 0.3);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.hero-cite {
|
||||
font-family: var(--font-display);
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-size: 0.92rem;
|
||||
line-height: 1.55;
|
||||
color: hsl(var(--color-text) / 0.45);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hero-cite + .hero-cite {
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
||||
/* ── Approach + Axes ── */
|
||||
|
||||
.hero-approach {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero-approach-text {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.82rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.03em;
|
||||
text-transform: uppercase;
|
||||
color: hsl(var(--color-text) / 0.35);
|
||||
margin: 0 0 0.6rem;
|
||||
}
|
||||
|
||||
.hero-axes {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.2rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hero-axis {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.4rem;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* ── Active sentence — opacity fade ── */
|
||||
|
||||
.hero-active {
|
||||
opacity: 0;
|
||||
transition: opacity 1s ease;
|
||||
.hero-axis dt {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: hsl(var(--color-primary));
|
||||
}
|
||||
|
||||
.hero-active.is-visible {
|
||||
opacity: 1;
|
||||
.hero-axis dt::after {
|
||||
content: ' →';
|
||||
color: hsl(var(--color-text) / 0.2);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* ── Locked sentences entrance ── */
|
||||
|
||||
.lock-enter-active {
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
}
|
||||
|
||||
.lock-enter-from {
|
||||
opacity: 0;
|
||||
transform: translateY(8px);
|
||||
}
|
||||
|
||||
.lock-move {
|
||||
transition: transform 0.5s ease;
|
||||
.hero-axis dd {
|
||||
font-family: var(--font-sans);
|
||||
font-size: 0.88rem;
|
||||
color: hsl(var(--color-text) / 0.5);
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user