/* ==========================================================================
   Écrans d'authentification — connexion, inscription, vérification d'adresse,
   mot de passe oublié.
   --------------------------------------------------------------------------
   Ces styles vivaient dans un `<style>` de `web/login.php`, seule page publique
   du produit. L'inscription self-serve en a amené quatre : les recopier
   quatre fois garantissait qu'un bouton finirait par ne plus ressembler aux
   trois autres, sur le premier écran que voit un nouveau client.

   Les noms de classes gardent leur préfixe `login-` : ils sont posés dans le
   gabarit ET dans le JS de chaque page, et un renommage cosmétique aurait
   touché plus de fichiers qu'il n'en aurait clarifié.
   ========================================================================== */

/* ==========================================================================
   Écran partagé : formulaire à gauche sur blanc, vitrine à droite.
   --------------------------------------------------------------------
   L'ancienne page posait une carte blanche au milieu d'un aplat vert :
   on passait d'un plein écran coloré à un dashboard blanc, avec une
   rupture visuelle à chaque connexion. Ici, la moitié gauche EST déjà
   le fond de l'application — logo au même endroit, sélecteur de langue
   au même endroit, mêmes couleurs.
   ========================================================================== */
html, body {
    height: 100%;
}

body {
    margin: 0;
    overflow: hidden;
}

.login-split {
    display: flex;
    min-height: 100vh;
}

/* Colonne du formulaire. `overflow-y: auto` malgré le « pas de scroll »
   attendu : la création du tout premier compte affiche trois champs de
   plus, et sur un portable en paysage la page doit rester utilisable
   plutôt que rogner le bouton. Le DOCUMENT, lui, ne défile jamais. */
.login-pane {
    flex: 0 0 44%;
    max-width: 44%;
    background: #fff;
    display: flex;
    flex-direction: column;
    padding: 28px 40px;
    overflow-y: auto;
}

/* Logo complet (symbole + nom) au-dessus du titre. C'est lui qui porte
   le nom du produit : le titre en dessous ne le répète donc pas. */
.login-logo {
    display: flex;
    justify-content: center;
    margin-bottom: 24px;
}

.login-logo img {
    /* Plafonné à 400px, soit la largeur de la colonne du formulaire,
       et bien en deçà des 910px de la source : jamais d'agrandissement
       flou, même en densité 2x. `width: 100%` pour que le logo se
       réduise avec la colonne sur les écrans étroits. */
    width: 100%;
    max-width: 400px;
    height: auto;
}

/* Le formulaire occupe l'espace restant et se centre dedans. */
.login-main {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 0;
    padding: 32px 0;
}

.login-box {
    width: 100%;
    max-width: 400px;
    margin: 0 auto;
}

.login-foot {
    flex: none;
    display: flex;
    align-items: center;
}

/* Le composant de langue est dimensionné pour une sidebar (100 % de sa
   colonne) : en pied de page, on le borne pour qu'il ne s'étire pas. */
.login-foot .lang-switch {
    width: 190px;
}

/* ---- Vitrine (droite) ---- */
.login-showcase {
    flex: 1;
    min-width: 0;
    background:
        radial-gradient(120% 90% at 82% 8%, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0) 55%),
        linear-gradient(150deg, var(--primary-color) 0%, var(--primary-dark) 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    /* L'écart texte ↔ capture vit ICI, dans le `gap` du conteneur, et
       nulle part ailleurs : une marge basse sur le texte viendrait s'y
       ajouter au lieu de la remplacer, et l'on chercherait longtemps
       d'où sortent les 72px. */
    gap: 48px;
    padding: 48px;
    overflow: hidden;
}

/* Le bloc de texte doit tenir tête au panneau : à 25px de titre et 15px
   de sous-titre, il flottait au milieu du vert. `max-width: 480px` force
   un retour à la ligne sur deux ou trois lignes plutôt que des lignes
   étirées d'un bord à l'autre. */
.login-claim {
    max-width: 480px;
    margin: 0;
    text-align: center;
    color: #fff;
    font-size: 1.875rem; /* 30px */
    line-height: 1.25;
    font-weight: 700;
    letter-spacing: -0.015em;
}

.login-claim span {
    display: block;
    margin-top: 16px;
    font-size: 1rem; /* 16px */
    font-weight: 400;
    line-height: 1.5;
    /* Opacité remontée : à 0.82 le sous-titre se diluait dans le vert. */
    color: rgba(255, 255, 255, 0.9);
}

/* Capture inclinée : la perspective donne la profondeur demandée sans
   avoir à produire un mockup en image. */
.login-shot {
    /* +13 % : à 760px l'interface n'était plus lisible et laissait du
       vert vide autour. Avec le `scale(1.02)` plus bas, l'image est
       rendue à 877px CSS — 1754px en densité 2x. La source fait
       1846×895, sa taille de capture native : elle couvre ce 2x sans
       qu'on l'ait retouchée, et un peu au-delà, ce qu'exige le bord que
       la perspective rapproche (~+6 %). La réduire à 1754 pour « coller »
       au chiffre théorique hacherait le texte fin de la capture. */
    width: min(860px, 100%);
    border-radius: 12px;
    box-shadow: 0 30px 70px -20px rgba(4, 30, 24, 0.55);
    transform: perspective(1400px) rotateY(-11deg) rotateX(3deg) scale(1.02);
    /* PAS de `will-change: transform` ici. Il promeut l'image en couche
       de composition : elle est alors tramée UNE fois à sa taille sans
       transformation, puis ré-échantillonnée par le GPU à travers la
       perspective — d'où un flou permanent sur une source pourtant
       nette. Sans lui, le navigateur trame en tenant compte de la
       transformation. L'image ne s'anime pas, la promotion n'apportait
       rien. */
}

/* ---- Responsive : le split n'a de sens qu'en grand écran ---- */
@media (max-width: 1024px) {
    .login-showcase { display: none; }
    .login-pane {
        flex: 1 1 100%;
        max-width: 100%;
        padding: 22px 20px;
    }
}

.login-header {
    text-align: center;
    margin-bottom: 2rem;
}

.login-title {
    font-size: 1.8rem;
    color: var(--text-primary);
    margin: 0 0 0.5rem;
}

.login-subtitle {
    color: var(--text-secondary);
    font-size: 0.95rem;
}

.setup-alert {
    background: #FFF3CD;
    border: 1px solid #FFE69C;
    border-radius: 8px;
    padding: 1rem;
    margin-bottom: 1.5rem;
    display: flex;
    gap: 0.75rem;
}

.setup-alert-icon {
    color: #856404;
    flex-shrink: 0;
}

.setup-alert-content {
    color: #856404;
    font-size: 0.9rem;
}

.login-form {
    margin-bottom: 1rem;
}

.form-group {
    margin-bottom: 1.25rem;
}

.form-label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--text-primary);
    font-weight: 500;
}

.form-input {
    width: 100%;
    padding: 0.75rem 1rem;
    border: 2px solid var(--border-color);
    border-radius: 8px;
    font-size: 1rem;
    transition: all 0.3s ease;
}

/* Le focus reprend le vert de la CHARTE (`--primary-color`), pas le
   #4ECDC4 codé en dur qui traînait ici : c'est l'ancien vert, plus terne
   et désaturé que celui du panneau de droite — deux verts sur le même
   écran, l'écart se voyait. */
.form-input:focus {
    outline: none;
    border-color: var(--primary-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 18%, transparent);
}

/* Champ en erreur qu'on vient corriger : le focus reprend la main. La
   règle suit celle du focus, donc la même spécificité — c'est l'ordre
   qui tranche, et il faut qu'elle vienne après `.has-error`. */
.form-input.has-error:focus {
    border-color: var(--primary-color);
}

/* Bandeau d'erreur.
   L'ancien `.error-message` était un aplat rose plein largeur qui
   repoussait brutalement les champs et criait « Erreur : ». Ici : fond
   très clair, filet rouge à gauche pour l'accroche du regard, icône, et
   un rayon identique à celui des champs pour que l'ensemble reste d'une
   seule famille. */
.login-error-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    /* Fond BLANC : le filet rouge, l'icône et le texte disent déjà tout.
       Un aplat rosé par-dessus en rajoutait sans rien apprendre. */
    background: #fff;
    border: 1px solid #FEE2E2;
    border-left: 3px solid #EF4444;
    border-radius: 8px;
    padding: 10px 14px;
    margin-bottom: 1rem;
    color: #991B1B;
    font-size: 0.85rem;
    font-weight: 500;
    line-height: 1.4;
}

.login-error-banner .material-symbols-outlined {
    font-size: 18px;
    color: #EF4444;
    flex: none;
}

/* Champs en erreur : bordure rouge LÉGÈRE, jamais un fond coloré — le
   champ doit rester lisible pendant qu'on le corrige. */
.form-input.has-error {
    border-color: #FCA5A5;
}

.btn-login {
    width: 100%;
    /* Respiration au-dessus : le bouton est L'action de la page, il ne
       doit pas coller à la ligne « se souvenir / mot de passe oublié ». */
    margin-top: 0.5rem;
    padding: 0.875rem;
    background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-dark) 100%);
    /* Jeton d'encre de marque, pas un blanc en dur : le vert s'ÉCLAIRCIT en
       mode sombre, l'encre posée dessus fait donc le chemin inverse
       (`--on-brand-fill` vaut #FFFFFF en clair, #06231C en sombre). Garde :
       tests/Unit/BrandInkGuardTest.php. */
    color: var(--on-brand-fill);
    border: none;
    border-radius: 8px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
}

.btn-login:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--primary-color) 40%, transparent);
}

.btn-login:active {
    transform: translateY(0);
}

.form-helper {
    font-size: 0.85rem;
    color: var(--text-secondary);
    margin-top: 0.25rem;
}

.password-field {
    position: relative;
}

.password-field .form-input {
    padding-right: 3rem;
}

.password-toggle {
    position: absolute;
    top: 50%;
    right: 0.625rem;
    width: 2rem;
    height: 2rem;
    transform: translateY(-50%);
    border: 0;
    border-radius: 6px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease, color 0.2s ease;
}

.password-toggle:hover,
.password-toggle:focus {
    background: rgba(78, 205, 196, 0.1);
    color: #2C3E50;
    outline: none;
}

.password-toggle .material-symbols-outlined {
    font-size: 1.25rem;
}

/* ---------------------------------------------------------------------------
   Checklist de mot de passe (partials/password-requirements.php)

   Une ligne par critère, cochée pendant la frappe. Deux états seulement :
   EN ATTENTE (gris, puce vide) et REMPLI (vert de marque, coche). Pas de
   rouge — on ne sanctionne pas une saisie en cours ; voir l'en-tête du
   partial. Toutes les couleurs passent par des jetons, le panneau suit donc
   le mode sombre sans règle propre.
   --------------------------------------------------------------------------- */
.pwd-rules {
    margin-top: 0.5rem;
    font-size: 0.8rem;
    color: var(--text-secondary);
    line-height: 1.5;
}

.pwd-rules-list,
.pwd-family-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.pwd-rule {
    display: flex;
    align-items: center;
    /* La ligne « familles » porte une sous-liste : elle doit pouvoir passer
       à la ligne SOUS son propre libellé plutôt que de le comprimer. */
    flex-wrap: wrap;
    gap: 0.375rem;
    margin-top: 0.25rem;
    transition: color 0.2s ease;
}

.pwd-rule-icon,
.pwd-family-icon {
    flex: none;
    color: var(--gray-dot-border);
    /* Largeur FIXE et glyphe centré dedans : la puce en attente est dessinée
       plus petite que la coche qui la remplace (un `circle` à taille de coche
       fait un gros anneau qui pèse plus lourd que le critère rempli), et sans
       cette largeur imposée le libellé se décalerait d'un ou deux pixels
       chaque fois qu'une ligne passe au vert. */
    width: 1.25rem;
    text-align: center;
    font-size: 1rem;
}

.pwd-rule:not(.is-done) > .pwd-rule-icon {
    font-size: 0.6875rem;
}

.pwd-family-icon {
    width: 1.125rem;
    font-size: 0.875rem;
}

.pwd-family:not(.is-done) > .pwd-family-icon {
    font-size: 0.5rem;
}

.pwd-rule.is-done,
.pwd-family.is-done {
    color: var(--success);
}

.pwd-rule.is-done > .pwd-rule-icon,
.pwd-family.is-done > .pwd-family-icon {
    color: var(--success);
}

/* Les quatre familles, en retrait sous leur ligne parente. `flex-basis: 100%`
   les envoie à la ligne suivante dans le `.pwd-rule` qui les contient. */
.pwd-family-list {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.75rem;
    /* Aligné sur le texte du parent, pas sur sa puce. */
    padding-left: 1.375rem;
    font-size: 0.75rem;
}

.pwd-family {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
}

/* Le mot d'état (« rempli » / « à faire ») n'existe que pour les lecteurs
   d'écran : à l'œil, c'est la coche verte qui le dit. Masqué sans
   `display: none`, qui le retirerait aussi de la restitution vocale. */
.pwd-rule-state {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Sélecteur scopé sur `.login-check-row`, et ce n'est pas décoratif :
   style.css:1368 pose `.form-group label { display: block; margin-bottom: .5rem }`.
   Le conteneur porte `form-group`, donc ce sélecteur à deux composants
   battait `.form-check-label` seul — le label n'était PAS un conteneur
   flex, et `align-items` comme `gap` étaient purement décoratifs. */
.login-check-row .form-check-label {
    display: inline-flex;
    align-items: center;
    /* L'écart se règle ici et pas par une espace dans le libellé :
       une espace de texte dépend de la police et de la langue, et se
       retrouve dans la sélection comme dans les traductions. */
    gap: 6px;
    /* Annule le margin-bottom hérité de `.form-group label`. */
    margin-bottom: 0;
    font-weight: 400;
    color: var(--text-secondary);
    font-size: 0.85rem;
    line-height: 1.4;
    cursor: pointer;
    /* Le libellé fait partie de la zone de clic : sans ça, cliquer
       dessus cochait la case ET sélectionnait le texte. */
    user-select: none;
}

/* Le texte porte sa propre hauteur de ligne, donc une boîte à la mesure
   de ce qu'on lit : c'est elle que `align-items: center` centre face à
   la case. */
.login-check-row .form-check-text {
    line-height: 16px;
}

/* Case à cocher DESSINÉE, pas la case native du navigateur.
   `accent-color` seul ne teinte que l'état coché : au repos, la case
   restait le carré brut du système, avec sa bordure et sa hauteur de
   ligne à lui — d'où le décalage vertical avec le texte à côté.
   `appearance: none` reprend la main sur les deux états. */
.login-check-row .form-check-label input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    flex: none;
    width: 16px;
    height: 16px;
    margin: 0;
    border: 1px solid var(--border-color-strong, #DCE2E6);
    border-radius: 4px;
    background: #fff;
    cursor: pointer;
    display: inline-grid;
    place-content: center;
    transition: background 0.12s ease, border-color 0.12s ease;
}

/* La coche : deux traits blancs tracés en CSS, donc nets à toute
   densité d'écran et sans dépendre de la police d'icônes. */
.login-check-row .form-check-label input[type="checkbox"]::after {
    content: '';
    width: 9px;
    height: 5px;
    border-left: 2px solid #fff;
    border-bottom: 2px solid #fff;
    transform: rotate(-45deg) translate(0.5px, -1px);
    opacity: 0;
}

.login-check-row .form-check-label input[type="checkbox"]:checked {
    background: var(--primary-color);
    border-color: var(--primary-color);
}

.login-check-row .form-check-label input[type="checkbox"]:checked::after {
    opacity: 1;
}

.login-check-row .form-check-label input[type="checkbox"]:hover:not(:checked) {
    border-color: var(--primary-color);
}

.login-check-row .form-check-label input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--primary-color);
    outline-offset: 2px;
}

/* « Se souvenir de moi » à gauche, « Mot de passe oublié ? » à droite,
   tous deux centrés sur la même ligne médiane. */
.login-check-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 12px;
}

/* Pas de soulignement au repos : le trait noir par défaut faisait daté.
   Couleur de lien de l'application, soulignement réservé au survol.
   `line-height: 1` et alignement sur la ligne de base de la case à
   cocher — sans quoi le lien flottait un ou deux pixels trop haut. */
.login-forgot {
    background: none;
    border: none;
    padding: 0;
    font-family: inherit;
    font-size: 0.85rem;
    line-height: 1.4;
    color: var(--primary-dark);
    text-decoration: none;
    cursor: pointer;
}

.login-forgot:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Lien secondaire sous le formulaire : « Pas encore de compte ? Créer un
   compte », « Retour à la connexion ». Centré, discret, mais bien un lien —
   c'est le seul chemin entre les quatre écrans publics. */
.login-alt-action {
    margin: 1.25rem 0 0;
    text-align: center;
    font-size: 0.875rem;
    color: var(--text-secondary);
}

.login-alt-action a {
    color: var(--primary-dark);
    font-weight: 600;
    text-decoration: none;
}

.login-alt-action a:hover {
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Bloc d'attente de la vérification d'adresse : grande icône, l'adresse
   destinataire en évidence, et le bouton de renvoi. */
.verify-hero {
    text-align: center;
    margin-bottom: 1.5rem;
}

.verify-hero .material-symbols-outlined {
    font-size: 52px;
    color: var(--primary-color);
}

.verify-email {
    display: block;
    margin: 0.35rem 0 0;
    font-weight: 600;
    color: var(--text-primary);
    word-break: break-all;
}

/* Retour d'un renvoi d'email : succès en vert, attente ou échec en gris. Le
   texte est écrit par le JS ; la zone est un `aria-live` pour qu'un lecteur
   d'écran l'annonce sans avoir à retrouver le message. */
.verify-feedback {
    margin: 0.85rem 0 0;
    font-size: 0.85rem;
    line-height: 1.5;
    color: var(--text-secondary);
}

.verify-feedback.is-success {
    color: var(--primary-dark);
}

/* ==========================================================================
   Sélecteur d'offre de l'inscription (`web/register.php`)
   --------------------------------------------------------------------------
   Motif bouton + menu du design system, et non un `<select>` natif : ce
   dernier se dessine avec les polices et les couleurs du système, et
   DIFFÉREMMENT sur chaque machine — ce qui passe sur l'une est cassé sur
   l'autre. Voir [[Éléments de formulaire]] ; `NativeSelectGuardTest` refuse
   tout nouvel ajout.

   Les cotes reprennent celles de `.form-input` (bordure de 2 px, rayon de
   8 px, même hauteur de frappe) : posé au milieu de cinq champs de saisie, le
   sélecteur doit appartenir à la même famille, pas ressembler à un bouton
   égaré dans un formulaire.
   ========================================================================== */

.rg-select {
    position: relative;
}

.rg-select-btn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    padding: 0.6rem 0.85rem;
    border: 2px solid var(--border-color);
    border-radius: 8px;
    background: var(--card-bg, #fff);
    font-family: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.2s ease;
}

/* Le survol FONCE le trait et ne touche pas au texte : le libellé est déjà
   sombre, l'éclaircir réduirait son contraste. */
.rg-select-btn:hover,
.rg-select.open .rg-select-btn {
    border-color: var(--primary-color);
}

.rg-select-btn:focus-visible {
    outline: 2px solid var(--primary-dark);
    outline-offset: 2px;
}

.rg-select-current {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
}

.rg-select-name {
    display: block;
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--text-primary);
}

.rg-select-meta {
    display: block;
    font-size: 0.8rem;
    color: var(--text-secondary);
}

.rg-select-caret {
    flex-shrink: 0;
    font-size: 20px;
    color: var(--text-secondary);
    transition: transform 0.2s ease;
}

.rg-select.open .rg-select-caret {
    transform: rotate(180deg);
}

.rg-select-menu {
    display: none;
    position: absolute;
    z-index: 60;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    max-height: 280px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    background: var(--card-bg, #fff);
    box-shadow: 0 12px 32px rgba(16, 26, 34, 0.14);
}

.rg-select.open .rg-select-menu {
    display: block;
}

.rg-select-item {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    width: 100%;
    padding: 0.5rem 0.65rem;
    border: none;
    border-radius: 7px;
    background: transparent;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}

.rg-select-item:hover {
    background: var(--primary-bg);
}

.rg-select-item.active {
    background: var(--primary-bg);
}

.rg-select-item.active .rg-select-name {
    color: var(--primary-dark);
}

.rg-plan-note {
    margin: -0.75rem 0 1.25rem;
    font-size: 0.82rem;
    line-height: 1.5;
    color: var(--text-secondary);
}
