/*
 * auth-vitrine.css — la mise en page « formulaire a gauche, vitrine a droite ».
 *
 * CE FICHIER NE DECIDE AUCUNE COULEUR. Toutes les valeurs viennent de tokens.css, qui doit etre
 * charge avant lui. C'est la condition pour que le meme habillage serve ensuite au planning sans
 * qu'on ait a rattraper des teintes ecrites ici a la main.
 *
 * COMPOSANTS FOURNIS, et ou ils servent ailleurs :
 *   .auth-ecran / .auth-vitrine   la mise en page deux colonnes, propre a l'authentification
 *   .champ, .bouton, .message     sortis dans composants.css : ce sont des briques
 *                                 d'application, pas d'authentification
 *   .note                         note courte etiquetee, reutilisable sur tout fond sombre
 *
 * TOUT EST EN CSS PUR : le projet n'embarque aucune bibliotheque d'animation et n'en a pas
 * besoin ici. Trois mouvements, aucune image, aucun canevas :
 *   - le ruban de notes, qui glisse horizontalement en boucle sans couture ;
 *   - une trame de points qui derive tres lentement en diagonale ;
 *   - deux halos flous qui se deplacent et respirent sur des durees premieres entre elles.
 * Les trois s'arretent net sous `prefers-reduced-motion` (section 7).
 */

/* ==========================================================================================
 * 1. La page
 * ========================================================================================== */

.auth-ecran {
    min-height: 100vh;
    /* dvh suit la barre d'adresse mobile, qui sinon rogne le bas de l'ecran. Declaration
     * separee : un navigateur qui ignore l'unite garde la ligne precedente. */
    min-height: 100dvh;
    display: grid;
    grid-template-columns: 1fr;
    background: var(--voile);
    color: var(--encre);
    font-family: var(--police-texte);
    font-size: var(--taille-base);
    line-height: var(--hauteur-texte);
    -webkit-font-smoothing: antialiased;
}

/* Le panneau visuel n'apparait qu'a partir du moment ou il reste une vraie place au
 * formulaire. En dessous, il disparait entierement — il n'est pas replie sous le formulaire :
 * personne ne fait defiler une page de connexion pour lire des citations. */
@media (min-width: 1024px) {
    /* A partir d'ici l'ecran ne defile plus : il occupe exactement la fenetre, et c'est la
     * colonne de gauche qui defile si sa hauteur ne suffit pas.
     *
     * POURQUOI `grid-template-rows: minmax(0, 1fr)` ET une hauteur fixe. Une rangee de grille se
     * dimensionne par defaut sur le contenu le plus haut. Or le contenu le plus haut est le
     * ruban de notes, qui mesure deux fois la liste : la rangee prenait 1 400 px, toute la
     * page defilait, et la vitrine cessait d'etre une fenetre tronquee pour devenir un tres long
     * ruban. Constate a l'ecran. `overflow: hidden` ne suffit pas : il rogne l'affichage, il ne
     * change pas la hauteur calculee. */
    .auth-ecran {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        grid-template-rows: minmax(0, 1fr);
        height: 100vh;
        height: 100dvh;
    }

    .auth-panneau { overflow-y: auto; }
}

@media (min-width: 1360px) {
    /* Au-dela, la vitrine peut prendre un peu plus : le formulaire, lui, est plafonne a 400 px
     * et n'a rien a faire d'une colonne plus large. */
    .auth-ecran { grid-template-columns: minmax(0, 46fr) minmax(0, 54fr); }
}

/* ==========================================================================================
 * 2. Colonne de gauche — le formulaire
 * ========================================================================================== */

.auth-panneau {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding: var(--espace-8) var(--espace-6);
    background: var(--papier);
}

@media (min-width: 640px) {
    .auth-panneau { padding: var(--espace-12) var(--espace-10); }
}

.auth-boite {
    width: 100%;
    max-width: 400px;
    display: flex;
    flex-direction: column;
    /* L'espacement vertical du formulaire tient dans cette seule valeur. */
    gap: var(--espace-6);
}

/* --- Marque --------------------------------------------------------------------------- */

.auth-marque {
    display: flex;
    align-items: center;
    gap: var(--espace-3);
}

.auth-marque__sigle {
    width: 34px;
    height: 34px;
    flex: none;
    display: grid;
    place-items: center;
    border-radius: var(--rayon-sm);
    background: var(--encre-forte);
    color: var(--papier);
    font-size: var(--taille-sm);
    font-weight: var(--graisse-forte);
    letter-spacing: .02em;
}

.dark .auth-marque__sigle {
    background: var(--encre);
    color: var(--voile);
}

.auth-marque__nom {
    font-size: var(--taille-base);
    font-weight: var(--graisse-appuyee);
    letter-spacing: var(--interlettre-titre);
    color: var(--encre-forte);
}

/* --- Titraille ------------------------------------------------------------------------- */

.auth-titre {
    margin: 0 0 var(--espace-2);
    font-size: var(--taille-xl);
    line-height: var(--hauteur-serree);
    font-weight: var(--graisse-forte);
    letter-spacing: var(--interlettre-titre);
    color: var(--encre-forte);
}

/* Le titre d'un ecran secondaire — « Reinitialiser l'acces » — reste un titre de premier
 * niveau pour la structure du document, mais pese moins a l'oeil : il ne s'annonce pas comme
 * l'entree principale. */
.auth-titre--second { font-size: var(--taille-lg); }

.auth-chapo {
    margin: 0;
    color: var(--encre-attenuee);
    font-size: var(--taille-base);
}

/* Les blocs de titraille et les paragraphes de pied de formulaire n'ont pas de marge propre :
 * c'est le `gap` du conteneur qui rythme la colonne, et une marge s'y ajouterait. */
.auth-bas p { margin: 0; }

.auth-note + .auth-note,
.bouton + .auth-note { margin-top: var(--espace-2); }

.lien--centre { align-self: center; }

/* ==========================================================================================
 * 3. Champs
 * ========================================================================================== */

.auth-formulaire {
    display: flex;
    flex-direction: column;
    gap: var(--espace-4);
}

/* Le Hub masque ses formulaires avec la classe Tailwind `.hidden`, qui vaut `display: none` —
 * meme specificite que la regle ci-dessus, donc c'est l'ordre d'injection de Tailwind qui
 * trancherait, et il n'est pas garanti. Deux classes, la question ne se pose plus. */
.auth-formulaire.hidden { display: none; }


/* ==========================================================================================
 * 5. Appoints du formulaire
 * ========================================================================================== */

.auth-appoint {
    display: flex;
    justify-content: flex-end;
    margin-top: calc(var(--espace-1) * -1);
}


.auth-bas {
    font-size: var(--taille-sm);
    color: var(--encre-attenuee);
    text-align: center;
}

.auth-note {
    margin: 0;
    font-size: var(--taille-xs);
    color: var(--encre-faible);
    text-align: center;
}

/* Pied de page legal — les trois liens obligatoires, presents sur chaque page. */
.auth-pied {
    width: 100%;
    max-width: 400px;
    margin-top: var(--espace-10);
}

.auth-pied nav {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--espace-1) var(--espace-5);
    font-size: var(--taille-xs);
}

.auth-pied a {
    color: var(--encre-faible);
    text-decoration: none;
}

.auth-pied a:hover { color: var(--encre); text-decoration: underline; }

/* ==========================================================================================
 * 6. Colonne de droite — la vitrine
 * ==========================================================================================
 * Un fond tres sombre anime, et les notes qui glissent sur UNE SEULE LIGNE, de droite a
 * gauche. C'est la forme du bloc dont s'inspire cet ecran ; la premiere version empilait des
 * colonnes verticales, ce qui n'etait pas le meme objet.
 *
 * LE PANNEAU RESTE SOMBRE DANS LES DEUX THEMES, volontairement. Ce n'est pas une surface de
 * travail : on n'y saisit rien, on n'y lit rien deux fois. Lui donner le meme papier que le
 * formulaire ferait disparaitre la partition en deux, qui est tout l'interet de la mise en page.
 * Ses couleurs viennent donc des jetons `--vitrine-*`, qui ne sont pas redefinis par `.dark`.
 */

.auth-vitrine {
    display: none; /* rallumee au-dessus de 1024 px */
    position: relative;
    overflow: hidden;
    background: var(--vitrine-fond);
    color: var(--vitrine-encre);
    /* En theme clair, la partition se lit d'elle-meme : blanc contre presque noir. En theme
     * sombre les deux surfaces se rapprochent (#171B20 contre #0A0E12) et la couture devient
     * douteuse — ce filet la retablit sans rien changer au theme clair. */
    border-left: 1px solid var(--vitrine-trait);
    /* Le contexte d'empilement est cree ici : les couches de fond se rangent sous le ruban sans
     * qu'aucun z-index n'ait a sortir de ce composant. */
    isolation: isolate;
}

@media (min-width: 1024px) {
    /* `align-content: center` : le ruban est centre verticalement dans le panneau, et le fond
     * occupe toute la hauteur derriere lui. */
    .auth-vitrine { display: grid; align-content: center; }
}

/* --- Le fond anime ----------------------------------------------------------------------
 * Deux couches, toutes deux decoratives et donc `aria-hidden` dans le balisage.
 *
 * 1. Une trame de points, dessinee par un degrade radial repete — aucune image, aucun fichier.
 *    Elle derive tres lentement en diagonale : le deplacement est de l'ordre de trois pixels
 *    par seconde, assez pour que la surface ne soit pas morte, trop peu pour attirer l'oeil.
 * 2. Deux halos flous qui se deplacent et respirent en boucle, sur des durees premieres entre
 *    elles — 24 s et 31 s — pour que leur superposition ne se repete jamais a l'identique.
 */

.vitrine__trame,
.vitrine__ciel,
.vitrine__lueur {
    position: absolute;
    z-index: 0;
    pointer-events: none;
}

/* --- Les points qui scintillent ----------------------------------------------------------
 * La trame ci-dessous donne la texture, mais elle ne peut pas scintiller : c'est UNE image de
 * fond, et une image de fond n'a qu'une opacite, la meme pour tous ses points. Faire clignoter
 * les points un par un demande donc un element par point.
 *
 * Ils sont semes par auth-vitrine.js, a positions et durees tirees au sort — mais par un tirage
 * REPRODUCTIBLE (voir la fonction) : le ciel est le meme d'un chargement a l'autre, ce qui evite
 * qu'une capture d'ecran ou un test ne tombe jamais deux fois sur la meme image.
 *
 * Le delai de chaque point est negatif : l'animation demarre donc en cours de route, a un point
 * different pour chacun. Sans cela les quatre-vingts points s'allumeraient ensemble au premier
 * affichage, ce qui se voit immediatement et ne ressemble a rien.
 */

.vitrine__ciel { inset: 0; }

.vitrine__point {
    position: absolute;
    border-radius: var(--rayon-plein);
    background: var(--vitrine-etincelle);
    opacity: 0;
    animation: scintille var(--scintille-duree, 4s) ease-in-out var(--scintille-delai, 0s) infinite alternate;
}

@keyframes scintille {
    from { opacity: .06; transform: scale(.7); }
    to   { opacity: .85; transform: scale(1.25); }
}

.vitrine__trame {
    /* Deborde volontairement : la trame derive, et un cadre exact laisserait apparaitre un bord
     * vide du cote vers lequel elle se deplace. */
    inset: -8%;
    background-image: radial-gradient(var(--vitrine-trame) 1px, transparent 1.6px);
    background-size: 26px 26px;
    animation: trame-derive 120s linear infinite;
}

.vitrine__lueur {
    width: 68%;
    aspect-ratio: 1;
    top: -18%;
    left: 6%;
    border-radius: var(--rayon-plein);
    background: radial-gradient(closest-side, var(--vitrine-lueur), transparent);
    animation: lueur-derive 24s ease-in-out infinite alternate;
}

.vitrine__lueur--seconde {
    top: auto;
    left: auto;
    bottom: -22%;
    right: 2%;
    width: 54%;
    background: radial-gradient(closest-side, var(--vitrine-lueur-2), transparent);
    animation-duration: 31s;
    animation-direction: alternate-reverse;
}

@keyframes trame-derive {
    to { background-position: 312px 156px; } /* multiples de 26 : la trame se reboucle pile */
}

@keyframes lueur-derive {
    from { transform: translate3d(-7%, -5%, 0) scale(1); }
    to   { transform: translate3d(9%, 7%, 0) scale(1.22); }
}

/* --- Le ruban ----------------------------------------------------------------------------
 * Meme principe que tout defilement en boucle : deux exemplaires de la liste, et une
 * translation d'exactement un exemplaire. Ici l'axe est horizontal, et le raisonnement sur
 * l'ecart est identique a celui d'une piste verticale.
 *
 * Pourquoi « -50% - ecart/2 » et non « -50% » : les cartes sont separees par `gap`, y compris
 * entre le dernier element du premier exemplaire et le premier du second. La moitie du ruban
 * tombe donc AU MILIEU de cet espace et non sur la limite. La demi-valeur remet la coupe au bon
 * endroit ; un « -50% » nu produit une saccade d'un demi-ecart a chaque tour. Ce decalage a ete
 * mesure pour de vrai sur la version verticale : 180 px d'ecart, une secousse par boucle.
 */

.vitrine__cadre {
    --ruban-ecart: 56px;

    position: relative;
    z-index: 1;
    overflow: hidden;
    /* Le fondu des deux bords. Un masque plutot qu'un degrade pose par-dessus : celui-ci
     * devrait connaitre la couleur du fond, et cesserait d'etre juste des qu'elle change. */
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 14%, #000 86%, transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 14%, #000 86%, transparent 100%);
}

.vitrine__ruban {
    display: flex;
    align-items: flex-start;
    gap: var(--ruban-ecart);
    /* C'est une <ul> : ses puces et ses retraits d'agent utilisateur n'ont rien a faire ici, et
     * le retrait gauche decalerait la premiere carte par rapport aux suivantes. */
    margin: 0;
    padding: 0;
    list-style: none;
    /* `max-content` : le ruban prend la largeur de ses cartes, et non celle de son parent —
     * sans quoi les cartes se comprimeraient au lieu de se suivre. */
    width: max-content;
    will-change: transform;
    animation: ruban-defile var(--ruban-duree, 72s) linear infinite;
}

@keyframes ruban-defile {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(calc(-50% - (var(--ruban-ecart) / 2)), 0, 0); }
}

/* Pause au survol, et aussi au focus clavier : sans le second, quelqu'un qui tabule dans une
 * carte verrait la cible lui echapper. */
.auth-vitrine:hover .vitrine__ruban,
.auth-vitrine:focus-within .vitrine__ruban { animation-play-state: paused; }

/* --- La commande de mouvement ------------------------------------------------------------
 * `data-mouvement` est pose par auth-vitrine.js sur le panneau, et vaut toujours « oui » ou
 * « non ». C'est LUI qui decide, pas la media query : celle-ci ne fournit que la valeur par
 * defaut, que la personne peut ensuite contredire dans les deux sens.
 *
 * POURQUOI CE BOUTON EXISTE. Un ecran qui bouge tout seul doit pouvoir etre arrete — c'est le
 * critere 2.2.2 des WCAG des qu'un mouvement dure plus de cinq secondes. Mais la reciproque
 * compte aussi : quelqu'un dont le systeme est regle sur « animations reduites » pour de tout
 * autres raisons — c'est le reglage par defaut sur bien des postes d'entreprise — se retrouvait
 * devant un ruban fige sans comprendre pourquoi, et sans aucun moyen de le lancer.
 */

.vitrine__commande {
    position: absolute;
    z-index: 2;
    left: var(--espace-8);
    bottom: var(--espace-8);
    display: inline-flex;
    align-items: center;
    gap: var(--espace-2);
    padding: var(--espace-2) var(--espace-4);
    font-family: inherit;
    font-size: var(--taille-xs);
    font-weight: var(--graisse-appuyee);
    color: var(--vitrine-encre-attenuee);
    background: var(--vitrine-relief);
    border: 1px solid var(--vitrine-trait);
    border-radius: var(--rayon-plein);
    cursor: pointer;
    transition: color var(--duree) var(--courbe), background-color var(--duree) var(--courbe);
}

.vitrine__commande:hover {
    color: var(--vitrine-encre);
    background: rgba(255, 255, 255, .12);
}

.vitrine__commande svg { width: 13px; height: 13px; }

.vitrine__mention {
    position: absolute;
    z-index: 2;
    left: var(--espace-8);
    bottom: calc(var(--espace-8) + 36px);
    margin: 0;
    max-width: 34ch;
    font-size: var(--taille-xs);
    color: var(--vitrine-encre-attenuee);
    opacity: .8;
}

/* --- Mouvement coupe : par la commande, ou par defaut si le systeme le demande ----------- */

.auth-vitrine[data-mouvement="non"] .vitrine__ruban,
.auth-vitrine[data-mouvement="non"] .vitrine__trame,
.auth-vitrine[data-mouvement="non"] .vitrine__lueur,
.auth-vitrine[data-mouvement="non"] .vitrine__point { animation: none; }

/* Fige a mi-course plutot qu'eteints : sans cela les points, dont l'opacite de depart est nulle,
 * disparaitraient purement et simplement et le ciel serait vide. */
.auth-vitrine[data-mouvement="non"] .vitrine__point { opacity: .42; }

/* Un ruban immobile ne montre que ses premieres cartes : l'exemplaire en double n'a plus
 * d'objet, et le laisser ferait lire deux fois la meme liste. */
.auth-vitrine[data-mouvement="non"] .vitrine__ruban [data-exemplaire="2"] { display: none; }

/* --- Mouvement demande explicitement ------------------------------------------------------
 * Specificite superieure a celle des regles de la media query plus bas (trois classes contre
 * une) : la demande de la personne l'emporte sur la valeur par defaut, sans `!important`. */

.auth-vitrine[data-mouvement="oui"] .vitrine__ruban {
    animation: ruban-defile var(--ruban-duree, 72s) linear infinite;
}

.auth-vitrine[data-mouvement="oui"] .vitrine__trame {
    animation: trame-derive 120s linear infinite;
}

.auth-vitrine[data-mouvement="oui"] .vitrine__lueur {
    animation: lueur-derive 24s ease-in-out infinite alternate;
}

.auth-vitrine[data-mouvement="oui"] .vitrine__lueur--seconde {
    animation-duration: 31s;
    animation-direction: alternate-reverse;
}

.auth-vitrine[data-mouvement="oui"] .vitrine__point {
    animation: scintille var(--scintille-duree, 4s) ease-in-out var(--scintille-delai, 0s) infinite alternate;
}

.auth-vitrine[data-mouvement="oui"] .vitrine__ruban [data-exemplaire="2"] { display: block; }

/* --- La carte ----------------------------------------------------------------------------
 * Pas de cadre, pas d'ombre, pas de fond : sur une surface sombre, une carte dessinee
 * ajouterait une deuxieme lecture par-dessus celle du texte. La note porte seule.
 *
 * La pastille de rubrique occupe la place ou se trouvait l'avatar des temoignages, mais EN
 * TETE et non en pied : c'est une etiquette de classement, qui se lit avant, et non une
 * signature, qu'on cherche apres. La composition et les mesures, elles, n'ont pas bouge.
 */

.note {
    margin: 0;
    flex: none;
    /* Bornee des deux cotes : en dessous de 300 px une note se hache en huit lignes, au-dela de
     * 420 px l'oeil doit revenir trop loin a gauche a chaque retour a la ligne. */
    width: clamp(300px, 26vw, 420px);
}

.note__rubrique {
    display: inline-block;
    margin-bottom: var(--espace-4);
    padding: var(--espace-1) var(--espace-3);
    border-radius: var(--rayon-plein);
    background: var(--vitrine-relief);
    border: 1px solid var(--vitrine-trait);
    color: var(--vitrine-encre-attenuee);
    font-size: var(--taille-xs);
    font-weight: var(--graisse-appuyee);
    letter-spacing: var(--interlettre-menu);
    text-transform: uppercase;
    /* Deux mots au plus par rubrique : la pastille ne doit pas passer sur deux lignes, sans
     * quoi le pied des cartes du ruban cesse d'etre aligne. */
    white-space: nowrap;
}

.note__texte {
    margin: 0;
    color: var(--vitrine-encre);
    font-size: var(--taille-md);
    line-height: 1.6;
    letter-spacing: -.005em;
}


/* ==========================================================================================
 * 7. Mouvement reduit
 * ==========================================================================================
 * `prefers-reduced-motion` n'est pas une preference esthetique : pour une partie des gens, un
 * defilement continu declenche des nausees ou des migraines. On ne le ralentit donc pas, on
 * l'arrete — fond compris, halos compris.
 *
 * CE N'EST QU'UNE VALEUR PAR DEFAUT. La commande decrite plus haut permet de lancer le
 * defilement malgre ce reglage, parce que « animations reduites » est actif sur beaucoup de
 * postes pour des raisons qui n'ont rien a voir — economie d'energie, image systeme d'entreprise
 * — et que la personne doit pouvoir dire le contraire. Les regles ci-dessous sont donc ecrites
 * avec une seule classe, pour etre battues sans `!important` par
 * `.auth-vitrine[data-mouvement="oui"] …`.
 *
 * PAS D'ASCENSEUR HORIZONTAL. Une premiere version rendait le cadre defilable a la main quand
 * le ruban s'arretait : la barre devenait le premier objet de l'ecran, et transformait un decor
 * en quelque chose a manipuler. Un ruban arrete montre ses deux premieres citations et s'en
 * tient la ; qui veut les lire toutes lance le defilement.
 */
@media (prefers-reduced-motion: reduce) {
    .vitrine__ruban {
        animation: none;
        will-change: auto;
    }

    .vitrine__ruban [data-exemplaire="2"] { display: none; }

    .vitrine__trame,
    .vitrine__lueur { animation: none; }

    .vitrine__point { animation: none; opacity: .42; }

}
