Corrections UI, refonte podium, page Roulette, navigation en menu unique

Upload de photo (signup + profil) :
- Remplace le contrôle natif du navigateur par un composant entièrement
  en français : input masqué (sr-only) déclenché par un vrai bouton
  (icône appareil photo + « Choisir une photo »/« Changer ma photo »),
  nom du fichier sélectionné affiché (tronqué) avec une croix pour le
  retirer, « Aucune photo sélectionnée » sinon.

Header : plus jamais masqué sur mobile
- "LE TRIBUNAL" et le chip utilisateur (photo + pseudo + points) restent
  visibles à toutes les tailles, y compris 320px — tailles de police et
  troncature au lieu de `hidden`. Vérifié sans débordement horizontal à
  320/375/414/768px.

Navigation : tout dans le menu déroulant
- Retire les onglets du header (ne garde que logo + chip). Le menu
  déroulant du chip contient désormais toutes les pages (Le Classement,
  La Roulette, Le Crieur, Mon profil, Le Conseil des Archontes si juge)
  avec une icône chacune (components/icons.tsx), fermeture au clic
  extérieur et à Échap, entrée de la page courante surlignée,
  déconnexion séparée en oxblood.

Podium :
- Contrôles de points en icônes ✓/✕ rondes (40×40, olive/oxblood) sous
  la carte du membre, aria-label + tooltip — uniquement sur le podium,
  le reste du classement garde ses contrôles textuels.
- Refonte visuelle : socles marbre veiné avec arête lumineuse
  (.pedestal-marble), chiffres romains gravés (toRoman(), .engraved),
  couronne de laurier + halo doré sur le 1er, accents argent/bronze sur
  2e/3e, points en gros chiffres dorés, animation d'entrée décalée par
  socle (~600ms, respecte prefers-reduced-motion).

Nouvelle page /roulette :
- Tirage aléatoire uniforme calculé avant l'animation (le random ne sert
  qu'à choisir, l'animation ne fait que le mettre en scène). Carrousel
  horizontal des avatars avec décélération (cubic-bezier long), repère
  central doré, révélation finale (couronne + halo + zoom) avec le
  pseudo en Cinzel. Filtre Citoyens/tous, bouton Rejouer, dernier élu
  affiché, prefers-reduced-motion affiche le résultat directement.
  Route protégée par le proxy comme les autres pages.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Valentin ROBIN
2026-07-12 20:44:32 +02:00
parent 9f4e58019b
commit 0ea6a36189
13 changed files with 629 additions and 87 deletions
+82
View File
@@ -10,6 +10,8 @@
--oxblood: #a5342a;
--sea: #2e6e7e;
--olive: #5e6b3b;
--silver: #c7cdd6;
--bronze: #b08d57;
--text-marble: #2a2116;
--text-mut: #7a6a4c;
@@ -27,6 +29,8 @@
--color-oxblood: var(--oxblood);
--color-sea: var(--sea);
--color-olive: var(--olive);
--color-silver: var(--silver);
--color-bronze: var(--bronze);
--color-text-marble: var(--text-marble);
--color-text-mut: var(--text-mut);
--color-background: var(--background);
@@ -83,3 +87,81 @@ body {
.animate-points-flash {
animation: points-flash 900ms ease-out;
}
/* Chiffre romain "gravé" dans le socle du podium. */
.engraved {
text-shadow:
0 1px 0 rgba(255, 255, 255, 0.35),
0 -1px 1px rgba(0, 0, 0, 0.35);
}
/* Socle du podium : marbre veiné + arête lumineuse en haut. */
.pedestal-marble {
position: relative;
background:
linear-gradient(100deg, transparent 0%, rgba(255, 255, 255, 0.12) 18%, transparent 32%),
linear-gradient(80deg, transparent 55%, rgba(255, 255, 255, 0.08) 68%, transparent 80%),
linear-gradient(180deg, color-mix(in srgb, var(--marble) 92%, white) 0%, var(--marble) 40%, var(--marble-2) 100%);
box-shadow:
inset 0 2px 0 rgba(255, 255, 255, 0.55),
0 10px 18px -6px rgba(10, 27, 51, 0.55);
}
.podium-glow {
box-shadow: 0 0 30px 6px color-mix(in srgb, var(--gold-bright) 45%, transparent);
}
@media (prefers-reduced-motion: no-preference) {
@keyframes podium-rise {
0% {
opacity: 0;
transform: translateY(28px) scale(0.92);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.animate-podium-rise {
animation: podium-rise 600ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
@keyframes wreath-pop {
0% {
opacity: 0;
transform: scale(0.5) translateY(6px);
}
70% {
opacity: 1;
transform: scale(1.08) translateY(0);
}
100% {
transform: scale(1) translateY(0);
}
}
.animate-wreath-pop {
animation: wreath-pop 500ms cubic-bezier(0.2, 0.7, 0.3, 1) 500ms both;
}
@keyframes reveal-pop {
0% {
opacity: 0;
transform: scale(0.82);
box-shadow: 0 0 0 0 color-mix(in srgb, var(--gold-bright) 0%, transparent);
}
60% {
opacity: 1;
transform: scale(1.04);
}
100% {
transform: scale(1);
box-shadow: 0 0 40px 8px color-mix(in srgb, var(--gold-bright) 45%, transparent);
}
}
.animate-reveal {
animation: reveal-pop 700ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
}
}