design : accueil en trois variantes (console, parcours, établi) + couleur par axe

- typo : Bricolage Grotesque (titres) + Atkinson Hyperlegible (texte),
  Syne gardée pour le logo seul ; une seule source de polices (Bunny)
- palettes : teinte propre à chaque axe dans les 4 ambiances ;
  pages d'axe en axis-scope, cartes sans bordure (canon design)
- accueil : console des trois curseurs (tablist clavier), boîte à outils,
  bloc format éditorial + événement + reproduction ; ?v=a|b|c|0
- numérique : carte LPK ; bouquet rendu avec statut et légende
- messages : sans bordure, deux colonnes en grand écran

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-09-28 10:15:46 +02:00
co-authored by Claude Opus 5.5
parent c3ada04e52
commit e9fce4be8f
29 changed files with 2901 additions and 56 deletions
+362
View File
@@ -0,0 +1,362 @@
<template>
<div class="format">
<header v-if="format && showHeader" class="format-head">
<h2 class="format-title">{{ format.title }}</h2>
<p class="format-text">{{ format.text }}</p>
</header>
<div class="format-grid">
<!-- Éditorial : le livre et les chansons -->
<article v-if="book" class="format-card format-card--book">
<div
class="format-cover"
role="img"
:aria-label="book.coverAlt"
:style="{ backgroundImage: `url(${book.coverImage})` }"
/>
<div class="format-body">
<p class="format-kicker">{{ book.kicker }}</p>
<h3 class="format-card-title">{{ book.title }}</h3>
<p class="format-desc">{{ book.description }}</p>
<div class="format-actions">
<button type="button" class="fbtn fbtn--main" @click="$emit('open-player')">
<span class="i-lucide-play h-4 w-4" aria-hidden="true" />
{{ book.cta?.player }}
</button>
<button type="button" class="fbtn" @click="$emit('open-pdf')">
<span class="i-lucide-book-open h-4 w-4" aria-hidden="true" />
{{ book.cta?.pdf }}
</button>
<NuxtLink to="/economique/modele-eco" class="fbtn fbtn--quiet">
<span class="i-lucide-list h-4 w-4" aria-hidden="true" />
Présentation des chapitres
</NuxtLink>
<NuxtLink to="/economique/commande" class="fbtn fbtn--quiet">
<span class="i-lucide-shopping-bag h-4 w-4" aria-hidden="true" />
Commandez le livre
</NuxtLink>
</div>
</div>
</article>
<!-- Événementiel -->
<NuxtLink v-if="evenement" :to="evenement.to" class="format-card format-card--event">
<p class="format-kicker">
{{ evenement.teaser }}
<span v-if="evenement.gestation" class="format-state">en gestation</span>
</p>
<h3 class="format-card-title format-card-title--event">{{ evenement.subtitle }}</h3>
<p v-if="evenement.tagline" class="format-tagline">{{ evenement.tagline }}</p>
<ul v-if="evenement.config.length" class="format-config">
<li v-for="c in evenement.config" :key="c.label">
<span :class="`i-lucide-${c.icon}`" class="h-4 w-4" aria-hidden="true" />
<span>{{ c.label }}</span>
</li>
</ul>
<span class="format-more">
Voir l'événement
<span class="i-lucide-arrow-right h-4 w-4" aria-hidden="true" />
</span>
</NuxtLink>
</div>
<!-- Reproduction + à qui l'on s'adresse -->
<div v-if="evenement?.reproduction || hero?.addressees?.length" class="format-repro">
<p v-if="evenement?.reproduction" class="format-repro-line">
<span class="format-basins" aria-hidden="true"><i v-for="n in 5" :key="n" /></span>
{{ evenement.reproduction }}
</p>
<div v-if="hero?.addressees?.length" class="format-audience">
<p class="format-audience-label">{{ hero.audience }}</p>
<ul>
<li v-for="a in hero.addressees" :key="a.label">
<strong>{{ a.label }}</strong> {{ a.value }}
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup lang="ts">
withDefaults(defineProps<{
format?: { title: string, text: string }
book?: any
evenement?: any
hero?: any
showHeader?: boolean
}>(), {
showHeader: true,
})
defineEmits<{
'open-player': []
'open-pdf': []
}>()
</script>
<style scoped>
.format {
display: grid;
gap: 1.5rem;
}
.format-head {
max-width: 44rem;
}
.format-title {
margin: 0;
font-family: var(--font-display);
font-weight: 800;
font-size: clamp(1.75rem, 4.2vw, 2.75rem);
letter-spacing: -0.03em;
line-height: 1.05;
color: hsl(var(--color-text));
}
.format-text {
margin: 0.75rem 0 0;
font-size: 1.1rem;
line-height: 1.5;
color: hsl(var(--color-text) / 0.72);
}
.format-grid {
display: grid;
gap: 1.25rem;
}
@media (min-width: 1024px) {
.format-grid { grid-template-columns: 1.35fr 1fr; }
}
.format-card {
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 1.5rem;
border-radius: 16px;
background: hsl(var(--color-surface));
}
.format-card--book {
flex-direction: row;
gap: 1.5rem;
}
.format-cover {
flex-shrink: 0;
width: clamp(6.5rem, 16vw, 10rem);
aspect-ratio: 1756 / 2480;
border-radius: 6px;
background-size: cover;
background-position: center;
box-shadow: 0 16px 30px -18px hsl(var(--color-text) / 0.6);
}
.format-body {
min-width: 0;
}
.format-kicker {
margin: 0;
font-family: var(--font-mono);
font-size: 0.72rem;
color: hsl(var(--axis-eco));
}
.format-card--event .format-kicker {
color: hsl(var(--axis-cit));
}
.format-state {
margin-left: 0.35rem;
color: hsl(var(--color-text) / 0.5);
}
.format-state::before {
content: '◌ ';
}
.format-card-title {
margin: 0.3rem 0 0;
font-family: var(--font-display);
font-weight: 800;
font-size: clamp(1.3rem, 2.4vw, 1.6rem);
letter-spacing: -0.02em;
line-height: 1.12;
color: hsl(var(--color-text));
}
.format-card-title--event {
font-weight: 700;
}
.format-desc {
margin: 0.5rem 0 0;
font-size: 0.95rem;
line-height: 1.5;
color: hsl(var(--color-text) / 0.72);
}
.format-actions {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
margin-top: 1rem;
}
.fbtn {
display: inline-flex;
align-items: center;
gap: 0.4rem;
min-height: 2.5rem;
padding: 0.45rem 1rem;
border-radius: 20px;
font-size: 0.86rem;
font-weight: 700;
color: hsl(var(--color-text) / 0.85);
background: hsl(var(--color-text) / 0.07);
transition: transform 0.1s ease, background 0.2s ease;
}
.fbtn:hover { transform: translateY(-1px); background: hsl(var(--axis-eco) / 0.14); }
.fbtn:active { transform: translateY(0); }
.fbtn--main {
color: hsl(var(--color-bg));
background: hsl(var(--axis-eco));
}
.fbtn--main:hover { background: hsl(var(--axis-eco) / 0.88); }
.fbtn--quiet {
font-weight: 400;
background: transparent;
}
.format-card--event {
color: hsl(var(--color-text));
transition: transform 0.12s ease;
}
.format-card--event:hover {
transform: translateY(-3px);
}
.format-tagline {
margin: 0.2rem 0 0;
font-family: var(--font-display);
font-size: 1.05rem;
color: hsl(var(--color-text) / 0.7);
}
.format-config {
list-style: none;
margin: 0.75rem 0 0;
padding: 0;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0.5rem;
font-size: 0.85rem;
color: hsl(var(--color-text) / 0.78);
}
.format-config li {
display: flex;
align-items: center;
gap: 0.45rem;
}
.format-config li > span:first-child {
color: hsl(var(--axis-cit));
flex-shrink: 0;
}
.format-more {
display: inline-flex;
align-items: center;
gap: 0.35rem;
margin-top: auto;
padding-top: 1rem;
font-family: var(--font-display);
font-weight: 700;
color: hsl(var(--axis-cit));
}
/* Reproduction */
.format-repro {
display: grid;
gap: 1.25rem;
padding: 1.25rem 0 0;
}
@media (min-width: 768px) {
.format-repro {
grid-template-columns: 1fr 1fr;
align-items: start;
}
}
.format-repro-line {
margin: 0;
font-family: var(--font-display);
font-weight: 700;
font-size: clamp(1.15rem, 2.2vw, 1.4rem);
line-height: 1.25;
letter-spacing: -0.015em;
color: hsl(var(--color-text));
}
/* One basin, then its copies */
.format-basins {
display: flex;
gap: 0.35rem;
margin-bottom: 0.6rem;
}
.format-basins i {
display: block;
width: 0.8rem;
height: 0.8rem;
border-radius: 50%;
box-shadow: inset 0 0 0 1.5px hsl(var(--axis-cit) / 0.6);
}
.format-basins i:first-child {
background: hsl(var(--axis-cit));
box-shadow: none;
}
.format-audience-label {
margin: 0 0 0.5rem;
font-family: var(--font-mono);
font-size: 0.72rem;
color: hsl(var(--color-text) / 0.5);
}
.format-audience ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.3rem;
font-size: 0.95rem;
color: hsl(var(--color-text) / 0.7);
}
.format-audience strong {
color: hsl(var(--color-text));
}
@media (max-width: 640px) {
.format-card--book { flex-direction: column; }
.format-config { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
.fbtn, .format-card--event { transition: none; }
}
</style>