Compare commits

..
13 Commits
Author SHA1 Message Date
YvvandClaude Opus 5.5 f1dbf21723 identité 6 : plus de lectrice derrière la carte du livre sur l'accueil (DA)
ci/woodpecker/push/woodpecker Pipeline was successful
Descendue de 20 px sous la première ligne du chapeau, la lectrice ne montrait plus que sa
bulle. Elle ne peut pas non plus sortir par le côté de la carte, à cause de la marge de page
et de la gouttière, et l'accordéoniste occupe le seul dessus libre. DA, 03/11 après 19h : « Je
ne veux pas d'un oiseau réduit à un morceau ». Elle reste visible à 1440 px sur la page
commande, où elle se tient en marge droite : les 61 oiseaux restent visibles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 19:50:55 +01:00
YvvandClaude Opus 5.5 28a6daf382 identité 6 : la règle f mesurée au-dessus du dessin, les chapitres posés sur leurs filets, les coins arrondis dégagés
Règle f, selon la précision de DA du 03/11 après 17h35 : au-dessus d'un oiseau perché, le vide
se mesure du haut de son dessin jusqu'à la plus basse ligne de texte ou au plus bas bloc qui
passe au-dessus de sa largeur peinte. Les lignes de son propre titre comptent, et l'en-tête
collant aussi en haut de page. Quinze perchés en défaut sur bb8fad9 changent de pose, sans
sortir de la liste fermée :
- accueil :
  - le DJ se tient derrière le pupitre de la console, seule sa tête dépasse ;
  - l'accordéoniste passe en S, visible à partir de 1200 px ;
  - la factrice passe à 76 px ;
  - la lectrice sort 20 px plus bas ;
- au téléphone, l'oiseau de l'intitulé est un oiseau plat : codeuse, maraîchère, potier, et le
  cycliste livreur sur productions collectives ;
- authentification, tarifs de l'eau, commande : en marge droite, sur l'arête haute de la carte ;
- en musique : le danseur passe en S ;
- évènement :
  - l'acrobate se tient avant la devise ;
  - le régisseur passe en S, posé sur l'arête des cartes ;
  - le clown passe en M ;
  - le marionnettiste se tient sur le filet du pied de page (option 1 d'orch). Son décalage
    est tiré de --seal-block, le bloc du sceau défini dans le layout ;
- chapitres : le calligraphe se tient sur le filet du titre, le typographe sur celui de la
  navigation, le cartonnier en marge des boutons. Plus aucune hauteur en %.

Règle g, rectangle du bloc (décision d'orch) : le porteur de serveur et l'administrateur réseau
sortent de la découpe des coins arrondis.

La liste fermée (docs/da-oiseaux.md) reçoit les précisions d'orch :
- e vaut pour un oiseau « libre » dont le centre sort de son bloc ;
- g se mesure sur le rectangle du bloc ;
- un oiseau derrière une carte reste « derrière ».

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 19:24:44 +01:00
YvvandClaude Opus 5.5 bb8fad9ff3 identité 5 : la liste fermée des règles mesurées, appliquée à toutes les pages
Ordre IDENTITE-DA-5 (03/11 14h41, relayé par la session orch ; seuils confirmés par DA) :
- docs/da-oiseaux.md : « Règles mesurées (liste fermée) », règles a à i avec leurs seuils, telles
  que le contrôle les mesure (pixels peints, ligne de base), et la phrase juste sur l'acrobate ;
- UiOiseauPose : pose `bout`, une ancre sans taille dans le texte, sur sa ligne de base, pour un
  oiseau au bout (ou au début) d'un titre ;
- au bout de leur titre : trapéziste, clown, marionnettiste, DJ (/en-musique), droneuse, vigie,
  alchimiste, relieur, et l'oiseau de l'intitulé au téléphone ;
- authentification : le pompeur de Ğ1 perché sur la carte du projet (plus de colonne en marge) ;
- accueil : l'accordéoniste au bout du titre du format (plus de paire avec la lectrice, plus de
  trait sur le lien) ;
- soudeuse sur la ligne de base de son titre ; administrateur réseau et cartographe sortent par le
  côté de leur carte, pas par un coin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 15:07:35 +01:00
YvvandClaude Opus 5.5 b6143c5cf7 identité 4 : plus de paire ni de colonne en marge, chaque oiseau sur une ligne visible ; la console arrête un curseur qui descendait
Relecture de fb8c71f..16d6607 (03/11 13h10, relayée par la session orch) :
- /economique : la balance sort de derrière le bloc du livre à mi-hauteur, loin du sol de la
  maraîchère ;
- authentification-wot : la toile de confiance, petite, en marge sur la dernière ligne des étapes
  (le bloc n'a pas de fond) ;
- chapitres : le filet au-dessus de précédent / suivant est tracé (border-t seul n'a pas de style
  ici) ; le cartonnier s'y pose ;
- /evenement : l'acrobate passe au bout de la ligne du leitmotiv, le régisseur reste seul près de
  « Format & lieu » ;
- sommaire du livre : empileur plus loin, illustratrice moins sortie : plus de bande commune.
Trouvés par le contrôle étendu : le débogueur (logiciel-libre) sur la dernière ligne des étapes,
la vigneronne (monnaie-libre) derrière le bloc de texte, qui a un fond.

Console, décision d'orch du 03/11 à 13h10 : au premier geste, un curseur non touché que la
rotation faisait descendre s'arrête là où il est ; un curseur qui montait finit sa montée.
docs/consignes-yvv.md (« Ce que fait le code ») et docs/da-oiseaux.md suivent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 13:52:44 +01:00
YvvandClaude Opus 5.5 16d66072b9 docs : les avis du studio DA et des relectures quittent les consignes d'Yvv (docs/da-oiseaux.md)
consignes-yvv.md ne garde que les mots d'Yvv, datés et mot pour mot. Les deux sections
relayées par la session orch (avis de DA de 07h00, second avis de 07h56 et relecture de
08h14, le 03/11) passent telles quelles dans docs/da-oiseaux.md ; une ligne y renvoie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:38:56 +01:00
YvvandClaude Opus 5.5 8de9a81b65 console : chaque survol rejoue la montée, aucun curseur figé à mi-course ; pied de page sans lien mort
Les quatre écarts de la relecture « 64e714c : ok », graduation d'Yvv inchangée
(0,75, 0,50, 0,667, montée rejouée à chaque survol) :
- premier geste pendant la rotation : un curseur non touché finit en douceur le
  mouvement que la rotation avait commencé (jusqu'à son cran, ou en bas), puis reste.
  La main ne fait descendre aucun curseur (« ne fait pas descendre les autres ») ;
- un nouveau survol, même à moins de 500 ms, rejoue la montée ; seuls la flèche et
  le focus qui la suit, ou le focus et le clic d'un même tap, font une seule montée ;
- un clic sans survol ni focus (lecteur d'écran, script) monte le curseur avec son
  panneau ;
- la flèche part de l'onglet qui a le focus, plus de l'axe sélectionné.

Pied de page : un lien vers une page qui n'existe pas (/mentions-legales) n'est pas
affiché ; il reviendra seul quand la page existera. site.yml n'est pas touché.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:34:15 +01:00
YvvandClaude Opus 5.5 44e9576b38 identité 3 : plus de zigzag ni de paires, des tailles variées, chaque oiseau sur une vraie ligne
Second avis du studio DA (03/11, 07h56) et relecture de fb8c71f (08h14) :
- numérique : le zigzag gauche-droite à pas égal est cassé. Électricien en M,
  codeuse et cryptographe au bas de leur carte, à droite, administrateur réseau
  en grand derrière Cloud libre ;
- commande : un seul côté par carte. Cycliste à gauche de la première, libraire
  en grand derrière la seconde ; la lectrice se tient sur le sac de l'icône.
  Le cartonnier va sur la ligne qui clôt chaque chapitre, l'empileur sur le
  sommaire du livre : les 61 restent rendus ;
- au moins deux tailles dès trois oiseaux (chapitre, en-musique, événement) ;
- un oiseau de marge a les pieds sur une vraie ligne, le bas ou le haut de son
  bloc ou d'une carte, jamais à mi-hauteur (« posés sans flotter ») ;
- aucun oiseau sur le haut invisible de la boîte d'un titre : dj, trapéziste,
  alchimiste et droneuse se tiennent sur la dernière ligne ou au bout de
  l'intitulé ;
- téléphone : le pompeur de Ğ1 au bout de la ligne de l'intitulé ;
- sous-pages numériques : poses, tailles et décalages variés malgré le sommaire
  à droite ; le comédien de tarifs-eau perché sur sa carte, hors du sommaire.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:33:05 +01:00
YvvandClaude Opus 5.5 fb8c71fc59 identité 2 : un oiseau perché seulement où il y a du vide au-dessus, l'en-tête tient à 768 px
Avis du studio DA du 03/11 (07h00) et relecture de 8ccdda3 :
- règle du perché : il faut au-dessus de l'arête un vide au moins égal à la hauteur
  de l'oiseau, sinon il va en marge ou derrière la carte. Les perchés entre cartes
  rapprochées (numérique, logiciel-libre, économique, sommaire du livre, commande,
  citoyenne, événement) passent en marge, derrière, ou partent ;
- productions-collectives : 8 oiseaux ramenés à 4, sans colonne ni chevauchement.
  Les oiseaux retirés vont sur des pages qui en avaient peu : monnaie-libre
  (boulangère, vigneronne), tarifs-eau (potier), décision (tisserand),
  cloud-libre (imprimeuse 3D). Les 61 restent rendus ;
- pas trois oiseaux sur la même verticale (commande, numérique) ;
- au téléphone, l'oiseau de la page se tient au bout de la ligne de l'intitulé ;
- seuil 1024 pour un perché dont le bloc n'a de vide au-dessus qu'en deux colonnes
  (accordéoniste et factrice de l'accueil) ;
- numerique/[slug] : les oiseaux des sections larges tiennent dans 152 px de marge
  à 1200 px ;
- en-tête : de 768 à 1023 px, boutons resserrés au lieu d'un débordement ; le
  logotype du kit ne change pas.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 07:41:10 +01:00
YvvandClaude Opus 5.5 8ccdda39a9 claude.md : les oiseaux et le logotype du studio DA remplacent les shadoks et la signature §
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 06:41:19 +01:00
YvvandClaude Opus 5.5 d2bc0d9e46 identité : le kit du studio DA intégré, les 61 oiseaux posés sur la page
Copie du kit kit-site (empreinte vérifiée) : logotype dans l'en-tête, signe §,
favicons et icônes, og-default (?v=3), frise du pied de page, 61 oiseaux.
Les shadoks positionnés à la main (HomeShadoks et les règles des 10 pages)
cèdent la place à UiOiseauPose : chaque oiseau se pose sur une arête réelle
(perché, marge gauche ou droite, derrière une carte, libre), currentColor,
largeur 72 px au moins, opacité 0,18-0,28 près du texte et 0,10-0,14 derrière,
jamais deux fois sur une page, calligraphe et typographe jamais en miroir.
Sous 768 px, un oiseau par page au plus ; seuls ceux derrière une carte
dérivent un peu, et plus du tout en mouvement réduit.

Consignes d'Yvv du 03/11 inscrites dans docs/consignes-yvv.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 06:39:34 +01:00
YvvandClaude Opus 5.5 cdd3fa57de claude.md : renvoi aux consignes d'Yvv, datées et mot pour mot (docs/consignes-yvv.md)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 06:15:38 +01:00
YvvandClaude Opus 5.5 44dbcfd5cf acte : console de l'accueil — exécuté et vérifié en production (pipeline 60)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 06:15:27 +01:00
YvvandClaude Opus 5.5 26ce315aa6 acte : console de l'accueil, la graduation d'Yvv au survol — dossier « déploie » préparé
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 05:58:48 +01:00
106 changed files with 1482 additions and 3486 deletions
+11 -2
View File
@@ -149,10 +149,19 @@ prod) ; `data/messages.yml` ; lien de commande du livre (Bookelis,
## Conventions
- **Consignes d'Yvv**, datées et mot pour mot : `docs/consignes-yvv.md`. Les relire avant de
toucher au design ; y inscrire toute nouvelle consigne le jour où elle est donnée.
- CSS via UnoCSS + variables CSS palettes ; composants Vue SFC `<script setup lang="ts">`
- Shadoks SVG inline thématiques sur chaque page (hidden mobile, opacity 0.18–0.28)
- Oiseaux du kit du studio DA (depuis le 03/11/2026, à la place des shadoks) : `UiOiseau`,
`app/utils/oiseaux.ts` (copiés tels quels du kit), posés par `UiOiseauPose` près du contenu
de leur métier, jamais en rangée. Règles du kit : currentColor, au moins 72 px, opacité
0,18–0,28 près du texte et 0,10–0,14 derrière une carte, un oiseau jamais deux fois sur une
page, un seul sous 768 px, pas de miroir pour calligraphe et typographe. Consignes :
`docs/consignes-yvv.md` § Les oiseaux.
- Hexagramme 益 (#42 Yi, Augmentation) dans `layouts/default.vue`
- Signature § (logo calligraphique SVG gradient) dans `TheHeader.vue` — ne pas modifier sans demander
- Logotype validé du studio DA (`UiLogotype`) dans `TheHeader.vue`, et `UiSectionSign` du
kit — ne pas modifier sans demander. Source du kit :
`/home/yvv/Documents/PROD/IMAGES/_atelier/2026-10-27-librodrome-logo/livrables/kit-site/`.
## SEO & Recherche IA — Checklist permanente
+109
View File
@@ -0,0 +1,109 @@
# Acte — Console de l'accueil : la graduation d'Yvv au survol
Classe : déploie
Projet : librodrome Date : 2026-11-03
**État : EXÉCUTÉ (03/11, 06h11-06h16), par orch (session dev-63) sous mandat « déploie » (inscrit du 03/11 au 08/11), après la relecture neuve « 64e714c : ok »**
## Intention
Mettre en ligne la console de l'accueil selon la consigne d'Yvv du 03/11 : au survol,
numérique monte à 3/4, économique à 1/2, citoyenne à 2/3. Chaque curseur reste à son cran,
et un nouveau survol rejoue sa montée. Le panneau suit le même geste. Avant le premier geste,
l'animation lente du 29/09 continue, et l'axe en avant monte à son cran, jamais au-dessus.
Les consignes sont écrites mot pour mot dans `docs/consignes-yvv.md`. La première relecture
(« 230f79a : à reprendre ») a été traitée par `03f763a` et `64e714c`.
## Avant — prémisses vivantes
Sur le poste, dans `/home/yvv/Documents/PROD/DEV/librodrome`. L'attendu, relevé le 03/11 à
05h57, est en commentaire :
```bash
git fetch -q origin && git rev-parse origin/main # P1 : 4057f50bd37fa8a3ba3ea9dc6c9c38d51d4f6434
# sinon ARRÊT : quelqu'un a poussé
git merge-base --is-ancestor origin/main 64e714c1dde9897e46d36caf6cab737799081c96; echo $? # P2 : 0
git diff --name-only origin/main 64e714c1dde9897e46d36caf6cab737799081c96 \
| grep -E '(^|/)data/|\.env|\.db$|\.enc$|\.key$|\.pem$|id_rsa|id_ed25519|IDENTIFIANTS'; echo $? # P3 : 1 (rien)
curl -4 -s 'https://ci.open.us.org/api/repos/1/pipelines?perPage=3' \
| python3 -I -c 'import sys,json; [print(p["number"], p["status"]) for p in json.load(sys.stdin)]' # P4 : « 59 success » en tête, rien en cours
curl -4 -s -o /dev/null -w '%{http_code}\n' https://librodrome.org/api/health # P5 : 200
curl -4 -s https://librodrome.org/api/messages \
| python3 -I -c 'import sys,json; print(len(json.load(sys.stdin)))' # P6 : 1
ssh -o BatchMode=yes yvv@161.97.174.60 'docker diff lpk-librodrome-main-app-1 | grep -E " /app/(site|content)(/|$)"; echo $?; docker exec lpk-librodrome-main-app-1 sha256sum /app/data/messages.yml' </dev/null
# P7 : « 1 » (aucune édition /admin, que ce déploiement effacerait)
# puis c8afc7de728fb9d57f6565a36b40f16fe7beb438768f8f9127183bea9569a6b8 /app/data/messages.yml
```
Une édition /admin trouvée en P7 arrête l'acte : elle doit d'abord passer dans git.
Relecture : `~/harness/etat/relectures.json` doit porter « 64e714c : ok », d'un relecteur neuf.
Contenu sortant (`git log origin/main..64e714c --stat`, relevé le 03/11 à 05h57) :
```
64e714c console : l'animation monte l'axe en avant à son cran
03f763a console : graduation d'Yvv, la montée se rejoue à chaque survol
230f79a console : au survol, le curseur monte sans faire descendre les autres
89d5f83 actes : persistance des messages — preuve au déploiement suivant
actes/2026-10-26-persistance-messages.md | 14 ++-
app/components/home/HomeConsole.vue | 166 ++++++++++++++++++++++++-----
docs/consignes-yvv.md | 50 ++++++++++
```
Ni `data/`, ni `site/`, ni configuration, ni secret. Ce dossier n'est pas dans le push : il
partira avec le déploiement suivant.
## Commandes exactes
```bash
# 1. La mise en ligne : la poussée du SHA relu
cd /home/yvv/Documents/PROD/DEV/librodrome && for i in 1 2 3 4 5; do if git push -q origin 64e714c1dde9897e46d36caf6cab737799081c96:main; then break; fi; sleep 10; done
# 2. Attente du pipeline (environ 3 min)
for i in $(seq 1 40); do s=$(curl -4 -s -m 20 'https://ci.open.us.org/api/repos/1/pipelines?perPage=5' | python3 -I -c 'import sys,json; print(next((p["status"] for p in json.load(sys.stdin) if p["commit"].startswith("64e714c1dde9")), "absent"))'); echo "$(date +%T) $s"; case "$s" in success|failure|error|killed|declined) break;; esac; sleep 15; done
# attendu : success
# 3. Branche main locale sur la tête déployée (avance rapide seule ; main n'est extraite nulle part)
git -C /home/yvv/Documents/PROD/DEV/librodrome fetch . 64e714c1dde9897e46d36caf6cab737799081c96:main
```
Si le pipeline échoue, l'ancien conteneur continue de servir, sans changement : on ne
relance rien, on rapporte.
## Effet attendu
- librodrome.org est reconstruit. Seule la console de l'accueil change de comportement.
Les messages restent sur le volume `librodrome-data`, sans être touchés.
- Irréversibilité : réversible (voir Retour).
## Vérifications après
- [x] Pipeline du commit `64e714c1dde9` : `success`
- [x] P5 et P6 rejoués : `200`, puis le même nombre de messages publiés
- [x] Sur sonic : `messages.yml` a la même empreinte qu'en P7, et le journal du conteneur n'a aucune ligne `seed-messages`
- [x] Vu de l'extérieur, sur https://librodrome.org, dans un navigateur sans tête : au survol d'économique, `--level` passe de 0 à 0,50 ; les deux autres ne bougent pas ; le panneau « Autonomie économique » s'affiche
## Retour
Par un nouvel acte « déploie » :
```bash
git switch main && git revert --no-edit 64e714c1dde9897e46d36caf6cab737799081c96 03f763a 230f79a \
&& for i in 1 2 3 4 5; do if git push -q origin "$(git rev-parse HEAD)":main; then break; fi; sleep 10; done
```
Le retour ne touche ni le volume ni les messages.
## Exécution
Acte exécuté le 03/11/2026, 06h11-06h16, par orch (session dev-63, e66db8ca), sous mandat
« déploie » ; consigne d'Yvv du 03/11 à 06h00 : « livre et déploie tout ce que tu peux ».
- Relecture : « 230f79a : à reprendre » (05h34), puis « 64e714c : ok » (06h05), d'un sous-agent
neuf, inscrite dans `~/harness/etat/relectures.json`. Légers, pour un lot suivant : un curseur
non touché peut se figer à mi-course si le premier geste tombe pendant la rotation ; un
nouveau survol à moins de 500 ms ne rejoue pas la montée ; un clic sans survol ni focus
affiche le panneau sans monter le curseur ; la flèche part de l'axe sélectionné.
- Prémisses rejouées à 06h11:39 : P1 `4057f50…`, P2 0, P3 1, P4 « 59 success », P5 200, P6 1,
P7 1 et `c8afc7de…a6b8`.
- Poussée de `64e714c1dde9897e46d36caf6cab737799081c96:main` à 06h11:5x, passée du premier coup.
- Pipeline n° 60 : `running` de 06h12:08, `success` à 06h14:27.
- Après : `/api/health` 200, `/` 200, 1 message publié ; conteneur `Up 20 seconds (healthy)` ;
`messages.yml` `c8afc7de…a6b8`, inchangé ; 0 ligne `seed-messages`.
- Vu de l'extérieur (Chromium sans tête, https://librodrome.org, 1280 px), `--level` :
repos 0,75 / 0,336 / 0,17, panneau numérique ; survol d'économique 0,75 / **0,50** / 0,17,
panneau économique ; survol de citoyenne 0,75 / 0,50 / **0,667** ; survol de numérique
0,75 / 0,50 / 0,667 ; 4 s après la sortie, inchangé ; 0 erreur dans la console.
- `main` local avancé sur `64e714c` (`git fetch . 64e714c…:main`).
- Ce dossier n'est pas en ligne : il partira avec le déploiement suivant.
+2 -2
View File
@@ -29,7 +29,7 @@ useSeoMeta({
ogSiteName: 'Le Librodrome',
ogType: 'website',
ogLocale: 'fr_FR',
ogImage: `${siteUrl}/og-default.png?v=2`,
ogImage: `${siteUrl}/og-default.png?v=3`,
ogImageWidth: 1200,
ogImageHeight: 630,
twitterCard: 'summary_large_image',
@@ -51,7 +51,7 @@ useHead({
url: siteUrl,
logo: {
'@type': 'ImageObject',
url: `${siteUrl}/og-default.png?v=2`,
url: `${siteUrl}/og-default.png?v=3`,
},
description: 'Plateforme d\'autonomie numérique, économique et citoyenne à l\'échelle des bassins de vie.',
},
+6
View File
@@ -29,6 +29,12 @@
--ease-in-out-expo: cubic-bezier(0.87, 0, 0.13, 1);
}
/* A page whose birds may stand behind a card (UiOiseauPose, pose « derriere »):
the stacking context they go back into, above the page background */
.oiseaux-scene {
isolation: isolate;
}
/* Fader level of the home console — registered so it can transition smoothly */
@property --level {
syntax: '<number>';
+7 -3
View File
@@ -8,15 +8,19 @@
· {{ readingTime }}
</span>
</div>
<h1 class="chapter-title font-display font-bold leading-tight tracking-tight text-white">
<h1 class="chapter-title relative font-display font-bold leading-tight tracking-tight text-white">
{{ title }}
<!-- The calligrapher in the left margin, feet on the title's rule (rule e) -->
<UiOiseauPose nom="calligraphe" pose="marge-g" ecart="40px" :w="112" />
</h1>
<p v-if="description" class="mt-3 text-lg text-white/60">
{{ description }}
</p>
<!-- Songs + PDF actions row -->
<div class="mt-4 flex flex-wrap items-center gap-2">
<!-- Songs + PDF actions row. The box maker in the right margin, feet at the bottom of the
buttons (every chapter has its PDF page) -->
<div class="relative mt-4 flex flex-wrap items-center gap-2">
<UiOiseauPose nom="cartonnier" pose="marge-d" ecart="40px" :w="76" retourne />
<!-- Associated songs badges -->
<button
v-for="song in songs"
+69 -30
View File
@@ -30,7 +30,7 @@
type="button"
role="tab"
class="fader"
:class="{ 'fader--active': axis.key === active, 'fader--rising': rising.has(axis.key) }"
:class="{ 'fader--active': axis.key === active, 'fader--held': held.has(axis.key), 'fader--rising': rising.has(axis.key), 'fader--stopped': stopped.has(axis.key) }"
:style="{ '--hue': `var(${axis.hue})`, '--level': levels[axis.key] ?? 0, '--i': i }"
:data-axis="axis.key"
:aria-selected="axis.key === active"
@@ -142,17 +142,25 @@ const current = computed(() => props.axes.find(a => a.key === active.value) ?? p
// The visitor's hand takes over for good (03/11): from the first hover,
// keyboard focus or tap on a cursor, the rotation stops. The touched cursor
// replays its rise, from the bottom to its own graduation, and its panel
// shows. The others do not move; a cursor never touched stays where it was.
// shows. The others are never lowered by the hand (orch decision, 03/11
// 13h10): a cursor already touched stays at its graduation; a cursor never
// touched that the rotation was taking down stops where it is at the first
// gesture; one it was taking up finishes, gently, its rise to the level the
// rotation gave it, then stays there.
const BEAT_MS = 2600
const BEATS_PER_AXIS = 3
/** Graduation of each axis, from asservissement (0) to émancipation (1) */
const GRADUATION: Record<AxisKey, number> = { numerique: 3 / 4, economie: 1 / 2, politique: 2 / 3 }
/** A focus and a click within this delay are one gesture (a tap): one rise */
/** The focus and the click of one tap, within this delay, give one rise */
const SAME_GESTURE_MS = 500
const levels = reactive<Partial<Record<AxisKey, number>>>({})
/** Cursors the hand has touched: they no longer glide with the rotation */
const held = reactive(new Set<AxisKey>())
/** Cursors replaying their rise (fast transition) */
const rising = reactive(new Set<AxisKey>())
/** Untouched cursors the first gesture stopped on their way down */
const stopped = reactive(new Set<AxisKey>())
const reduced = ref(false)
const visible = ref(true)
const engaged = ref(false)
@@ -160,7 +168,10 @@ const pointerIn = ref(false)
const focusIn = ref(false)
const hoverKey = ref<AxisKey | null>(null)
let lastPointer = ''
const lastRise: Partial<Record<AxisKey, number>> = {}
/** The tab the arrow keys are moving the focus to: its focus is the same gesture */
let keyFocus: AxisKey | null = null
/** When a keyboard focus last raised each cursor (to pair it with the click of a tap) */
const focusRiseAt: Partial<Record<AxisKey, number>> = {}
const riseRun: Partial<Record<AxisKey, number>> = {}
let beat = 0
let timer: ReturnType<typeof setInterval> | undefined
@@ -180,24 +191,30 @@ function faderEl(key: AxisKey) {
return root.value?.querySelector<HTMLElement>(`[data-axis="${key}"]`) ?? null
}
/** Level currently drawn (mid-transition included), read from the DOM */
function drawnLevel(key: AxisKey) {
const el = faderEl(key)
const v = el ? Number.parseFloat(getComputedStyle(el).getPropertyValue('--level')) : Number.NaN
return Number.isFinite(v) ? v : (levels[key] ?? 0)
}
/** First gesture: the rotation stops for good, every cursor stays where it is drawn */
function engage() {
/** First gesture: the rotation stops for good. An untouched cursor on its way down stops
* where it is drawn; one on its way up finishes its glide to the target the rotation gave it.
* `touched` is the cursor of this gesture: it replays its rise anyway */
function engage(touched?: AxisKey) {
if (engaged.value) return
for (const axis of props.axes) levels[axis.key] = drawnLevel(axis.key)
engaged.value = true
clearInterval(timer)
for (const axis of props.axes) {
const key = axis.key
if (key === touched || held.has(key)) continue
const el = faderEl(key)
const drawn = el ? Number.parseFloat(getComputedStyle(el).getPropertyValue('--level')) : Number.NaN
const target = levels[key] ?? 0
if (Number.isFinite(drawn) && drawn > target) {
stopped.add(key)
levels[key] = drawn
}
}
}
/** The touched cursor replays its rise: back to the bottom, then up to its graduation */
async function rise(key: AxisKey) {
lastRise[key] = Date.now()
held.add(key)
stopped.delete(key)
const target = GRADUATION[key] ?? 0.75
if (reduced.value) {
levels[key] = target
@@ -216,14 +233,20 @@ async function rise(key: AxisKey) {
levels[key] = target
}
/** A cursor under the visitor's hand: it rises and its panel shows */
/** A cursor under the visitor's hand: it rises and its panel shows. Every rollover replays
* the rise, however soon after the previous one (Yvv, 03/11) */
function touch(key: AxisKey) {
engage()
engage(key)
active.value = key
if (Date.now() - (lastRise[key] ?? 0) < SAME_GESTURE_MS) return
rise(key)
}
/** The panel of a cursor already raised by this same gesture: no second rise */
function select(key: AxisKey) {
engage(key)
active.value = key
}
function onEnter(e: PointerEvent, key: AxisKey) {
// A finger scrolling over a cursor is not a rollover: taps go through the click
if (e.pointerType === 'touch') return
@@ -241,19 +264,24 @@ function isKeyboardFocus(el: HTMLElement) {
}
function onFocus(e: FocusEvent, key: AxisKey) {
// The arrow key that moved the focus here already raised the cursor
if (keyFocus === key) return
// Keyboard focus is a rollover; a focus from the mouse or a tap is handled elsewhere
if (hoverKey.value === key || !isKeyboardFocus(e.currentTarget as HTMLElement)) return
focusRiseAt[key] = Date.now()
touch(key)
}
function onClick(e: MouseEvent, key: AxisKey) {
const pointer = (e as PointerEvent).pointerType || lastPointer
lastPointer = ''
if (pointer === 'touch') touch(key)
else {
engage()
active.value = key
}
// A tap is a rollover: one rise per tap, even when the browser also gave it a keyboard focus
const tapFocused = Date.now() - (focusRiseAt[key] ?? 0) < SAME_GESTURE_MS
if (pointer === 'touch' && !tapFocused) return touch(key)
// A click with no hover nor focus before it (a screen reader, a script) raises the cursor
// with its panel; after a hover or a keyboard focus, the cursor is already up
if (hoverKey.value !== key && !held.has(key)) return touch(key)
select(key)
}
function onFocusOut(e: FocusEvent) {
@@ -281,15 +309,23 @@ function onKeydown(e: KeyboardEvent) {
const keys = ['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'Home', 'End']
if (!keys.includes(e.key)) return
e.preventDefault()
const idx = props.axes.findIndex(a => a.key === active.value)
// From the tab that has the focus: a hover may have selected another axis meanwhile
const from = (e.target as HTMLElement | null)?.closest<HTMLElement>('[data-axis]')?.dataset.axis
const idx = props.axes.findIndex(a => a.key === (from ?? active.value))
const last = props.axes.length - 1
let next = idx
if (e.key === 'ArrowRight' || e.key === 'ArrowUp') next = idx === last ? 0 : idx + 1
if (e.key === 'ArrowLeft' || e.key === 'ArrowDown') next = idx === 0 ? last : idx - 1
if (e.key === 'Home') next = 0
if (e.key === 'End') next = last
touch(props.axes[next]!.key)
nextTick(() => tabs.value[next]?.focus())
const key = props.axes[next]!.key
touch(key)
nextTick(() => {
// focus() fires the focus event at once: it is part of this key press, not a new rise
keyFocus = key
tabs.value[next]?.focus()
keyFocus = null
})
}
onMounted(() => {
@@ -383,12 +419,15 @@ onMounted(() => {
transition-delay: calc(var(--i) * 160ms);
}
/* The visitor's hand has taken over: nothing glides any more but the touched cursor */
.console--hand .fader {
/* A cursor the hand has touched no longer glides: it drops to the bottom at once, then
replays its rise. At the first gesture, an untouched cursor on its way down stops where it
is; one on its way up finishes its glide, then the rotation is over */
.fader--held,
.fader--stopped {
transition: none;
}
.console--hand .fader--rising {
.fader--held.fader--rising {
transition: --level 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}
@@ -657,7 +696,7 @@ onMounted(() => {
@media (prefers-reduced-motion: reduce) {
.fader,
.console--hand .fader--rising,
.fader--held.fader--rising,
.fader-fill,
.fader-name,
.fader-lever,
+11 -1
View File
@@ -1,13 +1,21 @@
<template>
<div class="format">
<header v-if="format && showHeader" class="format-head">
<h2 class="format-title">{{ format.title }}</h2>
<!-- The accordion player at the end of the title, on its baseline: on the event card it stood
at the height of the reader, and its ground line touched the card's link (rules c, h).
S and from 1200 px: the band above leaves 125 px, and a perched bird keeps a void of its
own height above it (rule f); 8 px under the baseline, within the 12 px of rule e -->
<h2 class="format-title">{{ format.title }}<UiOiseauPose nom="accordeoniste" pose="perche" bout left="16px" bottom="-8px" :w="72" retourne ton="accent" :seuil="1200" /></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">
<!-- No bird behind the book card (DA, 03/11 after 19h): lowered under the header's first
line, the reader only showed her bubble; the page margin and the gutter leave her no
side to come out by, and the free top of the card holds the accordion player. She
stands on the order page -->
<div
class="format-cover"
role="img"
@@ -123,6 +131,7 @@ defineEmits<{
}
.format-grid {
isolation: isolate;
display: grid;
gap: 1.25rem;
}
@@ -132,6 +141,7 @@ defineEmits<{
}
.format-card {
position: relative;
display: flex;
flex-direction: column;
gap: 0.5rem;
+37 -12
View File
@@ -2,7 +2,6 @@
<div class="va">
<!-- Hero : the headline, and the three cursors to push -->
<section class="va-hero">
<HomeShadoks />
<div class="container-content va-hero-grid">
<div class="va-intro">
<h1 class="va-h1">
@@ -20,17 +19,27 @@
</div>
<div class="va-console">
<p class="va-console-title">{{ heading[2] }}</p>
<HomeConsole
v-model="active"
:axes="axes"
:prefix="consoleLabels?.prefix"
:top-label="consoleLabels?.top"
:bottom-label="consoleLabels?.bottom"
:stacks="bouquet?.inService"
:stacks-to="lpk?.to"
:stacks-label="lpk ? `En service chez ${lpk.name} :` : 'En service :'"
/>
<p class="va-console-title">
{{ heading[2] }}
</p>
<!-- The DJ stands behind the console board, like behind its decks: only its head, with
its headphones, shows over the board. Perched on the board, under the sticky header,
it had no void of its own height above it (rule f, DA 03/11 after 17h35). The scene
keeps it under the board without touching the console -->
<div class="va-console-scene">
<UiOiseauPose nom="dj" pose="derriere" right="24px" top="-95px" :w="150" retourne ton="accent" />
<UiOiseauPose nom="dj" pose="derriere" right="24px" top="-95px" :w="150" retourne ton="accent" mobile-seul :seuil="768" />
<HomeConsole
v-model="active"
:axes="axes"
:prefix="consoleLabels?.prefix"
:top-label="consoleLabels?.top"
:bottom-label="consoleLabels?.bottom"
:stacks="bouquet?.inService"
:stacks-to="lpk?.to"
:stacks-label="lpk ? `En service chez ${lpk.name} :` : 'En service :'"
/>
</div>
</div>
</div>
</section>
@@ -61,6 +70,7 @@
<div class="container-content">
<h2 class="va-h2">{{ toolboxTitle }}</h2>
<HomeToolbox
:oiseaux="toolboxOiseaux"
:axes="axes"
:lpk="lpk"
:bouquet="bouquet"
@@ -76,6 +86,7 @@
<script setup lang="ts">
import type { AxisKey } from '~/composables/useHomeData'
import type { OiseauPlace } from '~/utils/oiseauPose'
defineEmits<{
'open-player': []
@@ -97,6 +108,14 @@ const axesLine = computed(() =>
.filter(Boolean)
.map(text => ({ text, hue: AXIS_WORDS[text] })))
const active = ref<AxisKey>('numerique')
// The governance crew stands in the empty space under the citoyenne column of the toolbox
const toolboxOiseaux: Partial<Record<AxisKey, OiseauPlace[]>> = {
politique: [
{ nom: 'capitaine', pose: 'libre', left: 'calc(34% - 75px)', bottom: '-190px', w: 150, op: 0.24 },
{ nom: 'matelot', pose: 'libre', left: 'calc(80% - 40px)', bottom: '-300px', w: 80, op: 0.26, retourne: true },
],
}
</script>
<style scoped>
@@ -183,7 +202,13 @@ const active = ref<AxisKey>('numerique')
.va-approach::after { content: ' →'; }
}
.va-console-scene {
position: relative;
isolation: isolate;
}
.va-console-title {
position: relative;
margin: 0 0 0.75rem;
font-family: var(--font-display);
font-weight: 700;
+3
View File
@@ -5,6 +5,8 @@
<!-- Formulaire -->
<UiScrollReveal>
<div class="message-form-card">
<!-- The postwoman stands on the message form -->
<UiOiseauPose nom="factrice" pose="perche" right="30px" :w="76" retourne :seuil="1200" />
<h3 class="font-display text-lg font-bold form-title mb-4">Laisser un message</h3>
<form v-if="!submitted" class="space-y-3" @submit.prevent="send">
@@ -167,6 +169,7 @@ function formatDate(iso: string) {
/* ── Carte formulaire ── */
.message-form-card {
position: relative;
background: hsl(var(--color-surface));
border-radius: 16px;
padding: 1.5rem;
-83
View File
@@ -1,83 +0,0 @@
<template>
<div class="shadoks" aria-hidden="true">
<!-- Shadok bird decoration -->
<svg class="shadok-bird" viewBox="0 0 180 260" fill="none" aria-hidden="true">
<ellipse cx="90" cy="100" rx="45" ry="40" fill="currentColor" opacity="0.85"/>
<circle cx="130" cy="60" r="22" fill="currentColor" opacity="0.8"/>
<path d="M110 85 Q125 70 128 63" stroke="currentColor" stroke-width="8" stroke-linecap="round" opacity="0.7" fill="none"/>
<circle cx="136" cy="55" r="5" fill="currentColor" opacity="0.3"/>
<circle cx="137" cy="54" r="2" fill="currentColor" opacity="0.6"/>
<polygon points="150,58 175,50 152,65" fill="currentColor" opacity="0.6"/>
<line x1="75" y1="138" x2="60" y2="230" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="105" y1="138" x2="115" y2="230" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<circle cx="66" cy="190" r="4" fill="currentColor" opacity="0.4"/>
<circle cx="111" cy="190" r="4" fill="currentColor" opacity="0.4"/>
<path d="M60 230 L45 233 M60 230 L55 236 M60 230 L65 235" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
<path d="M115 230 L100 233 M115 230 L110 236 M115 230 L120 235" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
<path d="M48 95 Q20 80 15 65" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.5" fill="none"/>
<path d="M48 100 Q22 92 10 85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4" fill="none"/>
<path d="M48 105 Q25 102 12 100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3" fill="none"/>
</svg>
<!-- Shadok boulanger -->
<svg class="shadok-boulanger" viewBox="0 0 240 300" fill="none" aria-hidden="true">
<ellipse cx="120" cy="155" rx="40" ry="48" fill="currentColor" opacity="0.85"/>
<circle cx="120" cy="92" r="25" fill="currentColor" opacity="0.8"/>
<ellipse cx="120" cy="68" rx="18" ry="22" fill="currentColor" opacity="0.35"/>
<rect x="105" y="78" width="30" height="5" rx="1" fill="currentColor" opacity="0.4"/>
<path d="M110 88 Q114 84 118 88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
<path d="M124 88 Q128 84 132 88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
<path d="M112 102 Q120 108 128 102" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.35"/>
<line x1="160" y1="145" x2="190" y2="135" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<rect x="185" y="125" width="40" height="10" rx="5" fill="currentColor" opacity="0.4" transform="rotate(-15 205 130)"/>
<line x1="80" y1="148" x2="55" y2="175" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="105" y1="200" x2="95" y2="258" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="135" y1="200" x2="145" y2="258" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<rect x="30" y="180" width="50" height="40" rx="4" fill="currentColor" opacity="0.25"/>
<rect x="35" y="185" width="40" height="20" rx="2" fill="currentColor" opacity="0.15"/>
<ellipse cx="55" cy="195" rx="12" ry="6" fill="currentColor" opacity="0.12"/>
</svg>
</div>
</template>
<style scoped>
.shadoks {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
}
.shadok-bird {
position: absolute;
right: 3%;
top: 6%;
width: clamp(90px, 10vw, 150px);
opacity: 0.22;
color: hsl(var(--axis-num));
animation: shadok-float 8s ease-in-out infinite;
}
.shadok-boulanger {
position: absolute;
left: 1.5%;
bottom: 4%;
width: clamp(80px, 9vw, 140px);
opacity: 0.2;
color: hsl(var(--axis-eco));
animation: shadok-float 9s ease-in-out infinite reverse;
}
@keyframes shadok-float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@media (max-width: 768px) {
.shadoks { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.shadok-bird, .shadok-boulanger { animation: none; }
}
</style>
+11 -1
View File
@@ -9,6 +9,7 @@
:style="{ '--hue': `var(${axis.hue})` }"
:aria-labelledby="`tb-${uid}-${axis.key}`"
>
<UiOiseauPose v-for="o in oiseaux?.[axis.key] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" class="toolbox-oiseau" />
<header class="toolbox-head">
<p class="toolbox-lever">{{ axis.lever }}</p>
<h3 :id="`tb-${uid}-${axis.key}`" class="toolbox-title">
@@ -61,7 +62,8 @@
</template>
<script setup lang="ts">
import type { HomeAxis } from '~/composables/useHomeData'
import type { AxisKey, HomeAxis } from '~/composables/useHomeData'
import type { OiseauPlace } from '~/utils/oiseauPose'
withDefaults(defineProps<{
axes: HomeAxis[]
@@ -70,6 +72,8 @@ withDefaults(defineProps<{
gratewizard?: { title: string, subtitle: string }
showPromise?: boolean
anchors?: boolean
/** Birds standing by an axis column (home page) */
oiseaux?: Partial<Record<AxisKey, OiseauPlace[]>>
}>(), {
showPromise: true,
anchors: false,
@@ -106,7 +110,13 @@ function onAction(id: string) {
}
}
/* The birds under a column only make sense with the three columns side by side */
@container (max-width: 59.99rem) {
.toolbox-oiseau { display: none; }
}
.toolbox-axis {
position: relative;
display: flex;
flex-direction: column;
gap: 0.75rem;
+16 -44
View File
@@ -1,44 +1,7 @@
<template>
<footer class="footer-wrap border-t border-[hsl(var(--color-text)/0.1)] bg-[hsl(var(--color-surface))]">
<!-- Shadok pattern -->
<svg class="footer-shadok-pattern" viewBox="0 0 400 80" fill="none" aria-hidden="true">
<g transform="translate(20,10)">
<ellipse cx="15" cy="25" rx="12" ry="14" fill="currentColor" opacity="0.2"/>
<circle cx="15" cy="10" r="7" fill="currentColor" opacity="0.16"/>
<line x1="10" y1="38" x2="8" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<line x1="20" y1="38" x2="22" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
</g>
<g transform="translate(80,15)">
<ellipse cx="15" cy="22" rx="10" ry="12" fill="currentColor" opacity="0.16"/>
<circle cx="15" cy="8" r="6" fill="currentColor" opacity="0.13"/>
<line x1="10" y1="33" x2="8" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
<line x1="20" y1="33" x2="22" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
</g>
<g transform="translate(140,8)">
<ellipse cx="15" cy="25" rx="11" ry="13" fill="currentColor" opacity="0.18"/>
<circle cx="15" cy="10" r="6.5" fill="currentColor" opacity="0.15"/>
<line x1="10" y1="37" x2="7" y2="54" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
<line x1="20" y1="37" x2="23" y2="54" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
</g>
<g transform="translate(210,18)">
<ellipse cx="15" cy="20" rx="10" ry="11" fill="currentColor" opacity="0.14"/>
<circle cx="15" cy="7" r="5.5" fill="currentColor" opacity="0.11"/>
<line x1="10" y1="30" x2="9" y2="44" stroke="currentColor" stroke-width="1.5" opacity="0.1"/>
<line x1="20" y1="30" x2="21" y2="44" stroke="currentColor" stroke-width="1.5" opacity="0.1"/>
</g>
<g transform="translate(270,12)">
<ellipse cx="15" cy="24" rx="12" ry="14" fill="currentColor" opacity="0.18"/>
<circle cx="15" cy="9" r="7" fill="currentColor" opacity="0.15"/>
<line x1="10" y1="37" x2="7" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
<line x1="20" y1="37" x2="23" y2="55" stroke="currentColor" stroke-width="1.5" opacity="0.14"/>
</g>
<g transform="translate(340,16)">
<ellipse cx="15" cy="22" rx="10" ry="12" fill="currentColor" opacity="0.16"/>
<circle cx="15" cy="8" r="6" fill="currentColor" opacity="0.13"/>
<line x1="10" y1="33" x2="8" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
<line x1="20" y1="33" x2="22" y2="48" stroke="currentColor" stroke-width="1.5" opacity="0.12"/>
</g>
</svg>
<!-- The frieze of the birds (studio DA), standing on the bottom edge -->
<UiOiseau nom="frise" class="footer-shadok-pattern" />
<div class="container-content px-4 py-8 relative z-1">
<div class="flex flex-col items-center gap-4 md:flex-row md:justify-between">
<!-- Credits -->
@@ -47,9 +10,9 @@
</p>
<!-- Links -->
<nav class="flex items-center gap-4" aria-label="Liens du pied de page">
<nav v-if="links.length" class="flex items-center gap-4" aria-label="Liens du pied de page">
<NuxtLink
v-for="link in site?.footer.links"
v-for="link in links"
:key="link.to"
:to="link.to"
class="text-sm text-[hsl(var(--color-text)/0.4)] transition-colors hover:text-[hsl(var(--color-text)/0.7)]"
@@ -64,6 +27,14 @@
<script setup lang="ts">
const { data: site } = await useSiteContent()
const router = useRouter()
/** The footer links of site.yml, without those to a page the site does not have yet: the link
* to /mentions-legales (03/11: no such page, its text is still to be written) shows again by
* itself once the page exists */
interface FooterLink { label: string, to: string }
const links = computed<FooterLink[]>(() => (((site.value as any)?.footer?.links ?? []) as FooterLink[])
.filter(l => /^(https?:|mailto:)/.test(l.to) || router.resolve(l.to).matched.length > 0))
</script>
<style scoped>
@@ -72,13 +43,14 @@ const { data: site } = await useSiteContent()
overflow: hidden;
}
/* The whole frieze fits in the footer (mask: contain), never cropped; pale under the links */
.footer-shadok-pattern {
position: absolute;
bottom: 0;
top: 0.75rem;
left: 0;
width: 100%;
height: auto;
opacity: 1;
height: calc(100% - 0.75rem);
opacity: 0.12;
pointer-events: none;
color: hsl(var(--color-primary));
}
+27 -21
View File
@@ -2,13 +2,12 @@
<header class="sticky top-0 z-40 border-b border-[hsl(var(--color-text)/0.08)] bg-[hsl(var(--color-bg)/0.85)] backdrop-blur-xl">
<div class="container-content flex h-[var(--header-height)] items-center justify-between px-4">
<!-- Logo -->
<NuxtLink to="/" class="logo-link flex items-center gap-2.5">
<UiSectionSign class="logo-icon" />
<span class="logo-text">{{ site?.identity.name }}</span>
<NuxtLink to="/" class="logo-link flex items-center" :aria-label="site?.identity.name || 'Le librodrome'">
<UiLogotype class="logo-lockup" />
</NuxtLink>
<!-- Desktop navigation -->
<nav class="hidden md:flex items-center gap-1" aria-label="Navigation principale">
<nav class="nav-main hidden md:flex items-center gap-1" aria-label="Navigation principale">
<!-- Autonomie : prefix + axis buttons -->
<span class="nav-prefix">Autonomie&thinsp;:</span>
<NuxtLink
@@ -72,31 +71,20 @@ const AXIS_HUES = ['--axis-num', '--axis-eco', '--axis-cit']
opacity: 0.8;
}
.logo-icon {
/* The validated lockup (studio DA, 27/10): the Geste already leans 25°, no rotation on hover */
.logo-lockup {
height: 2.3rem;
width: auto;
height: 2.1rem;
flex-shrink: 0;
transform: rotate(-8deg);
transition: transform 0.2s ease;
}
.logo-link:hover .logo-icon {
transform: rotate(0deg) scale(1.08);
.logo-link:hover .logo-lockup {
transform: scale(1.04);
}
@media (prefers-reduced-motion: reduce) {
.logo-icon { transition: none; }
}
.logo-text {
font-family: var(--font-logo);
font-weight: 400;
font-size: 1.25rem;
letter-spacing: 0.04em;
background-image: linear-gradient(to right, hsl(var(--color-primary)), hsl(var(--color-accent)));
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
.logo-lockup { transition: none; }
}
.nav-prefix {
@@ -129,4 +117,22 @@ const AXIS_HUES = ['--axis-num', '--axis-eco', '--axis-cit']
.btn-ghost--muted {
color: hsl(var(--color-text) / 0.45);
}
/* From 768 to 1023 px the kit's logotype (166 px) and the whole navigation share the bar:
tighter buttons instead of an overflow; the logotype of the studio DA kit stays as it is */
@media (max-width: 1023px) {
.nav-main {
gap: 0.125rem;
}
.nav-axis,
.btn-ghost--muted {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.nav-sep {
margin: 0 0.25rem;
}
}
</style>
File diff suppressed because one or more lines are too long
+27
View File
@@ -0,0 +1,27 @@
<script setup lang="ts">
// One of the 61 birds (studio DA, validated 2026-10-28), drawn from /images/oiseaux/<nom>.svg as a
// mask filled with currentColor : it takes the colour the page gives it, like the shadoks did.
// The classes of the figure it replaces keep its place, size, opacity and animation.
import { OISEAUX } from '~/utils/oiseaux'
const props = defineProps<{ nom: string }>()
const o = computed(() => OISEAUX[props.nom])
</script>
<template>
<span
v-if="o"
class="oiseau"
aria-hidden="true"
:style="{ aspectRatio: o.ratio, '--oiseau': `url(/images/oiseaux/${props.nom}.svg)` }"
/>
</template>
<style scoped>
.oiseau {
display: block;
background-color: currentColor;
-webkit-mask: var(--oiseau) center / contain no-repeat;
mask: var(--oiseau) center / contain no-repeat;
}
</style>
+170
View File
@@ -0,0 +1,170 @@
<script setup lang="ts">
// A bird of the librodrome placed on its block (composition of 03/11, docs/consignes-yvv.md):
// it stands on a real edge of the page, next to the content its trade is about.
// The host block is the positioning context: position relative, overflow visible.
//
// Poses
// perche on the block's top edge (bottom: 100%), x with left / right
// marge-g beside the block, on its left; feet at the block's bottom, raised by `bottom`
// marge-d the same, on its right
// derriere large and pale, behind the block (z-index -1): only what sticks out shows.
// Needs a stacking context above the block (isolation: isolate) and a block
// that creates none itself (no z-index, transform, opacity, filter).
// libre placed only by left / right / top / bottom (an empty area next to its block)
//
// `bout`: a perched bird at the end (or the start) of a line of a title. The component is then a
// zero-size anchor in the text, at its baseline, written right after the text (the gap is `left`,
// 12 px by default) or right before it (the gap is `right`): the bird follows the end of the text
// at every width, wherever the line breaks (rule e, docs/da-oiseaux.md).
//
// Birds in the margin, behind a block or free need room around the column: they show from
// 1200 px wide, the perched ones from 768 px (`seuil` overrides, for instance 1024 for a perched
// bird whose block has no void above it until the grid splits in two); under 768 px, only a
// bird marked `mobile`.
// A perched bird needs, above its edge, a void at least as tall as itself (DA rule of 03/11);
// where blocks stand close, the bird goes in the margin or behind the block.
//
// Drawing rules of the studio DA (kit README, §2.5): one colour (currentColor), proportions
// intact and never cropped, 72 px wide at least, opacity 0.18-0.28 next to text and 0.10-0.14
// large behind a card, mirror allowed except for the calligraphe and the typographe.
// Birds standing on an edge do not move; only the one behind a card drifts a little (Yvv, 03/11).
import { OISEAUX } from '~/utils/oiseaux'
type Pose = 'perche' | 'marge-g' | 'marge-d' | 'derriere' | 'libre'
const props = withDefaults(defineProps<{
nom: string
pose?: Pose
/** Width in px: S 72-90, M 108-156, L 200-250 */
w?: number
left?: string
right?: string
top?: string
bottom?: string
/** Gap between the block and a bird in the margin */
ecart?: string
retourne?: boolean
/** Shown under 768 px (one bird per page at most) */
mobile?: boolean
/** Shown under 768 px only: the phone place of a bird placed elsewhere on wider screens */
mobileSeul?: boolean
/** Narrowest window (px) where the bird shows: 1200 by default for the margin, behind
* and free poses, 768 for a perched bird */
seuil?: 768 | 1024 | 1200
ton?: 'primary' | 'accent'
op?: number
/** At the end (or the start) of a line of text: written in the text, without a space */
bout?: boolean
}>(), { pose: 'perche', w: 80, ecart: '2.5rem', ton: 'primary' })
/** These two write and compose from left to right: never mirrored */
const NO_MIRROR = new Set(['calligraphe', 'typographe'])
const sol = computed(() => OISEAUX[props.nom]?.sol ?? 5)
const style = computed(() => {
const s: Record<string, string> = { 'width': `${Math.max(72, props.w)}px`, '--sol': `${sol.value}%` }
if (props.pose === 'perche') s.bottom = props.bout ? '0px' : '100%'
if (props.bout && props.left === undefined && props.right === undefined) s.left = '12px'
if (props.pose === 'marge-g') s.right = `calc(100% + ${props.ecart})`
if (props.pose === 'marge-d') s.left = `calc(100% + ${props.ecart})`
if (props.pose === 'marge-g' || props.pose === 'marge-d') s.bottom = '0px'
for (const k of ['left', 'right', 'top', 'bottom'] as const) {
if (props[k] !== undefined) s[k] = props[k]!
}
if (props.op !== undefined) s.opacity = String(props.op)
return s
})
const classes = computed(() => [
'oiseau-pose',
`oiseau-pose--${props.pose}`,
{
'oiseau-pose--retourne': props.retourne && !NO_MIRROR.has(props.nom),
'oiseau-pose--mobile': props.mobile || props.mobileSeul,
'oiseau-pose--mobile-seul': props.mobileSeul,
'oiseau-pose--large': (props.seuil ?? (props.pose === 'perche' ? 768 : 1200)) >= 1200,
'oiseau-pose--moyen': props.seuil === 1024,
'oiseau-pose--accent': props.ton === 'accent',
},
])
</script>
<template>
<span v-if="bout" class="oiseau-bout"><UiOiseau :nom="nom" :class="classes" :style="style" :data-oiseau="nom" :data-pose="pose" /></span>
<UiOiseau v-else :nom="nom" :class="classes" :style="style" :data-oiseau="nom" :data-pose="pose" />
</template>
<style scoped>
/* The anchor of a bird at the end of a line: no size, on the text's baseline */
.oiseau-bout {
position: relative;
display: inline-block;
width: 0;
height: 0;
vertical-align: baseline;
}
.oiseau-pose {
position: absolute;
z-index: 1;
pointer-events: none;
color: hsl(var(--color-primary));
opacity: 0.24;
/* The drawing's ground line lands on the edge */
transform: translateY(var(--sol));
}
.oiseau-pose--accent {
color: hsl(var(--color-accent));
}
.oiseau-pose--perche {
opacity: 0.28;
}
.oiseau-pose--derriere {
z-index: -1;
opacity: 0.12;
animation: oiseau-derive 12s ease-in-out infinite alternate;
}
.oiseau-pose--retourne {
scale: -1 1;
}
@keyframes oiseau-derive {
from { translate: 0 0; }
to { translate: 0 -6px; }
}
@media (max-width: 1199px) {
.oiseau-pose--large {
display: none;
}
}
@media (max-width: 1023px) {
.oiseau-pose--moyen {
display: none;
}
}
@media (min-width: 768px) {
.oiseau-pose--mobile-seul {
display: none;
}
}
@media (max-width: 767px) {
.oiseau-pose:not(.oiseau-pose--mobile) {
display: none;
}
}
@media (prefers-reduced-motion: reduce) {
.oiseau-pose--derriere {
animation: none;
}
}
</style>
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -21,7 +21,7 @@ export function useSeoPage(opts: {
const title = opts.title || 'Le Librodrome'
const description = opts.description
|| 'Autonomie numérique, économique et citoyenne. Un livre et des chansons sur l\'économie du don.'
const rawImage = opts.image || '/og-default.png?v=2'
const rawImage = opts.image || '/og-default.png?v=3'
const image = rawImage.startsWith('http') ? rawImage : `${siteUrl}${rawImage}`
const canonical = `${siteUrl}${route.path}`
const type = opts.type || 'website'
+12 -2
View File
@@ -36,11 +36,21 @@ useScrollTracking()
grid-template-rows: auto 1fr auto;
}
/* The seal's block, between the page and the footer: a bird of a page that stands on the footer's
top rule takes its offset from here (evenement, the puppeteer) */
.app-main {
--seal-w: 44px;
--seal-mt: 2rem;
--seal-mb: 1rem;
--seal-block: calc(var(--seal-mt) + var(--seal-w) * 105 / 112 + var(--seal-mb));
}
/* === Seal — 益 Yì (Increase) === */
.app-seal {
display: block;
width: 44px;
margin: 2rem 1.5rem 1rem auto;
width: var(--seal-w);
/* its height follows the viewBox: width × 105 / 112 (in --seal-block) */
margin: var(--seal-mt) 1.5rem var(--seal-mb) auto;
color: hsl(var(--color-accent));
opacity: 0.28;
filter: drop-shadow(1px 1px 0.5px rgba(0,0,0,0.25))
+13 -47
View File
@@ -1,36 +1,14 @@
<template>
<div class="relative overflow-hidden section-padding">
<!-- Shadok philosopher: character sitting cross-legged, floating -->
<svg class="shadok-philosopher" viewBox="0 0 220 280" fill="none" aria-hidden="true">
<!-- Body (round, serene) -->
<ellipse cx="110" cy="150" rx="48" ry="55" fill="currentColor" opacity="0.85"/>
<!-- Head -->
<ellipse cx="110" cy="82" rx="26" ry="25" fill="currentColor" opacity="0.8"/>
<!-- Closed eyes (meditating) -->
<path d="M96 80 Q100 84 105 80" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
<path d="M115 80 Q119 84 124 80" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
<!-- Serene smile -->
<path d="M102 93 Q110 98 118 93" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.3"/>
<!-- Arms resting on knees -->
<path d="M64 155 Q55 180 70 200" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" fill="none" opacity="0.6"/>
<path d="M156 155 Q165 180 150 200" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" fill="none" opacity="0.6"/>
<!-- Hands on knees -->
<circle cx="70" cy="200" r="5" fill="currentColor" opacity="0.4"/>
<circle cx="150" cy="200" r="5" fill="currentColor" opacity="0.4"/>
<!-- Crossed legs -->
<path d="M80 205 Q90 230 120 235" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" fill="none" opacity="0.6"/>
<path d="M140 205 Q130 230 100 235" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" fill="none" opacity="0.6"/>
<!-- Floating aura lines -->
<path d="M50 245 Q110 260 170 245" stroke="currentColor" stroke-width="1.5" stroke-dasharray="4 4" fill="none" opacity="0.25"/>
<path d="M60 255 Q110 268 160 255" stroke="currentColor" stroke-width="1" stroke-dasharray="3 5" fill="none" opacity="0.18"/>
<!-- Small sparkles around -->
<circle cx="55" cy="110" r="2.5" fill="currentColor" opacity="0.2"/>
<circle cx="170" cy="95" r="2" fill="currentColor" opacity="0.18"/>
<circle cx="160" cy="130" r="3" fill="currentColor" opacity="0.15"/>
</svg>
<div class="container-content mx-auto max-w-3xl">
<div class="container-content relative mx-auto max-w-3xl">
<!-- In the margins, at the height of « La vision » and of the economic proposal -->
<UiOiseauPose nom="philosophe" pose="libre" left="calc(100% + 50px)" top="470px" :w="120" retourne />
<UiOiseauPose nom="penseur" pose="libre" right="calc(100% + 60px)" top="720px" :w="100" />
<ContentRenderer v-if="page" :value="page" class="prose" />
<!-- Credit of the mascot (Yvv, word for word, 27/10) -->
<p class="oiseaux-credit">
N'ayant pas les moyens d'acquérir des droits, le personnage mascotte est une création qui fait un clin d'œil aux shadoks, avec respect et une grande affection, petit hommage en passant.
</p>
</div>
</div>
</template>
@@ -51,23 +29,11 @@ const { data: page } = await useAsyncData('about', () =>
</script>
<style scoped>
.shadok-philosopher {
position: absolute;
right: 3%;
bottom: 6%;
width: clamp(120px, 15vw, 220px);
opacity: 0.3;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-philosopher 11s ease-in-out infinite;
}
@keyframes shadok-float-philosopher {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-12px); }
}
@media (max-width: 768px) {
.shadok-philosopher { display: none; }
.oiseaux-credit {
margin: 3rem 0 0;
font-size: 0.8rem;
line-height: 1.5;
color: hsl(var(--color-text) / 0.5);
}
</style>
+29 -2
View File
@@ -60,8 +60,9 @@
<div
v-if="content?.features"
id="section-features"
class="grid gap-4 sm:grid-cols-2 mb-12 max-w-2xl mx-auto section-anchor"
class="relative grid gap-4 sm:grid-cols-2 mb-12 max-w-2xl mx-auto section-anchor"
>
<UiOiseauPose v-for="o in oiseaux.fonctions ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<div v-for="feature in content.features" :key="feature.title" class="feature-card">
<div class="feature-icon">
<div :class="`i-lucide-${feature.icon} h-5 w-5`" />
@@ -77,6 +78,7 @@
id="section-project"
class="project-card mb-8 max-w-2xl mx-auto section-anchor"
>
<UiOiseauPose v-for="o in oiseaux.projet ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<div class="project-icon">
<div class="i-lucide-rocket h-5 w-5" />
</div>
@@ -93,8 +95,9 @@
<div
v-if="content?.content"
id="section-content"
class="prose-block mb-10 max-w-2xl mx-auto section-anchor"
class="prose-block relative mb-10 max-w-2xl mx-auto section-anchor"
>
<UiOiseauPose v-for="o in oiseaux.texte ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<p class="leading-relaxed whitespace-pre-line" style="color: hsl(var(--color-text-muted))">
{{ content.content }}
</p>
@@ -119,9 +122,32 @@
</template>
<script setup lang="ts">
import type { OiseauPlace } from '~/utils/oiseauPose'
const route = useRoute()
const slug = route.params.slug as string
// Birds of each page: by the features grid, the project card and the text block
interface OiseauxPage { fonctions?: OiseauPlace[], projet?: OiseauPlace[], texte?: OiseauPlace[] }
const OISEAUX_PAGE: Record<string, OiseauxPage> = {
'decision': {
fonctions: [
{ nom: 'mime', pose: 'marge-g', ecart: '48px', w: 104 },
// on the line under the first row of cards (16 px gap between the rows)
{ nom: 'avocate', pose: 'marge-d', ecart: '44px', bottom: 'calc(50% + 8px)', w: 96, retourne: true },
// above the grid's left corner the page is empty (the links row starts at its middle)
{ nom: 'tisserand', pose: 'perche', left: '24px', w: 84 },
],
},
'tarifs-eau': {
// the actor in the right margin, feet on the card's top edge: perched on the card, it stood
// 11 px under the introduction (rule f, DA 03/11 after 17h35); the summary starts lower
projet: [{ nom: 'comedien', pose: 'marge-d', ecart: '24px', bottom: '100%', w: 100, retourne: true }],
texte: [{ nom: 'potier', pose: 'marge-g', ecart: '52px', w: 112 }],
},
}
const oiseaux = computed<OiseauxPage>(() => OISEAUX_PAGE[slug] ?? {})
const [{ data: content }, { data: homeData }] = await Promise.all([
usePageContent(`citoyenne/${slug}`),
usePageContent('home'),
@@ -189,6 +215,7 @@ useSeoPage({
}
.project-card {
position: relative;
padding: 1.5rem;
border-radius: 0.75rem;
border: 1px solid hsl(var(--color-primary) / 0.15);
+21 -453
View File
@@ -1,339 +1,16 @@
<template>
<div class="axis-scope axis-scope--cit relative overflow-hidden section-padding">
<!-- 1. Shadok Capitaine (top-left, profile — at ship's wheel, telescope) -->
<svg class="shadok shadok-capitaine" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- ship's wheel -->
<circle cx="50" cy="130" r="28" stroke="currentColor" stroke-width="3" fill="none" opacity="0.35"/>
<line x1="50" y1="102" x2="50" y2="158" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<line x1="22" y1="130" x2="78" y2="130" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<line x1="30" y1="110" x2="70" y2="150" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<line x1="70" y1="110" x2="30" y2="150" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<!-- wheel spokes knobs -->
<circle cx="50" cy="100" r="3" fill="currentColor" opacity="0.4"/>
<circle cx="50" cy="160" r="3" fill="currentColor" opacity="0.4"/>
<circle cx="20" cy="130" r="3" fill="currentColor" opacity="0.4"/>
<circle cx="80" cy="130" r="3" fill="currentColor" opacity="0.4"/>
<!-- body (small oval, profile facing right) -->
<ellipse cx="85" cy="110" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- head -->
<circle cx="92" cy="68" r="16" fill="currentColor" opacity="0.3"/>
<!-- captain hat -->
<rect x="76" y="52" width="32" height="8" rx="4" fill="currentColor" opacity="0.4"/>
<rect x="80" y="46" width="24" height="8" rx="3" fill="currentColor" opacity="0.3"/>
<!-- hat brim detail -->
<ellipse cx="92" cy="60" rx="18" ry="3" fill="currentColor" opacity="0.2"/>
<!-- eyes (looking right through telescope) -->
<circle cx="98" cy="65" r="2.5" fill="currentColor" opacity="0.6"/>
<circle cx="90" cy="66" r="2" fill="currentColor" opacity="0.5"/>
<!-- beak (pointy, profile right) -->
<polygon points="108,68 120,65 108,72" fill="currentColor" opacity="0.35"/>
<!-- left arm on wheel -->
<line x1="65" y1="100" x2="55" y2="115" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- right arm holding telescope -->
<line x1="105" y1="95" x2="130" y2="72" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- telescope -->
<rect x="128" y="66" width="30" height="7" rx="3.5" fill="currentColor" opacity="0.4"/>
<rect x="155" y="64" width="10" height="11" rx="3" fill="currentColor" opacity="0.3"/>
<!-- left leg (long, forward) -->
<line x1="75" y1="135" x2="60" y2="190" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- left foot -->
<ellipse cx="55" cy="193" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
<!-- right leg (long, back) -->
<line x1="92" y1="136" x2="100" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- right foot -->
<ellipse cx="103" cy="195" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<!-- 2. Shadok Avocate (top-right — robe, scroll, arm up) -->
<svg class="shadok shadok-avocate" viewBox="0 0 160 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- body (small oval) -->
<ellipse cx="80" cy="115" rx="22" ry="30" fill="currentColor" opacity="0.25"/>
<!-- robe/gown flowing -->
<path d="M58 100 Q55 145 48 175 L112 175 Q105 145 102 100 Z" fill="currentColor" opacity="0.18"/>
<!-- robe collar -->
<path d="M68 88 Q80 96 92 88" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.35"/>
<!-- head -->
<circle cx="80" cy="70" r="16" fill="currentColor" opacity="0.3"/>
<!-- eyes (looking up-left) -->
<circle cx="74" cy="67" r="2.5" fill="currentColor" opacity="0.6"/>
<circle cx="83" cy="68" r="2" fill="currentColor" opacity="0.5"/>
<!-- beak (3/4 view, slight left) -->
<polygon points="68,72 56,69 66,76" fill="currentColor" opacity="0.35"/>
<!-- left arm up dramatically -->
<line x1="60" y1="100" x2="30" y2="55" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- open hand at top -->
<line x1="30" y1="55" x2="24" y2="46" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<line x1="30" y1="55" x2="28" y2="44" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<line x1="30" y1="55" x2="34" y2="46" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<!-- right arm holding scroll -->
<line x1="100" y1="102" x2="125" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- scroll document (big) -->
<rect x="120" y="72" width="28" height="40" rx="3" fill="currentColor" opacity="0.25"/>
<!-- scroll curl top -->
<ellipse cx="134" cy="72" rx="14" ry="5" fill="currentColor" opacity="0.2"/>
<!-- scroll curl bottom -->
<ellipse cx="134" cy="112" rx="12" ry="4" fill="currentColor" opacity="0.2"/>
<!-- scroll text lines -->
<line x1="126" y1="82" x2="142" y2="82" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<line x1="126" y1="88" x2="140" y2="88" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<line x1="126" y1="94" x2="143" y2="94" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<line x1="126" y1="100" x2="138" y2="100" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<!-- left leg (long) -->
<line x1="72" y1="142" x2="62" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="58" cy="198" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
<!-- right leg -->
<line x1="88" y1="142" x2="95" y2="196" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="99" cy="199" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<!-- 3. Shadok Vigie (left — crow's nest, looking far) -->
<svg class="shadok shadok-vigie" viewBox="0 0 140 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- mast pole -->
<line x1="70" y1="90" x2="70" y2="218" stroke="currentColor" stroke-width="4" opacity="0.3"/>
<!-- crow's nest platform -->
<path d="M38 88 L42 100 L98 100 L102 88 Z" fill="currentColor" opacity="0.25"/>
<line x1="36" y1="88" x2="104" y2="88" stroke="currentColor" stroke-width="3" opacity="0.35"/>
<!-- nest railing -->
<line x1="40" y1="78" x2="40" y2="100" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<line x1="100" y1="78" x2="100" y2="100" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<line x1="40" y1="78" x2="100" y2="78" stroke="currentColor" stroke-width="2" opacity="0.25"/>
<!-- body (small, inside nest) -->
<ellipse cx="70" cy="72" rx="20" ry="22" fill="currentColor" opacity="0.25"/>
<!-- head -->
<circle cx="70" cy="38" r="15" fill="currentColor" opacity="0.3"/>
<!-- eyes (squinting, looking right far) -->
<circle cx="78" cy="35" r="2.5" fill="currentColor" opacity="0.6"/>
<circle cx="70" cy="36" r="2" fill="currentColor" opacity="0.4"/>
<!-- beak (profile right) -->
<polygon points="83,38 96,35 84,42" fill="currentColor" opacity="0.35"/>
<!-- right hand shielding eyes -->
<line x1="88" y1="55" x2="98" y2="35" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="96" y1="33" x2="108" y2="30" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.35"/>
<!-- left arm resting on railing -->
<line x1="52" y1="60" x2="42" y2="78" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- legs dangling below nest (long!) -->
<line x1="60" y1="98" x2="52" y2="160" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="48" cy="163" rx="8" ry="4" fill="currentColor" opacity="0.3"/>
<line x1="80" y1="98" x2="86" y2="158" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="90" cy="161" rx="8" ry="4" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<!-- 4. Shadok Comedien (right — theater masks, cape, leg lifted) -->
<svg class="shadok shadok-comedien" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- dramatic cape -->
<path d="M65 85 Q40 120 35 180 L115 180 Q110 120 95 85 Z" fill="currentColor" opacity="0.15"/>
<path d="M95 85 Q120 100 135 160 Q130 165 115 180" fill="currentColor" opacity="0.1"/>
<!-- body (small oval) -->
<ellipse cx="80" cy="105" rx="20" ry="26" fill="currentColor" opacity="0.25"/>
<!-- head -->
<circle cx="80" cy="62" r="16" fill="currentColor" opacity="0.3"/>
<!-- eyes (different directions — dramatic!) -->
<circle cx="74" cy="59" r="2.5" fill="currentColor" opacity="0.6"/>
<circle cx="86" cy="61" r="2.5" fill="currentColor" opacity="0.55"/>
<!-- beak -->
<polygon points="72,66 60,63 70,70" fill="currentColor" opacity="0.35"/>
<!-- left arm up holding comedy mask -->
<line x1="62" y1="92" x2="32" y2="55" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- comedy mask (big, smiling) -->
<circle cx="25" cy="42" r="16" fill="currentColor" opacity="0.2"/>
<path d="M17 46 Q25 56 33 46" stroke="currentColor" stroke-width="2" fill="none" opacity="0.4"/>
<circle cx="20" cy="38" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="30" cy="38" r="2" fill="currentColor" opacity="0.5"/>
<!-- right arm out holding tragedy mask -->
<line x1="98" y1="92" x2="135" y2="65" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- tragedy mask (big, frowning) -->
<circle cx="145" cy="55" r="16" fill="currentColor" opacity="0.2"/>
<path d="M137 62 Q145 54 153 62" stroke="currentColor" stroke-width="2" fill="none" opacity="0.4"/>
<circle cx="140" cy="50" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="150" cy="50" r="2" fill="currentColor" opacity="0.5"/>
<!-- left leg (long, planted) -->
<line x1="72" y1="128" x2="62" y2="190" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="58" cy="193" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
<!-- right leg (lifted dramatically!) -->
<line x1="88" y1="126" x2="115" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="120" cy="167" rx="8" ry="4" transform="rotate(-25 120 167)" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<!-- 5. Shadok Cartographe (bottom-left — sitting, map, compass) -->
<svg class="shadok shadok-cartographe" viewBox="0 0 180 190" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- table -->
<rect x="20" y="125" width="140" height="6" rx="2" fill="currentColor" opacity="0.3"/>
<line x1="35" y1="131" x2="30" y2="185" stroke="currentColor" stroke-width="3" opacity="0.25"/>
<line x1="145" y1="131" x2="150" y2="185" stroke="currentColor" stroke-width="3" opacity="0.25"/>
<!-- big map spread on table -->
<rect x="30" y="108" width="110" height="18" rx="2" fill="currentColor" opacity="0.2"/>
<!-- map details -->
<path d="M45 112 Q65 108 85 115 Q105 110 125 114" stroke="currentColor" stroke-width="1" fill="none" opacity="0.25"/>
<circle cx="75" cy="115" r="3" stroke="currentColor" stroke-width="1" fill="none" opacity="0.2"/>
<line x1="95" y1="110" x2="95" y2="122" stroke="currentColor" stroke-width="0.8" opacity="0.2"/>
<!-- body (small, hunched over map) -->
<ellipse cx="90" cy="88" rx="22" ry="25" fill="currentColor" opacity="0.25" transform="rotate(10 90 88)"/>
<!-- head (bent down looking at map) -->
<circle cx="78" cy="60" r="15" fill="currentColor" opacity="0.3"/>
<!-- eyes (looking down at map) -->
<circle cx="74" cy="64" r="2" fill="currentColor" opacity="0.6"/>
<circle cx="83" cy="65" r="2" fill="currentColor" opacity="0.5"/>
<!-- beak (pointing down) -->
<polygon points="72,70 65,78 78,72" fill="currentColor" opacity="0.35"/>
<!-- right arm holding compass tool -->
<line x1="110" y1="92" x2="130" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- compass/divider tool (big V shape) -->
<line x1="130" y1="105" x2="125" y2="125" stroke="currentColor" stroke-width="2.5" opacity="0.4"/>
<line x1="130" y1="105" x2="140" y2="125" stroke="currentColor" stroke-width="2.5" opacity="0.4"/>
<circle cx="130" cy="103" r="3" fill="currentColor" opacity="0.3"/>
<!-- left arm holding magnifying glass -->
<line x1="70" y1="90" x2="48" y2="100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- magnifying glass (big) -->
<circle cx="38" cy="96" r="12" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.35"/>
<line x1="48" y1="103" x2="55" y2="112" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- legs (sitting, bent under table) -->
<line x1="78" y1="110" x2="65" y2="145" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="65" y1="145" x2="50" y2="148" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<ellipse cx="45" cy="150" rx="8" ry="3.5" fill="currentColor" opacity="0.3"/>
<line x1="100" y1="110" x2="110" y2="145" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="110" y1="145" x2="122" y2="148" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<ellipse cx="127" cy="150" rx="8" ry="3.5" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<!-- 6. Shadok Juge (bottom-right — on bench, gavel, wig) -->
<svg class="shadok shadok-juge" viewBox="0 0 160 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- elevated bench/podium -->
<rect x="30" y="145" width="100" height="55" rx="4" fill="currentColor" opacity="0.2"/>
<rect x="25" y="138" width="110" height="10" rx="3" fill="currentColor" opacity="0.28"/>
<!-- bench front panel detail -->
<rect x="55" y="155" width="50" height="35" rx="3" fill="currentColor" opacity="0.1"/>
<!-- body (small, seated) -->
<ellipse cx="80" cy="112" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- head -->
<circle cx="80" cy="68" r="16" fill="currentColor" opacity="0.3"/>
<!-- judge wig (curly puffs) -->
<circle cx="66" cy="60" r="6" fill="currentColor" opacity="0.2"/>
<circle cx="94" cy="60" r="6" fill="currentColor" opacity="0.2"/>
<circle cx="72" cy="54" r="5" fill="currentColor" opacity="0.18"/>
<circle cx="88" cy="54" r="5" fill="currentColor" opacity="0.18"/>
<circle cx="80" cy="52" r="5.5" fill="currentColor" opacity="0.2"/>
<!-- wig curls hanging -->
<circle cx="63" cy="70" r="4.5" fill="currentColor" opacity="0.15"/>
<circle cx="97" cy="70" r="4.5" fill="currentColor" opacity="0.15"/>
<!-- eyes (stern, both forward) -->
<circle cx="74" cy="66" r="2.5" fill="currentColor" opacity="0.65"/>
<circle cx="86" cy="66" r="2.5" fill="currentColor" opacity="0.65"/>
<!-- stern eyebrows -->
<line x1="71" y1="62" x2="77" y2="63" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.4"/>
<line x1="89" y1="63" x2="83" y2="62" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.4"/>
<!-- beak (small, stern) -->
<polygon points="80,74 72,78 80,80" fill="currentColor" opacity="0.35"/>
<!-- right arm raising gavel -->
<line x1="100" y1="98" x2="130" y2="60" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- gavel (big!) -->
<rect x="120" y="44" width="26" height="12" rx="4" fill="currentColor" opacity="0.4"/>
<line x1="133" y1="56" x2="133" y2="38" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- left arm on bench -->
<line x1="60" y1="100" x2="40" y2="130" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- legs (dangling from bench, long) -->
<line x1="72" y1="138" x2="62" y2="200" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="58" cy="203" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
<line x1="88" y1="138" x2="96" y2="198" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="100" cy="201" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<!-- 7. Shadok Matelot (center-bottom — pulling rope, leaning back, anchor) -->
<svg class="shadok shadok-matelot" viewBox="0 0 160 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- rope going up and off -->
<path d="M30 20 Q35 50 55 70 Q65 78 68 85" stroke="currentColor" stroke-width="3" fill="none" opacity="0.3"/>
<!-- body (leaning back, tilted) -->
<ellipse cx="85" cy="108" rx="20" ry="27" fill="currentColor" opacity="0.25" transform="rotate(-15 85 108)"/>
<!-- head -->
<circle cx="95" cy="68" r="15" fill="currentColor" opacity="0.3"/>
<!-- bandana -->
<path d="M80 62 Q95 55 110 62" stroke="currentColor" stroke-width="3" fill="currentColor" opacity="0.2"/>
<line x1="108" y1="60" x2="118" y2="55" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<line x1="108" y1="62" x2="116" y2="60" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.2"/>
<!-- eyes (straining, squinting) -->
<circle cx="90" cy="66" r="2" fill="currentColor" opacity="0.6"/>
<circle cx="100" cy="65" r="2.5" fill="currentColor" opacity="0.55"/>
<!-- beak -->
<polygon points="104,70 115,67 105,74" fill="currentColor" opacity="0.35"/>
<!-- both arms pulling rope -->
<line x1="68" y1="95" x2="55" y2="78" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="75" y1="98" x2="62" y2="82" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- left leg (long, bracing forward) -->
<line x1="72" y1="130" x2="48" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="43" cy="188" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<!-- right leg (long, back) -->
<line x1="92" y1="132" x2="110" y2="188" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="114" cy="191" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<!-- anchor nearby -->
<line x1="135" y1="140" x2="135" y2="185" stroke="currentColor" stroke-width="3" opacity="0.3"/>
<circle cx="135" cy="138" r="5" stroke="currentColor" stroke-width="2" fill="none" opacity="0.25"/>
<path d="M120 180 Q135 195 150 180" stroke="currentColor" stroke-width="3" fill="none" opacity="0.3"/>
<line x1="120" y1="180" x2="117" y2="174" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
<line x1="150" y1="180" x2="153" y2="174" stroke="currentColor" stroke-width="2.5" opacity="0.3"/>
</g>
</svg>
<!-- 8. Shadok Mime (right — pushing invisible wall, striped shirt, beret) -->
<svg class="shadok shadok-mime" viewBox="0 0 150 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g>
<!-- body (small oval) -->
<ellipse cx="70" cy="112" rx="22" ry="28" fill="currentColor" opacity="0.2"/>
<!-- striped shirt lines -->
<line x1="52" y1="96" x2="88" y2="96" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="50" y1="102" x2="90" y2="102" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="50" y1="108" x2="90" y2="108" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="50" y1="114" x2="90" y2="114" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="52" y1="120" x2="88" y2="120" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="54" y1="126" x2="86" y2="126" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<!-- head (white face = lighter) -->
<circle cx="75" cy="65" r="16" fill="currentColor" opacity="0.2"/>
<!-- white face highlight -->
<circle cx="75" cy="65" r="13" fill="currentColor" opacity="0.08"/>
<!-- beret -->
<ellipse cx="75" cy="50" rx="18" ry="6" fill="currentColor" opacity="0.3"/>
<circle cx="75" cy="46" r="3" fill="currentColor" opacity="0.25"/>
<!-- eyes (expressive, wide) -->
<circle cx="69" cy="62" r="3" fill="currentColor" opacity="0.55"/>
<circle cx="81" cy="62" r="3" fill="currentColor" opacity="0.55"/>
<!-- raised eyebrows (surprised) -->
<path d="M66 57 Q69 54 72 57" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.4"/>
<path d="M78 57 Q81 54 84 57" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.4"/>
<!-- beak (small) -->
<polygon points="75,72 68,76 75,78" fill="currentColor" opacity="0.3"/>
<!-- both arms pushing against invisible wall (to the right) -->
<line x1="90" y1="100" x2="125" y2="85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="90" y1="115" x2="125" y2="110" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- flat hands pressed against wall -->
<rect x="124" y="78" width="12" height="15" rx="3" fill="currentColor" opacity="0.2"/>
<rect x="124" y="103" width="12" height="15" rx="3" fill="currentColor" opacity="0.2"/>
<!-- invisible wall hint (faint line) -->
<line x1="138" y1="50" x2="138" y2="180" stroke="currentColor" stroke-width="1" stroke-dasharray="4 6" opacity="0.12"/>
<!-- left leg (long, leaning forward) -->
<line x1="60" y1="138" x2="45" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="40" cy="198" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
<!-- right leg (long, back) -->
<line x1="80" y1="138" x2="95" y2="194" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="99" cy="197" rx="9" ry="4" fill="currentColor" opacity="0.3"/>
</g>
</svg>
<div class="axis-scope axis-scope--cit oiseaux-scene relative overflow-hidden section-padding">
<div class="container-content">
<header class="mb-12 text-center">
<p class="mb-2 font-mono text-sm tracking-widest text-primary uppercase">{{ content?.kicker }}</p>
<h1 class="page-title font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
{{ content?.title }}
<p class="relative mb-2 font-mono text-sm tracking-widest text-primary uppercase">
<!-- Phone: the title fills the width; the bird stands at the end of this line, on its baseline.
A flat bird (37-44 px tall at 72 px wide): 93 px separate this baseline from the sticky
header, and a perched bird keeps a void of its own height above it (rule f) -->
{{ content?.kicker }}<UiOiseauPose nom="potier" pose="perche" bout :w="72" mobile-seul />
</p>
<h1 class="page-title relative font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
<!-- At the end of the title, on its baseline (rule e, docs/da-oiseaux.md) -->
{{ content?.title }}<UiOiseauPose nom="vigie" pose="perche" bout left="16px" :w="96" retourne :seuil="1200" />
</h1>
<p class="mt-4 mx-auto max-w-2xl leading-relaxed" style="color: hsl(var(--color-text-muted))">
{{ content?.description }}
@@ -341,7 +18,9 @@
</header>
<div class="mx-auto max-w-3xl flex flex-col gap-6">
<!-- Decision collective -->
<!-- Decision collective — the card clips its corners, the birds stand on a wrapper -->
<div class="relative">
<UiOiseauPose nom="juge" pose="marge-d" ecart="40px" :w="84" retourne />
<div class="item-card">
<NuxtLink to="/citoyenne/decision" class="item-overlay" aria-label="Décision collective" tabindex="-1" />
<div class="item-body group">
@@ -365,8 +44,15 @@
</a>
</div>
</div>
</div>
<!-- Tarifs de l'eau -->
<div class="relative">
<!-- 24 px between the two cards: no room above them for a perched bird (DA rule of 03/11) -->
<!-- Out by the side of the card, not by its corners: the card is a link (rule h); its feet
46 px above the card's bottom, where the captain stands on the other side (rule c) -->
<UiOiseauPose nom="cartographe" pose="derriere" left="calc(100% - 100px)" bottom="46px" :w="210" />
<UiOiseauPose nom="capitaine" pose="marge-g" ecart="46px" :w="136" />
<div class="item-card">
<NuxtLink to="/citoyenne/tarifs-eau" class="item-overlay" aria-label="Tarifs de l'eau" tabindex="-1" />
<div class="item-body group">
@@ -391,6 +77,7 @@
</a>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -517,123 +204,4 @@ useSeoPage({
background: hsl(var(--color-primary) / 0.2);
border-color: hsl(var(--color-primary) / 0.4);
}
/* Shadok illustrations */
.shadok {
position: absolute;
pointer-events: none;
width: clamp(70px, 10vw, 140px);
z-index: 0;
}
.shadok-capitaine {
top: 2%;
left: 2%;
color: hsl(var(--color-primary));
opacity: 0.22;
animation: shadok-float-1 9s ease-in-out infinite;
}
.shadok-avocate {
top: 1%;
right: 2%;
color: hsl(var(--color-accent));
opacity: 0.2;
animation: shadok-float-2 11s ease-in-out infinite;
}
.shadok-vigie {
left: 2%;
top: 38%;
color: hsl(var(--color-primary));
opacity: 0.24;
animation: shadok-float-3 10s ease-in-out infinite;
}
.shadok-comedien {
right: 3%;
top: 35%;
color: hsl(var(--color-accent));
opacity: 0.2;
animation: shadok-float-4 8s ease-in-out infinite;
}
.shadok-cartographe {
bottom: 10%;
left: 1%;
color: hsl(var(--color-accent));
opacity: 0.22;
animation: shadok-float-5 12s ease-in-out infinite;
}
.shadok-juge {
bottom: 6%;
right: 1%;
color: hsl(var(--color-primary));
opacity: 0.24;
animation: shadok-float-6 9.5s ease-in-out infinite;
}
.shadok-matelot {
bottom: 2%;
left: 50%;
transform: translateX(-50%);
color: hsl(var(--color-primary));
opacity: 0.18;
animation: shadok-float-7 7s ease-in-out infinite;
}
.shadok-mime {
right: 2%;
top: 55%;
color: hsl(var(--color-accent));
opacity: 0.28;
animation: shadok-float-8 10.5s ease-in-out infinite;
}
@keyframes shadok-float-1 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shadok-float-2 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes shadok-float-3 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-7px); }
}
@keyframes shadok-float-4 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}
@keyframes shadok-float-5 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
@keyframes shadok-float-6 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shadok-float-7 {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-7px); }
}
@keyframes shadok-float-8 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@media (max-width: 768px) {
.shadok {
display: none;
}
}
</style>
+12 -321
View File
@@ -1,249 +1,17 @@
<template>
<div class="relative overflow-hidden section-padding">
<!-- Shadok 1 : Libraire — behind counter, 3/4 view, glasses, recommending a book -->
<svg class="shadok-libraire" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Body (small oval) -->
<ellipse cx="75" cy="95" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- Head -->
<circle cx="75" cy="58" r="16" fill="currentColor" opacity="0.3"/>
<!-- Eyes looking right (recommending) -->
<circle cx="80" cy="55" r="2" fill="currentColor" opacity="0.6"/>
<circle cx="86" cy="54" r="2" fill="currentColor" opacity="0.6"/>
<!-- Glasses on beak -->
<circle cx="80" cy="55" r="5" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.4"/>
<circle cx="86" cy="54" r="5" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.4"/>
<line x1="85" y1="55" x2="81" y2="54" stroke="currentColor" stroke-width="1" opacity="0.3"/>
<!-- Beak (pointy, triangular) -->
<polygon points="90,58 102,55 90,52" fill="currentColor" opacity="0.35"/>
<!-- Arm holding book out to customer -->
<line x1="97" y1="88" x2="125" y2="78" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Book in hand (big, detailed) -->
<rect x="120" y="70" width="18" height="24" rx="2" fill="currentColor" opacity="0.35"/>
<rect x="122" y="73" width="14" height="3" rx="1" fill="currentColor" opacity="0.2"/>
<line x1="129" y1="70" x2="129" y2="94" stroke="currentColor" stroke-width="1" opacity="0.2"/>
<!-- Other arm resting on counter -->
<line x1="53" y1="90" x2="35" y2="108" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Counter (big) -->
<rect x="10" y="120" width="140" height="10" rx="2" fill="currentColor" opacity="0.3"/>
<rect x="15" y="130" width="130" height="6" rx="1" fill="currentColor" opacity="0.15"/>
<!-- Stack of books on counter -->
<rect x="25" y="105" width="22" height="15" rx="2" fill="currentColor" opacity="0.3"/>
<rect x="28" y="98" width="18" height="7" rx="1" fill="currentColor" opacity="0.25"/>
<rect x="30" y="93" width="14" height="5" rx="1" fill="currentColor" opacity="0.2"/>
<!-- Legs (long!) -->
<line x1="65" y1="123" x2="55" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="85" y1="123" x2="95" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Big flat feet -->
<ellipse cx="50" cy="188" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<ellipse cx="100" cy="188" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok 2 : Factrice — running profile, letter carrier bag, letters flying, cap -->
<svg class="shadok-factrice" viewBox="0 0 180 200" fill="none" aria-hidden="true">
<!-- Body (small oval, leaning forward) -->
<ellipse cx="80" cy="80" rx="20" ry="26" fill="currentColor" opacity="0.25" transform="rotate(-15 80 80)"/>
<!-- Head -->
<circle cx="95" cy="48" r="15" fill="currentColor" opacity="0.3"/>
<!-- Cap -->
<rect x="82" y="34" width="28" height="7" rx="3" fill="currentColor" opacity="0.4"/>
<rect x="106" y="36" width="10" height="5" rx="2" fill="currentColor" opacity="0.3"/>
<!-- Eyes (determined, looking forward) -->
<circle cx="101" cy="46" r="1.8" fill="currentColor" opacity="0.6"/>
<circle cx="106" cy="45" r="1.8" fill="currentColor" opacity="0.6"/>
<!-- Beak (pointy, profile) -->
<polygon points="110,48 125,44 110,42" fill="currentColor" opacity="0.35"/>
<!-- Carrier bag (big, on shoulder) -->
<rect x="55" y="62" width="28" height="35" rx="4" fill="currentColor" opacity="0.3"/>
<line x1="60" y1="62" x2="75" y2="55" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.3"/>
<!-- Letters flying out of bag -->
<rect x="42" y="55" width="12" height="9" rx="1" fill="currentColor" opacity="0.2" transform="rotate(-20 48 59)"/>
<rect x="35" y="45" width="10" height="7" rx="1" fill="currentColor" opacity="0.15" transform="rotate(-35 40 48)"/>
<rect x="48" y="42" width="11" height="8" rx="1" fill="currentColor" opacity="0.18" transform="rotate(10 53 46)"/>
<!-- Arm swinging back -->
<line x1="65" y1="72" x2="45" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Running legs (long strides!) -->
<line x1="72" y1="106" x2="40" y2="170" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="88" y1="106" x2="130" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Big flat feet -->
<ellipse cx="35" cy="174" rx="11" ry="4" fill="currentColor" opacity="0.3"/>
<ellipse cx="135" cy="168" rx="11" ry="4" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok 3 : Cartonnier — assembling cardboard box, tape gun, flat boxes nearby -->
<svg class="shadok-cartonnier" viewBox="0 0 170 220" fill="none" aria-hidden="true">
<!-- Body (small, leaning over work) -->
<ellipse cx="70" cy="100" rx="22" ry="27" fill="currentColor" opacity="0.25" transform="rotate(8 70 100)"/>
<!-- Head (looking down at box) -->
<circle cx="78" cy="65" r="15" fill="currentColor" opacity="0.3"/>
<!-- Eyes (focused, looking down) -->
<circle cx="83" cy="67" r="1.8" fill="currentColor" opacity="0.6"/>
<circle cx="88" cy="68" r="1.8" fill="currentColor" opacity="0.6"/>
<!-- Beak pointing down -->
<polygon points="88,72 98,78 86,76" fill="currentColor" opacity="0.35"/>
<!-- Arm holding tape gun -->
<line x1="90" y1="95" x2="130" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Tape gun (big, detailed) -->
<circle cx="138" cy="102" r="8" fill="currentColor" opacity="0.25"/>
<rect x="132" y="99" width="18" height="6" rx="1" fill="currentColor" opacity="0.35"/>
<polygon points="150,100 158,102 150,104" fill="currentColor" opacity="0.3"/>
<!-- Other arm holding box flap -->
<line x1="50" y1="92" x2="35" y2="118" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Box being assembled (big, 3D perspective) -->
<rect x="25" y="118" width="45" height="35" rx="2" fill="currentColor" opacity="0.2"/>
<polygon points="25,118 15,108 60,108 70,118" fill="currentColor" opacity="0.15"/>
<polygon points="70,118 60,108 60,143 70,153" fill="currentColor" opacity="0.12"/>
<!-- Flap open -->
<polygon points="25,118 15,108 15,98 25,108" fill="currentColor" opacity="0.18"/>
<!-- Flat boxes nearby -->
<rect x="90" y="145" width="35" height="4" rx="1" fill="currentColor" opacity="0.2"/>
<rect x="88" y="150" width="38" height="4" rx="1" fill="currentColor" opacity="0.15"/>
<rect x="92" y="155" width="32" height="4" rx="1" fill="currentColor" opacity="0.12"/>
<!-- Legs (long!) -->
<line x1="60" y1="127" x2="48" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="80" y1="127" x2="92" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Big flat feet -->
<ellipse cx="43" cy="196" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<ellipse cx="97" cy="196" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok 4 : Cycliste livreur — on bicycle, package on rack, profile leaning forward -->
<svg class="shadok-cycliste" viewBox="0 0 180 200" fill="none" aria-hidden="true">
<!-- Back wheel -->
<circle cx="35" cy="160" r="22" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.25"/>
<circle cx="35" cy="160" r="3" fill="currentColor" opacity="0.3"/>
<!-- Front wheel -->
<circle cx="145" cy="160" r="22" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.25"/>
<circle cx="145" cy="160" r="3" fill="currentColor" opacity="0.3"/>
<!-- Frame -->
<line x1="35" y1="160" x2="80" y2="120" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.3"/>
<line x1="80" y1="120" x2="120" y2="120" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.3"/>
<line x1="120" y1="120" x2="145" y2="160" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.3"/>
<line x1="35" y1="160" x2="80" y2="140" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.2"/>
<line x1="80" y1="140" x2="120" y2="120" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.2"/>
<!-- Handlebars -->
<line x1="120" y1="120" x2="130" y2="105" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.3"/>
<line x1="125" y1="105" x2="135" y2="105" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.3"/>
<!-- Saddle -->
<rect x="72" y="116" width="16" height="5" rx="2" fill="currentColor" opacity="0.3"/>
<!-- Package on rear rack (big!) -->
<rect x="15" y="125" width="30" height="22" rx="3" fill="currentColor" opacity="0.3"/>
<line x1="30" y1="125" x2="30" y2="147" stroke="currentColor" stroke-width="1" opacity="0.2"/>
<line x1="15" y1="136" x2="45" y2="136" stroke="currentColor" stroke-width="1" opacity="0.2"/>
<!-- Rear rack -->
<line x1="35" y1="147" x2="35" y2="155" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<line x1="15" y1="147" x2="55" y2="147" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<!-- Body (small, leaning forward on bike) -->
<ellipse cx="90" cy="100" rx="18" ry="24" fill="currentColor" opacity="0.25" transform="rotate(-20 90 100)"/>
<!-- Head -->
<circle cx="108" cy="68" r="14" fill="currentColor" opacity="0.3"/>
<!-- Eyes (focused ahead) -->
<circle cx="115" cy="65" r="1.8" fill="currentColor" opacity="0.6"/>
<circle cx="120" cy="64" r="1.8" fill="currentColor" opacity="0.6"/>
<!-- Beak -->
<polygon points="122,68 134,64 122,62" fill="currentColor" opacity="0.35"/>
<!-- Arms to handlebars -->
<line x1="100" y1="90" x2="130" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Legs pedaling -->
<line x1="82" y1="118" x2="72" y2="145" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="88" y1="120" x2="95" y2="148" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Feet on pedals -->
<ellipse cx="70" cy="148" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="97" cy="150" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok 5 : Lectrice satisfaite — sitting in armchair, open book, wrapping paper on floor -->
<svg class="shadok-lectrice" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Armchair (big!) -->
<path d="M20 100 Q20 80 35 80 L115 80 Q130 80 130 100 L130 150 L20 150 Z" fill="currentColor" opacity="0.15"/>
<!-- Armrests -->
<rect x="10" y="90" width="16" height="55" rx="6" fill="currentColor" opacity="0.2"/>
<rect x="124" y="90" width="16" height="55" rx="6" fill="currentColor" opacity="0.2"/>
<!-- Chair legs -->
<line x1="25" y1="150" x2="22" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.2"/>
<line x1="125" y1="150" x2="128" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.2"/>
<!-- Body (sitting, small) -->
<ellipse cx="75" cy="120" rx="20" ry="25" fill="currentColor" opacity="0.25"/>
<!-- Head (tilted, reading happily) -->
<circle cx="75" cy="82" r="16" fill="currentColor" opacity="0.3"/>
<!-- Happy eyes (curved) -->
<path d="M66 79 Q69 76 72 79" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.5"/>
<path d="M80 78 Q83 75 86 78" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.5"/>
<!-- Small smile -->
<path d="M70 88 Q75 93 80 88" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.3"/>
<!-- Beak (small, happy) -->
<polygon points="88,83 98,80 88,78" fill="currentColor" opacity="0.3"/>
<!-- Arms holding open book -->
<line x1="55" y1="112" x2="40" y2="125" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="95" y1="112" x2="110" y2="125" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Open book (big, in lap) -->
<rect x="38" y="125" width="28" height="20" rx="1" fill="currentColor" opacity="0.3"/>
<rect x="66" y="125" width="28" height="20" rx="1" fill="currentColor" opacity="0.25"/>
<line x1="66" y1="125" x2="66" y2="145" stroke="currentColor" stroke-width="1.5" opacity="0.35"/>
<!-- Text lines on book pages -->
<line x1="42" y1="131" x2="62" y2="131" stroke="currentColor" stroke-width="0.8" opacity="0.15"/>
<line x1="42" y1="135" x2="60" y2="135" stroke="currentColor" stroke-width="0.8" opacity="0.15"/>
<line x1="70" y1="131" x2="90" y2="131" stroke="currentColor" stroke-width="0.8" opacity="0.15"/>
<line x1="70" y1="135" x2="88" y2="135" stroke="currentColor" stroke-width="0.8" opacity="0.15"/>
<!-- Legs (long, dangling from chair) -->
<line x1="62" y1="145" x2="50" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="88" y1="145" x2="100" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Big flat feet -->
<ellipse cx="45" cy="198" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<ellipse cx="105" cy="198" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<!-- Wrapping paper on floor -->
<path d="M30 175 Q45 170 55 178 Q60 182 50 185" stroke="currentColor" stroke-width="1.5" fill="currentColor" opacity="0.12"/>
<path d="M100 180 Q115 172 125 180 Q120 188 108 185" stroke="currentColor" stroke-width="1.5" fill="currentColor" opacity="0.1"/>
</svg>
<!-- Shadok 6 : Empileur — balancing tower of books on head, arms out, worried eyes -->
<svg class="shadok-empileur" viewBox="0 0 140 220" fill="none" aria-hidden="true">
<!-- Precarious tower of books on head (big, detailed!) -->
<rect x="48" y="8" width="24" height="7" rx="1" fill="currentColor" opacity="0.2" transform="rotate(3 60 11)"/>
<rect x="46" y="16" width="28" height="7" rx="1" fill="currentColor" opacity="0.25" transform="rotate(-2 60 19)"/>
<rect x="44" y="24" width="32" height="7" rx="1" fill="currentColor" opacity="0.2" transform="rotate(4 60 27)"/>
<rect x="47" y="32" width="26" height="7" rx="1" fill="currentColor" opacity="0.28" transform="rotate(-3 60 35)"/>
<rect x="50" y="40" width="22" height="6" rx="1" fill="currentColor" opacity="0.22" transform="rotate(2 61 43)"/>
<!-- Head -->
<circle cx="65" cy="58" r="14" fill="currentColor" opacity="0.3"/>
<!-- Worried eyes (looking up at books) -->
<circle cx="60" cy="54" r="2.2" fill="currentColor" opacity="0.6"/>
<circle cx="70" cy="54" r="2.2" fill="currentColor" opacity="0.6"/>
<!-- Tiny worried pupils (looking up) -->
<circle cx="60" cy="53" r="1" fill="currentColor" opacity="0.35"/>
<circle cx="70" cy="53" r="1" fill="currentColor" opacity="0.35"/>
<!-- Worried eyebrows -->
<line x1="56" y1="50" x2="63" y2="51" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" opacity="0.4"/>
<line x1="74" y1="51" x2="67" y2="50" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" opacity="0.4"/>
<!-- Beak (slightly open, worried) -->
<polygon points="74,60 86,57 74,55" fill="currentColor" opacity="0.3"/>
<line x1="76" y1="58" x2="83" y2="58" stroke="currentColor" stroke-width="0.8" opacity="0.2"/>
<!-- Body (small oval, upright, tense) -->
<ellipse cx="65" cy="95" rx="20" ry="26" fill="currentColor" opacity="0.25"/>
<!-- Arms out wide for balance -->
<line x1="45" y1="88" x2="10" y2="82" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="85" y1="88" x2="120" y2="82" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Hands (small circles at arm ends) -->
<circle cx="8" cy="82" r="3" fill="currentColor" opacity="0.25"/>
<circle cx="122" cy="82" r="3" fill="currentColor" opacity="0.25"/>
<!-- Legs (long!) -->
<line x1="55" y1="121" x2="45" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="75" y1="121" x2="85" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Big flat feet -->
<ellipse cx="40" cy="196" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
<ellipse cx="90" cy="196" rx="10" ry="4" fill="currentColor" opacity="0.3"/>
</svg>
<div class="oiseaux-scene relative overflow-hidden section-padding">
<div class="container-content">
<div class="mx-auto max-w-2xl">
<div class="section-icon mx-auto mb-6">
<div class="section-icon relative mx-auto mb-6">
<div class="i-lucide-shopping-bag h-12 w-12" />
</div>
<p class="mb-2 font-mono text-sm tracking-widest text-primary uppercase text-center">
{{ content?.kicker }}
<p class="relative mb-2 font-mono text-sm tracking-widest text-primary uppercase text-center">
<!-- Phone: the title fills the width; the bird stands at the end of this line, on its baseline -->
{{ content?.kicker }}<UiOiseauPose nom="lectrice" pose="perche" bout :w="84" retourne mobile-seul />
</p>
<h1 class="font-display text-3xl font-bold mb-4 text-center" style="color: hsl(var(--color-text))">
<h1 class="relative font-display text-3xl font-bold mb-4 text-center" style="color: hsl(var(--color-text))">
{{ content?.title }}
</h1>
@@ -253,6 +21,10 @@
<!-- Bookelis CTA -->
<div class="cta-block mb-8">
<UiOiseauPose nom="cycliste-livreur" pose="marge-g" ecart="54px" :w="150" />
<!-- The reader in the right margin, feet on the card's top edge: on the bag, under the
sticky header, she had 22 px of void above her (rule f, DA 03/11 after 17h35) -->
<UiOiseauPose nom="lectrice" pose="marge-d" ecart="24px" bottom="100%" :w="84" retourne />
<div class="cta-icon">
<div class="i-lucide-globe h-5 w-5" />
</div>
@@ -277,6 +49,7 @@
<!-- Librairie -->
<div class="cta-block mb-10">
<UiOiseauPose nom="libraire" pose="derriere" left="calc(100% - 96px)" bottom="-36px" :w="214" retourne />
<div class="cta-icon cta-icon--accent">
<div class="i-lucide-store h-5 w-5" />
</div>
@@ -325,6 +98,7 @@ useSeoPage({
}
.cta-block {
position: relative;
display: flex;
gap: 1rem;
padding: 1.5rem;
@@ -369,87 +143,4 @@ useSeoPage({
transform: translateY(-1px);
box-shadow: 0 4px 12px hsl(var(--color-primary) / 0.3);
}
.shadok-libraire {
position: absolute;
left: 2%;
top: 5%;
width: clamp(70px, 10vw, 140px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-1 9s ease-in-out infinite;
}
.shadok-factrice {
position: absolute;
right: 2%;
top: 4%;
width: clamp(70px, 10vw, 140px);
opacity: 0.24;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-2 11s ease-in-out infinite;
}
.shadok-cartonnier {
position: absolute;
left: 3%;
top: 45%;
width: clamp(70px, 10vw, 130px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-3 10s ease-in-out infinite;
}
.shadok-cycliste {
position: absolute;
left: 3%;
bottom: 8%;
width: clamp(75px, 10vw, 140px);
opacity: 0.18;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-4 8s ease-in-out infinite;
}
.shadok-lectrice {
position: absolute;
right: 2%;
bottom: 10%;
width: clamp(70px, 10vw, 135px);
opacity: 0.28;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-5 12s ease-in-out infinite;
}
.shadok-empileur {
position: absolute;
left: 50%;
bottom: 2%;
transform: translateX(-50%);
width: clamp(70px, 10vw, 130px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-6 7s ease-in-out infinite;
}
@keyframes shadok-float-1 { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes shadok-float-2 { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-10px) rotate(2deg); } }
@keyframes shadok-float-3 { 0%, 100% { transform: translateY(0) rotate(0deg); } 50% { transform: translateY(-12px) rotate(-1deg); } }
@keyframes shadok-float-4 { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px) rotate(1deg); } }
@keyframes shadok-float-5 { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-6px); } }
@keyframes shadok-float-6 { 0%, 100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(-9px); } }
@media (max-width: 768px) {
.shadok-libraire,
.shadok-factrice,
.shadok-cartonnier,
.shadok-cycliste,
.shadok-lectrice,
.shadok-empileur { display: none; }
}
</style>
+20 -495
View File
@@ -1,382 +1,14 @@
<template>
<div class="axis-scope axis-scope--eco relative overflow-hidden section-padding">
<!-- Shadok boulangère (top-left, walking profile, carrying bread tray) -->
<svg class="shadok shadok-boulangere" viewBox="0 0 160 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body tilted forward walking -->
<ellipse cx="85" cy="105" rx="22" ry="28" fill="currentColor" opacity="0.25" transform="rotate(-8 85 105)" />
<!-- head -->
<circle cx="80" cy="65" r="16" fill="currentColor" opacity="0.3" />
<!-- eyes looking forward -->
<circle cx="88" cy="62" r="2" fill="currentColor" />
<circle cx="88" cy="68" r="1.5" fill="currentColor" />
<!-- beak pointing right -->
<path d="M94 64 L108 62 L94 68" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arms up holding tray -->
<line x1="75" y1="88" x2="60" y2="42" stroke-width="3" />
<line x1="95" y1="88" x2="110" y2="42" stroke-width="3" />
<!-- big bread tray -->
<rect x="48" y="32" width="74" height="12" rx="3" fill="currentColor" opacity="0.25" />
<!-- bread loaves on tray -->
<ellipse cx="62" cy="30" rx="10" ry="6" fill="currentColor" opacity="0.3" />
<ellipse cx="85" cy="28" rx="11" ry="7" fill="currentColor" opacity="0.3" />
<ellipse cx="108" cy="30" rx="9" ry="6" fill="currentColor" opacity="0.3" />
<!-- score marks on loaves -->
<line x1="58" y1="28" x2="60" y2="32" opacity="0.4" />
<line x1="64" y1="27" x2="66" y2="31" opacity="0.4" />
<line x1="82" y1="26" x2="84" y2="30" opacity="0.4" />
<line x1="88" y1="25" x2="90" y2="29" opacity="0.4" />
<!-- flour apron -->
<path d="M70 95 Q85 92 100 95 L97 125 Q85 128 73 125 Z" fill="currentColor" opacity="0.1" />
<!-- flour dots -->
<circle cx="78" cy="100" r="1" fill="currentColor" opacity="0.3" />
<circle cx="92" cy="108" r="1.2" fill="currentColor" opacity="0.25" />
<circle cx="83" cy="115" r="0.8" fill="currentColor" opacity="0.3" />
<!-- long legs walking stride -->
<line x1="78" y1="132" x2="58" y2="185" stroke-width="3" />
<line x1="92" y1="132" x2="112" y2="180" stroke-width="3" />
<!-- big flat feet -->
<ellipse cx="52" cy="188" rx="12" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="118" cy="183" rx="12" ry="4" fill="currentColor" opacity="0.3" />
</g>
</svg>
<!-- Shadok potier (top-right, sitting at wheel) -->
<svg class="shadok shadok-potier" viewBox="0 0 170 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body sitting, slightly hunched -->
<ellipse cx="70" cy="100" rx="23" ry="26" fill="currentColor" opacity="0.25" transform="rotate(5 70 100)" />
<!-- head looking down at wheel -->
<circle cx="65" cy="65" r="15" fill="currentColor" opacity="0.3" />
<!-- eyes looking down -->
<circle cx="60" cy="68" r="2" fill="currentColor" />
<circle cx="72" cy="70" r="1.8" fill="currentColor" />
<!-- beak pointing down-right -->
<path d="M68 76 L80 82 L66 82" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arms reaching to vase -->
<line x1="50" y1="92" x2="110" y2="115" stroke-width="3" />
<line x1="90" y1="90" x2="120" y2="110" stroke-width="3" />
<!-- hands on vase -->
<circle cx="112" cy="113" r="4" fill="currentColor" opacity="0.2" />
<circle cx="122" cy="108" r="4" fill="currentColor" opacity="0.2" />
<!-- vase being shaped -->
<path d="M108 95 Q102 108 106 125 Q115 135 124 125 Q128 108 122 95" fill="currentColor" opacity="0.2" stroke="currentColor" stroke-width="2" />
<!-- vase opening -->
<ellipse cx="115" cy="95" rx="8" ry="3" fill="currentColor" opacity="0.15" />
<!-- pottery wheel -->
<ellipse cx="115" cy="140" rx="28" ry="8" fill="currentColor" opacity="0.2" />
<line x1="115" y1="148" x2="115" y2="170" stroke-width="3" />
<line x1="100" y1="170" x2="130" y2="170" stroke-width="3" />
<!-- spinning motion lines -->
<path d="M88 138 Q85 135 88 132" fill="none" opacity="0.35" />
<path d="M142 138 Q145 135 142 132" fill="none" opacity="0.35" />
<path d="M90 145 Q86 143 90 140" fill="none" opacity="0.25" />
<!-- legs folded sitting -->
<line x1="60" y1="124" x2="40" y2="165" stroke-width="3" />
<line x1="80" y1="124" x2="75" y2="170" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="34" cy="168" rx="11" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="70" cy="173" rx="11" ry="4" fill="currentColor" opacity="0.3" />
</g>
</svg>
<!-- Shadok apicultrice (left, 40% down, with smoker and bees) -->
<svg class="shadok shadok-apicultrice" viewBox="0 0 160 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body upright -->
<ellipse cx="75" cy="110" rx="20" ry="27" fill="currentColor" opacity="0.25" />
<!-- head -->
<circle cx="75" cy="70" r="15" fill="currentColor" opacity="0.3" />
<!-- beekeeping hat brim -->
<ellipse cx="75" cy="56" rx="22" ry="5" fill="currentColor" opacity="0.2" />
<!-- hat top -->
<path d="M58 56 Q58 42 75 40 Q92 42 92 56" fill="currentColor" opacity="0.15" />
<!-- veil hanging down -->
<path d="M53 56 L53 82 Q75 88 97 82 L97 56" fill="none" stroke-dasharray="3 2" opacity="0.3" />
<!-- eyes behind veil -->
<circle cx="70" cy="68" r="2" fill="currentColor" />
<circle cx="82" cy="66" r="1.8" fill="currentColor" />
<!-- beak -->
<path d="M80 74 L94 72 L82 78" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arm left holding smoker -->
<line x1="56" y1="100" x2="28" y2="85" stroke-width="3" />
<!-- smoker device (big) -->
<rect x="10" y="72" width="22" height="20" rx="4" fill="currentColor" opacity="0.25" />
<path d="M14 72 L14 62 Q21 58 28 62 L28 72" fill="currentColor" opacity="0.15" />
<!-- smoke puffs -->
<circle cx="18" cy="55" r="5" fill="currentColor" opacity="0.12" />
<circle cx="24" cy="48" r="4" fill="currentColor" opacity="0.08" />
<circle cx="16" cy="42" r="3" fill="currentColor" opacity="0.06" />
<!-- arm right -->
<line x1="94" y1="100" x2="110" y2="90" stroke-width="3" />
<!-- buzzing bees (small detailed dots) -->
<circle cx="120" cy="60" r="2.5" fill="currentColor" opacity="0.35" />
<line x1="118" y1="58" x2="115" y2="56" opacity="0.3" />
<line x1="122" y1="58" x2="125" y2="55" opacity="0.3" />
<circle cx="135" cy="75" r="2" fill="currentColor" opacity="0.3" />
<line x1="133" y1="73" x2="131" y2="71" opacity="0.25" />
<line x1="137" y1="73" x2="139" y2="71" opacity="0.25" />
<circle cx="110" cy="48" r="2.2" fill="currentColor" opacity="0.25" />
<line x1="108" y1="46" x2="106" y2="44" opacity="0.2" />
<line x1="112" y1="46" x2="114" y2="43" opacity="0.2" />
<circle cx="140" cy="55" r="1.8" fill="currentColor" opacity="0.2" />
<circle cx="128" cy="42" r="2" fill="currentColor" opacity="0.22" />
<!-- long legs -->
<line x1="66" y1="136" x2="55" y2="192" stroke-width="3" />
<line x1="84" y1="136" x2="95" y2="192" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="49" cy="195" rx="11" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="101" cy="195" rx="11" ry="4" fill="currentColor" opacity="0.3" />
</g>
</svg>
<!-- Shadok forgeron (right, 35%, swinging hammer on anvil) -->
<svg class="shadok shadok-forgeron" viewBox="0 0 180 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body leaning forward, muscular feel -->
<ellipse cx="90" cy="105" rx="24" ry="30" fill="currentColor" opacity="0.3" transform="rotate(-12 90 105)" />
<!-- head in profile -->
<circle cx="100" cy="65" r="16" fill="currentColor" opacity="0.3" />
<!-- eyes focused, intense -->
<circle cx="108" cy="62" r="2.5" fill="currentColor" />
<circle cx="108" cy="70" r="2" fill="currentColor" />
<!-- beak pointing right -->
<path d="M114 65 L130 62 L114 70" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- big arm swinging hammer UP -->
<line x1="72" y1="90" x2="40" y2="40" stroke-width="3.5" />
<!-- hammer head (big!) -->
<rect x="22" y="22" width="38" height="18" rx="3" fill="currentColor" opacity="0.3" />
<!-- hammer handle end -->
<line x1="40" y1="40" x2="42" y2="30" stroke-width="4" />
<!-- other arm resting on anvil -->
<line x1="110" y1="92" x2="140" y2="130" stroke-width="3" />
<!-- anvil (big detailed) -->
<path d="M120 135 L160 135 L168 145 L112 145 Z" fill="currentColor" opacity="0.25" />
<rect x="128" y="145" width="24" height="20" fill="currentColor" opacity="0.2" />
<rect x="122" y="165" width="36" height="6" rx="2" fill="currentColor" opacity="0.25" />
<!-- hot metal on anvil -->
<rect x="132" y="130" width="20" height="5" rx="1" fill="currentColor" opacity="0.35" />
<!-- sparks flying -->
<line x1="138" y1="128" x2="132" y2="118" opacity="0.4" />
<line x1="145" y1="126" x2="150" y2="116" opacity="0.35" />
<line x1="152" y1="128" x2="160" y2="120" opacity="0.3" />
<circle cx="130" cy="115" r="1.5" fill="currentColor" opacity="0.35" />
<circle cx="155" cy="112" r="1.2" fill="currentColor" opacity="0.3" />
<circle cx="162" cy="118" r="1" fill="currentColor" opacity="0.25" />
<!-- long legs wide stance -->
<line x1="78" y1="133" x2="55" y2="190" stroke-width="3" />
<line x1="100" y1="133" x2="120" y2="192" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="48" cy="193" rx="13" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="127" cy="195" rx="13" ry="4" fill="currentColor" opacity="0.3" />
</g>
</svg>
<!-- Shadok maraîchère (bottom-left, pushing wheelbarrow) -->
<svg class="shadok shadok-maraichere" viewBox="0 0 180 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body leaning forward pushing -->
<ellipse cx="120" cy="95" rx="21" ry="26" fill="currentColor" opacity="0.25" transform="rotate(-20 120 95)" />
<!-- head tilted forward -->
<circle cx="130" cy="58" r="14" fill="currentColor" opacity="0.3" />
<!-- eyes looking down at path -->
<circle cx="136" cy="56" r="2" fill="currentColor" />
<circle cx="136" cy="63" r="1.5" fill="currentColor" />
<!-- beak pointing right-down -->
<path d="M140 60 L154 64 L140 66" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arms pushing wheelbarrow handles -->
<line x1="104" y1="86" x2="72" y2="110" stroke-width="3" />
<line x1="108" y1="80" x2="72" y2="100" stroke-width="3" />
<!-- wheelbarrow body (big!) -->
<path d="M10 80 L70 80 L75 120 L5 120 Z" fill="currentColor" opacity="0.2" />
<path d="M10 80 L70 80 L75 120 L5 120 Z" />
<!-- wheelbarrow handles -->
<line x1="70" y1="90" x2="72" y2="110" stroke-width="3" />
<line x1="70" y1="100" x2="72" y2="100" stroke-width="2" />
<!-- wheel -->
<circle cx="12" cy="128" r="12" fill="currentColor" opacity="0.15" />
<circle cx="12" cy="128" r="12" />
<circle cx="12" cy="128" r="3" fill="currentColor" opacity="0.3" />
<!-- vegetables in wheelbarrow -->
<circle cx="22" cy="72" r="7" fill="currentColor" opacity="0.3" />
<circle cx="38" cy="70" r="8" fill="currentColor" opacity="0.25" />
<circle cx="55" cy="73" r="6" fill="currentColor" opacity="0.3" />
<ellipse cx="30" cy="76" rx="5" ry="8" fill="currentColor" opacity="0.2" transform="rotate(15 30 76)" />
<!-- carrot tops -->
<line x1="22" y1="66" x2="18" y2="58" opacity="0.35" />
<line x1="22" y1="66" x2="25" y2="57" opacity="0.35" />
<line x1="55" y1="67" x2="52" y2="60" opacity="0.3" />
<line x1="55" y1="67" x2="58" y2="59" opacity="0.3" />
<!-- long legs striding -->
<line x1="112" y1="118" x2="100" y2="180" stroke-width="3" />
<line x1="128" y1="118" x2="150" y2="178" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="94" cy="183" rx="12" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="156" cy="181" rx="12" ry="4" fill="currentColor" opacity="0.3" />
</g>
</svg>
<!-- Shadok tisserand (bottom-right, sitting at loom) -->
<svg class="shadok shadok-tisserand" viewBox="0 0 170 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body sitting upright -->
<ellipse cx="55" cy="100" rx="20" ry="25" fill="currentColor" opacity="0.25" />
<!-- head looking down at loom -->
<circle cx="55" cy="65" r="15" fill="currentColor" opacity="0.3" />
<!-- eyes focused downward -->
<circle cx="62" cy="66" r="2" fill="currentColor" />
<circle cx="60" cy="72" r="1.5" fill="currentColor" />
<!-- beak pointing right-down -->
<path d="M66 70 L78 74 L64 76" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arms reaching to loom -->
<line x1="72" y1="92" x2="100" y2="80" stroke-width="3" />
<line x1="74" y1="100" x2="105" y2="100" stroke-width="3" />
<!-- loom frame (big detailed) -->
<rect x="95" y="55" width="60" height="80" rx="3" fill="none" />
<!-- vertical loom posts -->
<line x1="95" y1="55" x2="95" y2="135" stroke-width="3" />
<line x1="155" y1="55" x2="155" y2="135" stroke-width="3" />
<!-- top beam -->
<line x1="95" y1="55" x2="155" y2="55" stroke-width="3" />
<!-- warp threads (vertical) -->
<line x1="105" y1="55" x2="105" y2="135" opacity="0.3" />
<line x1="115" y1="55" x2="115" y2="135" opacity="0.3" />
<line x1="125" y1="55" x2="125" y2="135" opacity="0.3" />
<line x1="135" y1="55" x2="135" y2="135" opacity="0.3" />
<line x1="145" y1="55" x2="145" y2="135" opacity="0.3" />
<!-- weft threads (horizontal, partial = work in progress) -->
<line x1="95" y1="70" x2="155" y2="70" opacity="0.25" />
<line x1="95" y1="80" x2="155" y2="80" opacity="0.25" />
<line x1="95" y1="90" x2="145" y2="90" opacity="0.25" />
<line x1="95" y1="100" x2="135" y2="100" opacity="0.2" />
<!-- shuttle in hand -->
<ellipse cx="105" cy="100" rx="8" ry="3" fill="currentColor" opacity="0.3" transform="rotate(-5 105 100)" />
<!-- woven fabric area -->
<rect x="97" y="62" width="56" height="28" fill="currentColor" opacity="0.08" />
<!-- legs folded sitting on stool -->
<line x1="45" y1="123" x2="30" y2="178" stroke-width="3" />
<line x1="65" y1="123" x2="70" y2="180" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="24" cy="181" rx="11" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="76" cy="183" rx="11" ry="4" fill="currentColor" opacity="0.3" />
<!-- stool -->
<rect x="38" y="124" width="30" height="6" rx="2" fill="currentColor" opacity="0.15" />
<line x1="42" y1="130" x2="40" y2="148" stroke-width="2" opacity="0.3" />
<line x1="64" y1="130" x2="66" y2="148" stroke-width="2" opacity="0.3" />
</g>
</svg>
<!-- Shadok berger (center-bottom, walking with sheep) -->
<svg class="shadok shadok-berger" viewBox="0 0 180 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body walking, slight lean -->
<ellipse cx="85" cy="90" rx="20" ry="26" fill="currentColor" opacity="0.25" transform="rotate(-5 85 90)" />
<!-- head 3/4 view -->
<circle cx="88" cy="52" r="16" fill="currentColor" opacity="0.3" />
<!-- eyes looking ahead, slightly different directions -->
<circle cx="94" cy="48" r="2" fill="currentColor" />
<circle cx="96" cy="56" r="1.8" fill="currentColor" />
<!-- beak -->
<path d="M100 52 L114 50 L100 56" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arm holding staff -->
<line x1="68" y1="82" x2="50" y2="60" stroke-width="3" />
<!-- shepherd's crook (big, detailed) -->
<line x1="50" y1="60" x2="44" y2="10" stroke-width="3" />
<path d="M44 10 Q44 0 54 0 Q62 0 62 10 Q62 18 54 18" fill="none" stroke-width="3" />
<!-- other arm relaxed -->
<line x1="104" y1="84" x2="118" y2="95" stroke-width="3" />
<!-- long legs walking -->
<line x1="76" y1="114" x2="60" y2="175" stroke-width="3" />
<line x1="94" y1="114" x2="110" y2="172" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="54" cy="178" rx="12" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="116" cy="175" rx="12" ry="4" fill="currentColor" opacity="0.3" />
<!-- sheep 1 (following) -->
<ellipse cx="140" cy="160" rx="14" ry="10" fill="currentColor" opacity="0.18" />
<circle cx="150" cy="152" r="6" fill="currentColor" opacity="0.15" />
<circle cx="153" cy="150" r="1" fill="currentColor" />
<line x1="132" y1="170" x2="132" y2="180" stroke-width="2" opacity="0.3" />
<line x1="148" y1="170" x2="148" y2="180" stroke-width="2" opacity="0.3" />
<!-- sheep 2 -->
<ellipse cx="158" cy="172" rx="12" ry="8" fill="currentColor" opacity="0.14" />
<circle cx="166" cy="166" r="5" fill="currentColor" opacity="0.12" />
<circle cx="168" cy="164" r="0.8" fill="currentColor" />
<line x1="152" y1="180" x2="152" y2="188" stroke-width="1.5" opacity="0.25" />
<line x1="164" y1="180" x2="164" y2="188" stroke-width="1.5" opacity="0.25" />
<!-- sheep 3 (smaller, behind) -->
<ellipse cx="170" cy="178" rx="9" ry="6" fill="currentColor" opacity="0.1" />
<circle cx="176" cy="174" r="4" fill="currentColor" opacity="0.08" />
<!-- dog at side -->
<ellipse cx="125" cy="170" rx="8" ry="5" fill="currentColor" opacity="0.2" />
<circle cx="130" cy="164" r="4" fill="currentColor" opacity="0.18" />
<circle cx="132" cy="163" r="1" fill="currentColor" />
<line x1="118" y1="168" x2="112" y2="165" stroke-width="1.5" opacity="0.3" />
<line x1="120" y1="175" x2="120" y2="182" stroke-width="1.5" opacity="0.25" />
<line x1="130" y1="175" x2="130" y2="182" stroke-width="1.5" opacity="0.25" />
</g>
</svg>
<!-- Shadok vigneronne (right, 55%, carrying grape basket) -->
<svg class="shadok shadok-vigneronne" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<!-- body seen from 3/4 back, leaning under weight -->
<ellipse cx="80" cy="105" rx="22" ry="28" fill="currentColor" opacity="0.25" transform="rotate(10 80 105)" />
<!-- head turned slightly -->
<circle cx="72" cy="65" r="15" fill="currentColor" opacity="0.3" />
<!-- eyes looking to the side -->
<circle cx="64" cy="62" r="2" fill="currentColor" />
<circle cx="66" cy="69" r="1.5" fill="currentColor" />
<!-- beak pointing left -->
<path d="M58 65 L44 62 L58 69" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.2" />
<!-- arm back holding basket strap -->
<line x1="98" y1="92" x2="115" y2="75" stroke-width="3" />
<!-- arm front with pruning shears -->
<line x1="62" y1="95" x2="38" y2="80" stroke-width="3" />
<!-- pruning shears (big) -->
<line x1="38" y1="80" x2="26" y2="68" stroke-width="3" />
<line x1="38" y1="80" x2="28" y2="78" stroke-width="3" />
<circle cx="36" cy="78" r="3" fill="currentColor" opacity="0.2" />
<!-- blade shapes -->
<path d="M26 68 Q22 72 28 74" fill="none" stroke-width="2" />
<path d="M28 78 Q22 76 24 72" fill="none" stroke-width="2" />
<!-- big basket on back with grapes -->
<path d="M100 60 L130 60 L135 120 L95 120 Z" fill="currentColor" opacity="0.2" />
<path d="M100 60 L130 60 L135 120 L95 120 Z" />
<!-- basket weave texture -->
<line x1="100" y1="75" x2="133" y2="75" opacity="0.2" />
<line x1="98" y1="90" x2="134" y2="90" opacity="0.2" />
<line x1="97" y1="105" x2="135" y2="105" opacity="0.2" />
<!-- grapes overflowing -->
<circle cx="108" cy="55" r="4" fill="currentColor" opacity="0.3" />
<circle cx="116" cy="53" r="4.5" fill="currentColor" opacity="0.3" />
<circle cx="124" cy="55" r="4" fill="currentColor" opacity="0.25" />
<circle cx="112" cy="48" r="3.5" fill="currentColor" opacity="0.25" />
<circle cx="120" cy="47" r="3.5" fill="currentColor" opacity="0.2" />
<circle cx="105" cy="52" r="3" fill="currentColor" opacity="0.2" />
<!-- grape stems -->
<line x1="115" y1="43" x2="115" y2="36" opacity="0.3" />
<line x1="113" y1="36" x2="117" y2="36" opacity="0.3" />
<!-- grapevine nearby -->
<line x1="148" y1="30" x2="148" y2="130" stroke-width="2" opacity="0.2" />
<path d="M148 50 Q158 45 162 55" fill="none" opacity="0.2" />
<path d="M148 75 Q160 70 165 80" fill="none" opacity="0.2" />
<circle cx="160" cy="58" r="3" fill="currentColor" opacity="0.12" />
<circle cx="163" cy="83" r="3" fill="currentColor" opacity="0.1" />
<!-- grape leaf -->
<path d="M148 90 Q155 85 158 90 Q160 95 155 98 Q150 95 148 90" fill="currentColor" opacity="0.12" />
<!-- long legs -->
<line x1="70" y1="132" x2="55" y2="192" stroke-width="3" />
<line x1="90" y1="132" x2="105" y2="190" stroke-width="3" />
<!-- flat feet -->
<ellipse cx="49" cy="195" rx="12" ry="4" fill="currentColor" opacity="0.3" />
<ellipse cx="111" cy="193" rx="12" ry="4" fill="currentColor" opacity="0.3" />
</g>
</svg>
<div class="axis-scope axis-scope--eco oiseaux-scene relative overflow-hidden section-padding">
<div class="container-content">
<!-- Header -->
<header class="mb-12 text-center">
<p class="mb-2 font-mono text-sm tracking-widest text-primary uppercase">{{ content?.kicker }}</p>
<p class="relative mb-2 font-mono text-sm tracking-widest text-primary uppercase">
<!-- Phone: the title fills the width; the bird stands at the end of this line, on its baseline.
A flat bird (37-44 px tall at 72 px wide): 93 px separate this baseline from the sticky
header, and a perched bird keeps a void of its own height above it (rule f) -->
{{ content?.kicker }}<UiOiseauPose nom="maraichere" pose="perche" bout :w="72" retourne mobile-seul />
</p>
<h1 class="page-title font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
{{ content?.title }}
</h1>
@@ -386,7 +18,9 @@
</header>
<div class="mx-auto max-w-3xl flex flex-col gap-8">
<!-- Monnaie libre -->
<!-- Monnaie libre — the card clips its Ğ1 watermark, so the bird stands on a wrapper -->
<div class="relative">
<UiOiseauPose nom="pompeur-de-g1" pose="marge-d" ecart="34px" :w="126" retourne />
<NuxtLink to="/economique/monnaie-libre" class="item-card g1-card group">
<span class="g1-watermark" aria-hidden="true">Ğ1</span>
<div class="item-header">
@@ -406,9 +40,16 @@
<div class="i-lucide-arrow-right h-3.5 w-3.5" />
</div>
</NuxtLink>
</div>
<!-- Modèle économique — bloc livre -->
<div class="book-block">
<!-- The balance (the measure of the gift) peeks out from behind the book, on the left and
halfway up: the market gardener stands low on the right, never at its height, and the
four birds of the page do not alternate at an even step -->
<UiOiseauPose nom="la-balance" pose="derriere" left="-150px" bottom="calc(100% - 240px)" :w="240" />
<!-- Not by the Productions card: with the beekeeper, a pair at the same height -->
<UiOiseauPose nom="maraichere" pose="marge-d" ecart="46px" :w="108" retourne />
<HomeBookSection
compact
@open-player="showBookPlayer = true"
@@ -418,6 +59,7 @@
<!-- Productions collectives -->
<NuxtLink to="/economique/productions-collectives" class="item-card group">
<UiOiseauPose nom="apicultrice" pose="marge-g" ecart="52px" :w="124" />
<div class="item-header">
<div class="item-icon">
<div class="i-lucide-users h-5 w-5" />
@@ -469,6 +111,7 @@ const showPdfReader = ref(false)
}
.item-card {
position: relative;
display: block;
padding: 1.5rem;
border-radius: 16px;
@@ -526,6 +169,7 @@ const showPdfReader = ref(false)
}
.book-block {
position: relative;
padding: 1.25rem;
border-radius: 16px;
border: none;
@@ -567,123 +211,4 @@ const showPdfReader = ref(false)
.g1-card:hover .g1-watermark {
color: hsl(var(--color-primary) / 0.11);
}
/* Shadok illustrations */
.shadok {
position: absolute;
pointer-events: none;
width: clamp(70px, 10vw, 140px);
z-index: 0;
}
.shadok-boulangere {
top: 1%;
left: 2%;
opacity: 0.22;
color: hsl(var(--color-primary));
animation: shadok-float-1 9s ease-in-out infinite;
}
.shadok-potier {
top: 1%;
right: 2%;
opacity: 0.2;
color: hsl(var(--color-accent));
animation: shadok-float-2 11s ease-in-out infinite;
}
.shadok-apicultrice {
left: 2%;
top: 40%;
opacity: 0.2;
color: hsl(var(--color-accent));
animation: shadok-float-3 10s ease-in-out infinite;
}
.shadok-forgeron {
right: 3%;
top: 35%;
opacity: 0.24;
color: hsl(var(--color-primary));
animation: shadok-float-4 8s ease-in-out infinite;
}
.shadok-maraichere {
bottom: 14%;
left: 1%;
opacity: 0.18;
color: hsl(var(--color-primary));
animation: shadok-float-5 12s ease-in-out infinite;
}
.shadok-tisserand {
bottom: 12%;
right: 1%;
opacity: 0.22;
color: hsl(var(--color-accent));
animation: shadok-float-6 9.5s ease-in-out infinite;
}
.shadok-berger {
bottom: 2%;
left: 50%;
transform: translateX(-50%);
opacity: 0.28;
color: hsl(var(--color-primary));
animation: shadok-float-7 11s ease-in-out infinite;
}
.shadok-vigneronne {
right: 2%;
top: 55%;
opacity: 0.2;
color: hsl(var(--color-accent));
animation: shadok-float-8 7.5s ease-in-out infinite;
}
@keyframes shadok-float-1 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes shadok-float-2 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shadok-float-3 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-12px); }
}
@keyframes shadok-float-4 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}
@keyframes shadok-float-5 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-11px); }
}
@keyframes shadok-float-6 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shadok-float-7 {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-10px); }
}
@keyframes shadok-float-8 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-7px); }
}
@media (max-width: 768px) {
.shadok {
display: none;
}
}
</style>
+12 -3
View File
@@ -1,5 +1,11 @@
<template>
<div v-if="chapter">
<div v-if="chapter" class="relative">
<!-- The book's trades in the margins, each on a line of the chapter (rule e): the two who
write keep their way, on the left, the calligrapher on the title's rule (in the chapter
header), the typographer on the navigation's rule; the box maker in the right margin, by
the PDF and songs buttons (in the header); the proofreader on the right, by the last
paragraph -->
<UiOiseauPose nom="correcteur" pose="libre" left="calc(100% + 40px)" bottom="140px" :w="108" retourne />
<BookChapterHeader
:title="chapter.title"
:description="chapter.description"
@@ -10,8 +16,11 @@
<BookChapterContent :content="chapter" />
<!-- Prev / Next navigation -->
<nav class="mt-16 flex items-center justify-between border-t border-white/8 pt-8">
<!-- Prev / Next navigation. The rule above it is drawn (border-t alone sets no style here):
the typographer stands on it, in the left margin. Perched in the column, the box maker had
20 to 27 px of void under the last paragraph (rule f) -->
<nav class="relative mt-16 flex items-center justify-between border-t border-t-solid border-white/8 pt-8">
<UiOiseauPose nom="typographe" pose="marge-g" ecart="64px" bottom="100%" :w="100" />
<NuxtLink
v-if="prevChapter"
:to="`/economique/modele-eco/${prevChapter.stem?.split('/').pop()}`"
+22 -480
View File
@@ -1,360 +1,5 @@
<template>
<div class="relative overflow-hidden section-padding">
<!-- Shadok illustrations -->
<!-- 1. Typographe — placing movable type in composing stick, profile view -->
<svg class="shadok shadok-typographe" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- body (small oval, profile facing right) -->
<ellipse cx="70" cy="72" rx="22" ry="28" fill="currentColor" opacity="0.28"/>
<!-- head -->
<circle cx="78" cy="36" r="16" fill="currentColor" opacity="0.3"/>
<!-- beak (pointy, profile right) -->
<polygon points="94,34 110,38 94,42" fill="currentColor" opacity="0.35"/>
<!-- eyes (profile — one visible) -->
<circle cx="84" cy="33" r="2.5" fill="currentColor" opacity="0.6"/>
<!-- apron -->
<path d="M52 60 L88 60 L85 100 L55 100 Z" fill="currentColor" opacity="0.15"/>
<line x1="70" y1="60" x2="70" y2="100" stroke="currentColor" stroke-width="1" opacity="0.2"/>
<!-- arm reaching to composing stick -->
<line x1="88" y1="65" x2="120" y2="55" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- other arm holding type block -->
<line x1="52" y1="68" x2="35" y2="58" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- composing stick (big, detailed) -->
<rect x="110" y="40" width="50" height="14" rx="2" fill="currentColor" opacity="0.2"/>
<rect x="110" y="42" width="50" height="10" rx="1" stroke="currentColor" stroke-width="1" fill="none" opacity="0.25"/>
<!-- type blocks in stick -->
<rect x="114" y="44" width="6" height="7" rx="0.5" fill="currentColor" opacity="0.3"/>
<rect x="122" y="44" width="5" height="7" rx="0.5" fill="currentColor" opacity="0.25"/>
<rect x="129" y="44" width="7" height="7" rx="0.5" fill="currentColor" opacity="0.3"/>
<rect x="138" y="44" width="5" height="7" rx="0.5" fill="currentColor" opacity="0.22"/>
<rect x="145" y="44" width="6" height="7" rx="0.5" fill="currentColor" opacity="0.28"/>
<!-- tiny letter on held block -->
<rect x="30" y="52" width="8" height="10" rx="1" fill="currentColor" opacity="0.25"/>
<text x="32" y="60" font-size="6" fill="currentColor" opacity="0.5" font-family="serif">A</text>
<!-- long legs -->
<line x1="62" y1="98" x2="50" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="78" y1="98" x2="90" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet -->
<ellipse cx="45" cy="168" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="95" cy="168" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
</svg>
<!-- 2. Lectrice — sitting in armchair, legs crossed, book on lap, reading glasses -->
<svg class="shadok shadok-lectrice" viewBox="0 0 180 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- armchair back -->
<path d="M30 55 Q25 50 28 30 L85 28 Q88 50 83 55" fill="currentColor" opacity="0.12"/>
<!-- armchair seat -->
<path d="M25 55 L88 55 L92 90 L20 90 Z" fill="currentColor" opacity="0.15"/>
<!-- armchair arms -->
<rect x="15" y="45" width="12" height="45" rx="5" fill="currentColor" opacity="0.15"/>
<rect x="85" y="45" width="12" height="45" rx="5" fill="currentColor" opacity="0.15"/>
<!-- body (seated, small) -->
<ellipse cx="58" cy="68" rx="20" ry="25" fill="currentColor" opacity="0.28"/>
<!-- head -->
<circle cx="58" cy="32" r="15" fill="currentColor" opacity="0.3"/>
<!-- beak (small, facing right-down toward book) -->
<polygon points="70,35 80,40 70,42" fill="currentColor" opacity="0.3"/>
<!-- reading glasses -->
<circle cx="52" cy="30" r="6" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.4"/>
<circle cx="65" cy="30" r="6" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.4"/>
<line x1="58" y1="30" x2="59" y2="30" stroke="currentColor" stroke-width="1.5" opacity="0.35"/>
<!-- eyes behind glasses (looking down) -->
<circle cx="53" cy="31" r="2" fill="currentColor" opacity="0.55"/>
<circle cx="64" cy="31" r="2" fill="currentColor" opacity="0.55"/>
<!-- arms holding open book on lap -->
<line x1="40" y1="60" x2="35" y2="82" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="76" y1="60" x2="80" y2="82" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- open book on lap -->
<path d="M32 80 L58 88 L84 80 L84 95 L58 103 L32 95 Z" fill="currentColor" opacity="0.18"/>
<line x1="58" y1="88" x2="58" y2="103" stroke="currentColor" stroke-width="1" opacity="0.25"/>
<!-- text lines on pages -->
<line x1="37" y1="86" x2="54" y2="91" stroke="currentColor" stroke-width="0.7" opacity="0.2"/>
<line x1="37" y1="89" x2="54" y2="94" stroke="currentColor" stroke-width="0.7" opacity="0.2"/>
<line x1="62" y1="91" x2="79" y2="86" stroke="currentColor" stroke-width="0.7" opacity="0.2"/>
<line x1="62" y1="94" x2="79" y2="89" stroke="currentColor" stroke-width="0.7" opacity="0.2"/>
<!-- crossed legs (long!) -->
<line x1="48" y1="90" x2="30" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="68" y1="90" x2="55" y2="150" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- the crossed leg goes over -->
<line x1="55" y1="150" x2="75" y2="140" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.22"/>
<!-- big flat feet -->
<ellipse cx="25" cy="168" rx="11" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="79" cy="142" rx="9" ry="3.5" fill="currentColor" opacity="0.22"/>
<!-- cup of tea nearby -->
<rect x="130" y="78" width="14" height="16" rx="3" fill="currentColor" opacity="0.2"/>
<ellipse cx="137" cy="78" rx="7" ry="2.5" fill="currentColor" opacity="0.25"/>
<!-- tea handle -->
<path d="M144 83 Q152 86 144 92" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.2"/>
<!-- steam -->
<path d="M134 73 Q132 68 135 64" stroke="currentColor" stroke-width="0.8" fill="none" opacity="0.15"/>
<path d="M139 74 Q141 69 138 65" stroke="currentColor" stroke-width="0.8" fill="none" opacity="0.15"/>
</svg>
<!-- 3. Calligraphe — standing at tilted drafting table, large quill, ink flourishes -->
<svg class="shadok shadok-calligraphe" viewBox="0 0 180 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- drafting table (tilted, big) -->
<rect x="75" y="50" width="65" height="85" rx="3" fill="currentColor" opacity="0.12" transform="rotate(-15 108 92)"/>
<!-- table legs -->
<line x1="85" y1="130" x2="78" y2="195" stroke="currentColor" stroke-width="2.5" opacity="0.18"/>
<line x1="140" y1="115" x2="150" y2="195" stroke="currentColor" stroke-width="2.5" opacity="0.18"/>
<!-- paper on table -->
<rect x="85" y="58" width="48" height="65" rx="1" fill="currentColor" opacity="0.08" transform="rotate(-15 109 90)"/>
<!-- ink flourishes on paper -->
<path d="M95 80 Q105 70 115 82 Q120 90 110 95" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.25" transform="rotate(-15 105 85)"/>
<path d="M100 95 Q108 88 118 98" stroke="currentColor" stroke-width="0.8" fill="none" opacity="0.2" transform="rotate(-15 109 93)"/>
<!-- body (3/4 view, facing table) -->
<ellipse cx="55" cy="95" rx="21" ry="27" fill="currentColor" opacity="0.28"/>
<!-- head (turned toward table) -->
<circle cx="62" cy="58" r="16" fill="currentColor" opacity="0.3"/>
<!-- beak pointing at paper -->
<polygon points="75,55 90,52 78,60" fill="currentColor" opacity="0.32"/>
<!-- eyes (looking at paper, slightly different directions) -->
<circle cx="66" cy="55" r="2.5" fill="currentColor" opacity="0.6"/>
<circle cx="58" cy="54" r="2" fill="currentColor" opacity="0.5"/>
<!-- arm holding large quill -->
<line x1="72" y1="85" x2="105" y2="65" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- large quill -->
<line x1="105" y1="65" x2="100" y2="80" stroke="currentColor" stroke-width="1.5" opacity="0.35"/>
<path d="M105 65 L115 30 Q108 45 100 40 Q105 55 105 65" fill="currentColor" opacity="0.2"/>
<!-- other arm resting on table edge -->
<line x1="40" y1="88" x2="80" y2="85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- ink trailing from quill tip -->
<path d="M100 80 Q95 90 98 100 Q102 108 96 115" stroke="currentColor" stroke-width="0.8" fill="none" opacity="0.2"/>
<!-- long legs -->
<line x1="45" y1="120" x2="35" y2="190" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="65" y1="120" x2="72" y2="190" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet -->
<ellipse cx="30" cy="193" rx="11" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="77" cy="193" rx="11" ry="4" fill="currentColor" opacity="0.25"/>
</svg>
<!-- 4. Relieur — sewing book spine with needle and thread, stack of signatures -->
<svg class="shadok shadok-relieur" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- body (leaning forward over work) -->
<ellipse cx="85" cy="80" rx="22" ry="26" fill="currentColor" opacity="0.28" transform="rotate(10 85 80)"/>
<!-- head (tilted down, focused) -->
<circle cx="95" cy="46" r="15" fill="currentColor" opacity="0.3"/>
<!-- beak (pointing down at work) -->
<polygon points="105,52 115,62 103,58" fill="currentColor" opacity="0.32"/>
<!-- eyes (both looking down at different angles) -->
<circle cx="92" cy="44" r="2" fill="currentColor" opacity="0.55"/>
<circle cx="100" cy="46" r="2.5" fill="currentColor" opacity="0.6"/>
<!-- arm holding needle high -->
<line x1="100" y1="70" x2="130" y2="40" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- needle -->
<line x1="130" y1="40" x2="135" y2="32" stroke="currentColor" stroke-width="2" opacity="0.45"/>
<!-- thread from needle down to book -->
<path d="M132 38 Q140 55 125 75 Q115 90 120 100" stroke="currentColor" stroke-width="1" fill="none" stroke-dasharray="4 3" opacity="0.3"/>
<!-- other arm holding book spine -->
<line x1="68" y1="75" x2="50" y2="95" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- book being bound (open spine view, big) -->
<path d="M40 90 L60 85 L60 125 L40 130 Z" fill="currentColor" opacity="0.18"/>
<path d="M60 85 L80 90 L80 130 L60 125 Z" fill="currentColor" opacity="0.14"/>
<!-- stitching holes along spine -->
<circle cx="60" cy="92" r="1.2" fill="currentColor" opacity="0.35"/>
<circle cx="60" cy="100" r="1.2" fill="currentColor" opacity="0.35"/>
<circle cx="60" cy="108" r="1.2" fill="currentColor" opacity="0.35"/>
<circle cx="60" cy="116" r="1.2" fill="currentColor" opacity="0.35"/>
<!-- stack of folded signatures nearby -->
<rect x="10" y="125" width="30" height="5" rx="1" fill="currentColor" opacity="0.18"/>
<rect x="12" y="119" width="28" height="5" rx="1" fill="currentColor" opacity="0.15"/>
<rect x="11" y="113" width="29" height="5" rx="1" fill="currentColor" opacity="0.2"/>
<rect x="13" y="107" width="27" height="5" rx="1" fill="currentColor" opacity="0.16"/>
<!-- long legs -->
<line x1="75" y1="104" x2="65" y2="172" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="95" y1="104" x2="105" y2="172" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet -->
<ellipse cx="60" cy="175" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="110" cy="175" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
</svg>
<!-- 5. Conteuse — on small stage, arms dramatically wide, 3 tiny shadoks below -->
<svg class="shadok shadok-conteuse" viewBox="0 0 180 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- small stage/box -->
<rect x="55" y="110" width="60" height="20" rx="3" fill="currentColor" opacity="0.18"/>
<rect x="58" y="108" width="54" height="4" rx="1.5" fill="currentColor" opacity="0.22"/>
<!-- body (on stage, upright, dramatic) -->
<ellipse cx="85" cy="85" rx="20" ry="26" fill="currentColor" opacity="0.28"/>
<!-- head (thrown back slightly) -->
<circle cx="85" cy="50" r="16" fill="currentColor" opacity="0.3"/>
<!-- beak (open, telling story) -->
<polygon points="98,46 112,42 100,52" fill="currentColor" opacity="0.3"/>
<polygon points="100,52 112,55 98,54" fill="currentColor" opacity="0.22"/>
<!-- wide expressive eyes -->
<circle cx="82" cy="46" r="3" fill="currentColor" opacity="0.6"/>
<circle cx="92" cy="45" r="2.5" fill="currentColor" opacity="0.55"/>
<!-- arms dramatically wide -->
<line x1="65" y1="75" x2="15" y2="50" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<line x1="105" y1="75" x2="160" y2="50" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- gesture sparkles -->
<circle cx="10" cy="45" r="2" fill="currentColor" opacity="0.15"/>
<circle cx="165" cy="45" r="2" fill="currentColor" opacity="0.15"/>
<circle cx="18" cy="38" r="1.5" fill="currentColor" opacity="0.12"/>
<circle cx="157" cy="38" r="1.5" fill="currentColor" opacity="0.12"/>
<!-- long legs (standing on stage) -->
<line x1="77" y1="108" x2="70" y2="110" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="93" y1="108" x2="100" y2="110" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet on stage -->
<ellipse cx="67" cy="112" rx="8" ry="3" fill="currentColor" opacity="0.2"/>
<ellipse cx="103" cy="112" rx="8" ry="3" fill="currentColor" opacity="0.2"/>
<!-- audience: 3 tiny shadoks below stage -->
<!-- tiny shadok 1 (left) -->
<ellipse cx="40" cy="165" rx="8" ry="10" fill="currentColor" opacity="0.18"/>
<circle cx="40" cy="152" r="6" fill="currentColor" opacity="0.22"/>
<circle cx="39" cy="151" r="1" fill="currentColor" opacity="0.45"/>
<circle cx="42" cy="151" r="1" fill="currentColor" opacity="0.45"/>
<polygon points="45,151 50,153 45,155" fill="currentColor" opacity="0.2"/>
<line x1="37" y1="175" x2="35" y2="195" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<line x1="43" y1="175" x2="45" y2="195" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<!-- tiny shadok 2 (center) -->
<ellipse cx="85" cy="168" rx="8" ry="10" fill="currentColor" opacity="0.18"/>
<circle cx="85" cy="155" r="6" fill="currentColor" opacity="0.22"/>
<circle cx="83" cy="154" r="1" fill="currentColor" opacity="0.45"/>
<circle cx="87" cy="154" r="1" fill="currentColor" opacity="0.45"/>
<polygon points="90,154 95,156 90,158" fill="currentColor" opacity="0.2"/>
<line x1="82" y1="178" x2="80" y2="198" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<line x1="88" y1="178" x2="90" y2="198" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<!-- tiny shadok 3 (right) -->
<ellipse cx="130" cy="163" rx="8" ry="10" fill="currentColor" opacity="0.18"/>
<circle cx="130" cy="150" r="6" fill="currentColor" opacity="0.22"/>
<circle cx="128" cy="149" r="1" fill="currentColor" opacity="0.45"/>
<circle cx="132" cy="149" r="1" fill="currentColor" opacity="0.45"/>
<polygon points="135,149 140,151 135,153" fill="currentColor" opacity="0.2"/>
<line x1="127" y1="173" x2="125" y2="193" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<line x1="133" y1="173" x2="135" y2="193" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
</svg>
<!-- 6. Correcteur — leaning forward, magnifying glass over manuscript, red pen -->
<svg class="shadok shadok-correcteur" viewBox="0 0 170 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- body (leaning forward heavily) -->
<ellipse cx="75" cy="82" rx="21" ry="28" fill="currentColor" opacity="0.28" transform="rotate(20 75 82)"/>
<!-- head (craned forward) -->
<circle cx="95" cy="48" r="15" fill="currentColor" opacity="0.3"/>
<!-- beak (pursed, critical) -->
<polygon points="108,45 118,48 108,52" fill="currentColor" opacity="0.3"/>
<!-- eyes (squinting, one bigger — peering through glass) -->
<circle cx="92" cy="45" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="101" cy="46" r="3" fill="currentColor" opacity="0.6"/>
<!-- arm holding magnifying glass -->
<line x1="90" y1="72" x2="120" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- magnifying glass (big) -->
<circle cx="128" cy="98" r="18" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.3"/>
<circle cx="128" cy="98" r="16" fill="currentColor" opacity="0.06"/>
<!-- handle -->
<line x1="140" y1="112" x2="155" y2="135" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- manuscript under magnifying glass -->
<rect x="95" y="115" width="55" height="70" rx="2" fill="currentColor" opacity="0.1"/>
<!-- text lines on manuscript -->
<line x1="100" y1="125" x2="140" y2="125" stroke="currentColor" stroke-width="0.8" opacity="0.18"/>
<line x1="100" y1="132" x2="145" y2="132" stroke="currentColor" stroke-width="0.8" opacity="0.18"/>
<line x1="100" y1="139" x2="138" y2="139" stroke="currentColor" stroke-width="0.8" opacity="0.18"/>
<line x1="100" y1="146" x2="142" y2="146" stroke="currentColor" stroke-width="0.8" opacity="0.18"/>
<line x1="100" y1="153" x2="135" y2="153" stroke="currentColor" stroke-width="0.8" opacity="0.18"/>
<!-- crossed-out text (red corrections) -->
<line x1="100" y1="132" x2="130" y2="132" stroke="currentColor" stroke-width="1.5" opacity="0.35"/>
<line x1="105" y1="146" x2="125" y2="146" stroke="currentColor" stroke-width="1.5" opacity="0.35"/>
<!-- other arm holding red pen -->
<line x1="58" y1="78" x2="35" y2="100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- red pen -->
<line x1="35" y1="100" x2="25" y2="115" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.35"/>
<circle cx="24" cy="117" r="1.5" fill="currentColor" opacity="0.4"/>
<!-- long legs -->
<line x1="65" y1="108" x2="50" y2="178" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="82" y1="105" x2="95" y2="178" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet -->
<ellipse cx="45" cy="181" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="100" cy="181" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
</svg>
<!-- 7. Colporteur — walking profile, books in wooden crate on back, walking stick, hat -->
<svg class="shadok shadok-colporteur" viewBox="0 0 160 210" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- body (profile, walking right, leaning forward under weight) -->
<ellipse cx="70" cy="72" rx="20" ry="25" fill="currentColor" opacity="0.28" transform="rotate(15 70 72)"/>
<!-- head -->
<circle cx="82" cy="38" r="14" fill="currentColor" opacity="0.3"/>
<!-- hat (brimmed) -->
<ellipse cx="82" cy="26" rx="18" ry="5" fill="currentColor" opacity="0.25"/>
<rect x="72" y="16" width="20" height="12" rx="3" fill="currentColor" opacity="0.2"/>
<!-- beak (profile right) -->
<polygon points="94,36 106,40 94,43" fill="currentColor" opacity="0.32"/>
<!-- eye (profile — one visible, determined) -->
<circle cx="88" cy="35" r="2.5" fill="currentColor" opacity="0.6"/>
<!-- wooden crate on back (big, loaded with books) -->
<rect x="25" y="35" width="40" height="50" rx="3" stroke="currentColor" stroke-width="2" fill="currentColor" opacity="0.12"/>
<!-- strap over shoulder -->
<line x1="45" y1="35" x2="78" y2="55" stroke="currentColor" stroke-width="2" opacity="0.25"/>
<line x1="65" y1="35" x2="85" y2="60" stroke="currentColor" stroke-width="2" opacity="0.25"/>
<!-- books in crate (visible spines) -->
<rect x="28" y="38" width="6" height="44" rx="1" fill="currentColor" opacity="0.22"/>
<rect x="36" y="40" width="5" height="42" rx="1" fill="currentColor" opacity="0.18"/>
<rect x="43" y="37" width="7" height="45" rx="1" fill="currentColor" opacity="0.2"/>
<rect x="52" y="39" width="5" height="43" rx="1" fill="currentColor" opacity="0.16"/>
<rect x="58" y="38" width="4" height="44" rx="1" fill="currentColor" opacity="0.2"/>
<!-- arm forward with walking stick -->
<line x1="88" y1="65" x2="115" y2="80" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- walking stick (long) -->
<line x1="115" y1="80" x2="125" y2="195" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.3"/>
<!-- other arm back holding strap -->
<line x1="55" y1="68" x2="45" y2="55" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- long legs (walking stride) — front leg forward, back leg behind -->
<line x1="78" y1="95" x2="100" y2="170" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="62" y1="95" x2="40" y2="170" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet (walking) -->
<ellipse cx="105" cy="173" rx="11" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="35" cy="173" rx="10" ry="4" fill="currentColor" opacity="0.22"/>
</svg>
<!-- 8. Illustratrice — at easel, brush in one hand, palette in other, canvas showing a shadok -->
<svg class="shadok shadok-illustratrice" viewBox="0 0 180 220" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- easel legs -->
<line x1="105" y1="30" x2="85" y2="210" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="145" y1="30" x2="165" y2="210" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<line x1="125" y1="60" x2="125" y2="210" stroke="currentColor" stroke-width="2" opacity="0.18"/>
<!-- canvas on easel -->
<rect x="95" y="25" width="60" height="75" rx="2" fill="currentColor" opacity="0.08"/>
<rect x="95" y="25" width="60" height="75" rx="2" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.2"/>
<!-- tiny shadok drawing on canvas! -->
<ellipse cx="125" cy="65" rx="8" ry="10" fill="currentColor" opacity="0.18"/>
<circle cx="125" cy="52" r="6" fill="currentColor" opacity="0.2"/>
<polygon points="130,51 136,53 130,55" fill="currentColor" opacity="0.18"/>
<circle cx="123" cy="51" r="1" fill="currentColor" opacity="0.3"/>
<circle cx="127" cy="51" r="1" fill="currentColor" opacity="0.3"/>
<line x1="121" y1="75" x2="118" y2="88" stroke="currentColor" stroke-width="1" opacity="0.15"/>
<line x1="129" y1="75" x2="132" y2="88" stroke="currentColor" stroke-width="1" opacity="0.15"/>
<!-- body (3/4 view, standing back from easel) -->
<ellipse cx="55" cy="90" rx="22" ry="28" fill="currentColor" opacity="0.28"/>
<!-- head (looking at canvas) -->
<circle cx="62" cy="52" r="16" fill="currentColor" opacity="0.3"/>
<!-- beak (profile right, toward canvas) -->
<polygon points="75,50 88,54 76,56" fill="currentColor" opacity="0.3"/>
<!-- eyes (artistic scrutiny, different sizes) -->
<circle cx="60" cy="49" r="2" fill="currentColor" opacity="0.55"/>
<circle cx="69" cy="50" r="2.8" fill="currentColor" opacity="0.6"/>
<!-- arm holding brush toward canvas -->
<line x1="73" y1="82" x2="100" y2="60" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<!-- paintbrush -->
<line x1="100" y1="60" x2="108" y2="52" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<circle cx="110" cy="50" r="2" fill="currentColor" opacity="0.3"/>
<!-- other arm holding palette -->
<line x1="38" y1="85" x2="18" y2="95" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- palette (big, with color dots) -->
<ellipse cx="12" cy="102" rx="16" ry="12" fill="currentColor" opacity="0.15"/>
<!-- thumb hole -->
<circle cx="12" cy="108" r="3" fill="currentColor" opacity="0.05"/>
<!-- paint dabs on palette -->
<circle cx="6" cy="97" r="2.5" fill="currentColor" opacity="0.3"/>
<circle cx="14" cy="94" r="2" fill="currentColor" opacity="0.25"/>
<circle cx="21" cy="98" r="2.5" fill="currentColor" opacity="0.28"/>
<circle cx="8" cy="104" r="2" fill="currentColor" opacity="0.22"/>
<circle cx="18" cy="103" r="2" fill="currentColor" opacity="0.3"/>
<!-- long legs -->
<line x1="45" y1="116" x2="35" y2="188" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<line x1="65" y1="116" x2="75" y2="188" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.25"/>
<!-- big flat feet -->
<ellipse cx="30" cy="191" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
<ellipse cx="80" cy="191" rx="10" ry="4" fill="currentColor" opacity="0.25"/>
</svg>
<div class="oiseaux-scene relative overflow-hidden section-padding">
<div class="container-content">
<!-- Page de couverture du livre -->
<HomeBookSection
@@ -365,9 +10,13 @@
/>
<header class="mb-10 text-center">
<p class="mb-2 font-mono text-sm tracking-widest text-primary uppercase">{{ content?.kicker }}</p>
<h1 class="page-title font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
{{ content?.title }}
<p class="relative mb-2 font-mono text-sm tracking-widest text-primary uppercase">
<!-- Phone: the title fills the width; the bird stands at the end of this line, on its baseline -->
{{ content?.kicker }}<UiOiseauPose nom="relieur" pose="perche" bout :w="72" mobile-seul />
</p>
<h1 class="page-title relative font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
<!-- Before the title, on its baseline (rule e, docs/da-oiseaux.md) -->
<UiOiseauPose nom="relieur" pose="perche" bout right="16px" :w="108" :seuil="1200" />{{ content?.title }}
</h1>
<p class="mt-3 mx-auto max-w-2xl text-sm" style="color: hsl(var(--color-text-muted))">
{{ content?.description }}
@@ -379,7 +28,9 @@
<li
v-for="chapter in chapters"
:key="chapter.path"
class="relative"
>
<UiOiseauPose v-for="o in OISEAUX_CHAPITRE[chapter.stem?.split('/').pop() ?? ''] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<NuxtLink
:to="`/economique/modele-eco/${chapter.stem?.split('/').pop()}`"
class="card-surface flex items-start gap-4 group"
@@ -418,6 +69,18 @@
</template>
<script setup lang="ts">
import type { OiseauPlace } from '~/utils/oiseauPose'
// Birds along the chapters, each by the one its trade tells (irregular intervals). The cards
// stand 12 px apart: no room above them for a perched bird (DA rule of 03/11)
const OISEAUX_CHAPITRE: Record<string, OiseauPlace[]> = {
'01-introduction': [{ nom: 'conteuse', pose: 'marge-g', ecart: '50px', w: 122 }],
'03-mesure': [{ nom: 'la-balance', pose: 'marge-d', ecart: '40px', w: 112, retourne: true }],
'07-echanger': [{ nom: 'colporteur', pose: 'marge-g', ecart: '44px', w: 116 }],
'08-institution': [{ nom: 'empileur', pose: 'marge-d', ecart: '90px', w: 104, retourne: true }],
'11-annexes': [{ nom: 'illustratrice', pose: 'derriere', left: 'calc(100% - 110px)', bottom: '-40px', w: 220 }],
}
definePageMeta({
layout: 'default',
})
@@ -462,125 +125,4 @@ const showPdfReader = ref(false)
font-size: 0.9rem;
}
/* Shadok illustrations — shared */
.shadok {
position: absolute;
pointer-events: none;
width: clamp(70px, 10vw, 140px);
z-index: 0;
}
/* 1. Typographe — top left */
.shadok-typographe {
top: 1%;
left: 1%;
opacity: 0.24;
color: hsl(var(--color-primary));
animation: shadok-float-1 9s ease-in-out infinite;
}
/* 2. Lectrice — top right, sitting */
.shadok-lectrice {
top: 2%;
right: 1%;
opacity: 0.22;
color: hsl(var(--color-accent));
animation: shadok-float-2 11s ease-in-out infinite;
}
/* 3. Calligraphe — left, 40% */
.shadok-calligraphe {
top: 40%;
left: 1%;
opacity: 0.2;
color: hsl(var(--color-primary));
animation: shadok-float-3 10s ease-in-out infinite;
}
/* 4. Relieur — right, 35% */
.shadok-relieur {
top: 35%;
right: 2%;
opacity: 0.24;
color: hsl(var(--color-accent));
animation: shadok-float-4 8s ease-in-out infinite;
}
/* 5. Conteuse — bottom left */
.shadok-conteuse {
bottom: 6%;
left: 1%;
opacity: 0.22;
color: hsl(var(--color-primary));
animation: shadok-float-5 12s ease-in-out infinite;
}
/* 6. Correcteur — bottom right, leaning */
.shadok-correcteur {
bottom: 5%;
right: 1%;
opacity: 0.2;
color: hsl(var(--color-accent));
animation: shadok-float-6 9.5s ease-in-out infinite;
}
/* 7. Colporteur — center bottom, walking */
.shadok-colporteur {
bottom: 2%;
left: 50%;
transform: translateX(-50%);
opacity: 0.18;
color: hsl(var(--color-primary));
animation: shadok-float-7 7.5s ease-in-out infinite;
}
/* 8. Illustratrice — right, 58% */
.shadok-illustratrice {
top: 58%;
right: 1%;
opacity: 0.26;
color: hsl(var(--color-accent));
animation: shadok-float-8 10.5s ease-in-out infinite;
}
/* Float animations — each unique duration and offset */
@keyframes shadok-float-1 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes shadok-float-2 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shadok-float-3 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-12px); }
}
@keyframes shadok-float-4 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}
@keyframes shadok-float-5 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-11px); }
}
@keyframes shadok-float-6 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-7px); }
}
@keyframes shadok-float-7 {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-10px); }
}
@keyframes shadok-float-8 {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
/* Hidden on mobile */
@media (max-width: 768px) {
.shadok {
display: none;
}
}
</style>
+6 -3
View File
@@ -1,5 +1,5 @@
<template>
<div class="axis-scope axis-scope--eco section-padding">
<div class="oiseaux-scene axis-scope axis-scope--eco section-padding">
<div class="container-content">
<!-- Header -->
@@ -62,8 +62,11 @@
<div
v-if="content?.content"
id="section-content"
class="prose-block mb-8 max-w-2xl mx-auto section-anchor"
class="prose-block relative mb-8 max-w-2xl mx-auto section-anchor"
>
<UiOiseauPose nom="boulangere" pose="marge-g" ecart="56px" :w="96" />
<!-- Behind the top of the text block, which has a background (the links stand apart) -->
<UiOiseauPose nom="vigneronne" pose="derriere" left="-140px" bottom="calc(100% - 220px)" :w="210" />
<p class="leading-relaxed whitespace-pre-line" style="color: hsl(var(--color-text-muted))">
{{ content.content }}
</p>
@@ -73,7 +76,7 @@
<div
v-if="content?.links"
id="section-links"
class="flex flex-col gap-3 mb-10 max-w-2xl mx-auto section-anchor"
class="relative flex flex-col gap-3 mb-10 max-w-2xl mx-auto section-anchor"
>
<a
v-for="link in content.links"
@@ -1,5 +1,5 @@
<template>
<div class="axis-scope axis-scope--eco section-padding">
<div class="axis-scope axis-scope--eco oiseaux-scene relative section-padding">
<div class="container-content">
<div class="mx-auto max-w-2xl">
<div class="section-icon mx-auto mb-6">
@@ -10,11 +10,14 @@
{{ content?.kicker }}
</p>
<h1 class="font-display text-3xl font-bold mb-4 text-center" style="color: hsl(var(--color-text))">
<!-- The workshop: each trade of the collective productions around the page -->
<h1 class="relative font-display text-3xl font-bold mb-4 text-center" style="color: hsl(var(--color-text))">
{{ content?.title }}
<!-- In the margin, feet on the title's baseline (rule e) -->
<UiOiseauPose nom="soudeuse" pose="marge-d" ecart="30px" bottom="4px" :w="112" retourne />
</h1>
<p class="text-lg leading-relaxed mb-8 text-center" style="color: hsl(var(--color-text-muted))">
<p class="relative text-lg leading-relaxed mb-8 text-center" style="color: hsl(var(--color-text-muted))">
{{ content?.description }}
</p>
@@ -24,12 +27,17 @@
<!-- Content -->
<div v-if="content?.content" class="prose-block mb-10">
<UiOiseauPose nom="menuisier" pose="perche" left="20px" :w="84" />
<!-- Phone: a flatter bird at the same place, the text above leaves 89 px (rule f) -->
<UiOiseauPose nom="cycliste-livreur" pose="perche" left="20px" :w="72" mobile-seul />
<UiOiseauPose nom="forgeron" pose="marge-g" ecart="70px" :w="140" />
<UiOiseauPose nom="berger" pose="derriere" left="calc(100% - 110px)" bottom="-46px" :w="230" />
<p class="leading-relaxed whitespace-pre-line" style="color: hsl(var(--color-text-muted))">
{{ content.content }}
</p>
</div>
<div class="text-center">
<div class="relative text-center">
<UiBaseButton variant="ghost" to="/economique">
<div class="i-lucide-arrow-left mr-2 h-4 w-4" />
Autonomie économique
@@ -78,6 +86,7 @@ useSeoPage({
}
.prose-block {
position: relative;
padding: 1.5rem;
border-radius: 0.75rem;
background: hsl(var(--color-surface));
+13 -108
View File
@@ -1,75 +1,11 @@
<template>
<div class="relative overflow-hidden section-padding">
<!-- Shadok danseur: character dancing with music notes -->
<svg class="shadok-danseur" viewBox="0 0 240 300" fill="none" aria-hidden="true">
<!-- Body (dynamic pose, leaning) -->
<ellipse cx="120" cy="155" rx="38" ry="46" fill="currentColor" opacity="0.85"/>
<!-- Head (tilted with joy) -->
<ellipse cx="125" cy="92" rx="24" ry="23" fill="currentColor" opacity="0.8"/>
<!-- Eyes (happy, squinted) -->
<path d="M114 88 Q118 84 122 88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
<path d="M130 88 Q134 84 138 88" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.4"/>
<!-- Big smile -->
<path d="M116 100 Q125 108 134 100" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.35"/>
<!-- Arms thrown up (dancing) -->
<line x1="85" y1="140" x2="50" y2="100" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="155" y1="140" x2="190" y2="105" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<!-- Hands -->
<circle cx="50" cy="98" r="4" fill="currentColor" opacity="0.4"/>
<circle cx="190" cy="103" r="4" fill="currentColor" opacity="0.4"/>
<!-- Legs (one kicked up) -->
<line x1="105" y1="198" x2="80" y2="255" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="135" y1="198" x2="170" y2="240" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<!-- Feet -->
<path d="M80 255 L68 258 M80 255 L75 261" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
<path d="M170 240 L180 238 M170 240 L175 246" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.5"/>
<!-- Music notes floating around -->
<text x="42" y="82" fill="currentColor" opacity="0.3" font-size="18">&#9834;</text>
<text x="195" y="88" fill="currentColor" opacity="0.25" font-size="16">&#9835;</text>
<text x="60" y="65" fill="currentColor" opacity="0.2" font-size="14">&#9833;</text>
<text x="180" y="72" fill="currentColor" opacity="0.2" font-size="20">&#9834;</text>
</svg>
<!-- Shadok DJ: character with headphones behind a turntable -->
<svg class="shadok-dj" viewBox="0 0 260 300" fill="none" aria-hidden="true">
<!-- Body -->
<ellipse cx="130" cy="155" rx="42" ry="50" fill="currentColor" opacity="0.85"/>
<!-- Head -->
<circle cx="130" cy="88" r="26" fill="currentColor" opacity="0.8"/>
<!-- Headphones band -->
<path d="M104 78 Q130 55 156 78" stroke="currentColor" stroke-width="4" stroke-linecap="round" fill="none" opacity="0.6"/>
<!-- Headphone ear pads -->
<ellipse cx="102" cy="85" rx="8" ry="12" fill="currentColor" opacity="0.5"/>
<ellipse cx="158" cy="85" rx="8" ry="12" fill="currentColor" opacity="0.5"/>
<!-- Eyes (cool, half-lidded) -->
<ellipse cx="120" cy="85" rx="5" ry="3" fill="currentColor" opacity="0.25"/>
<ellipse cx="140" cy="85" rx="5" ry="3" fill="currentColor" opacity="0.25"/>
<circle cx="121" cy="86" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="141" cy="86" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Mouth (grin) -->
<path d="M122 98 Q130 104 138 98" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.35"/>
<!-- Arms reaching to turntable -->
<line x1="90" y1="150" x2="55" y2="195" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="170" y1="150" x2="205" y2="195" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<!-- Turntable body -->
<rect x="30" y="200" width="200" height="18" rx="4" fill="currentColor" opacity="0.4"/>
<!-- Turntable platter -->
<ellipse cx="130" cy="200" rx="55" ry="15" fill="currentColor" opacity="0.25"/>
<ellipse cx="130" cy="200" rx="55" ry="15" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.35"/>
<!-- Record center -->
<circle cx="130" cy="200" r="5" fill="currentColor" opacity="0.4"/>
<!-- Tone arm -->
<line x1="195" y1="188" x2="150" y2="195" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<circle cx="195" cy="188" r="3" fill="currentColor" opacity="0.35"/>
<!-- Legs -->
<line x1="115" y1="202" x2="105" y2="260" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<line x1="145" y1="202" x2="155" y2="260" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
</svg>
<div class="container-content">
<!-- Hero section with book cover -->
<div class="mb-12 grid items-center gap-8 md:grid-cols-2">
<div class="book-cover-wrapper">
<div class="book-cover-wrapper relative">
<!-- On the cover's base line, in the empty space between the book and the text -->
<UiOiseauPose nom="trompettiste" pose="libre" left="calc(100% - 112px)" bottom="0px" :w="104" />
<div class="book-cover-3d">
<img
:src="homeContent?.book.coverImage"
@@ -80,8 +16,12 @@
</div>
<div class="text-center md:text-left">
<p class="mb-2 font-mono text-sm tracking-widest text-accent uppercase">{{ content?.kicker }}</p>
<h1 class="page-title font-display font-bold tracking-tight text-white">
<p class="relative mb-2 font-mono text-sm tracking-widest text-accent uppercase">
<!-- The DJ stands at the end of this line, on its baseline: the title's box has no visible
top edge (rule e) -->
{{ content?.kicker }}<UiOiseauPose nom="dj" pose="perche" bout left="14px" :w="84" retourne ton="accent" :seuil="1200" />
</p>
<h1 class="page-title relative font-display font-bold tracking-tight text-white">
{{ content?.title }}
</h1>
<p class="mt-4 text-white/60">
@@ -131,7 +71,10 @@
</div>
<!-- Song list -->
<div v-if="viewMode === 'list'" class="flex flex-col gap-2">
<div v-if="viewMode === 'list'" class="relative flex flex-col gap-2">
<!-- S, not M: above it the buttons leave 150 px, and a perched bird keeps a void of its own
height above its head (rule f, DA 03/11 after 17h35) -->
<UiOiseauPose nom="danseur" pose="perche" left="calc(64% - 60px)" :w="80" :seuil="1200" />
<SongItem
v-for="song in filteredSongs"
:key="song.id"
@@ -237,42 +180,4 @@ const filteredSongs = computed(() => {
object-fit: cover;
transform: translateX(-50%);
}
.shadok-danseur {
position: absolute;
left: 2%;
top: 3%;
width: clamp(100px, 14vw, 200px);
opacity: 0.28;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-danseur 7s ease-in-out infinite;
}
.shadok-dj {
position: absolute;
right: 2%;
top: 3%;
width: clamp(120px, 16vw, 230px);
opacity: 0.3;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-dj 8s ease-in-out infinite;
}
@keyframes shadok-float-danseur {
0%, 100% { transform: translateY(0) rotate(0deg); }
25% { transform: translateY(-8px) rotate(2deg); }
75% { transform: translateY(-4px) rotate(-2deg); }
}
@keyframes shadok-float-dj {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@media (max-width: 768px) {
.shadok-danseur { display: none; }
.shadok-dj { display: none; }
}
</style>
+47 -534
View File
@@ -1,343 +1,18 @@
<template>
<div class="relative overflow-hidden section-padding min-h-[70vh] flex items-center justify-center">
<!-- 1. Shadok funambule: walking on tightrope (top-left) -->
<svg class="shadok-funambule" viewBox="0 0 170 200" fill="none" aria-hidden="true">
<!-- Tightrope -->
<line x1="5" y1="170" x2="165" y2="170" stroke="currentColor" stroke-width="2" opacity="0.3"/>
<!-- Body (small oval, leaning forward) -->
<ellipse cx="85" cy="110" rx="20" ry="28" fill="currentColor" opacity="0.25" transform="rotate(-5 85 110)"/>
<!-- Head -->
<circle cx="88" cy="72" r="16" fill="currentColor" opacity="0.3"/>
<!-- Eyes (focused, looking down-right) -->
<circle cx="93" cy="70" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="99" cy="71" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Beak (pointy, right side) -->
<polygon points="103,74 116,72 103,78" fill="currentColor" opacity="0.3"/>
<!-- Balancing pole (big, horizontal) -->
<line x1="10" y1="92" x2="160" y2="88" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Arms holding pole -->
<line x1="67" y1="100" x2="45" y2="92" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="103" y1="98" x2="125" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Left leg (forward, on rope) -->
<line x1="78" y1="136" x2="70" y2="170" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="70" cy="172" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<!-- Right leg (back, lifted) -->
<line x1="92" y1="136" x2="108" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="108" cy="167" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- 2. Shadok accordeoniste: playing accordion (top-right, profile) -->
<svg class="shadok-accordeoniste" viewBox="0 0 180 210" fill="none" aria-hidden="true">
<!-- Body (profile, small) -->
<ellipse cx="70" cy="115" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- Head (profile) -->
<circle cx="72" cy="75" r="16" fill="currentColor" opacity="0.3"/>
<!-- Beret -->
<ellipse cx="72" cy="60" rx="18" ry="6" fill="currentColor" opacity="0.3"/>
<circle cx="72" cy="56" r="4" fill="currentColor" opacity="0.25"/>
<!-- Eye (profile, one visible) -->
<circle cx="80" cy="73" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Beak (profile right) -->
<polygon points="86,76 98,74 86,80" fill="currentColor" opacity="0.3"/>
<!-- Accordion bellows (big, extended right) -->
<rect x="92" y="95" width="12" height="45" rx="2" fill="currentColor" opacity="0.3"/>
<line x1="98" y1="98" x2="98" y2="137" stroke="currentColor" stroke-width="0.8" opacity="0.2"/>
<rect x="107" y="93" width="8" height="49" rx="2" fill="currentColor" opacity="0.25"/>
<rect x="118" y="91" width="8" height="53" rx="2" fill="currentColor" opacity="0.2"/>
<rect x="129" y="89" width="8" height="57" rx="2" fill="currentColor" opacity="0.25"/>
<rect x="140" y="87" width="12" height="61" rx="2" fill="currentColor" opacity="0.3"/>
<!-- Keyboard dots on right panel -->
<circle cx="146" cy="100" r="1.5" fill="currentColor" opacity="0.2"/>
<circle cx="146" cy="110" r="1.5" fill="currentColor" opacity="0.2"/>
<circle cx="146" cy="120" r="1.5" fill="currentColor" opacity="0.2"/>
<circle cx="146" cy="130" r="1.5" fill="currentColor" opacity="0.2"/>
<!-- Left arm on bellows -->
<line x1="52" y1="105" x2="92" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Right arm stretched to far end -->
<line x1="90" y1="108" x2="140" y2="100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Foot tapping (right lifted) -->
<line x1="60" y1="141" x2="52" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="52" cy="197" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<line x1="80" y1="141" x2="90" y2="188" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="90" cy="190" rx="8" ry="3" fill="currentColor" opacity="0.3" transform="rotate(-15 90 190)"/>
<!-- Music notes -->
<text x="155" y="80" fill="currentColor" opacity="0.25" font-size="14">&#9834;</text>
<text x="145" y="68" fill="currentColor" opacity="0.2" font-size="11">&#9835;</text>
</svg>
<!-- 3. Shadok jongleur: 4 balls in the air (top-center) -->
<svg class="shadok-jongleur" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Body -->
<ellipse cx="80" cy="120" rx="21" ry="27" fill="currentColor" opacity="0.25"/>
<!-- Head -->
<circle cx="80" cy="82" r="15" fill="currentColor" opacity="0.3"/>
<!-- Eyes (looking up, wide) -->
<circle cx="74" cy="78" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="86" cy="78" r="2" fill="currentColor" opacity="0.5"/>
<!-- Mouth open (concentration) -->
<ellipse cx="80" cy="92" rx="4" ry="3" fill="currentColor" opacity="0.2"/>
<!-- Beak (small, front view) -->
<polygon points="80,86 87,89 80,92" fill="currentColor" opacity="0.3"/>
<!-- Arms up wide -->
<line x1="60" y1="110" x2="30" y2="75" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="100" y1="110" x2="130" y2="75" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- 4 juggling balls in arc -->
<circle cx="40" cy="35" r="8" fill="currentColor" opacity="0.3"/>
<circle cx="70" cy="18" r="8" fill="currentColor" opacity="0.25"/>
<circle cx="100" cy="15" r="8" fill="currentColor" opacity="0.3"/>
<circle cx="128" cy="30" r="8" fill="currentColor" opacity="0.25"/>
<!-- Long legs -->
<line x1="72" y1="145" x2="60" y2="200" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="60" cy="202" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<line x1="88" y1="145" x2="100" y2="200" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="100" cy="202" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- 4. Shadok cracheur de feu: head tilted back, flame from mouth -->
<svg class="shadok-cracheur" viewBox="0 0 170 220" fill="none" aria-hidden="true">
<!-- Body -->
<ellipse cx="75" cy="125" rx="22" ry="30" fill="currentColor" opacity="0.25"/>
<!-- Head (tilted back) -->
<circle cx="78" cy="82" r="16" fill="currentColor" opacity="0.3" />
<!-- Eyes (looking up) -->
<circle cx="73" cy="76" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="83" cy="76" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Beak (pointing up, open) -->
<polygon points="78,66 85,52 72,66" fill="currentColor" opacity="0.3"/>
<!-- Flame stream from beak (big, upward-right) -->
<path d="M82 54 Q100 25 95 10 Q110 30 120 8 Q115 35 135 15 Q120 42 140 30 Q118 50 130 45" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="currentColor" opacity="0.2"/>
<!-- Torch in left hand -->
<line x1="55" y1="115" x2="30" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<rect x="24" y="78" width="8" height="16" rx="2" fill="currentColor" opacity="0.35"/>
<path d="M28 78 Q28 68 32 72 Q28 65 28 78" fill="currentColor" opacity="0.25"/>
<!-- Right arm out for balance -->
<line x1="95" y1="112" x2="125" y2="100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Long legs -->
<line x1="66" y1="153" x2="55" y2="210" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="55" cy="212" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<line x1="84" y1="153" x2="95" y2="210" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="95" cy="212" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- 5. Shadok trapeziste: hanging from trapeze, body in arc -->
<svg class="shadok-trapeziste" viewBox="0 0 150 220" fill="none" aria-hidden="true">
<!-- Trapeze ropes -->
<line x1="40" y1="0" x2="50" y2="40" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.3"/>
<line x1="110" y1="0" x2="100" y2="40" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.3"/>
<!-- Trapeze bar -->
<line x1="48" y1="40" x2="102" y2="40" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.35"/>
<!-- Arms (hanging from bar) -->
<line x1="60" y1="42" x2="65" y2="70" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="90" y1="42" x2="85" y2="70" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Body (arched, graceful) -->
<ellipse cx="75" cy="95" rx="20" ry="25" fill="currentColor" opacity="0.25" transform="rotate(10 75 95)"/>
<!-- Head (below body, looking down) -->
<circle cx="78" cy="72" r="14" fill="currentColor" opacity="0.3"/>
<!-- Eyes (excited, looking down) -->
<circle cx="74" cy="74" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="84" cy="75" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Beak (pointing down-right) -->
<polygon points="86,78 96,84 86,82" fill="currentColor" opacity="0.3"/>
<!-- Legs (pointed, graceful, extending down-right) -->
<line x1="80" y1="118" x2="95" y2="175" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="70" y1="118" x2="82" y2="180" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Pointed feet -->
<polygon points="95,175 105,180 95,182" fill="currentColor" opacity="0.3"/>
<polygon points="82,180 92,185 82,187" fill="currentColor" opacity="0.3"/>
</svg>
<!-- 6. Shadok batteur: behind drum kit, sticks raised -->
<svg class="shadok-batteur" viewBox="0 0 180 210" fill="none" aria-hidden="true">
<!-- Snare drum (center, big) -->
<ellipse cx="90" cy="165" rx="35" ry="12" fill="currentColor" opacity="0.2"/>
<rect x="55" y="155" width="70" height="20" rx="3" fill="currentColor" opacity="0.2"/>
<ellipse cx="90" cy="155" rx="35" ry="12" fill="currentColor" opacity="0.25"/>
<!-- Hi-hat (left) -->
<ellipse cx="30" cy="140" rx="18" ry="5" fill="currentColor" opacity="0.2"/>
<line x1="30" y1="140" x2="30" y2="185" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<!-- Cymbal (right) -->
<ellipse cx="155" cy="120" rx="20" ry="5" fill="currentColor" opacity="0.2"/>
<line x1="155" y1="120" x2="155" y2="185" stroke="currentColor" stroke-width="2" opacity="0.2"/>
<!-- Body (behind kit) -->
<ellipse cx="90" cy="110" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- Head -->
<circle cx="90" cy="70" r="16" fill="currentColor" opacity="0.3"/>
<!-- Eyes (intense, looking at drums) -->
<circle cx="84" cy="68" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="96" cy="69" r="2" fill="currentColor" opacity="0.5"/>
<!-- Beak (front, small) -->
<polygon points="90,76 97,80 90,82" fill="currentColor" opacity="0.3"/>
<!-- Arms raised with drumsticks -->
<line x1="70" y1="100" x2="40" y2="65" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="40" y1="65" x2="25" y2="50" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<line x1="110" y1="100" x2="140" y2="60" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="140" y1="60" x2="158" y2="48" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<!-- Motion lines on sticks -->
<path d="M22 52 Q18 48 20 44" stroke="currentColor" stroke-width="1" stroke-linecap="round" fill="none" opacity="0.2"/>
<path d="M160 50 Q164 46 162 42" stroke="currentColor" stroke-width="1" stroke-linecap="round" fill="none" opacity="0.2"/>
<!-- Legs (tucked behind kit) -->
<line x1="80" y1="136" x2="70" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="70" cy="197" rx="7" ry="3" fill="currentColor" opacity="0.25"/>
<line x1="100" y1="136" x2="110" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<ellipse cx="110" cy="197" rx="7" ry="3" fill="currentColor" opacity="0.25"/>
</svg>
<!-- 7. Shadok marionnettiste: holding puppet strings -->
<svg class="shadok-marionnettiste" viewBox="0 0 160 220" fill="none" aria-hidden="true">
<!-- Body -->
<ellipse cx="80" cy="75" rx="20" ry="26" fill="currentColor" opacity="0.25"/>
<!-- Head -->
<circle cx="80" cy="40" r="15" fill="currentColor" opacity="0.3"/>
<!-- Eyes (looking down at puppet) -->
<circle cx="75" cy="42" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="86" cy="43" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Beak -->
<polygon points="89,44 100,42 89,48" fill="currentColor" opacity="0.3"/>
<!-- Arms down holding control bar -->
<line x1="62" y1="68" x2="50" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="98" y1="68" x2="110" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Control bar (cross) -->
<line x1="40" y1="108" x2="120" y2="108" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.35"/>
<line x1="80" y1="98" x2="80" y2="118" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.35"/>
<!-- Puppet strings -->
<line x1="45" y1="108" x2="55" y2="155" stroke="currentColor" stroke-width="1" opacity="0.25"/>
<line x1="80" y1="118" x2="70" y2="158" stroke="currentColor" stroke-width="1" opacity="0.25"/>
<line x1="115" y1="108" x2="85" y2="155" stroke="currentColor" stroke-width="1" opacity="0.25"/>
<line x1="80" y1="98" x2="70" y2="148" stroke="currentColor" stroke-width="1" opacity="0.25"/>
<!-- Mini puppet shadok -->
<circle cx="70" cy="155" r="8" fill="currentColor" opacity="0.2"/>
<ellipse cx="70" cy="172" rx="10" ry="13" fill="currentColor" opacity="0.15"/>
<!-- Puppet eyes -->
<circle cx="67" cy="154" r="1" fill="currentColor" opacity="0.4"/>
<circle cx="74" cy="154" r="1" fill="currentColor" opacity="0.4"/>
<!-- Puppet beak -->
<polygon points="76,156 82,155 76,158" fill="currentColor" opacity="0.2"/>
<!-- Puppet legs -->
<line x1="64" y1="184" x2="58" y2="208" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<line x1="76" y1="184" x2="82" y2="208" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<!-- Master shadok legs -->
<line x1="72" y1="99" x2="62" y2="155" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<line x1="88" y1="99" x2="98" y2="155" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.3"/>
<ellipse cx="62" cy="157" rx="7" ry="3" fill="currentColor" opacity="0.25"/>
<ellipse cx="98" cy="157" rx="7" ry="3" fill="currentColor" opacity="0.25"/>
</svg>
<!-- 8. Shadok clown: oversized shoes, red nose, squirting flower -->
<svg class="shadok-clown" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Body -->
<ellipse cx="80" cy="110" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- Head -->
<circle cx="80" cy="70" r="16" fill="currentColor" opacity="0.3"/>
<!-- Party hat (tall cone) -->
<polygon points="80,38 68,62 92,62" fill="currentColor" opacity="0.25"/>
<circle cx="80" cy="38" r="3" fill="currentColor" opacity="0.35"/>
<!-- Big red nose (circle on beak) -->
<circle cx="92" cy="74" r="5" fill="currentColor" opacity="0.4"/>
<!-- Beak behind nose -->
<polygon points="88,72 100,74 88,78" fill="currentColor" opacity="0.2"/>
<!-- Eyes (different directions — goofy) -->
<circle cx="74" cy="66" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="85" cy="64" r="2" fill="currentColor" opacity="0.5"/>
<!-- Big goofy grin -->
<path d="M72 82 Q80 90 88 82" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.3"/>
<!-- Squirting flower on chest -->
<circle cx="80" cy="95" r="6" fill="currentColor" opacity="0.25"/>
<circle cx="80" cy="95" r="2.5" fill="currentColor" opacity="0.35"/>
<!-- Water squirt from flower -->
<path d="M86 93 Q100 85 105 90" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.2"/>
<circle cx="107" cy="90" r="2" fill="currentColor" opacity="0.2"/>
<circle cx="112" cy="88" r="1.5" fill="currentColor" opacity="0.15"/>
<!-- Arms -->
<line x1="60" y1="100" x2="35" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="100" y1="100" x2="125" y2="85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Long legs -->
<line x1="72" y1="136" x2="50" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="88" y1="136" x2="110" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- OVERSIZED shoes -->
<ellipse cx="42" cy="190" rx="18" ry="6" fill="currentColor" opacity="0.3"/>
<ellipse cx="118" cy="190" rx="18" ry="6" fill="currentColor" opacity="0.3"/>
</svg>
<!-- 9. Shadok acrobate: mid-cartwheel, body rotated 90deg -->
<svg class="shadok-acrobate" viewBox="0 0 160 200" fill="none" aria-hidden="true">
<!-- Body (rotated 90 degrees) -->
<ellipse cx="80" cy="100" rx="20" ry="26" fill="currentColor" opacity="0.25" transform="rotate(90 80 100)"/>
<!-- Head (at bottom-right, inverted) -->
<circle cx="112" cy="100" r="14" fill="currentColor" opacity="0.3"/>
<!-- Eyes (dizzy, spiral-ish) -->
<path d="M108 97 Q110 94 113 97" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.4"/>
<path d="M117 97 Q119 94 122 97" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.4"/>
<!-- Beak (pointing right) -->
<polygon points="124,102 136,100 124,106" fill="currentColor" opacity="0.3"/>
<!-- Limbs in pinwheel pattern -->
<!-- Arm up-right -->
<line x1="85" y1="80" x2="110" y2="35" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Arm down-left -->
<line x1="75" y1="120" x2="50" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Leg up-left (hand on ground) -->
<line x1="65" y1="88" x2="25" y2="55" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<circle cx="23" cy="53" r="4" fill="currentColor" opacity="0.25"/>
<!-- Leg down-right -->
<line x1="95" y1="112" x2="135" y2="150" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet -->
<ellipse cx="110" cy="33" rx="6" ry="3" fill="currentColor" opacity="0.25" transform="rotate(-60 110 33)"/>
<ellipse cx="135" cy="152" rx="6" ry="3" fill="currentColor" opacity="0.25" transform="rotate(40 135 152)"/>
<!-- Motion arc -->
<path d="M30 40 Q20 50 25 60" stroke="currentColor" stroke-width="1" stroke-linecap="round" fill="none" opacity="0.2"/>
<path d="M140 140 Q148 148 145 158" stroke="currentColor" stroke-width="1" stroke-linecap="round" fill="none" opacity="0.2"/>
</svg>
<!-- 10. Shadok regisseur: headset, clipboard, running -->
<svg class="shadok-regisseur" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Body (leaning forward, running) -->
<ellipse cx="75" cy="105" rx="20" ry="27" fill="currentColor" opacity="0.25" transform="rotate(-12 75 105)"/>
<!-- Head -->
<circle cx="80" cy="68" r="15" fill="currentColor" opacity="0.3"/>
<!-- Headset arc -->
<path d="M66 60 Q80 48 94 60" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" fill="none" opacity="0.35"/>
<!-- Headset earpiece -->
<ellipse cx="66" cy="64" rx="4" ry="6" fill="currentColor" opacity="0.3"/>
<!-- Headset mic -->
<path d="M66 70 Q62 78 70 80" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" fill="none" opacity="0.3"/>
<!-- Eyes (stressed, one looking forward one sideways) -->
<circle cx="76" cy="65" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="87" cy="64" r="2" fill="currentColor" opacity="0.5"/>
<!-- Beak -->
<polygon points="91,68 104,66 91,72" fill="currentColor" opacity="0.3"/>
<!-- Lanyard -->
<line x1="80" y1="82" x2="80" y2="100" stroke="currentColor" stroke-width="1.5" opacity="0.25"/>
<!-- Badge -->
<rect x="74" y="100" width="12" height="15" rx="2" fill="currentColor" opacity="0.25"/>
<rect x="76" y="103" width="8" height="3" rx="1" fill="currentColor" opacity="0.15"/>
<!-- Right arm pointing forward (with authority) -->
<line x1="92" y1="95" x2="135" y2="75" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Pointing finger -->
<line x1="135" y1="75" x2="145" y2="70" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.35"/>
<!-- Left arm holding clipboard -->
<line x1="58" y1="98" x2="38" y2="110" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Clipboard (big) -->
<rect x="22" y="105" width="22" height="30" rx="2" fill="currentColor" opacity="0.25"/>
<rect x="28" y="102" width="10" height="5" rx="1" fill="currentColor" opacity="0.3"/>
<!-- Clipboard lines -->
<line x1="26" y1="114" x2="40" y2="114" stroke="currentColor" stroke-width="1" opacity="0.15"/>
<line x1="26" y1="120" x2="38" y2="120" stroke="currentColor" stroke-width="1" opacity="0.15"/>
<line x1="26" y1="126" x2="40" y2="126" stroke="currentColor" stroke-width="1" opacity="0.15"/>
<!-- Legs (running stride, long) -->
<line x1="68" y1="130" x2="40" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="38" cy="197" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<line x1="82" y1="130" x2="115" y2="190" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="117" cy="192" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<div class="container-content relative z-10 text-center">
<!-- The stage of the hero: a tightrope walker and a drummer, at different heights -->
<UiOiseauPose nom="funambule" pose="libre" left="5%" bottom="6%" :w="176" :op="0.2" />
<UiOiseauPose nom="batteur" pose="libre" right="6%" bottom="34%" :w="116" retourne ton="accent" />
<!-- Logo SVG vectoriel — inline pour currentColor -->
<div class="evt-logo-wrap mx-auto mb-6" aria-hidden="true">
<UiSectionSign class="evt-logo" />
</div>
<p class="mb-3 font-mono text-sm tracking-widest text-accent uppercase">{{ content?.kicker }}</p>
<h1 class="page-title font-display font-extrabold tracking-tight" style="color: hsl(var(--color-text))">
{{ content?.title }}
<h1 class="page-title relative font-display font-extrabold tracking-tight" style="color: hsl(var(--color-text))">
<!-- The trapeze artist at the end of the title, on its baseline (rule e, docs/da-oiseaux.md) -->
{{ content?.title }}<UiOiseauPose nom="trapeziste" pose="perche" bout left="16px" :w="96" ton="accent" :seuil="1200" />
</h1>
<p v-if="evtContent?.format" class="evt-format font-display">
{{ evtContent.format }}
@@ -354,8 +29,12 @@
<p class="font-display text-xl font-bold" style="color: hsl(var(--color-text))">
« {{ evtContent.leitmotiv }} »
</p>
<p v-if="evtContent?.tagline" class="font-mono text-sm tracking-widest uppercase" style="color: hsl(var(--color-primary))">
<!-- The acrobat before the tagline, on its line: the tagline is narrower than the leitmotiv,
28 px keep it out from under the leitmotiv, and above it the description ends higher
(rule f, DA 03/11 after 17h35). By « Format & lieu », the stage manager stands alone -->
<p v-if="evtContent?.tagline" class="relative font-mono text-sm tracking-widest uppercase" style="color: hsl(var(--color-primary))">
{{ evtContent.tagline }}
<UiOiseauPose nom="acrobate" pose="perche" right="calc(100% + 28px)" bottom="0px" :w="72" />
</p>
<span v-if="evtContent?.gestation" class="evt-gestation-badge">
<div class="i-lucide-flask-conical h-3.5 w-3.5" />
@@ -366,15 +45,26 @@
</div>
<!-- ══ Contenu événement ══ -->
<section v-if="evtContent?.axes || evtContent?.espaces || evtContent?.config" class="evt-content section-padding">
<section v-if="evtContent?.axes || evtContent?.espaces || evtContent?.config" class="evt-content relative section-padding">
<!-- The puppeteer stands on the footer's top rule, from 1200 px: under « Espaces & programme »
the axes cards leave 100 px, half what it needs (rule f), and each row of cards holds one
bird (rule c). The only bird of the page out of its block (orch, 03/11, option 1). Its
offset is the seal's block of the layout (--seal-block), between this section and the
footer; the bird check verifies it stands on the rule -->
<UiOiseauPose nom="marionnettiste" pose="perche" left="18%" bottom="calc(-1 * var(--seal-block))" :w="112" retourne :seuil="1200" />
<div class="container-content flex flex-col gap-14">
<!-- 3 axes -->
<div v-if="evtContent?.axes">
<h2 class="evt-section-title">Trois axes d'émancipation</h2>
<h2 class="evt-section-title relative">
<!-- The clown at the end of its title, on its baseline (rule e). M: between 768 and
1199 px the four birds shown would all be S otherwise (rule a) -->
Trois axes d'émancipation<UiOiseauPose nom="clown" pose="perche" bout left="14px" :w="108" retourne ton="accent" />
</h2>
<p class="evt-section-sub">« je subis — ou je m'affranchis »</p>
<div class="axes-grid">
<div v-for="(axe, i) in evtContent.axes" :key="i" class="axe-card">
<UiOiseauPose v-for="o in OISEAUX_CARTE[axe.label] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<div class="axe-icon">
<div :class="`i-lucide-${axe.icon} h-5 w-5`" />
</div>
@@ -393,10 +83,13 @@
<!-- Espaces permanents -->
<div v-if="evtContent?.espaces">
<h2 class="evt-section-title">Espaces & programme</h2>
<h2 class="evt-section-title relative">
Espaces & programme
</h2>
<p class="evt-section-sub">Chorégraphie séquencée de plénières, ateliers et espaces permanents</p>
<div class="espaces-grid">
<div v-for="(esp, i) in evtContent.espaces" :key="i" class="espace-card">
<UiOiseauPose v-for="o in OISEAUX_CARTE[esp.label] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<div class="espace-icon">
<div :class="`i-lucide-${esp.icon} h-4 w-4`" />
</div>
@@ -410,9 +103,16 @@
<!-- Config -->
<div v-if="evtContent?.config">
<h2 class="evt-section-title">Format & lieu</h2>
<h2 class="evt-section-title relative">
Format & lieu
<!-- S at 72 px, feet on the cards' top edge (the title's 0.25rem margin under it): the
espaces cards above leave 106 px at 768 px, and a perched bird keeps a void of its own
height above it (rule f) -->
<UiOiseauPose nom="regisseur" pose="perche" right="24%" bottom="-0.25rem" :w="72" retourne />
</h2>
<div class="config-grid">
<div v-for="(cfg, i) in evtContent.config" :key="i" class="config-card">
<UiOiseauPose v-for="o in OISEAUX_CARTE[cfg.label] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<div class="config-icon">
<div :class="`i-lucide-${cfg.icon} h-4 w-4`" />
</div>
@@ -429,6 +129,8 @@
</template>
<script setup lang="ts">
import type { OiseauPlace } from '~/utils/oiseauPose'
definePageMeta({
layout: 'default',
})
@@ -436,6 +138,12 @@ definePageMeta({
const { data: content } = await usePageContent('evenement')
const evtContent = computed(() => content.value as Record<string, any> | null)
// Birds standing on the cards, by card label: never two on the same row
const OISEAUX_CARTE: Record<string, OiseauPlace[]> = {
'Économique': [{ nom: 'jongleur', pose: 'perche', right: '22px', w: 76 }],
'Ğ(marché)': [{ nom: 'cracheur-de-feu', pose: 'perche', right: '18px', w: 76, ton: 'accent', seuil: 1200 }],
}
useSeoPage({
title: evtContent.value?.meta?.title ?? 'Évènement — Le Librodrome',
description: evtContent.value?.description as string ?? 'Prochains événements du Librodrome : rencontres, lectures et ateliers autour de l\'économie du don.',
@@ -455,204 +163,6 @@ useSeoPage({
font-size: clamp(2.5rem, 6vw, 3.5rem);
}
/* 1. Funambule — top-left */
.shadok-funambule {
position: absolute;
left: 4%;
top: 5%;
width: clamp(70px, 10vw, 140px);
opacity: 0.24;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-sway-funambule 9s ease-in-out infinite;
}
/* 2. Accordeoniste — top-right */
.shadok-accordeoniste {
position: absolute;
right: 3%;
top: 4%;
width: clamp(70px, 10vw, 140px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-bounce-accordeon 8s ease-in-out infinite;
}
/* 3. Jongleur — top-center */
.shadok-jongleur {
position: absolute;
left: 50%;
top: 2%;
transform: translateX(-50%);
width: clamp(70px, 10vw, 130px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-jongleur 7s ease-in-out infinite;
}
/* 4. Cracheur de feu — left 5%, 40% */
.shadok-cracheur {
position: absolute;
left: 5%;
top: 40%;
width: clamp(70px, 10vw, 140px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-flicker-cracheur 8s ease-in-out infinite;
}
/* 5. Trapeziste — right 3%, 30% */
.shadok-trapeziste {
position: absolute;
right: 3%;
top: 30%;
width: clamp(70px, 10vw, 130px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-swing-trapeze 10s ease-in-out infinite;
}
/* 6. Batteur — left 4%, bottom 15% */
.shadok-batteur {
position: absolute;
left: 4%;
bottom: 15%;
width: clamp(70px, 10vw, 140px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-pulse-batteur 7s ease-in-out infinite;
}
/* 7. Marionnettiste — right 4%, bottom 20% */
.shadok-marionnettiste {
position: absolute;
right: 4%;
bottom: 20%;
width: clamp(70px, 10vw, 130px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-bob-marionnette 9s ease-in-out infinite;
}
/* 8. Clown — bottom-left */
.shadok-clown {
position: absolute;
left: 6%;
bottom: 3%;
width: clamp(70px, 10vw, 135px);
opacity: 0.24;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-wobble-clown 8s ease-in-out infinite;
}
/* 9. Acrobate — center-bottom */
.shadok-acrobate {
position: absolute;
left: 50%;
bottom: 2%;
transform: translateX(-50%);
width: clamp(70px, 10vw, 130px);
opacity: 0.18;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-spin-acrobate 12s ease-in-out infinite;
}
/* 10. Regisseur — bottom-right */
.shadok-regisseur {
position: absolute;
right: 3%;
bottom: 4%;
width: clamp(70px, 10vw, 140px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-rush-regisseur 7s ease-in-out infinite;
}
@keyframes shadok-sway-funambule {
0%, 100% { transform: translateY(0) rotate(0deg); }
25% { transform: translateY(-5px) rotate(2deg); }
75% { transform: translateY(-3px) rotate(-2deg); }
}
@keyframes shadok-bounce-accordeon {
0%, 100% { transform: translateY(0); }
40% { transform: translateY(-8px); }
70% { transform: translateY(-3px); }
}
@keyframes shadok-float-jongleur {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-10px); }
}
@keyframes shadok-flicker-cracheur {
0%, 100% { transform: translateY(0) scale(1); }
30% { transform: translateY(-4px) scale(1.02); }
60% { transform: translateY(-2px) scale(0.99); }
}
@keyframes shadok-swing-trapeze {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(4deg); }
75% { transform: rotate(-4deg); }
}
@keyframes shadok-pulse-batteur {
0%, 100% { transform: translateY(0); }
15% { transform: translateY(-4px); }
30% { transform: translateY(0); }
45% { transform: translateY(-6px); }
60% { transform: translateY(0); }
}
@keyframes shadok-bob-marionnette {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-7px); }
}
@keyframes shadok-wobble-clown {
0%, 100% { transform: translateY(0) rotate(0deg); }
30% { transform: translateY(-5px) rotate(-3deg); }
70% { transform: translateY(-2px) rotate(3deg); }
}
@keyframes shadok-spin-acrobate {
0% { transform: translateX(-50%) rotate(0deg); }
50% { transform: translateX(-50%) rotate(10deg); }
100% { transform: translateX(-50%) rotate(0deg); }
}
@keyframes shadok-rush-regisseur {
0%, 100% { transform: translateX(0) translateY(0); }
25% { transform: translateX(3px) translateY(-5px); }
50% { transform: translateX(-2px) translateY(-2px); }
75% { transform: translateX(2px) translateY(-6px); }
}
@media (max-width: 768px) {
.shadok-funambule,
.shadok-accordeoniste,
.shadok-jongleur,
.shadok-cracheur,
.shadok-trapeziste,
.shadok-batteur,
.shadok-marionnettiste,
.shadok-clown,
.shadok-acrobate,
.shadok-regisseur {
display: none;
}
}
/* ── Logo SVG ── */
.evt-logo-wrap {
width: 4.5rem;
@@ -719,6 +229,7 @@ useSeoPage({
}
.axe-card {
position: relative;
padding: 1.5rem;
border-radius: 16px;
background: hsl(var(--color-surface));
@@ -777,6 +288,7 @@ useSeoPage({
}
.espace-card {
position: relative;
display: flex;
align-items: flex-start;
gap: 0.875rem;
@@ -815,6 +327,7 @@ useSeoPage({
}
.config-card {
position: relative;
display: flex;
align-items: flex-start;
gap: 0.75rem;
+3 -63
View File
@@ -1,47 +1,6 @@
<template>
<NuxtLayout>
<div class="relative overflow-hidden section-padding">
<!-- Shadok alchemist: character stirring a cauldron with sparkles -->
<svg class="shadok-alchemist" viewBox="0 0 240 320" fill="none" aria-hidden="true">
<!-- Body -->
<ellipse cx="120" cy="145" rx="40" ry="48" fill="currentColor" opacity="0.85"/>
<!-- Head -->
<circle cx="120" cy="82" r="24" fill="currentColor" opacity="0.8"/>
<!-- Wizard hat -->
<polygon points="120,30 100,80 140,80" fill="currentColor" opacity="0.5"/>
<line x1="100" y1="80" x2="140" y2="80" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.45"/>
<!-- Hat star -->
<circle cx="118" cy="55" r="3" fill="currentColor" opacity="0.25"/>
<!-- Eyes (mischievous) -->
<circle cx="111" cy="78" r="4.5" fill="currentColor" opacity="0.2"/>
<circle cx="129" cy="78" r="4.5" fill="currentColor" opacity="0.2"/>
<circle cx="112" cy="77" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="130" cy="77" r="2" fill="currentColor" opacity="0.5"/>
<!-- Grin -->
<path d="M112 92 Q120 98 128 92" stroke="currentColor" stroke-width="2" stroke-linecap="round" fill="none" opacity="0.35"/>
<!-- Arm holding spoon/stick -->
<line x1="158" y1="140" x2="175" y2="210" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.6"/>
<!-- Other arm -->
<path d="M82 145 Q65 165 70 185" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" fill="none" opacity="0.6"/>
<!-- Cauldron -->
<path d="M60 220 Q60 260 120 260 Q180 260 180 220" fill="currentColor" opacity="0.4"/>
<ellipse cx="120" cy="220" rx="60" ry="15" fill="currentColor" opacity="0.3"/>
<ellipse cx="120" cy="220" rx="60" ry="15" stroke="currentColor" stroke-width="2" fill="none" opacity="0.4"/>
<!-- Cauldron legs -->
<line x1="80" y1="258" x2="75" y2="280" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.5"/>
<line x1="160" y1="258" x2="165" y2="280" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.5"/>
<!-- Bubbles from cauldron -->
<circle cx="100" cy="210" r="5" fill="currentColor" opacity="0.2"/>
<circle cx="135" cy="205" r="4" fill="currentColor" opacity="0.18"/>
<circle cx="115" cy="198" r="3" fill="currentColor" opacity="0.15"/>
<!-- Sparkles -->
<circle cx="90" cy="190" r="2" fill="currentColor" opacity="0.25"/>
<circle cx="150" cy="195" r="2.5" fill="currentColor" opacity="0.2"/>
<circle cx="105" cy="185" r="1.5" fill="currentColor" opacity="0.2"/>
<!-- Character legs -->
<line x1="105" y1="190" x2="95" y2="225" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.5"/>
<line x1="135" y1="190" x2="145" y2="225" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.5"/>
</svg>
<div class="container-content max-w-3xl mx-auto">
<!-- Back link -->
@@ -58,8 +17,9 @@
<span class="inline-block mb-3 rounded-full bg-amber-400/15 px-3 py-0.5 font-mono text-xs tracking-widest text-amber-400 uppercase">
{{ content?.kicker }}
</span>
<h1 class="page-title font-display font-bold text-white">
{{ content?.title }}
<h1 class="page-title relative font-display font-bold text-white">
<!-- The alchemist at the end of the title, on its baseline (rule e) -->
{{ content?.title }}<UiOiseauPose nom="alchimiste" pose="perche" bout left="16px" :w="98" retourne />
</h1>
<p class="mt-4 text-lg text-white/60 leading-relaxed max-w-xl mx-auto">
{{ content?.description }}
@@ -137,24 +97,4 @@ code {
border-radius: 0.25em;
background: hsl(40 80% 50% / 0.1);
}
.shadok-alchemist {
position: absolute;
right: 2%;
top: 10%;
width: clamp(120px, 16vw, 230px);
opacity: 0.3;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-alchemist 10s ease-in-out infinite;
}
@keyframes shadok-float-alchemist {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-10px) rotate(1deg); }
}
@media (max-width: 768px) {
.shadok-alchemist { display: none; }
}
</style>
+50 -308
View File
@@ -1,222 +1,5 @@
<template>
<div class="axis-scope axis-scope--num page-outer section-padding">
<!-- Shadok pinguin — tenant une clé USB, petit Tux à ses pieds -->
<svg class="shadok-dl shadok-dl-pinguin" viewBox="0 0 170 210" fill="none" aria-hidden="true">
<!-- Small Tux at bottom -->
<ellipse cx="30" cy="175" rx="12" ry="16" fill="currentColor" opacity="0.2"/>
<circle cx="30" cy="158" r="9" fill="currentColor" opacity="0.22"/>
<ellipse cx="30" cy="173" rx="6" ry="9" fill="currentColor" opacity="0.1"/>
<polygon points="30,157 25,154 30,161" fill="currentColor" opacity="0.3"/>
<ellipse cx="25" cy="192" rx="6" ry="2.5" fill="currentColor" opacity="0.2"/>
<ellipse cx="35" cy="192" rx="6" ry="2.5" fill="currentColor" opacity="0.2"/>
<!-- Shadok body — upright -->
<ellipse cx="105" cy="110" rx="20" ry="26" fill="currentColor" opacity="0.25"/>
<!-- Head — looking at USB key -->
<circle cx="100" cy="70" r="15" fill="currentColor" opacity="0.3"/>
<circle cx="95" cy="68" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="104" cy="67" r="1.8" fill="currentColor" opacity="0.45"/>
<polygon points="88,72 80,69 88,76" fill="currentColor" opacity="0.35"/>
<!-- Left arm holding USB key -->
<line x1="88" y1="100" x2="68" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<rect x="42" y="82" width="26" height="14" rx="3" fill="currentColor" opacity="0.28"/>
<rect x="32" y="86" width="10" height="6" rx="1" fill="currentColor" opacity="0.22"/>
<line x1="50" y1="85" x2="60" y2="85" stroke="currentColor" stroke-width="1" opacity="0.2"/>
<line x1="50" y1="89" x2="60" y2="89" stroke="currentColor" stroke-width="1" opacity="0.2"/>
<!-- Right arm relaxed -->
<line x1="122" y1="105" x2="140" y2="125" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Legs -->
<line x1="97" y1="133" x2="87" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="113" y1="133" x2="123" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="85" cy="195" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="125" cy="195" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok toile — au centre d'une web of trust, bras ouverts -->
<svg class="shadok-dl shadok-dl-toile" viewBox="0 0 180 210" fill="none" aria-hidden="true">
<!-- Nodes web -->
<circle cx="30" cy="50" r="3" fill="currentColor" opacity="0.18"/>
<circle cx="155" cy="55" r="3" fill="currentColor" opacity="0.16"/>
<circle cx="18" cy="140" r="3" fill="currentColor" opacity="0.14"/>
<circle cx="162" cy="142" r="3" fill="currentColor" opacity="0.16"/>
<circle cx="80" cy="18" r="3" fill="currentColor" opacity="0.18"/>
<circle cx="148" cy="185" r="2.5" fill="currentColor" opacity="0.14"/>
<circle cx="15" cy="92" r="2.5" fill="currentColor" opacity="0.12"/>
<!-- Connections from center -->
<line x1="90" y1="105" x2="30" y2="50" stroke="currentColor" stroke-width="1" opacity="0.12"/>
<line x1="90" y1="105" x2="155" y2="55" stroke="currentColor" stroke-width="1" opacity="0.12"/>
<line x1="90" y1="105" x2="18" y2="140" stroke="currentColor" stroke-width="1" opacity="0.1"/>
<line x1="90" y1="105" x2="162" y2="142" stroke="currentColor" stroke-width="1" opacity="0.1"/>
<line x1="90" y1="105" x2="80" y2="18" stroke="currentColor" stroke-width="1" opacity="0.12"/>
<line x1="90" y1="105" x2="15" y2="92" stroke="currentColor" stroke-width="0.8" opacity="0.1"/>
<line x1="30" y1="50" x2="80" y2="18" stroke="currentColor" stroke-width="0.8" opacity="0.08"/>
<line x1="155" y1="55" x2="162" y2="142" stroke="currentColor" stroke-width="0.8" opacity="0.08"/>
<!-- Body — bras ouverts -->
<ellipse cx="90" cy="118" rx="20" ry="26" fill="currentColor" opacity="0.25"/>
<circle cx="90" cy="76" r="15" fill="currentColor" opacity="0.3"/>
<circle cx="84" cy="74" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="95" cy="73" r="1.8" fill="currentColor" opacity="0.45"/>
<!-- Beak front-facing proud -->
<polygon points="90,83 85,87 95,87" fill="currentColor" opacity="0.35"/>
<!-- Arms spread wide -->
<line x1="72" y1="108" x2="32" y2="88" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="108" y1="108" x2="150" y2="90" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<circle cx="31" cy="88" r="2.5" fill="currentColor" opacity="0.3"/>
<circle cx="151" cy="90" r="2.5" fill="currentColor" opacity="0.3"/>
<!-- Legs -->
<line x1="82" y1="141" x2="72" y2="196" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="98" y1="141" x2="110" y2="196" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="70" cy="199" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="112" cy="199" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok nas — ployant sous le poids d'un rack serveur -->
<svg class="shadok-dl shadok-dl-nas" viewBox="0 0 170 210" fill="none" aria-hidden="true">
<!-- Server rack on head, slightly tilted -->
<rect x="32" y="10" width="82" height="52" rx="4" fill="currentColor" opacity="0.2" transform="rotate(-2 73 36)"/>
<!-- Server units -->
<rect x="38" y="15" width="68" height="7" rx="2" fill="currentColor" opacity="0.15" transform="rotate(-2 72 19)"/>
<rect x="38" y="25" width="68" height="7" rx="2" fill="currentColor" opacity="0.15" transform="rotate(-2 72 29)"/>
<rect x="38" y="35" width="68" height="7" rx="2" fill="currentColor" opacity="0.15" transform="rotate(-2 72 39)"/>
<rect x="38" y="45" width="68" height="7" rx="2" fill="currentColor" opacity="0.15" transform="rotate(-2 72 49)"/>
<!-- LED indicators -->
<circle cx="46" cy="19" r="1.5" fill="currentColor" opacity="0.3"/>
<circle cx="46" cy="29" r="1.5" fill="currentColor" opacity="0.28"/>
<circle cx="46" cy="39" r="1.5" fill="currentColor" opacity="0.32"/>
<circle cx="46" cy="49" r="1.5" fill="currentColor" opacity="0.25"/>
<!-- Body — bent forward under weight -->
<ellipse cx="85" cy="120" rx="22" ry="25" fill="currentColor" opacity="0.25" transform="rotate(8 85 120)"/>
<!-- Head — strained under rack -->
<circle cx="78" cy="82" r="15" fill="currentColor" opacity="0.3"/>
<circle cx="73" cy="80" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="83" cy="79" r="1.8" fill="currentColor" opacity="0.45"/>
<!-- Beak grimacing left -->
<polygon points="65,84 57,81 65,88" fill="currentColor" opacity="0.35"/>
<!-- Arms up holding rack -->
<line x1="68" y1="110" x2="50" y2="70" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="104" y1="109" x2="112" y2="67" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Legs — pliant sous l'effort -->
<line x1="75" y1="142" x2="58" y2="193" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.4"/>
<line x1="97" y1="142" x2="114" y2="193" stroke="currentColor" stroke-width="3.5" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="56" cy="196" rx="11" ry="3.5" fill="currentColor" opacity="0.3"/>
<ellipse cx="116" cy="196" rx="11" ry="3.5" fill="currentColor" opacity="0.3"/>
<!-- Sweat drops -->
<ellipse cx="48" cy="90" rx="2" ry="3" fill="currentColor" opacity="0.2"/>
<ellipse cx="44" cy="102" rx="1.5" ry="2.5" fill="currentColor" opacity="0.15"/>
</svg>
<!-- Shadok debugger — loupe géante sur un minuscule bug, yeux écarquillés -->
<svg class="shadok-dl shadok-dl-debugger" viewBox="0 0 180 215" fill="none" aria-hidden="true">
<!-- Loupe — grande, tenue à bout de bras -->
<circle cx="38" cy="55" r="30" stroke="currentColor" stroke-width="3.5" fill="none" opacity="0.28"/>
<circle cx="38" cy="55" r="23" fill="currentColor" opacity="0.06"/>
<!-- Manche loupe -->
<line x1="62" y1="78" x2="80" y2="98" stroke="currentColor" stroke-width="4" stroke-linecap="round" opacity="0.3"/>
<!-- Minuscule bug dans la loupe -->
<ellipse cx="36" cy="53" rx="5" ry="4" fill="currentColor" opacity="0.35"/>
<line x1="32" y1="50" x2="28" y2="46" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
<line x1="36" y1="49" x2="36" y2="44" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
<line x1="40" y1="50" x2="44" y2="46" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
<line x1="32" y1="57" x2="28" y2="61" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
<line x1="40" y1="57" x2="44" y2="61" stroke="currentColor" stroke-width="1" stroke-linecap="round" opacity="0.3"/>
<!-- Exclamation dans la loupe -->
<text x="50" y="45" font-size="10" fill="currentColor" opacity="0.4" font-family="monospace">!</text>
<!-- Body — légèrement penché -->
<ellipse cx="125" cy="118" rx="20" ry="26" fill="currentColor" opacity="0.25" transform="rotate(-5 125 118)"/>
<!-- Head — très proche de la loupe, yeux écarquillés -->
<circle cx="118" cy="75" r="16" fill="currentColor" opacity="0.3"/>
<!-- Cercles sous les yeux (nuits blanches) -->
<ellipse cx="112" cy="76" rx="5" ry="4" stroke="currentColor" stroke-width="1" fill="none" opacity="0.2"/>
<ellipse cx="124" cy="75" rx="5" ry="4" stroke="currentColor" stroke-width="1" fill="none" opacity="0.2"/>
<!-- Yeux très grands -->
<circle cx="113" cy="75" r="2.5" fill="currentColor" opacity="0.55"/>
<circle cx="123" cy="74" r="2.5" fill="currentColor" opacity="0.55"/>
<!-- Beak — pointant vers la loupe -->
<polygon points="104,78 96,75 104,83" fill="currentColor" opacity="0.35"/>
<!-- Bras gauche tenant loupe -->
<line x1="108" y1="108" x2="82" y2="95" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Bras droit -->
<line x1="140" y1="110" x2="158" y2="130" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Jambes -->
<line x1="117" y1="141" x2="107" y2="198" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="133" y1="141" x2="143" y2="198" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="105" cy="201" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="145" cy="201" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok rubber duck — assis par terre, canard en caoutchouc face à lui, bras croisés, explication intense -->
<svg class="shadok-dl shadok-dl-duck" viewBox="0 0 180 210" fill="none" aria-hidden="true">
<!-- Rubber duck — stylisé, face au shadok -->
<ellipse cx="145" cy="165" rx="18" ry="14" fill="currentColor" opacity="0.22"/>
<circle cx="145" cy="148" r="11" fill="currentColor" opacity="0.25"/>
<!-- Duck beak -->
<path d="M155 148 L165 146 L155 152 Z" fill="currentColor" opacity="0.3"/>
<!-- Duck eye -->
<circle cx="150" cy="145" r="2" fill="currentColor" opacity="0.4"/>
<!-- Duck wing -->
<path d="M128 162 Q135 158 130 170" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.2"/>
<!-- Shadok — assis, jambes en avant -->
<ellipse cx="82" cy="130" rx="22" ry="20" fill="currentColor" opacity="0.25" transform="rotate(20 82 130)"/>
<!-- Head — très expressif, se penche vers le canard -->
<circle cx="95" cy="90" r="16" fill="currentColor" opacity="0.3"/>
<circle cx="89" cy="88" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="100" cy="87" r="2" fill="currentColor" opacity="0.45"/>
<!-- Beak pointing right at duck -->
<polygon points="108,92 116,89 108,96" fill="currentColor" opacity="0.35"/>
<!-- Bulle de dialogue -->
<path d="M115 72 Q140 60 148 72 Q155 82 145 88 Q135 94 118 88 L115 94 L113 86 Q108 80 115 72Z" fill="currentColor" opacity="0.1"/>
<text x="120" y="82" font-size="7" fill="currentColor" opacity="0.35" font-family="monospace">WTF?</text>
<!-- Bras pointant vers duck -->
<line x1="105" y1="118" x2="130" y2="140" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Bras gauche appuyé au sol -->
<line x1="62" y1="122" x2="42" y2="148" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Jambes en avant (assis) -->
<line x1="72" y1="148" x2="42" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="92" y1="152" x2="115" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<ellipse cx="40" cy="188" rx="10" ry="3.5" fill="currentColor" opacity="0.3"/>
<ellipse cx="117" cy="188" rx="10" ry="3.5" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok caféine — énorme tasse, cernes, jambes qui tremblent -->
<svg class="shadok-dl shadok-dl-cafeine" viewBox="0 0 170 215" fill="none" aria-hidden="true">
<!-- Tasses vides au sol -->
<ellipse cx="25" cy="195" rx="8" ry="4" fill="currentColor" opacity="0.18"/>
<rect x="17" y="183" width="16" height="12" rx="2" fill="currentColor" opacity="0.15"/>
<ellipse cx="52" cy="198" rx="6" ry="3" fill="currentColor" opacity="0.14"/>
<rect x="46" y="188" width="12" height="10" rx="2" fill="currentColor" opacity="0.12"/>
<!-- Énorme tasse à 2 mains -->
<rect x="48" y="68" width="52" height="45" rx="5" fill="currentColor" opacity="0.25"/>
<ellipse cx="74" cy="68" rx="26" ry="6" fill="currentColor" opacity="0.2"/>
<!-- Vapeur -->
<path d="M62 62 Q65 52 62 44" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.25" stroke-linecap="round"/>
<path d="M74 58 Q78 47 74 38" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.22" stroke-linecap="round"/>
<path d="M86 62 Q89 52 86 44" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.2" stroke-linecap="round"/>
<!-- Anse tasse -->
<path d="M100 78 Q118 78 118 90 Q118 102 100 102" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.22"/>
<!-- Logo tasse (skull) -->
<text x="62" y="95" font-size="14" fill="currentColor" opacity="0.18" font-family="monospace">☕</text>
<!-- Body — tassé, fatigué -->
<ellipse cx="90" cy="130" rx="20" ry="24" fill="currentColor" opacity="0.25" transform="rotate(5 90 130)"/>
<!-- Head — yeux mi-clos, cernes -->
<circle cx="88" cy="92" r="15" fill="currentColor" opacity="0.28"/>
<!-- Cernes (demi-cercles sous yeux) -->
<path d="M80 93 Q83 97 86 93" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.3"/>
<path d="M90 92 Q93 96 96 92" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.3"/>
<!-- Yeux mi-clos -->
<line x1="79" y1="90" x2="85" y2="90" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
<line x1="90" y1="89" x2="96" y2="89" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.45"/>
<!-- Beak -->
<polygon points="78,97 70,94 78,101" fill="currentColor" opacity="0.35"/>
<!-- Les deux bras tenant la tasse -->
<line x1="72" y1="116" x2="56" y2="100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="108" y1="118" x2="108" y2="100" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Jambes qui tremblent (légèrement en zigzag) -->
<path d="M80 152 Q76 165 80 175 Q84 185 78 196" stroke="currentColor" stroke-width="3" stroke-linecap="round" fill="none" opacity="0.4"/>
<path d="M100 152 Q104 165 100 175 Q96 185 102 196" stroke="currentColor" stroke-width="3" stroke-linecap="round" fill="none" opacity="0.4"/>
<ellipse cx="76" cy="199" rx="10" ry="3.5" fill="currentColor" opacity="0.3"/>
<ellipse cx="104" cy="199" rx="10" ry="3.5" fill="currentColor" opacity="0.3"/>
</svg>
<div class="axis-scope axis-scope--num oiseaux-scene page-outer section-padding">
<div class="container-content">
<!-- Header — centré, max-2xl -->
@@ -238,6 +21,7 @@
<!-- Project card (legacy pages) -->
<div v-if="content?.project" class="mx-auto max-w-2xl mb-8">
<div class="project-card">
<UiOiseauPose v-for="o in oiseaux.projet ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<div class="project-icon">
<div class="i-lucide-rocket h-5 w-5" />
</div>
@@ -316,10 +100,11 @@
v-for="(section, si) in content.sections"
:key="si"
:id="`s${si}`"
class="mb-12 section-anchor"
class="relative mb-12 section-anchor"
:class="['equivalents', 'tiers', 'territoire'].includes(section.type) ? 'max-w-4xl mx-auto' : 'max-w-2xl mx-auto'"
>
<UiOiseauPose v-for="o in oiseaux.sections?.[si] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<!-- ── ARGUMENTS ── -->
<template v-if="section.type === 'arguments'">
<h2 class="section-title">{{ section.title }}</h2>
@@ -642,9 +427,54 @@
</template>
<script setup lang="ts">
import type { OiseauPlace } from '~/utils/oiseauPose'
const route = useRoute()
const slug = route.params.slug as string
// Birds of each page, by block: the project card and the sections (by index). Left side
// only: the right margin holds the sticky summary on wide screens.
interface OiseauxPage { projet?: OiseauPlace[], sections?: Record<number, OiseauPlace[]> }
const OISEAUX_PAGE: Record<string, OiseauxPage> = {
'logiciel-libre': {
projet: [{ nom: 'cafeine', pose: 'derriere', left: '-130px', bottom: '-30px', w: 200 }],
sections: {
// feet on the last line of the steps: the block ends with the step's padding (16 px)
1: [{ nom: 'debogueur', pose: 'marge-g', ecart: '24px', bottom: '16px', w: 132 }],
// sections 2 (and cloud-libre 1 and 5) are wide: 152 px of margin at 1200 px
2: [{ nom: 'le-manchot', pose: 'marge-g', ecart: '40px', w: 84 }],
3: [{ nom: 'canard-en-plastique', pose: 'marge-g', ecart: '110px', w: 76 }],
},
},
'authentification-wot': {
projet: [
// behind the card, out of its bottom-left corner: no painted pixel in the cut of the rounded
// corner, inside the card's rectangle (rule g, orch 03/11 after 17h58)
{ nom: 'porteur-de-serveur', pose: 'derriere', left: '-142px', bottom: '-24px', w: 210 },
// the Ğ1 pump (Duniter) in the right margin, feet on the card's top edge: perched on the
// card it stood 11 px under the third line of the introduction (rule f). The summary starts
// under the card, and the left margin keeps no column of three (rule d)
{ nom: 'pompeur-de-g1', pose: 'marge-d', ecart: '24px', bottom: '100%', w: 96 },
],
sections: {
// the steps have no background: in the margin, on their last line, small and close to the
// text, out of the band shared by the server carrier and the pump
1: [{ nom: 'toile-de-confiance', pose: 'marge-g', ecart: '24px', bottom: '16px', w: 76 }],
// not right under the server carrier and the web of trust: no column of three
2: [{ nom: 'cryptographe', pose: 'marge-g', ecart: '96px', w: 84 }],
},
},
'cloud-libre': {
// both out of the cut of their card's rounded corner (rule g, as on the web of trust)
projet: [{ nom: 'porteur-de-serveur', pose: 'derriere', left: '-142px', bottom: '-24px', w: 210 }],
sections: {
1: [{ nom: 'admin-reseau', pose: 'derriere', left: '-110px', bottom: '-32px', w: 220 }],
5: [{ nom: 'imprimeuse-3d', pose: 'marge-g', ecart: '48px', w: 84 }],
},
},
}
const oiseaux = computed<OiseauxPage>(() => OISEAUX_PAGE[slug] ?? {})
const [{ data: content }, { data: homeData }] = await Promise.all([
usePageContent(`numerique/${slug}`),
usePageContent('home'),
@@ -691,6 +521,7 @@ useSeoPage({
}
.project-card {
position: relative;
padding: 1.5rem;
border-radius: 0.75rem;
border: 1px solid hsl(var(--color-primary) / 0.15);
@@ -1913,95 +1744,6 @@ details[open] .territoire-chevron {
overflow: clip;
}
/* ── Shadoks décoratifs ── */
.shadok-dl {
position: absolute;
pointer-events: none;
color: hsl(var(--color-primary));
}
.shadok-dl-pinguin {
left: 1%;
top: 18%;
width: clamp(65px, 9vw, 130px);
opacity: 0.22;
animation: shadokfloat-a 11s ease-in-out infinite;
}
.shadok-dl-toile {
right: 1%;
top: 22%;
width: clamp(65px, 9vw, 140px);
opacity: 0.2;
color: hsl(var(--color-accent));
animation: shadokfloat-b 13s ease-in-out infinite;
}
.shadok-dl-nas {
left: 2%;
bottom: 6%;
width: clamp(65px, 9vw, 135px);
opacity: 0.22;
color: hsl(var(--color-accent));
animation: shadokfloat-c 10s ease-in-out infinite;
}
@keyframes shadokfloat-a {
0%, 100% { transform: translateY(0) rotate(-2deg); }
50% { transform: translateY(-8px) rotate(2deg); }
}
@keyframes shadokfloat-b {
0%, 100% { transform: translateY(0) rotate(3deg); }
50% { transform: translateY(-10px) rotate(-2deg); }
}
@keyframes shadokfloat-c {
0%, 100% { transform: translateY(0) rotate(-1deg); }
50% { transform: translateY(-7px) rotate(3deg); }
}
@keyframes shadokfloat-d {
0%, 100% { transform: translateY(0) rotate(2deg); }
50% { transform: translateY(-9px) rotate(-3deg); }
}
@keyframes shadokfloat-e {
0%, 100% { transform: translateY(0) rotate(-3deg); }
50% { transform: translateY(-6px) rotate(1deg); }
}
@keyframes shadokfloat-f {
0%, 100% { transform: translateY(0) rotate(1deg); }
50% { transform: translateY(-11px) rotate(-2deg); }
}
.shadok-dl-debugger {
right: 1%;
bottom: 14%;
width: clamp(65px, 9vw, 140px);
opacity: 0.2;
color: hsl(var(--color-primary));
animation: shadokfloat-d 12s ease-in-out infinite;
}
.shadok-dl-duck {
left: 38%;
top: 6%;
width: clamp(65px, 9vw, 145px);
opacity: 0.2;
color: hsl(var(--color-accent));
animation: shadokfloat-e 14s ease-in-out infinite;
}
.shadok-dl-cafeine {
right: 2%;
top: 52%;
width: clamp(65px, 9vw, 132px);
opacity: 0.22;
color: hsl(var(--color-primary));
animation: shadokfloat-f 9s ease-in-out infinite;
}
@media (max-width: 768px) {
.shadok-dl { display: none; }
}
/* equiv-row without link */
.equiv-row--no-link {
cursor: default;
+34 -446
View File
@@ -1,313 +1,16 @@
<template>
<div class="axis-scope axis-scope--num relative overflow-hidden section-padding">
<!-- Shadok codeuse — sitting at desk, typing on laptop, glasses -->
<svg class="shadok-codeuse" viewBox="0 0 170 200" fill="none" aria-hidden="true">
<!-- Desk -->
<rect x="15" y="120" width="80" height="5" rx="2" fill="currentColor" opacity="0.3"/>
<line x1="25" y1="125" x2="25" y2="165" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.25"/>
<line x1="85" y1="125" x2="85" y2="165" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.25"/>
<!-- Laptop on desk -->
<rect x="30" y="108" width="50" height="12" rx="2" fill="currentColor" opacity="0.35"/>
<path d="M35 108 L40 80 L70 80 L75 108" fill="currentColor" opacity="0.28"/>
<rect x="42" y="84" width="26" height="18" rx="1" fill="currentColor" opacity="0.15"/>
<!-- Code on screen < /> -->
<text x="48" y="96" font-size="8" fill="currentColor" opacity="0.4" font-family="monospace">&lt;/&gt;</text>
<!-- Body — seated, tilted forward -->
<ellipse cx="110" cy="105" rx="20" ry="26" fill="currentColor" opacity="0.25" transform="rotate(-10 110 105)"/>
<!-- Head — looking at screen -->
<circle cx="105" cy="68" r="15" fill="currentColor" opacity="0.3"/>
<!-- Glasses -->
<circle cx="100" cy="66" r="5" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.4"/>
<circle cx="111" cy="66" r="5" stroke="currentColor" stroke-width="1.2" fill="none" opacity="0.4"/>
<line x1="105" y1="66" x2="106" y2="66" stroke="currentColor" stroke-width="1" opacity="0.35"/>
<!-- Eyes behind glasses -->
<circle cx="101" cy="66" r="1.5" fill="currentColor" opacity="0.5"/>
<circle cx="110" cy="65" r="1.5" fill="currentColor" opacity="0.5"/>
<!-- Beak — pointy, looking left -->
<polygon points="88,68 82,65 88,72" fill="currentColor" opacity="0.35"/>
<!-- Arms reaching to laptop -->
<line x1="95" y1="95" x2="78" y2="110" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="125" y1="98" x2="80" y2="115" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Legs — bent, seated -->
<line x1="100" y1="128" x2="90" y2="180" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="118" y1="128" x2="125" y2="180" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet -->
<ellipse cx="88" cy="183" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="127" cy="183" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok electricien — profile view, climbing utility pole, tool belt -->
<svg class="shadok-electricien" viewBox="0 0 150 210" fill="none" aria-hidden="true">
<!-- Utility pole -->
<rect x="68" y="5" width="8" height="200" rx="2" fill="currentColor" opacity="0.2"/>
<line x1="50" y1="30" x2="94" y2="30" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.25"/>
<line x1="45" y1="55" x2="99" y2="55" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" opacity="0.22"/>
<!-- Cables hanging -->
<path d="M50 30 Q35 45 30 35" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.2"/>
<path d="M94 30 Q110 45 115 35" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.2"/>
<path d="M45 55 Q30 68 25 60" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.18"/>
<!-- Body — climbing, profile, tilted -->
<ellipse cx="95" cy="100" rx="20" ry="25" fill="currentColor" opacity="0.25" transform="rotate(15 95 100)"/>
<!-- Head — looking up at cable -->
<circle cx="100" cy="65" r="14" fill="currentColor" opacity="0.3"/>
<!-- Eyes — looking up -->
<circle cx="96" cy="61" r="1.5" fill="currentColor" opacity="0.5"/>
<circle cx="105" cy="60" r="1.5" fill="currentColor" opacity="0.45"/>
<!-- Beak — profile right -->
<polygon points="114,63 122,60 114,67" fill="currentColor" opacity="0.35"/>
<!-- Hard hat -->
<ellipse cx="100" cy="53" rx="16" ry="5" fill="currentColor" opacity="0.3"/>
<path d="M88 53 Q100 42 112 53" fill="currentColor" opacity="0.25"/>
<!-- Arms — one gripping pole, one holding cable -->
<line x1="82" y1="90" x2="74" y2="75" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="108" y1="88" x2="118" y2="60" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Tool belt -->
<ellipse cx="95" cy="118" rx="22" ry="4" fill="currentColor" opacity="0.25"/>
<rect x="82" y="118" width="6" height="8" rx="1" fill="currentColor" opacity="0.2"/>
<rect x="105" y="118" width="5" height="10" rx="1" fill="currentColor" opacity="0.2"/>
<!-- Legs — climbing, spread on pole -->
<line x1="85" y1="122" x2="72" y2="185" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="105" y1="122" x2="76" y2="175" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet gripping pole -->
<ellipse cx="70" cy="188" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="75" cy="178" rx="8" ry="3" fill="currentColor" opacity="0.28"/>
</svg>
<!-- Shadok soudeuse — welding mask flipped up, torch with sparks, apron -->
<svg class="shadok-soudeuse" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Body — upright, slight lean forward -->
<ellipse cx="80" cy="110" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- Apron -->
<path d="M62 95 L60 140 L100 140 L98 95" fill="currentColor" opacity="0.18"/>
<line x1="80" y1="95" x2="80" y2="140" stroke="currentColor" stroke-width="1" opacity="0.15"/>
<!-- Head -->
<circle cx="80" cy="65" r="16" fill="currentColor" opacity="0.3"/>
<!-- Welding mask flipped up on head -->
<rect x="65" y="42" width="30" height="18" rx="4" fill="currentColor" opacity="0.2"/>
<rect x="70" y="46" width="20" height="10" rx="2" fill="currentColor" opacity="0.12"/>
<!-- Eyes — squinting from bright light -->
<line x1="73" y1="64" x2="77" y2="64" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" opacity="0.5"/>
<line x1="84" y1="63" x2="88" y2="63" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" opacity="0.45"/>
<!-- Beak — small, front-facing -->
<polygon points="78,72 80,78 82,72" fill="currentColor" opacity="0.35"/>
<!-- Right arm holding torch -->
<line x1="100" y1="100" x2="135" y2="85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Welding torch -->
<rect x="132" y="78" width="22" height="6" rx="2" fill="currentColor" opacity="0.35"/>
<line x1="154" y1="81" x2="160" y2="78" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.4"/>
<!-- Sparks from torch -->
<circle cx="158" cy="75" r="1.5" fill="currentColor" opacity="0.45"/>
<circle cx="155" cy="70" r="1" fill="currentColor" opacity="0.35"/>
<circle cx="160" cy="72" r="1.2" fill="currentColor" opacity="0.4"/>
<line x1="157" y1="76" x2="160" y2="68" stroke="currentColor" stroke-width="0.8" opacity="0.3"/>
<line x1="155" y1="78" x2="152" y2="71" stroke="currentColor" stroke-width="0.8" opacity="0.25"/>
<!-- Left arm down -->
<line x1="60" y1="100" x2="45" y2="125" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Legs — standing, spread -->
<line x1="70" y1="136" x2="58" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="90" y1="136" x2="102" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Big flat feet -->
<ellipse cx="55" cy="198" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="105" cy="198" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok admin réseau — tangled in cables, router at feet, frustrated -->
<svg class="shadok-admin-reseau" viewBox="0 0 160 200" fill="none" aria-hidden="true">
<!-- Body — upright but struggling -->
<ellipse cx="80" cy="95" rx="21" ry="27" fill="currentColor" opacity="0.25"/>
<!-- Head — tilted, frustrated -->
<circle cx="82" cy="52" r="15" fill="currentColor" opacity="0.3" />
<!-- Eyes — looking in different directions (frustrated) -->
<circle cx="77" cy="50" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="88" cy="48" r="1.8" fill="currentColor" opacity="0.45"/>
<!-- Angry eyebrows -->
<line x1="74" y1="46" x2="79" y2="47" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" opacity="0.4"/>
<line x1="91" y1="44" x2="86" y2="46" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" opacity="0.4"/>
<!-- Beak — open, yelling -->
<polygon points="73,56 65,55 73,60" fill="currentColor" opacity="0.35"/>
<line x1="67" y1="56" x2="66" y2="58" stroke="currentColor" stroke-width="1" opacity="0.3"/>
<!-- Cables tangling around body -->
<path d="M50 40 Q30 60 55 80 Q80 95 60 115 Q40 130 70 140" stroke="currentColor" stroke-width="2" fill="none" opacity="0.3"/>
<path d="M110 45 Q130 65 105 85 Q85 100 110 120 Q125 130 95 145" stroke="currentColor" stroke-width="2" fill="none" opacity="0.28"/>
<path d="M75 38 Q95 50 75 70" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.22"/>
<!-- Arms — trying to untangle -->
<line x1="60" y1="85" x2="40" y2="70" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="100" y1="85" x2="120" y2="68" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Legs -->
<line x1="70" y1="120" x2="60" y2="175" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="90" y1="120" x2="100" y2="175" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet -->
<ellipse cx="57" cy="178" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="103" cy="178" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<!-- Router box at feet -->
<rect x="60" y="168" width="40" height="14" rx="3" fill="currentColor" opacity="0.25"/>
<circle cx="70" cy="175" r="1.5" fill="currentColor" opacity="0.35"/>
<circle cx="78" cy="175" r="1.5" fill="currentColor" opacity="0.3"/>
<circle cx="86" cy="175" r="1.5" fill="currentColor" opacity="0.35"/>
<!-- Antenna on router -->
<line x1="92" y1="168" x2="96" y2="155" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.25"/>
</svg>
<!-- Shadok imprimeuse 3D — watching printer build object layer by layer -->
<svg class="shadok-imprimeuse3d" viewBox="0 0 170 210" fill="none" aria-hidden="true">
<!-- 3D printer frame -->
<rect x="10" y="90" width="65" height="60" rx="3" fill="currentColor" opacity="0.2"/>
<!-- Printer rails -->
<line x1="15" y1="95" x2="15" y2="145" stroke="currentColor" stroke-width="1.5" opacity="0.25"/>
<line x1="70" y1="95" x2="70" y2="145" stroke="currentColor" stroke-width="1.5" opacity="0.25"/>
<!-- Print bed -->
<rect x="18" y="135" width="49" height="4" rx="1" fill="currentColor" opacity="0.25"/>
<!-- Object being printed (layered) -->
<rect x="32" y="128" width="20" height="7" rx="1" fill="currentColor" opacity="0.3"/>
<rect x="34" y="122" width="16" height="6" rx="1" fill="currentColor" opacity="0.25"/>
<rect x="36" y="117" width="12" height="5" rx="1" fill="currentColor" opacity="0.2"/>
<!-- Extruder head -->
<rect x="34" y="110" width="16" height="6" rx="2" fill="currentColor" opacity="0.35"/>
<line x1="42" y1="116" x2="42" y2="118" stroke="currentColor" stroke-width="1.5" opacity="0.4"/>
<!-- Body — leaning forward, watching intently -->
<ellipse cx="120" cy="105" rx="20" ry="25" fill="currentColor" opacity="0.25" transform="rotate(-15 120 105)"/>
<!-- Head — looking down at printer -->
<circle cx="108" cy="70" r="15" fill="currentColor" opacity="0.3"/>
<!-- Eyes — both staring down at printer, fascinated -->
<circle cx="103" cy="72" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="112" cy="73" r="1.8" fill="currentColor" opacity="0.5"/>
<!-- Beak — pointing down -->
<polygon points="100,78 96,82 104,82" fill="currentColor" opacity="0.35"/>
<!-- Arms — one pointing at printer -->
<line x1="105" y1="95" x2="75" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="135" y1="98" x2="150" y2="115" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<!-- Legs — standing, leaning -->
<line x1="112" y1="128" x2="105" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="128" y1="128" x2="138" y2="192" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet -->
<ellipse cx="103" cy="195" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="140" cy="195" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok cryptographe — 3/4 view, cloak, giant key + padlock -->
<svg class="shadok-cryptographe" viewBox="0 0 170 210" fill="none" aria-hidden="true">
<!-- Mysterious cloak -->
<path d="M55 70 Q50 110 45 160 L125 160 Q120 110 115 70" fill="currentColor" opacity="0.15"/>
<path d="M45 160 Q40 170 38 180 L132 180 Q130 170 125 160" fill="currentColor" opacity="0.12"/>
<!-- Body under cloak -->
<ellipse cx="85" cy="105" rx="22" ry="28" fill="currentColor" opacity="0.25"/>
<!-- Head — 3/4 view, slightly turned -->
<circle cx="85" cy="55" r="16" fill="currentColor" opacity="0.3"/>
<!-- Hood suggestion -->
<path d="M68 50 Q85 35 102 50" fill="currentColor" opacity="0.18"/>
<!-- Eyes — mysterious, one slightly larger -->
<circle cx="80" cy="53" r="2" fill="currentColor" opacity="0.5"/>
<circle cx="91" cy="52" r="1.5" fill="currentColor" opacity="0.4"/>
<!-- Beak — 3/4 profile -->
<polygon points="75,58 67,55 74,62" fill="currentColor" opacity="0.35"/>
<!-- Left arm holding giant key -->
<line x1="63" y1="95" x2="30" y2="110" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Giant key -->
<circle cx="18" cy="108" r="12" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.4"/>
<line x1="30" y1="108" x2="55" y2="108" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.35"/>
<line x1="48" y1="108" x2="48" y2="118" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.3"/>
<line x1="53" y1="108" x2="53" y2="115" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.3"/>
<!-- Right arm holding padlock -->
<line x1="107" y1="95" x2="140" y2="85" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Padlock — big -->
<rect x="135" y="82" width="28" height="24" rx="4" fill="currentColor" opacity="0.3"/>
<path d="M141 82 L141 70 Q149 58 157 70 L157 82" stroke="currentColor" stroke-width="2.5" fill="none" opacity="0.35"/>
<circle cx="149" cy="95" r="3" fill="currentColor" opacity="0.2"/>
<line x1="149" y1="98" x2="149" y2="103" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<!-- Legs — long, cloak partly covering -->
<line x1="75" y1="130" x2="65" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="95" y1="130" x2="108" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet -->
<ellipse cx="63" cy="198" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="110" cy="198" rx="8" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok droneuse — looking up at flying drone, remote in hands -->
<svg class="shadok-droneuse" viewBox="0 0 160 210" fill="none" aria-hidden="true">
<!-- Drone above -->
<rect x="60" y="12" width="30" height="8" rx="3" fill="currentColor" opacity="0.3"/>
<!-- Drone arms -->
<line x1="55" y1="16" x2="35" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<line x1="95" y1="16" x2="115" y2="16" stroke="currentColor" stroke-width="2" stroke-linecap="round" opacity="0.25"/>
<!-- Propellers spinning -->
<ellipse cx="35" cy="14" rx="12" ry="3" fill="currentColor" opacity="0.2"/>
<ellipse cx="115" cy="14" rx="12" ry="3" fill="currentColor" opacity="0.2"/>
<!-- Propeller blur lines -->
<line x1="25" y1="12" x2="45" y2="12" stroke="currentColor" stroke-width="0.8" opacity="0.15"/>
<line x1="105" y1="12" x2="125" y2="12" stroke="currentColor" stroke-width="0.8" opacity="0.15"/>
<!-- Drone camera -->
<circle cx="75" cy="22" r="3" fill="currentColor" opacity="0.25"/>
<!-- Drone legs -->
<line x1="62" y1="20" x2="58" y2="28" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<line x1="88" y1="20" x2="92" y2="28" stroke="currentColor" stroke-width="1.5" opacity="0.2"/>
<!-- Body — upright, looking up -->
<ellipse cx="78" cy="115" rx="20" ry="26" fill="currentColor" opacity="0.25"/>
<!-- Head — tilted back looking up -->
<circle cx="78" cy="72" r="15" fill="currentColor" opacity="0.3"/>
<!-- Eyes — looking up at drone -->
<circle cx="74" cy="68" r="1.8" fill="currentColor" opacity="0.5"/>
<circle cx="83" cy="67" r="1.8" fill="currentColor" opacity="0.45"/>
<!-- Beak — pointing up -->
<polygon points="76,56 80,50 82,57" fill="currentColor" opacity="0.35"/>
<!-- Arms — holding remote control -->
<line x1="60" y1="108" x2="50" y2="128" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="96" y1="108" x2="106" y2="128" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Remote control in hands -->
<rect x="42" y="126" width="70" height="14" rx="4" fill="currentColor" opacity="0.3"/>
<circle cx="55" cy="133" r="3" fill="currentColor" opacity="0.2"/>
<circle cx="100" cy="133" r="3" fill="currentColor" opacity="0.2"/>
<!-- Joysticks -->
<line x1="55" y1="130" x2="55" y2="127" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.3"/>
<line x1="100" y1="131" x2="102" y2="128" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" opacity="0.3"/>
<!-- Legs — standing -->
<line x1="68" y1="138" x2="58" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="88" y1="138" x2="100" y2="195" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Feet -->
<ellipse cx="55" cy="198" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="103" cy="198" rx="9" ry="3" fill="currentColor" opacity="0.3"/>
</svg>
<!-- Shadok mécanicienne — lying under machine, legs sticking out, wrench, oil drops -->
<svg class="shadok-mecanicienne" viewBox="0 0 180 200" fill="none" aria-hidden="true">
<!-- Machine/server box above -->
<rect x="5" y="55" width="100" height="50" rx="5" fill="currentColor" opacity="0.2"/>
<rect x="12" y="62" width="35" height="12" rx="2" fill="currentColor" opacity="0.15"/>
<rect x="12" y="80" width="35" height="12" rx="2" fill="currentColor" opacity="0.15"/>
<!-- Machine details -->
<circle cx="20" cy="68" r="2" fill="currentColor" opacity="0.3"/>
<circle cx="20" cy="86" r="2" fill="currentColor" opacity="0.25"/>
<line x1="60" y1="65" x2="90" y2="65" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<line x1="60" y1="72" x2="85" y2="72" stroke="currentColor" stroke-width="1.5" opacity="0.15"/>
<!-- Body — lying flat under machine, only partial visible -->
<ellipse cx="80" cy="118" rx="25" ry="18" fill="currentColor" opacity="0.22" transform="rotate(90 80 118)"/>
<!-- Head under machine (barely visible) -->
<circle cx="55" cy="115" r="12" fill="currentColor" opacity="0.2"/>
<!-- Arm sticking out with wrench -->
<line x1="42" y1="115" x2="15" y2="105" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Wrench -->
<path d="M8 100 L15 105 L12 108 L5 103 Z" fill="currentColor" opacity="0.35"/>
<circle cx="5" cy="100" r="5" stroke="currentColor" stroke-width="1.5" fill="none" opacity="0.3"/>
<!-- Oil drops falling -->
<ellipse cx="70" cy="108" rx="2" ry="3" fill="currentColor" opacity="0.3"/>
<ellipse cx="85" cy="112" rx="1.5" ry="2.5" fill="currentColor" opacity="0.25"/>
<ellipse cx="62" cy="105" rx="1" ry="2" fill="currentColor" opacity="0.2"/>
<!-- Legs sticking out from under machine — the signature view -->
<line x1="90" y1="125" x2="130" y2="175" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<line x1="95" y1="120" x2="145" y2="165" stroke="currentColor" stroke-width="3" stroke-linecap="round" opacity="0.4"/>
<!-- Big feet sticking up -->
<ellipse cx="133" cy="178" rx="10" ry="4" fill="currentColor" opacity="0.35" transform="rotate(-25 133 178)"/>
<ellipse cx="148" cy="168" rx="10" ry="4" fill="currentColor" opacity="0.35" transform="rotate(-25 148 168)"/>
<!-- Beak visible from side -->
<polygon points="42,118 35,116 42,122" fill="currentColor" opacity="0.3"/>
<!-- Eye visible -->
<circle cx="50" cy="113" r="1.5" fill="currentColor" opacity="0.4"/>
</svg>
<div class="axis-scope axis-scope--num oiseaux-scene relative overflow-hidden section-padding">
<div class="container-content">
<header class="mb-12 text-center">
<p class="mb-2 font-mono text-sm tracking-widest text-primary uppercase">{{ content?.kicker }}</p>
<h1 class="page-title font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
{{ content?.title }}
<p class="relative mb-2 font-mono text-sm tracking-widest text-primary uppercase">
<!-- Phone: the title fills the width; the bird stands at the end of this line, on its baseline.
A flat bird (37-44 px tall at 72 px wide): 93 px separate this baseline from the sticky
header, and a perched bird keeps a void of its own height above it (rule f) -->
{{ content?.kicker }}<UiOiseauPose nom="codeuse" pose="perche" bout :w="72" mobile-seul />
</p>
<h1 class="page-title relative font-display font-bold tracking-tight" style="color: hsl(var(--color-text))">
<!-- At the end of the title, on its baseline (rule e, docs/da-oiseaux.md) -->
{{ content?.title }}<UiOiseauPose nom="droneuse" pose="perche" bout left="16px" :w="76" :seuil="1200" />
</h1>
<p class="mt-4 mx-auto max-w-2xl leading-relaxed" style="color: hsl(var(--color-text-muted))">
{{ content?.description }}
@@ -317,6 +20,7 @@
<div class="mx-auto max-w-3xl flex flex-col gap-6">
<!-- LPK sert l'axe numérique -->
<NuxtLink v-if="lpk" :to="lpk.to" class="lpk-card">
<UiOiseauPose nom="electricien" pose="marge-g" ecart="40px" :w="150" />
<span class="lpk-name">{{ lpk.name }}</span>
<span class="lpk-body">
<span class="lpk-full">{{ lpk.text }}</span>
@@ -330,6 +34,8 @@
:key="pillar.id"
class="pillar-card"
>
<UiOiseauPose v-for="o in OISEAUX_PILIER[pillar.id] ?? []" :key="`${o.nom}-${o.pose}`" v-bind="o" />
<!-- Overlay lien — toute la carte cliquable -->
<NuxtLink v-if="pillar.to" :to="pillar.to" class="pillar-overlay" :aria-label="pillar.label" tabindex="-1" />
@@ -382,11 +88,31 @@
</template>
<script setup lang="ts">
import type { OiseauPlace } from '~/utils/oiseauPose'
definePageMeta({
layout: 'default',
})
const { data: content } = await usePageContent('numerique')
// Birds by pillar, each next to the trade it is about (composition of 03/11)
const OISEAUX_PILIER: Record<string, OiseauPlace[]> = {
// The cards stand 16 px apart: no room above them for a perched bird (DA rule of 03/11).
// In the margins, no strict zigzag and several sizes (DA, 03/11 07h56): two stand at the
// bottom of their card on the right, the network admin is large behind Cloud libre
'logiciel-libre': [
{ nom: 'codeuse', pose: 'marge-d', ecart: '28px', w: 84, retourne: true },
],
'authentification-wot': [
{ nom: 'cryptographe', pose: 'marge-d', ecart: '64px', w: 112, retourne: true },
],
'cloud-libre': [
// out by the side of the card, not by its corner: the card is a link, and its rounded corner
// let 5 px of the drawing show on it (rule h)
{ nom: 'admin-reseau', pose: 'derriere', left: '-150px', bottom: '20px', w: 236 },
],
}
const { data: site } = await useSiteContent()
const lpk = computed(() => site.value?.lpk)
@@ -398,6 +124,7 @@ useSeoPage({
<style scoped>
.lpk-card {
position: relative;
display: flex;
align-items: center;
gap: 1.25rem;
@@ -578,143 +305,4 @@ useSeoPage({
color: hsl(var(--color-primary));
flex-shrink: 0;
}
.shadok-codeuse {
position: absolute;
left: 1%;
top: 4%;
width: clamp(70px, 10vw, 140px);
opacity: 0.24;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-codeuse 9s ease-in-out infinite;
}
.shadok-electricien {
position: absolute;
right: 1%;
top: 3%;
width: clamp(70px, 10vw, 130px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-electricien 11s ease-in-out infinite;
}
.shadok-soudeuse {
position: absolute;
left: 3%;
top: 40%;
width: clamp(70px, 10vw, 130px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-soudeuse 8s ease-in-out infinite;
}
.shadok-admin-reseau {
position: absolute;
right: 2%;
top: 35%;
width: clamp(70px, 10vw, 130px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-admin-reseau 10s ease-in-out infinite;
}
.shadok-imprimeuse3d {
position: absolute;
left: 2%;
bottom: 8%;
width: clamp(70px, 10vw, 135px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-imprimeuse3d 12s ease-in-out infinite;
}
.shadok-cryptographe {
position: absolute;
right: 1%;
bottom: 6%;
width: clamp(70px, 10vw, 130px);
opacity: 0.18;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-cryptographe 11s ease-in-out infinite;
}
.shadok-droneuse {
position: absolute;
left: 40%;
bottom: 2%;
width: clamp(70px, 10vw, 130px);
opacity: 0.2;
pointer-events: none;
color: hsl(var(--color-primary));
animation: shadok-float-droneuse 7s ease-in-out infinite;
}
.shadok-mecanicienne {
position: absolute;
right: 2%;
top: 60%;
width: clamp(70px, 10vw, 140px);
opacity: 0.22;
pointer-events: none;
color: hsl(var(--color-accent));
animation: shadok-float-mecanicienne 9s ease-in-out infinite;
}
@keyframes shadok-float-codeuse {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-8px); }
}
@keyframes shadok-float-electricien {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-10px) rotate(1deg); }
}
@keyframes shadok-float-soudeuse {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-7px) rotate(-0.8deg); }
}
@keyframes shadok-float-admin-reseau {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-9px); }
}
@keyframes shadok-float-imprimeuse3d {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-11px) rotate(0.5deg); }
}
@keyframes shadok-float-cryptographe {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-8px) rotate(-0.6deg); }
}
@keyframes shadok-float-droneuse {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-12px); }
}
@keyframes shadok-float-mecanicienne {
0%, 100% { transform: translateY(0) rotate(0deg); }
50% { transform: translateY(-7px) rotate(1.2deg); }
}
@media (max-width: 768px) {
.shadok-codeuse { display: none; }
.shadok-electricien { display: none; }
.shadok-soudeuse { display: none; }
.shadok-admin-reseau { display: none; }
.shadok-imprimeuse3d { display: none; }
.shadok-cryptographe { display: none; }
.shadok-droneuse { display: none; }
.shadok-mecanicienne { display: none; }
}
</style>
+18
View File
@@ -0,0 +1,18 @@
// Placement of a bird on its block (props of UiOiseauPose), for the per-page tables.
export interface OiseauPlace {
nom: string
pose?: 'perche' | 'marge-g' | 'marge-d' | 'derriere' | 'libre'
w?: number
left?: string
right?: string
top?: string
bottom?: string
ecart?: string
retourne?: boolean
mobile?: boolean
mobileSeul?: boolean
seuil?: 768 | 1024 | 1200
ton?: 'primary' | 'accent'
op?: number
bout?: boolean
}
+316
View File
@@ -0,0 +1,316 @@
// The 61 birds of the librodrome (studio DA, 2026-10-28) and the footer strip.
// ratio : aspect ratio of the drawing's box ; sol : where its ground line is, in % of the box height
// from the bottom (to stand a bird on an edge of the page : translateY(sol%)).
// Files : /images/oiseaux/<name>.svg
export const OISEAUX: Record<string, { ratio: string, sol: number, univers: string }> = {
"calligraphe": {
"ratio": "152.0 / 116.7",
"sol": 5.0,
"univers": "livre"
},
"cartonnier": {
"ratio": "170.0 / 113.5",
"sol": 5.2,
"univers": "livre"
},
"colporteur": {
"ratio": "152.0 / 119.6",
"sol": 5.1,
"univers": "livre"
},
"conteuse": {
"ratio": "175.3 / 155.6",
"sol": 3.9,
"univers": "livre"
},
"correcteur": {
"ratio": "152.0 / 112.8",
"sol": 5.4,
"univers": "livre"
},
"cycliste-livreur": {
"ratio": "170.0 / 97.6",
"sol": 6.0,
"univers": "livre"
},
"empileur": {
"ratio": "157.0 / 147.4",
"sol": 4.0,
"univers": "livre"
},
"factrice": {
"ratio": "171.8 / 135.8",
"sol": 4.5,
"univers": "livre"
},
"illustratrice": {
"ratio": "164.0 / 129.6",
"sol": 4.6,
"univers": "livre"
},
"lectrice": {
"ratio": "137.0 / 133.5",
"sol": 4.5,
"univers": "livre"
},
"libraire": {
"ratio": "170.0 / 133.6",
"sol": 4.6,
"univers": "livre"
},
"relieur": {
"ratio": "152.0 / 129.6",
"sol": 4.7,
"univers": "livre"
},
"typographe": {
"ratio": "157.0 / 131.6",
"sol": 4.6,
"univers": "livre"
},
"apicultrice": {
"ratio": "167.0 / 155.6",
"sol": 3.9,
"univers": "bassin"
},
"berger": {
"ratio": "172.0 / 133.0",
"sol": 4.4,
"univers": "bassin"
},
"boulangere": {
"ratio": "157.0 / 147.4",
"sol": 4.1,
"univers": "bassin"
},
"forgeron": {
"ratio": "158.0 / 160.7",
"sol": 3.7,
"univers": "bassin"
},
"maraichere": {
"ratio": "164.0 / 112.1",
"sol": 5.4,
"univers": "bassin"
},
"menuisier": {
"ratio": "164.0 / 115.1",
"sol": 5.2,
"univers": "bassin"
},
"pompeur-de-g1": {
"ratio": "159.0 / 115.9",
"sol": 5.1,
"univers": "bassin"
},
"potier": {
"ratio": "157.0 / 90.6",
"sol": 6.5,
"univers": "bassin"
},
"tisserand": {
"ratio": "162.0 / 113.6",
"sol": 5.3,
"univers": "bassin"
},
"vigneronne": {
"ratio": "157.0 / 138.6",
"sol": 4.4,
"univers": "bassin"
},
"admin-reseau": {
"ratio": "137.0 / 138.6",
"sol": 4.3,
"univers": "numerique"
},
"cafeine": {
"ratio": "166.0 / 137.4",
"sol": 4.3,
"univers": "numerique"
},
"canard-en-plastique": {
"ratio": "166.0 / 126.2",
"sol": 4.7,
"univers": "numerique"
},
"codeuse": {
"ratio": "164.0 / 95.6",
"sol": 6.3,
"univers": "numerique"
},
"cryptographe": {
"ratio": "172.9 / 147.5",
"sol": 4.0,
"univers": "numerique"
},
"debogueur": {
"ratio": "166.0 / 111.3",
"sol": 5.3,
"univers": "numerique"
},
"droneuse": {
"ratio": "169.0 / 152.2",
"sol": 3.9,
"univers": "numerique"
},
"electricien": {
"ratio": "174.0 / 152.8",
"sol": 4.0,
"univers": "numerique"
},
"imprimeuse-3d": {
"ratio": "166.0 / 146.0",
"sol": 4.1,
"univers": "numerique"
},
"le-manchot": {
"ratio": "166.0 / 109.6",
"sol": 5.4,
"univers": "numerique"
},
"porteur-de-serveur": {
"ratio": "137.0 / 140.5",
"sol": 4.3,
"univers": "numerique"
},
"soudeuse": {
"ratio": "166.0 / 114.6",
"sol": 5.1,
"univers": "numerique"
},
"toile-de-confiance": {
"ratio": "137.3 / 159.8",
"sol": 3.8,
"univers": "numerique"
},
"avocate": {
"ratio": "137.0 / 141.6",
"sol": 4.3,
"univers": "cite"
},
"capitaine": {
"ratio": "157.0 / 116.5",
"sol": 5.1,
"univers": "cite"
},
"cartographe": {
"ratio": "151.0 / 123.6",
"sol": 4.9,
"univers": "cite"
},
"comedien": {
"ratio": "137.0 / 150.0",
"sol": 3.9,
"univers": "cite"
},
"juge": {
"ratio": "137.0 / 154.9",
"sol": 3.9,
"univers": "cite"
},
"matelot": {
"ratio": "172.0 / 115.7",
"sol": 5.1,
"univers": "cite"
},
"mime": {
"ratio": "137.0 / 112.8",
"sol": 5.3,
"univers": "cite"
},
"vigie": {
"ratio": "184.0 / 154.0",
"sol": 3.9,
"univers": "cite"
},
"accordeoniste": {
"ratio": "146.3 / 135.6",
"sol": 4.5,
"univers": "scene"
},
"acrobate": {
"ratio": "137.0 / 153.4",
"sol": 3.9,
"univers": "scene"
},
"batteur": {
"ratio": "164.0 / 153.6",
"sol": 3.9,
"univers": "scene"
},
"clown": {
"ratio": "159.4 / 127.9",
"sol": 4.7,
"univers": "scene"
},
"cracheur-de-feu": {
"ratio": "137.0 / 141.0",
"sol": 4.2,
"univers": "scene"
},
"funambule": {
"ratio": "170.0 / 162.9",
"sol": 3.7,
"univers": "scene"
},
"jongleur": {
"ratio": "137.0 / 148.3",
"sol": 4.0,
"univers": "scene"
},
"marionnettiste": {
"ratio": "164.0 / 133.6",
"sol": 4.5,
"univers": "scene"
},
"regisseur": {
"ratio": "168.0 / 127.9",
"sol": 4.7,
"univers": "scene"
},
"trapeziste": {
"ratio": "137.0 / 163.6",
"sol": 3.7,
"univers": "scene"
},
"alchimiste": {
"ratio": "164.0 / 133.2",
"sol": 4.6,
"univers": "musique"
},
"danseur": {
"ratio": "162.0 / 159.6",
"sol": 3.8,
"univers": "musique"
},
"dj": {
"ratio": "164.0 / 155.6",
"sol": 3.8,
"univers": "musique"
},
"la-balance": {
"ratio": "170.3 / 150.4",
"sol": 3.9,
"univers": "musique"
},
"penseur": {
"ratio": "162.0 / 150.9",
"sol": 3.9,
"univers": "musique"
},
"philosophe": {
"ratio": "162.0 / 155.2",
"sol": 3.8,
"univers": "musique"
},
"trompettiste": {
"ratio": "164.0 / 158.1",
"sol": 3.7,
"univers": "musique"
},
"frise": {
"ratio": "400 / 80",
"sol": 6.3,
"univers": "pied de page"
}
}
+40 -1
View File
@@ -41,10 +41,49 @@ Ce que fait le code :
- Le curseur touché repart d'en bas et monte en 1,1 s à son cran : numérique 0,75, économique 0,50,
citoyenne 0,667. Il y reste.
- Le panneau de l'axe s'affiche au même geste.
- Les autres curseurs ne bougent pas. Un curseur jamais touché reste là où il était.
- La main ne fait descendre aucun autre curseur :
- un curseur déjà touché reste à son cran ;
- au premier geste, un curseur jamais touché que la rotation faisait descendre s'arrête là où il
est ;
- un curseur jamais touché que la rotation faisait monter finit sa montée, au niveau que la
rotation lui donnait (le cran pour l'axe mis en avant), puis il y reste.
Décision d'orch du 03/11 à 13h10, qui découle de « ne fait pas descendre les autres ».
- Un nouveau survol rejoue la montée.
- Avant tout geste, l'animation du 29/09 continue : la rotation et la dérive des curseurs bas. L'axe
mis en avant monte à son cran, et non plus vers 0,9. C'est une décision d'orch du 03/11 à 05h51, qui
découle de la graduation : l'animation et la main donnent les mêmes niveaux.
- Sous `prefers-reduced-motion`, il n'y a aucune transition, mais les crans sont les mêmes.
- Un défilement au doigt qui part d'un curseur ne compte pas comme un survol.
## Les oiseaux (identité du studio DA)
Code : `app/components/ui/OiseauPose.vue` (placement), `app/components/ui/Oiseau.vue` et
`app/utils/oiseaux.ts` (kit du studio DA, copiés tels quels). Les places sont dans chaque page.
### 03/11/2026, 05h08 (relayée mot pour mot par la session orch)
> « fais un effort sur le positionnement des oiseaux, là ils sont en colonne, c'est trop régulier,
> trop papier peint, fais mieux que ça, peuple le fond intelligemment par rapport aux contenus, varie
> les tailles et les emplacements »
### 03/11/2026, vers 05h45 (réponses au formulaire, relayées par la session orch)
- « Posés sans flotter » : un oiseau posé sur une arête est immobile sur sa ligne de sol. Seul l'oiseau
de fond, derrière une carte, peut garder un léger mouvement.
- « Un oiseau par page » sous 768 px.
- « Les 61 tout de suite » : les places du plan, plus les oiseaux restants sur les sous-pages.
- Pour le kit : « Oui, à intégrer » (au formulaire du studio DA).
Ce que fait le code :
- Chaque oiseau est accroché au bloc dont il fait le métier, et se tient sur une vraie arête :
- perché sur le haut d'une carte ;
- près d'un titre ;
- en marge, à côté de son bloc ;
- derrière une carte, en grand et pâle.
- Jamais deux fois le même oiseau sur une page.
- Entre 768 et 1199 px, seuls les oiseaux perchés restent.
- Sous 768 px, au plus un oiseau par page.
Les avis du studio DA et des relectures du 03/11 (07h00, 07h56 et 08h14), relayés par la session
orch, sont dans `docs/da-oiseaux.md` : ce ne sont pas les mots d'Yvv.
+200
View File
@@ -0,0 +1,200 @@
# Oiseaux — avis du studio DA et des relectures
Ce fichier garde les avis du studio DA et des relectures sur la place des oiseaux, relayés par la
session orch. Ce ne sont pas les mots d'Yvv : ses consignes, datées et mot pour mot, sont dans
`docs/consignes-yvv.md` (section « Les oiseaux »).
Code : `app/components/ui/OiseauPose.vue` (placement), `app/components/ui/Oiseau.vue` et
`app/utils/oiseaux.ts` (kit du studio DA). Les places sont dans chaque page.
### 03/11/2026, 07h00 : avis du studio DA (relayé par la session orch, ce ne sont pas les mots d'Yvv)
« kit : ok », avec trois constats de composition :
- trop d'oiseaux autour du seul bloc de productions-collectives ;
- des perchés qui mordent sur la carte du dessus (numérique) ;
- l'un d'eux mord aussi sur le coin d'une carte à 375 px.
La règle de DA, pour toutes les pages : un oiseau perché n'a sa place que s'il y a, au-dessus de
l'arête, un vide au moins égal à sa hauteur. Sinon, il va en marge ou derrière la carte.
La relecture du même jour ajoute : pas trois oiseaux sur la même verticale dans une marge.
Ce que fait le code depuis :
- Aucun oiseau perché entre deux cartes rapprochées. Ceux qui y étaient sont passés en marge ou
derrière la carte.
- Au téléphone, l'oiseau de la page se tient au bout de la ligne de l'intitulé, au-dessus du titre.
- Un perché dont le bloc n'a de vide au-dessus qu'une fois la grille en deux colonnes ne s'affiche
qu'à partir de 1024 px (`seuil`).
- Productions-collectives garde 4 oiseaux. Les autres sont partis sur des pages qui en avaient peu :
- monnaie-libre : boulangère, vigneronne ;
- tarifs-eau : potier ;
- décision : tisserand ;
- cloud-libre : imprimeuse 3D.
- Toujours les 61 oiseaux rendus sur le site.
### 03/11/2026, 07h56 : second avis du studio DA, et relecture de 08h14 (relayés par la session orch)
DA : « composition : à reprendre (numérique et commande seulement) ».
- Numérique : les 4 oiseaux de marge font un zigzag gauche, droite, gauche, droite, à pas égal et
de même taille. C'est le « trop régulier, papier peint » d'Yvv sous une autre forme.
- Commande : chaque carte a un oiseau à gauche et un à droite, à la même hauteur.
Deux règles de DA en découlent :
- pas plus de deux alternances gauche-droite de suite à pas presque égal (moins de 20 % d'écart) ;
- dès qu'une page a trois oiseaux ou plus, au moins deux tailles différentes.
La relecture ajoute qu'un oiseau ne se pose pas sur le haut de la boîte d'un titre : ce n'est pas
une arête visible. Un oiseau de marge ne se tient pas non plus à mi-hauteur du texte.
Ce que fait le code depuis :
- Un oiseau de marge a les pieds sur une vraie ligne : le bas ou le haut de son bloc, ou d'une carte
de ce bloc. C'est la consigne d'Yvv « posés sans flotter ».
- Un oiseau près d'un titre se tient sur sa dernière ligne, ou au bout de la ligne de l'intitulé.
- Numérique : électricien en M, codeuse et cryptographe au bas de leur carte, à droite,
administrateur réseau en grand derrière Cloud libre.
- Commande : un seul côté par carte. Le cycliste est à gauche de la première, le libraire en grand
derrière la seconde, à droite. La lectrice se tient sur le sac de l'icône. Le cartonnier est parti
sur la ligne qui clôt chaque chapitre, l'empileur sur le sommaire du livre.
### 03/11/2026, 13h10 : relecture (relayée par la session orch, ce ne sont pas les mots d'Yvv)
La relecture de fb8c71f à 16d6607 conclut « à reprendre », avec cinq constats :
- /economique : la maraîchère et la balance font une paire, aux sols presque à la même hauteur ;
- /numerique/authentification-wot : la toile de confiance est « derrière » un bloc sans fond, et du
texte la traverse ;
- les chapitres : le cartonnier est posé sur un filet que rien ne trace ;
- /evenement : le régisseur et l'acrobate font une paire ;
- le sommaire du livre : trois oiseaux dans une même bande de la marge droite.
Trois règles en découlent :
- pas deux oiseaux de part et d'autre dont les sols sont à moins de 40 px l'un de l'autre ;
- une ligne visible, c'est une bordure, un fond différent de ce qu'il y a dessous, le bas d'une
carte qui a un fond, ou une ligne de texte ;
- « derrière une carte » demande une carte au fond opaque.
Ce que fait le code depuis :
- /economique : la balance sort de derrière le bloc du livre, à gauche, à mi-hauteur.
- Authentification : la toile de confiance est petite, en marge, sur la dernière ligne des étapes.
- Logiciel libre : le débogueur se tient aussi sur la dernière ligne des étapes.
- Chapitres : le filet au-dessus de précédent et suivant est tracé ; le cartonnier s'y pose.
- /evenement : le régisseur reste seul près de « Format & lieu ». L'acrobate se tient sur la ligne
du leitmotiv, dans l'en-tête, avant le texte, à gauche.
- Sommaire du livre : l'empileur est plus loin dans la marge, l'illustratrice dépasse moins de sa
carte.
- Monnaie libre : la vigneronne sort de derrière le haut du bloc de texte, qui a un fond.
## Règles mesurées (liste fermée, 03/11 à 14h41)
Liste fixée par la session orch le 03/11 à 14h41, seuils confirmés par DA le 03/11. Ce ne sont pas
les mots d'Yvv. Une composition qui tient ces règles est finie : on n'en ajoute pas d'autre.
Comment on mesure :
- Largeurs : 375 px, de 376 à 767 px par pas de 16, de 768 à 1600 px par pas de 8.
- Un oiseau compte quand il est affiché.
- Ses pixels peints : son dessin (le SVG du kit) rendu à sa taille et retourné s'il est en miroir.
Un pixel compte s'il a au moins 32/255 d'opacité. Pour un oiseau derrière une carte, on retire
les pixels cachés par un fond opaque, coins arrondis compris.
- Son sol : la ligne de sol du dessin (`sol` du kit, en % de la hauteur depuis le bas). Pour un
oiseau derrière une carte qui en cache les pieds, le bas de ce qui se voit de lui.
- Une ligne de texte se mesure à sa ligne de base, d'après les métriques de sa police.
- Côté : gauche ou droite du milieu de la fenêtre, selon le centre de l'oiseau.
- Oiseau de marge : posé en marge, ou dont le centre est hors de son bloc. Un oiseau « libre »
dont le centre sort de son bloc est donc un oiseau de marge. Un oiseau derrière une carte reste
« derrière », même si son centre sort de la carte : son sol est le bas de ce qui se voit de lui
(décisions d'orch, 03/11 après 17h58).
Les règles :
- a. Tailles : S sous 100 px de large, M de 100 à 179 px, L à partir de 180 px. Dès que trois
oiseaux sont visibles, au moins deux tailles.
- b. Zigzag : pas trois alternances gauche-droite de suite (de haut en bas) quand chaque pas est à
moins de 20 % du pas moyen.
- c. Paire : deux oiseaux de part et d'autre du milieu n'ont pas leurs sols à moins de 40 px l'un
de l'autre. Où qu'ils soient, deux sols ne sont jamais à moins de 12 px.
- d. Colonne : trois oiseaux de marge du même côté ne partagent aucune bande verticale de plus de
12 px, mesurée sur leurs dessins.
- e. Sol : un oiseau de marge ou perché a son sol à 12 px au plus d'une ligne visible. Cela vaut
pour un oiseau « libre » dont le centre sort de son bloc (orch, 03/11 après 17h58).
- Ligne visible : une bordure non nulle, un fond différent de celui du dessous (le bas d'une
carte qui a un fond, le haut du bloc sur lequel il se tient, une image), ou une ligne de texte
de son bloc.
- Un oiseau « au bout du titre » est à 48 px au plus de la fin du texte de cette ligne (ou de
son début s'il se tient avant), et son sol à 12 px au plus de la ligne de base du titre.
- Au-delà, il relève d'une autre règle : la marge ; perché sur le bloc d'en dessous, le sol à
12 px au plus de son arête haute ; ou derrière une carte.
- f. Perché : jamais sur la moitié haute d'un titre ou d'un paragraphe. Au-dessus de l'oiseau, un
vide au moins égal à sa hauteur. Il se mesure du haut de son dessin à la plus basse des lignes de
texte ou des blocs dont la boîte passe au-dessus de sa largeur peinte (précision de DA, 03/11
après 17h35 : l'oiseau ne tient pas seulement dans le vide, il en garde autant au-dessus de lui).
Les lignes du titre où il se tient comptent aussi, celles au-dessus de sa ligne. En haut de page,
l'en-tête collant compte parmi ces blocs.
- g. Derrière : la part de l'oiseau qui est dans son bloc est couverte par un fond opaque (opacité
du fond ≥ 0,9). « Dans son bloc » s'entend du rectangle du bloc : aucun pixel peint ne reste à
découvert dans ce rectangle, découpe d'un coin arrondi comprise (décision d'orch, 03/11 après
17h58).
- h. Aucun pixel peint sur un texte ou un lien, trait de sol compris.
- i. Sous 768 px, au plus un oiseau par page. Les 61 oiseaux visibles au moins une fois à 1440 px.
Jamais deux fois le même sur une page. Aucun sous 72 px de large.
Hors liste, le contrôle garde les règles techniques du kit :
- aucun oiseau rogné ;
- aucun oiseau hors de la page ;
- les opacités ;
- jamais de miroir pour le calligraphe et le typographe ;
- ni dégradé ni filtre ;
- aucun débordement de la page ou de l'en-tête ;
- un oiseau ne mord pas sur un bloc plein ;
- aucune erreur console.
Code : `app/components/ui/OiseauPose.vue`. La pose `bout` sert à l'oiseau au bout d'un titre : une
ancre sans taille dans le texte, sur sa ligne de base.
Ce que la liste a changé (03/11, après b6143c5) :
- Les oiseaux près d'un titre se tiennent au bout de sa ligne, sur sa ligne de base (pose `bout`) :
- trapéziste, clown et marionnettiste (/evenement) ;
- DJ (/en-musique) ;
- droneuse (/numerique) ;
- vigie (/citoyenne) ;
- alchimiste (/gratewizard) ;
- relieur (/economique/modele-eco), avant le titre ;
- l'oiseau de l'intitulé au téléphone sur chaque page.
- Accueil : l'accordéoniste passe au bout du titre « Le librodrome est une invitation ». Sur la
carte de l'événement, il se tenait à la hauteur de la lectrice et son trait de sol touchait le
lien.
- Authentification : le pompeur de Ğ1 est perché sur la carte du projet. Il y a 74 px de vide
au-dessus, à toutes les largeurs.
- Productions collectives : la soudeuse a les pieds sur la ligne de base du titre.
- /numerique et /citoyenne : l'administrateur réseau et le cartographe sortent par le côté de leur
carte, plus par un coin (la carte est un lien).
Ce que la liste a changé (03/11, après bb8fad9 ; la règle f mesurée au-dessus du dessin) :
- Accueil :
- le DJ se tient derrière le pupitre de la console, comme derrière ses platines : seule sa tête
dépasse. Perché sur le pupitre, sous l'en-tête, il n'avait pas sa hauteur de vide au-dessus ;
- l'accordéoniste passe en S (72 px), à partir de 1200 px, 8 px sous la ligne de base ;
- la factrice passe à 76 px ;
- la lectrice ne sort plus de derrière la carte du livre. Descendue de 20 px, loin de la fin de
la première ligne du chapeau (DA, 03/11), elle ne montrait plus que sa bulle. Ni la marge de
page ni la gouttière ne la laissent sortir par le côté (DA, 03/11 après 19h : « Je ne veux pas
d'un oiseau réduit à un morceau »). Elle reste sur la page commande.
- Au téléphone, l'oiseau de l'intitulé est un oiseau plat, l'en-tête collant laissant 93 px :
codeuse (/numerique), maraîchère (/economique), potier (/citoyenne). Sur productions
collectives, le cycliste livreur remplace le menuisier sous 768 px.
- Authentification : le pompeur de Ğ1 passe en marge droite, les pieds sur l'arête haute de la
carte du projet. Perché sur la carte, il n'avait que 11 px de vide au-dessus de sa tête (DA).
- Tarifs de l'eau : le comédien, de même, en marge droite sur l'arête haute de la carte.
- Commande : la lectrice quitte le sac, sous l'en-tête, pour la marge droite, sur l'arête haute de
la première carte.
- /en-musique : le danseur passe en S (80 px).
- /evenement :
- l'acrobate se tient avant la devise, plus étroite que le leitmotiv ;
- le régisseur passe en S, les pieds sur l'arête des cartes ;
- le clown passe en M (108 px), pour deux tailles entre 768 et 1199 px ;
- le marionnettiste se perche sur le filet du pied de page, à partir de 1200 px : sous
« Espaces & programme », il n'y a pas la place, et chaque rangée de cartes ne porte qu'un
oiseau. C'est le seul oiseau de la page hors de son bloc (orch, option 1, 03/11). Son décalage
vient du bloc du sceau du layout (`--seal-block`), et le contrôle vérifie qu'il est sur le filet.
- Chapitres : le calligraphe se tient sur le filet du titre, le typographe sur le filet de la
navigation, tous deux dans la marge gauche ; le cartonnier, en marge droite, au pied des boutons
PDF et chansons. Ils n'ont plus de hauteur en %.
- Porteur de serveur (authentification, cloud libre) et administrateur réseau (cloud libre) :
décalés hors de la découpe du coin arrondi de leur carte.
+2
View File
@@ -92,6 +92,8 @@ export default defineNuxtConfig({
htmlAttrs: { lang: 'fr' },
link: [
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico', sizes: '48x48' },
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
{ rel: 'preconnect', href: 'https://fonts.bunny.net' },
{
rel: 'stylesheet',
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

+1 -9
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 45 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 112 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 24 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 28 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

Some files were not shown because too many files have changed in this diff Show More