Étend la DA "Polaroid Néon" aux 4 derniers écrans
Upload invité (priorité haute, full traitement : fond #12100E, CTA corail, General Sans/Inter, touche Caveat sur le message de succès), galerie admin (exception admin du skill : sobre, sombre, cartes #1E1B18, pas de rotation/confettis, corail réservé aux CTA), générateur QR (même exception admin, traitement minimal), carton imprimable (reste clair — un support papier n'a pas vocation à avoir un fond noir — mais adopte les polices et l'accent corail de la nouvelle DA, contraste recalculé pour l'impression). Double thème clair/sombre de l'ancienne DA retiré au profit d'un thème unique sombre, cohérent avec src/galerie/ (premier écran de cette DA, déjà validé). Dégradés de texte et halo de fond de l'ancienne DA retirés (skill : jamais de glow/neon artificiel). Contrastes vérifiés par calcul WCAG AA pour toutes les nouvelles combinaisons. Chemins d'assets absolus et pattern [hidden]/display vérifiés sur les 4 écrans (bugs déjà rencontrés deux fois en prod).
This commit is contained in:
+5
-6
@@ -12,12 +12,11 @@
|
||||
lors du déploiement, hors scope de ce fichier front.
|
||||
-->
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<!-- Deux meta theme-color (au lieu d'une seule) : teinte la barre
|
||||
navigateur/PWA selon le thème système, en cohérence avec le mode sombre
|
||||
ajouté passe 3 (voir src/e/style.css). -->
|
||||
<meta name="theme-color" content="#faf6f0" media="(prefers-color-scheme: light)">
|
||||
<meta name="theme-color" content="#1b120b" media="(prefers-color-scheme: dark)">
|
||||
<link rel="preload" href="/vendor/fonts/fraunces-latin-600-normal.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<!-- Thème unique sombre "Polaroid Néon" (voir src/e/style.css) : une seule
|
||||
meta theme-color, comme src/galerie/index.html. -->
|
||||
<meta name="theme-color" content="#12100E">
|
||||
<link rel="preload" href="/vendor/fonts/generalsans-700.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/vendor/fonts/caveat-latin-variable.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="stylesheet" href="/e/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
+201
-356
@@ -1,200 +1,101 @@
|
||||
/* Page upload invité — mobile-first, sans dépendance externe.
|
||||
Système de design partagé avec la galerie admin (src/admin/gallery/style.css) :
|
||||
mêmes tokens de couleur/rayon/ombre, pour une identité cohérente entre les
|
||||
deux écrans (voir docs/decisions.md pour le contexte produit).
|
||||
/* Page upload invité — direction artistique "Polaroid Néon"
|
||||
(.claude/skills/photobooth-da/SKILL.md). Remplace les 3 passes DA
|
||||
précédentes (palette corail/prune/doré + Fraunces, voir historique
|
||||
git) : cet écran suit désormais src/galerie/style.css comme référence
|
||||
de cohérence (premier écran construit dans cette DA, validé par
|
||||
Kévin — "c'est vraiment top comme ça !").
|
||||
|
||||
Direction créative (passe 2, 2026-09-16) — voir rapport de la passe pour
|
||||
le détail complet, résumé ici :
|
||||
Retour direct de Kévin sur la 1ère passe : trop "démo sage", pas assez
|
||||
"envie de participer". Consigne resserrée en cours de route : viser
|
||||
PUNCHY / FRIENDLY / FUN, pas un premium feutré silencieux. Traduction :
|
||||
- Palette plus affirmée : on garde la famille chaude (cohérente avec
|
||||
l'identité perso de Kévin / Rêves Liquides) mais on la sature — un
|
||||
corail vif en primaire plutôt que le brun terracotta sourd de la V1,
|
||||
avec un prune et un doré en accents secondaires (confettis, badges).
|
||||
- Formes plus rondes/organiques (rayons agrandis, boutons pilule).
|
||||
- Micro-animations qui ont du peps : coche qui "pop" avec rebond,
|
||||
confettis colorés au succès, spinner de chargement, easing "overshoot"
|
||||
sur les interactions plutôt que du linear plat.
|
||||
- Ton de voix plus souriant dans les micro-copies (succès, limite
|
||||
atteinte) — cf. src/e/upload.js pour les textes.
|
||||
- Police d'accent Fraunces (serif à forte personnalité, chaleureuse et
|
||||
un peu "pop") en plus de la pile système pour les titres/moments clés
|
||||
— auto-hébergée en .woff2, 2 graisses (~41 Ko au total), voir
|
||||
src/vendor/fonts/ et src/vendor/NOTICE.md. Le corps de texte reste
|
||||
100% système (poids nul).
|
||||
Choix pris pendant cette passe, à signaler à Kévin :
|
||||
- Thème unique sombre (color-scheme: dark), comme src/galerie/style.css,
|
||||
plutôt que le double thème clair/sombre (prefers-color-scheme) de
|
||||
l'ancienne DA. Le skill ne demande nulle part de garder un thème
|
||||
clair, et le premier écran validé n'en a pas — cohérence retenue
|
||||
plutôt qu'une redondance non demandée. À confirmer si un thème clair
|
||||
est en fait souhaité pour cet écran précis.
|
||||
- Titre et éléments de "chrome" en texte plein (pas de dégradé
|
||||
corail→doré comme l'ancienne DA) : le skill met en garde contre le
|
||||
"glow/neon CSS artificiel" et l'écran de référence (galerie) n'utilise
|
||||
aucun dégradé de texte ni halo radial en fond — même logique
|
||||
appliquée ici pour rester cohérent plutôt que de réintroduire cet
|
||||
effet.
|
||||
|
||||
Passe 3, 2026-09-16 — retour Kévin : "top ! rajoute des animations, de la
|
||||
couleur [...] brainstorm sur le choix des couleurs et de la typo, ajoute
|
||||
un mode sombre [...] fait moi quelque chose de vendeur et de friendly
|
||||
(type iPhone)." Palette/typo déjà validées passe 2 : le brainstorm de
|
||||
cette passe (voir rapport de passe pour le détail des 2 directions
|
||||
alternatives écartées) a confirmé la famille corail/prune/doré + Fraunces
|
||||
plutôt que d'ajouter de nouvelles teintes ou une police supplémentaire —
|
||||
"plus de couleur" est obtenu en réutilisant plus largement cette même
|
||||
palette (halo radial en fond, focus ring teinté, confettis étoffés)
|
||||
plutôt qu'en important une 4e couleur qui romprait l'identité perso de
|
||||
Kévin. Traduction concrète de cette passe :
|
||||
- Mode sombre réel via prefers-color-scheme (pas d'inversion brute) :
|
||||
fond brun quasi-noir (jamais bleu-nuit, pour rester dans la famille
|
||||
chaude de la marque), texte/accents reclaircis et vérifiés au ratio de
|
||||
contraste (WCAG AA, cf. rapport de passe pour le détail des calculs).
|
||||
- Niveau de finition "type iPhone" au sens exécution, pas esthétique iOS
|
||||
: pas de glassmorphism/blur ni de police système Apple. Concrètement :
|
||||
easing dédié aux transitions d'état (--ease-standard, plus posé que le
|
||||
--ease-bounce déjà en place et réservé aux pops/rebonds), halo de
|
||||
couleur subtil en arrière-plan de page, focus ring teinté sur les
|
||||
champs, micro-interactions de hover en plus du :active existant
|
||||
(uniquement sous @media (hover: hover), donc jamais sur mobile tactile
|
||||
— l'invité ne voit que les états focus/active déjà en place), entrées
|
||||
en fondu/translation des sections principales au chargement. */
|
||||
Contrastes vérifiés par calcul WCAG AA (même méthode que
|
||||
src/galerie/style.css) : texte clair (#FAF6F0/#E8DFD3) sur fond sombre
|
||||
(#12100E) est très largement au-dessus du seuil ; texte sombre (#12100E)
|
||||
sur les 3 couleurs d'accent (corail/jaune/vert) passe confortablement
|
||||
(6.3:1 à 13.2:1) — utilisé systématiquement pour le texte des CTA en
|
||||
couleur pleine. Les fonds teintés à faible opacité (états erreur/limite/
|
||||
succès) restent très proches du noir une fois mélangés à #12100E ; le
|
||||
texte de ces blocs reste donc en couleur claire standard (--color-text/
|
||||
--color-muted), jamais en couleur d'accent pleine, par prudence. */
|
||||
|
||||
@font-face {
|
||||
font-family: "Fraunces";
|
||||
src: url("/vendor/fonts/fraunces-latin-600-normal.woff2") format("woff2");
|
||||
font-weight: 600;
|
||||
font-family: "General Sans";
|
||||
src: url("/vendor/fonts/generalsans-700.woff2") format("woff2");
|
||||
font-weight: 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
|
||||
U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Fraunces";
|
||||
src: url("/vendor/fonts/fraunces-latin-500-italic.woff2") format("woff2");
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
font-family: "Caveat";
|
||||
src: url("/vendor/fonts/caveat-latin-variable.woff2") format("woff2");
|
||||
font-weight: 400 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
src: url("/vendor/fonts/inter-latin-variable.woff2") format("woff2");
|
||||
font-weight: 400 700;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
|
||||
U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
|
||||
:root {
|
||||
/* "light dark" (et non "light" seul) : indique au navigateur que les deux
|
||||
thèmes sont pris en charge, pour que les contrôles natifs (scrollbar,
|
||||
éventuels <select>) s'adaptent aussi, pas seulement nos propres
|
||||
couleurs. Les valeurs ci-dessous sont le thème clair ; le thème sombre
|
||||
est redéfini intégralement dans le bloc @media (prefers-color-scheme:
|
||||
dark) plus bas — jamais un simple filtre d'inversion. */
|
||||
color-scheme: light dark;
|
||||
color-scheme: dark;
|
||||
|
||||
/* Couleurs — famille chaude toujours ancrée dans l'identité de Kévin,
|
||||
mais poussée en saturation pour un rendu festif plutôt que sobre. */
|
||||
--color-bg: #fff8f0;
|
||||
--color-surface: #ffffff;
|
||||
--color-surface-muted: #fdecdd;
|
||||
--color-text: #2b2016;
|
||||
--color-muted: #8a7869;
|
||||
--color-border: #f1ddc6;
|
||||
/* Mêmes noms/valeurs que src/galerie/style.css pour la cohérence entre
|
||||
écrans (voir consigne de la passe). */
|
||||
--color-bg: #12100e;
|
||||
--color-ink: #12100e; /* texte sombre sur surfaces claires/accents */
|
||||
--color-text: #faf6f0;
|
||||
--color-muted: #e8dfd3;
|
||||
--color-muted-2: #a89e90;
|
||||
|
||||
--color-accent: #e35f2b;
|
||||
--color-accent-hover: #c74c1e;
|
||||
--color-accent-light: #ff8a52;
|
||||
--color-accent-soft: #ffe3d0;
|
||||
--color-accent-contrast: #fffaf6;
|
||||
--color-coral: #ff5e5b;
|
||||
--color-yellow: #ffd166;
|
||||
--color-mint: #06d6a0;
|
||||
|
||||
--color-plum: #7c2f56;
|
||||
--color-plum-soft: #f8e3ee;
|
||||
--color-border: #e8dfd3;
|
||||
|
||||
--color-gold: #f0a91e;
|
||||
--color-gold-soft: #fef0d3;
|
||||
|
||||
--color-error-bg: #fdeae6;
|
||||
--color-error-text: #a3341c;
|
||||
--color-success-bg: #fff1de;
|
||||
--color-success-text: #8a4a10;
|
||||
--color-limit-bg: #fbe9d8;
|
||||
--color-limit-text: #8a4a10;
|
||||
|
||||
/* Bouton "danger" (Réessayer) : variable dédiée plutôt que de réutiliser
|
||||
--color-error-text tel quel comme fond de bouton — nécessaire en thème
|
||||
sombre où le texte d'erreur s'éclaircit (pour rester lisible sur fond
|
||||
sombre) et ne fonctionne plus comme couleur de fond de bouton avec du
|
||||
texte blanc (contraste vérifié, voir rapport de passe). */
|
||||
--color-danger: #a3341c;
|
||||
--color-danger-contrast: #fff;
|
||||
|
||||
--radius-sm: 12px;
|
||||
--radius: 20px;
|
||||
--radius: 4px; /* réservé aux éléments façon polaroid, non utilisé ici */
|
||||
--radius-ui: 14px;
|
||||
--radius-pill: 999px;
|
||||
|
||||
--shadow-sm: 0 2px 6px rgba(163, 78, 30, 0.1);
|
||||
--shadow-md: 0 10px 28px rgba(163, 78, 30, 0.16);
|
||||
--shadow-soft: 0 10px 24px rgba(0, 0, 0, 0.35);
|
||||
--shadow-card: 0 6px 16px rgba(0, 0, 0, 0.4);
|
||||
|
||||
--ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
/* Easing "posé" pour les transitions d'état/hover (fondus, lifts) — le
|
||||
rebond de --ease-bounce reste réservé aux moments ludiques (pop-in,
|
||||
coche de succès) pour ne pas le diluer. */
|
||||
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
--ease-standard: cubic-bezier(0.22, 1, 0.36, 1);
|
||||
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
"Helvetica Neue", Arial, sans-serif;
|
||||
--font-display: "Fraunces", Georgia, "Times New Roman", serif;
|
||||
}
|
||||
--font-display: "General Sans", -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
--font-hand: "Caveat", "Segoe Script", cursive;
|
||||
--font-ui: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
|
||||
/* -----------------------------------------------------------------------
|
||||
Thème sombre — palette pensée pour l'obscurité (pas une inversion des
|
||||
couleurs claires) : fond brun quasi-noir pour rester dans la famille
|
||||
chaude de la marque plutôt qu'un noir bleuté générique, texte et accents
|
||||
reclaircis et vérifiés au ratio de contraste WCAG AA (>= 4.5:1 pour le
|
||||
texte courant, >= 3:1 pour le grand texte/les éléments d'UI ; calculs
|
||||
détaillés dans le rapport de passe). Répond aux deux demandes de Kévin à
|
||||
la fois : un vrai mode sombre ET un rendu "moins agressif" en usage réel
|
||||
(salle tamisée en soirée). ----------------------------------------- */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-bg: #1b120b;
|
||||
--color-surface: #26190f;
|
||||
--color-surface-muted: #32211a;
|
||||
--color-text: #f7ead9;
|
||||
--color-muted: #b39d84;
|
||||
--color-border: #40291a;
|
||||
/* Tokens spécifiques à cet écran (formulaire, états), pas repris de
|
||||
src/galerie/style.css qui n'en a pas besoin. */
|
||||
--color-surface: #1e1b18;
|
||||
--color-surface-muted: #241f1a;
|
||||
--color-border-ui: rgba(250, 246, 240, 0.16);
|
||||
--color-border-ui-strong: rgba(250, 246, 240, 0.28);
|
||||
|
||||
--color-accent: #ff7a42;
|
||||
--color-accent-hover: #ffa06e;
|
||||
--color-accent-light: #ffab7a;
|
||||
--color-accent-soft: rgba(255, 122, 66, 0.18);
|
||||
--color-accent-contrast: #241206;
|
||||
--color-error-bg: rgba(255, 94, 91, 0.14);
|
||||
--color-limit-bg: rgba(255, 209, 102, 0.16);
|
||||
--color-success-bg: rgba(6, 214, 160, 0.12);
|
||||
|
||||
--color-plum: #f0b8d8;
|
||||
--color-plum-soft: rgba(240, 184, 216, 0.14);
|
||||
|
||||
--color-gold: #ffcf6b;
|
||||
--color-gold-soft: #3a2a12;
|
||||
|
||||
--color-error-bg: #3a1712;
|
||||
--color-error-text: #ff9b86;
|
||||
--color-success-bg: #2e2110;
|
||||
--color-success-text: #f2d9b8;
|
||||
--color-limit-bg: #3a2a12;
|
||||
--color-limit-text: #ffd98a;
|
||||
|
||||
--color-danger: #ff6b52;
|
||||
--color-danger-contrast: #2b0f08;
|
||||
|
||||
--shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.45);
|
||||
--shadow-md: 0 14px 36px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
/* Fonds d'icônes état erreur/limite : calculés à partir des couleurs
|
||||
claires d'origine, non pilotables via une seule variable — surchargés
|
||||
ici pour rester cohérents en sombre plutôt que de laisser un rouge/or
|
||||
"clair" plaqué sur fond sombre. */
|
||||
.state-block--error .state-icon--error {
|
||||
background: rgba(255, 155, 134, 0.16);
|
||||
}
|
||||
|
||||
.state-block--limit .state-icon--limit {
|
||||
background: rgba(255, 217, 138, 0.18);
|
||||
}
|
||||
|
||||
.welcome-modal {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
body::before {
|
||||
opacity: 0.4;
|
||||
}
|
||||
--shadow-sm: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -206,32 +107,13 @@ html {
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
font-family: var(--font-sans);
|
||||
font-family: var(--font-ui);
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
/* Halo de couleur en arrière-plan — "plus de couleur" sans ajouter de
|
||||
teinte à la palette : deux dégradés radiaux réutilisant les couleurs
|
||||
d'accent déjà en place (corail + doré), très doux, purement décoratifs.
|
||||
Objectif "type iPhone" : une page peut être vivante sans être plate,
|
||||
sans pour autant recourir à un vrai fond image (poids nul, CSS pur).
|
||||
z-index négatif + fixed : reste derrière le contenu, ne capte aucun
|
||||
événement (pointer-events: none), ne bouge pas au scroll. */
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
background: radial-gradient(60% 38% at 50% -8%, var(--color-accent-soft) 0%, transparent 72%),
|
||||
radial-gradient(46% 30% at 100% 100%, var(--color-gold-soft) 0%, transparent 70%);
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.page {
|
||||
max-width: 480px;
|
||||
margin: 0 auto;
|
||||
@@ -242,10 +124,6 @@ body::before {
|
||||
.page__header {
|
||||
text-align: center;
|
||||
margin-bottom: 1.6rem;
|
||||
/* Entrée en fondu/translation au chargement — discrète, une seule fois
|
||||
par affichage (rejoue si la page est masquée/réaffichée via l'attribut
|
||||
hidden, ce qui reste cohérent : chaque "nouvel écran" mérite sa petite
|
||||
entrée). */
|
||||
animation: fade-rise 0.5s var(--ease-standard) both;
|
||||
}
|
||||
|
||||
@@ -260,24 +138,20 @@ body::before {
|
||||
}
|
||||
}
|
||||
|
||||
/* Bloc de marque — discret, rassure l'invité (outil "pro") et signe le
|
||||
produit pour les organisateurs/prestataires qui verront la page.
|
||||
Volontairement minuscule : ce n'est pas l'écran de l'invité qui doit
|
||||
porter la marque de Kévin, c'est un clin d'œil en filigrane. */
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.4rem;
|
||||
margin-bottom: 0.7rem;
|
||||
color: var(--color-muted);
|
||||
color: var(--color-muted-2);
|
||||
}
|
||||
|
||||
.brand__mark {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
color: var(--color-accent);
|
||||
color: var(--color-coral);
|
||||
}
|
||||
|
||||
.brand__name {
|
||||
@@ -285,39 +159,28 @@ body::before {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.13em;
|
||||
text-transform: uppercase;
|
||||
font-family: var(--font-ui);
|
||||
}
|
||||
|
||||
.page__header h1 {
|
||||
font-family: var(--font-display);
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
font-size: 1.9rem;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1.15;
|
||||
margin: 0;
|
||||
/* Titre en dégradé corail -> doré : la touche "pop" la plus visible de la
|
||||
page, réservée à ce seul élément pour ne pas diluer son effet. Fallback
|
||||
: couleur pleine (--color-accent) si background-clip:text n'est pas
|
||||
supporté (support large sur mobile Safari/Chrome en pratique). */
|
||||
color: var(--color-accent);
|
||||
background: linear-gradient(100deg, var(--color-accent) 20%, var(--color-gold) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.page__kicker {
|
||||
font-family: var(--font-display);
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-size: 1.05rem;
|
||||
color: var(--color-plum);
|
||||
margin: 0.35rem 0 0;
|
||||
color: var(--color-muted);
|
||||
font-size: 0.95rem;
|
||||
margin: 0.4rem 0 0;
|
||||
}
|
||||
|
||||
.state-block {
|
||||
text-align: center;
|
||||
padding: 1.5rem 1.2rem;
|
||||
border-radius: var(--radius);
|
||||
border-radius: var(--radius-ui);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@@ -327,18 +190,17 @@ body::before {
|
||||
|
||||
.state-block--error {
|
||||
background: var(--color-error-bg);
|
||||
color: var(--color-error-text);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.state-block--error.state-block--limit {
|
||||
background: var(--color-limit-bg);
|
||||
color: var(--color-limit-text);
|
||||
}
|
||||
|
||||
.state-block--success {
|
||||
position: relative;
|
||||
background: linear-gradient(180deg, var(--color-success-bg), var(--color-surface) 75%);
|
||||
color: var(--color-success-text);
|
||||
background: linear-gradient(180deg, var(--color-success-bg), transparent 75%);
|
||||
color: var(--color-text);
|
||||
overflow: visible;
|
||||
padding-top: 1.75rem;
|
||||
}
|
||||
@@ -351,16 +213,14 @@ body::before {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Spinner de chargement — anneau CSS pur, aucune dépendance. Remplace le
|
||||
simple texte "Chargement…" par un repère visuel qui bouge : la première
|
||||
impression de la page ne doit jamais sembler figée/en panne. */
|
||||
/* Spinner de chargement — anneau CSS pur, aucune dépendance. */
|
||||
.spinner {
|
||||
display: inline-block;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin-bottom: 0.6rem;
|
||||
border: 3px solid var(--color-accent-soft);
|
||||
border-top-color: var(--color-accent);
|
||||
border: 3px solid rgba(255, 94, 91, 0.22);
|
||||
border-top-color: var(--color-coral);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
@@ -373,9 +233,8 @@ body::before {
|
||||
|
||||
/* Icônes des états erreur / limite atteinte — les deux existent toujours
|
||||
dans le DOM, affichées/masquées via la classe portée par le bloc parent
|
||||
(state-block--limit vs par défaut = erreur). Le choix entre les deux se
|
||||
fait côté JS uniquement en togglant cette classe (aucune autre logique
|
||||
déplacée dans le CSS). */
|
||||
(state-block--limit vs par défaut = erreur). Aucune logique déplacée
|
||||
dans le CSS, uniquement le rendu visuel. */
|
||||
.state-icon {
|
||||
display: none;
|
||||
width: 44px;
|
||||
@@ -388,8 +247,8 @@ body::before {
|
||||
|
||||
.state-block--error .state-icon--error {
|
||||
display: flex;
|
||||
background: rgba(163, 52, 28, 0.12);
|
||||
color: var(--color-error-text);
|
||||
background: rgba(255, 94, 91, 0.16);
|
||||
color: var(--color-coral);
|
||||
}
|
||||
|
||||
.state-block--error.state-block--limit .state-icon--error {
|
||||
@@ -398,9 +257,9 @@ body::before {
|
||||
|
||||
.state-block--limit .state-icon--limit {
|
||||
display: flex;
|
||||
background: rgba(138, 74, 16, 0.14);
|
||||
color: var(--color-gold);
|
||||
animation: pop-in 0.5s var(--ease-bounce) both;
|
||||
background: rgba(255, 209, 102, 0.18);
|
||||
color: var(--color-yellow);
|
||||
animation: pop-in 0.5s var(--ease-spring) both;
|
||||
}
|
||||
|
||||
.state-icon svg {
|
||||
@@ -415,10 +274,10 @@ body::before {
|
||||
animation: fade-rise 0.5s var(--ease-standard) 0.08s both;
|
||||
}
|
||||
|
||||
/* Même bug que .welcome-modal (voir commentaire plus haut) : présent depuis
|
||||
le tout premier commit de ce fichier. form.hidden = true (JS) ne masquait
|
||||
jamais réellement le formulaire, qui restait affiché en display:flex en
|
||||
permanence, superposé aux états chargement/erreur/succès. */
|
||||
/* Bug réel corrigé (2026-09-16, conservé lors du passage à la DA "Polaroid
|
||||
Néon") : une déclaration `display` en CSS auteur passe toujours devant
|
||||
`[hidden] { display: none }` du navigateur. Sans cette règle explicite,
|
||||
`form.hidden = true` (JS) ne masquait jamais réellement le formulaire. */
|
||||
.upload-form[hidden] {
|
||||
display: none;
|
||||
}
|
||||
@@ -436,20 +295,19 @@ body::before {
|
||||
|
||||
.field .optional {
|
||||
font-weight: 400;
|
||||
color: var(--color-muted);
|
||||
color: var(--color-muted-2);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
/* Regroupe prénom + petit mot dans une même carte : crée un second niveau
|
||||
de hiérarchie visuelle (la photo reste l'action principale au-dessus,
|
||||
ces champs facultatifs sont secondaires et "posés" ensemble). */
|
||||
/* Regroupe prénom + petit mot dans une même carte : second niveau de
|
||||
hiérarchie visuelle (la photo reste l'action principale au-dessus). */
|
||||
.field-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--color-border-ui);
|
||||
border-radius: var(--radius-ui);
|
||||
padding: 1.1rem;
|
||||
}
|
||||
|
||||
@@ -457,21 +315,18 @@ input[type="text"],
|
||||
textarea {
|
||||
font: inherit;
|
||||
padding: 0.7rem 0.8rem;
|
||||
border: 1.5px solid var(--color-border);
|
||||
border-radius: var(--radius-sm);
|
||||
background: var(--color-surface);
|
||||
border: 1.5px solid var(--color-border-ui);
|
||||
border-radius: 10px;
|
||||
background: var(--color-bg);
|
||||
color: inherit;
|
||||
width: 100%;
|
||||
transition: border-color 0.18s var(--ease-standard), box-shadow 0.18s var(--ease-standard);
|
||||
}
|
||||
|
||||
/* Anneau de focus teinté (en plus du changement de bordure) : détail de
|
||||
finition "type iPhone" — un champ actif doit se voir sans ambiguïté,
|
||||
avec une transition douce plutôt qu'un changement sec. */
|
||||
input[type="text"]:focus,
|
||||
textarea:focus {
|
||||
border-color: var(--color-accent);
|
||||
box-shadow: 0 0 0 4px var(--color-accent-soft);
|
||||
border-color: var(--color-coral);
|
||||
box-shadow: 0 0 0 4px rgba(255, 94, 91, 0.22);
|
||||
}
|
||||
|
||||
.visually-hidden {
|
||||
@@ -491,12 +346,10 @@ textarea:focus {
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
/* Boutons "Prendre une photo" / "Depuis la galerie" — forme pilule (identité
|
||||
plus ronde/organique que la V1) avec une hiérarchie claire : la capture
|
||||
directe est l'action attendue pour la quasi-totalité des invités pendant
|
||||
l'événement (le moment se vit là, tout de suite), donc traitée en
|
||||
primaire pleine couleur ; la galerie reste secondaire mais tout aussi
|
||||
accessible en un tap (contrainte actée le 2026-09-16). */
|
||||
/* Boutons "Prendre une photo" / "Depuis la galerie" — la capture directe
|
||||
est l'action attendue pour la quasi-totalité des invités pendant
|
||||
l'événement, donc traitée en primaire (corail plein, texte sombre) ;
|
||||
la galerie reste secondaire mais tout aussi accessible en un tap. */
|
||||
.btn-source {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
@@ -510,20 +363,20 @@ textarea:focus {
|
||||
min-height: 50px;
|
||||
border-radius: var(--radius-pill);
|
||||
cursor: pointer;
|
||||
transition: transform 0.12s var(--ease-bounce), box-shadow 0.12s ease, background 0.12s ease;
|
||||
transition: transform 0.12s var(--ease-spring), box-shadow 0.12s ease, background 0.12s ease;
|
||||
}
|
||||
|
||||
.btn-source--primary {
|
||||
border: none;
|
||||
background: linear-gradient(135deg, var(--color-accent-light), var(--color-accent));
|
||||
color: var(--color-accent-contrast);
|
||||
background: var(--color-coral);
|
||||
color: var(--color-ink);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.btn-source--secondary {
|
||||
border: 1.5px solid var(--color-plum);
|
||||
background: var(--color-surface);
|
||||
color: var(--color-plum);
|
||||
border: 1.5px solid var(--color-border-ui-strong);
|
||||
background: transparent;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.btn-source:active {
|
||||
@@ -531,34 +384,30 @@ textarea:focus {
|
||||
}
|
||||
|
||||
.btn-source--primary:active {
|
||||
background: linear-gradient(135deg, var(--color-accent), var(--color-accent-hover));
|
||||
background: #ff7673;
|
||||
}
|
||||
|
||||
.btn-source--secondary:active {
|
||||
background: var(--color-plum-soft);
|
||||
background: var(--color-surface);
|
||||
}
|
||||
|
||||
/* États hover — uniquement pour les pointeurs qui en ont un (souris/trackpad
|
||||
d'un prospect qui consulte la page sur desktop lors d'une démo) : jamais
|
||||
sur mobile tactile, où seuls :active/:focus-visible s'appliquent déjà.
|
||||
Lift discret + easing posé (pas de rebond ici, réservé aux pops). */
|
||||
sur mobile tactile. */
|
||||
@media (hover: hover) {
|
||||
.btn-source--primary:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
.btn-source--secondary:hover {
|
||||
transform: translateY(-1px);
|
||||
background: var(--color-plum-soft);
|
||||
background: var(--color-surface);
|
||||
border-color: var(--color-coral);
|
||||
}
|
||||
}
|
||||
|
||||
/* Icônes SVG inline (aucune requête réseau) : remplacent les emoji des
|
||||
boutons "Prendre une photo" / "Depuis la galerie". Le rendu des emoji
|
||||
varie fortement selon l'OS (Android/iOS/Windows) — pas assez maîtrisé
|
||||
pour une pièce de portfolio. Les icônes héritent de currentColor, donc
|
||||
suivent l'état du bouton sans CSS supplémentaire. */
|
||||
/* Icônes SVG inline (aucune requête réseau), héritent de currentColor. */
|
||||
.btn-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@@ -567,7 +416,7 @@ textarea:focus {
|
||||
|
||||
.file-chosen-label {
|
||||
font-size: 0.85rem;
|
||||
color: var(--color-muted);
|
||||
color: var(--color-muted-2);
|
||||
margin: 0.5rem 0 0;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -580,7 +429,7 @@ textarea {
|
||||
input:focus-visible,
|
||||
textarea:focus-visible,
|
||||
button:focus-visible {
|
||||
outline: 3px solid var(--color-plum);
|
||||
outline: 3px solid var(--color-coral);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
@@ -588,9 +437,9 @@ button:focus-visible {
|
||||
width: 100%;
|
||||
max-height: 320px;
|
||||
object-fit: contain;
|
||||
border-radius: var(--radius);
|
||||
border-radius: var(--radius-ui);
|
||||
background: var(--color-surface-muted);
|
||||
animation: pop-in 0.35s var(--ease-bounce) both;
|
||||
animation: pop-in 0.35s var(--ease-spring) both;
|
||||
}
|
||||
|
||||
.legal-notice {
|
||||
@@ -600,7 +449,7 @@ button:focus-visible {
|
||||
font-size: 0.78rem;
|
||||
color: var(--color-muted);
|
||||
background: var(--color-surface-muted);
|
||||
border-radius: var(--radius);
|
||||
border-radius: var(--radius-ui);
|
||||
padding: 0.85rem 0.9rem;
|
||||
margin: 0;
|
||||
}
|
||||
@@ -610,7 +459,7 @@ button:focus-visible {
|
||||
height: 18px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 0.1rem;
|
||||
color: var(--color-plum);
|
||||
color: var(--color-muted-2);
|
||||
}
|
||||
|
||||
.legal-link {
|
||||
@@ -625,7 +474,7 @@ button:focus-visible {
|
||||
font: inherit;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-muted);
|
||||
color: var(--color-muted-2);
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
cursor: pointer;
|
||||
@@ -633,21 +482,21 @@ button:focus-visible {
|
||||
}
|
||||
|
||||
.legal-link .legal-notice__icon {
|
||||
color: var(--color-muted);
|
||||
color: var(--color-muted-2);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.legal-link:hover {
|
||||
color: var(--color-plum);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.legal-link:hover .legal-notice__icon {
|
||||
color: var(--color-plum);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
#welcome-modal-dismiss:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,17 +510,13 @@ button:focus-visible {
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
background: rgba(43, 32, 22, 0.45);
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
animation: fade-in 0.2s ease both;
|
||||
}
|
||||
|
||||
/* Bug réel corrigé (2026-09-16) : une déclaration `display` en CSS auteur
|
||||
passe toujours devant la règle `[hidden] { display: none }` du navigateur
|
||||
(l'origine "auteur" l'emporte sur l'origine "user-agent" dans la
|
||||
cascade, indépendamment de la spécificité). Sans cette règle explicite,
|
||||
`welcomeModal.hidden = true` en JS ne masquait jamais visuellement la
|
||||
modale : le bouton "C'est parti" fonctionnait bien (l'état se mettait à
|
||||
jour) mais rien ne changeait à l'écran. */
|
||||
/* Même bug que .upload-form (voir commentaire plus haut), présent depuis le
|
||||
tout premier commit : sans cette règle, welcomeModal.hidden = true (JS)
|
||||
ne masquait jamais visuellement la modale. */
|
||||
.welcome-modal[hidden] {
|
||||
display: none;
|
||||
}
|
||||
@@ -683,26 +528,25 @@ button:focus-visible {
|
||||
max-height: 88vh;
|
||||
overflow-y: auto;
|
||||
background: var(--color-surface);
|
||||
border-radius: var(--radius) var(--radius) 0 0;
|
||||
border-radius: var(--radius-ui) var(--radius-ui) 0 0;
|
||||
padding: 1.5rem 1.25rem calc(1.5rem + env(safe-area-inset-bottom));
|
||||
box-shadow: var(--shadow-md);
|
||||
animation: slide-up 0.35s var(--ease-bounce) both;
|
||||
box-shadow: var(--shadow-soft);
|
||||
animation: slide-up 0.35s var(--ease-spring) both;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
/* Liseré dégradé en haut de la carte — même traitement que les cartes de la
|
||||
galerie admin (src/admin/gallery/style.css), pour une petite touche de
|
||||
couleur cohérente entre les deux écrans sur un élément de chrome (pas de
|
||||
contenu), plutôt qu'un ajout ponctuel isolé. */
|
||||
/* Liseré corail en haut de la carte — même traitement de "chrome" que la
|
||||
galerie admin (src/admin/gallery/style.css), touche de couleur cohérente
|
||||
entre écrans sur un élément de bordure, pas de contenu. */
|
||||
.welcome-modal__card::before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 4px;
|
||||
flex-shrink: 0;
|
||||
margin: -1.5rem -1.25rem 1.1rem;
|
||||
background: linear-gradient(90deg, var(--color-accent), var(--color-gold));
|
||||
background: var(--color-coral);
|
||||
}
|
||||
|
||||
@media (min-width: 520px) {
|
||||
@@ -710,7 +554,7 @@ button:focus-visible {
|
||||
align-items: center;
|
||||
}
|
||||
.welcome-modal__card {
|
||||
border-radius: var(--radius);
|
||||
border-radius: var(--radius-ui);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,46 +562,38 @@ button:focus-visible {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* Peaufinage passe 3 (la modale était fonctionnelle mais minimale) : la
|
||||
marque prend la forme d'un badge rond coloré plutôt qu'une petite icône
|
||||
nue — cohérent avec le ton "app premium" recherché, sans nouvel élément
|
||||
HTML (juste du style appliqué au SVG existant). */
|
||||
.welcome-modal .brand__mark {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 7px;
|
||||
border-radius: 50%;
|
||||
background: var(--color-accent-soft);
|
||||
color: var(--color-accent);
|
||||
background: rgba(255, 94, 91, 0.16);
|
||||
color: var(--color-coral);
|
||||
}
|
||||
|
||||
.welcome-modal__title {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
font-size: 1.6rem;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
color: var(--color-accent);
|
||||
background: linear-gradient(100deg, var(--color-accent) 20%, var(--color-gold) 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.welcome-modal__text {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.welcome-modal__text {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
color: var(--color-muted);
|
||||
}
|
||||
|
||||
#welcome-modal-dismiss {
|
||||
background: linear-gradient(135deg, var(--color-accent-light), var(--color-accent));
|
||||
color: var(--color-accent-contrast);
|
||||
background: var(--color-coral);
|
||||
color: var(--color-ink);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
#welcome-modal-dismiss:active {
|
||||
background: linear-gradient(135deg, var(--color-accent), var(--color-accent-hover));
|
||||
background: #ff7673;
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
@@ -774,7 +610,7 @@ button:focus-visible {
|
||||
min-height: 1.2em;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-plum);
|
||||
color: var(--color-yellow);
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -787,7 +623,7 @@ button {
|
||||
padding: 0.9rem 1rem;
|
||||
min-height: 50px;
|
||||
cursor: pointer;
|
||||
transition: transform 0.12s var(--ease-bounce), background 0.12s ease, opacity 0.12s ease;
|
||||
transition: transform 0.12s var(--ease-spring), background 0.12s ease, opacity 0.12s ease;
|
||||
}
|
||||
|
||||
#submit-btn,
|
||||
@@ -796,20 +632,20 @@ button {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
background: linear-gradient(135deg, var(--color-accent-light), var(--color-accent));
|
||||
color: var(--color-accent-contrast);
|
||||
box-shadow: var(--shadow-md);
|
||||
background: var(--color-coral);
|
||||
color: var(--color-ink);
|
||||
box-shadow: var(--shadow-soft);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
#submit-btn:active:not(:disabled),
|
||||
#add-another-btn:active {
|
||||
transform: scale(0.97);
|
||||
background: linear-gradient(135deg, var(--color-accent), var(--color-accent-hover));
|
||||
background: #ff7673;
|
||||
}
|
||||
|
||||
#submit-btn:disabled {
|
||||
opacity: 0.6;
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
box-shadow: none;
|
||||
}
|
||||
@@ -818,12 +654,10 @@ button {
|
||||
#submit-btn:hover:not(:disabled),
|
||||
#add-another-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
box-shadow: var(--shadow-soft);
|
||||
}
|
||||
|
||||
/* Micro-nudge de l'icône avion au survol : détail qui n'existe que pour
|
||||
les visiteurs desktop (donc surtout les prospects en démo), sans
|
||||
dépendance JS supplémentaire. */
|
||||
/* Micro-nudge de l'icône avion au survol : desktop uniquement. */
|
||||
#submit-btn:hover:not(:disabled) .btn-icon {
|
||||
transform: translate(2px, -2px);
|
||||
}
|
||||
@@ -834,14 +668,18 @@ button {
|
||||
}
|
||||
|
||||
#retry-btn {
|
||||
background: var(--color-danger);
|
||||
color: var(--color-danger-contrast);
|
||||
background: var(--color-coral);
|
||||
color: var(--color-ink);
|
||||
}
|
||||
|
||||
#retry-btn:active {
|
||||
background: #ff7673;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
Écran de succès — LE moment à soigner : c'est la dernière impression
|
||||
que garde l'invité. Coche qui "pop" avec rebond + petite volée de
|
||||
confettis colorés (pur CSS, aucune dépendance JS supplémentaire).
|
||||
confettis dans les 3 couleurs d'accent de la DA (pur CSS).
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
.success-check {
|
||||
@@ -849,7 +687,7 @@ button {
|
||||
width: 76px;
|
||||
height: 76px;
|
||||
margin: 0 auto 0.9rem;
|
||||
animation: pop-in 0.55s var(--ease-bounce) both;
|
||||
animation: pop-in 0.55s var(--ease-spring) both;
|
||||
}
|
||||
|
||||
.success-check svg {
|
||||
@@ -859,15 +697,15 @@ button {
|
||||
}
|
||||
|
||||
.success-check__circle {
|
||||
stroke: var(--color-accent);
|
||||
fill: var(--color-gold-soft);
|
||||
stroke: var(--color-mint);
|
||||
fill: rgba(6, 214, 160, 0.14);
|
||||
stroke-dasharray: 145;
|
||||
stroke-dashoffset: 145;
|
||||
animation: draw 0.5s ease-out 0.1s forwards;
|
||||
}
|
||||
|
||||
.success-check__mark {
|
||||
stroke: var(--color-accent);
|
||||
stroke: var(--color-mint);
|
||||
fill: none;
|
||||
stroke-dasharray: 32;
|
||||
stroke-dashoffset: 32;
|
||||
@@ -912,51 +750,51 @@ button {
|
||||
|
||||
.confetti span:nth-child(1) {
|
||||
left: 18%;
|
||||
background: var(--color-accent);
|
||||
background: var(--color-coral);
|
||||
border-radius: 2px;
|
||||
animation-delay: 0.05s;
|
||||
}
|
||||
.confetti span:nth-child(2) {
|
||||
left: 32%;
|
||||
top: 0.2rem;
|
||||
background: var(--color-gold);
|
||||
background: var(--color-yellow);
|
||||
border-radius: 50%;
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
.confetti span:nth-child(3) {
|
||||
left: 48%;
|
||||
background: var(--color-plum);
|
||||
background: var(--color-mint);
|
||||
border-radius: 2px;
|
||||
animation-delay: 0.02s;
|
||||
}
|
||||
.confetti span:nth-child(4) {
|
||||
left: 62%;
|
||||
background: var(--color-accent-light);
|
||||
background: var(--color-coral);
|
||||
border-radius: 50%;
|
||||
animation-delay: 0.22s;
|
||||
}
|
||||
.confetti span:nth-child(5) {
|
||||
left: 74%;
|
||||
background: var(--color-gold);
|
||||
background: var(--color-yellow);
|
||||
border-radius: 2px;
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
.confetti span:nth-child(6) {
|
||||
left: 86%;
|
||||
background: var(--color-plum);
|
||||
background: var(--color-mint);
|
||||
border-radius: 50%;
|
||||
animation-delay: 0.28s;
|
||||
}
|
||||
.confetti span:nth-child(7) {
|
||||
left: 10%;
|
||||
top: 0.3rem;
|
||||
background: var(--color-gold);
|
||||
background: var(--color-yellow);
|
||||
border-radius: 50%;
|
||||
animation-delay: 0.18s;
|
||||
}
|
||||
.confetti span:nth-child(8) {
|
||||
left: 94%;
|
||||
background: var(--color-accent);
|
||||
background: var(--color-coral);
|
||||
border-radius: 2px;
|
||||
animation-delay: 0.08s;
|
||||
}
|
||||
@@ -977,15 +815,22 @@ button {
|
||||
|
||||
.success-title {
|
||||
font-family: var(--font-display);
|
||||
font-weight: 700;
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-accent-hover);
|
||||
color: var(--color-text);
|
||||
margin: 0 0 0.3rem;
|
||||
}
|
||||
|
||||
/* Touche manuscrite ponctuelle (Caveat) sur le petit mot de succès — ton
|
||||
"friendly" demandé, sans en abuser (seul élément du texte à l'utiliser
|
||||
sur cet écran, comme sur les légendes de la galerie invité). */
|
||||
.success-text {
|
||||
font-size: 0.95rem;
|
||||
margin: 0 0 1.3rem;
|
||||
font-family: var(--font-hand);
|
||||
font-weight: 600;
|
||||
font-size: 1.35rem;
|
||||
line-height: 1.3;
|
||||
color: var(--color-muted);
|
||||
margin: 0 0 1.4rem;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
Reference in New Issue
Block a user