/* ==========================================================================
   ESPACE CLIENT — 6. FORMULAIRES
   ==========================================================================
   Le vocabulaire de saisie de l'espace sombre : libellés, champs, aides,
   groupes de pilules, compteurs.

   ─────────────────────────────────────────────────────────────────────────
   LA RÈGLE À DEUX CROCHETS
   ─────────────────────────────────────────────────────────────────────────
   Chaque composant est écrit UNE FOIS, avec DEUX sélecteurs :

       .c-label,
       .c-body .form-label { … }

   Le premier est le nom NATIF : c'est celui qu'on écrit dans le markup neuf.
   Le second est le PLACAGE : il habille le markup qu'on ne possède pas — les
   vues partagées avec l'administration, les partials communs, et surtout le
   markup que le JavaScript injecte à l'exécution (card-create.js reconstruit
   des groupes de pilules Tabler dans la boîte des classifications ;
   searchable-select.js fabrique tout son composant).

   POURQUOI DEUX CROCHETS ET NON DEUX FEUILLES. Écrire une bibliothèque native
   puis une bibliothèque de placage, ce serait deux vérités pour un seul
   composant : elles divergeraient au premier ajustement, et l'écran plaqué
   finirait moins bien fini que l'écran natif. Une règle, deux sélecteurs : la
   divergence devient mécaniquement impossible.

   POURQUOI C'EST SANS DANGER POUR L'ADMINISTRATION. Les trois espaces posent
   trois classes de corps DISJOINTES : `app-app-body` (administration),
   `app-public` (public), `c-body` (client). Aucune règle préfixée `.c-body`
   ne peut donc atteindre l'administration ni la chaîne de rendu Puppeteer.
   L'immunité n'est pas une précaution d'écriture, elle est structurelle — et
   vérifiable d'un simple `grep` sur le préfixe.

   ON NE RENOMME QUE CE QU'ON POSSÈDE. `form-label`, `form-control`, `mb-3`,
   `text-danger`, `form-selectgroup*` restent tels quels dans les vues : ce
   sont des chaînes lues par du code partagé. Leur donner un crochet coûte une
   ligne ; les renommer coûterait une chasse dans 48 fichiers.

   Dépend de : client/tokens.css, client/base.css
   ========================================================================== */

/* ---------- Rythme vertical ---------------------------------------------- */
/* Le seul espacement entre deux blocs de champs. `mb-3` est la classe Tabler
   qu'emploient toutes les vues existantes : elle vaut 1rem chez eux, elle vaut
   1rem ici — on reprend la mesure, pas seulement le nom. */
.c-form-group,
.c-body .mb-3 { margin-bottom: var(--c-spacer); }

.c-form-group--last,
.c-body .mb-0 { margin-bottom: 0; }

/* ---------- Libellés ------------------------------------------------------ */
.c-label,
.c-body .form-label {
    display: block;
    margin-bottom: var(--c-spacer-xs);
    font-size: var(--c-font-size-sm);
    font-weight: 600;
    color: var(--c-ink);
}

/* L'astérisque du champ obligatoire. `.text-danger` est la classe Tabler que
   les vues emploient pour lui — même rôle, donc même règle. */
.c-req,
.c-body .text-danger { color: var(--c-danger); }

/* ---------- Un groupe de champ -------------------------------------------
   `app-form-group` / `app-form-label` / `app-required` : le vocabulaire de
   formulaire des vues PARTAGÉES. Ces trois règles vivaient dans
   client/rangs.css, la feuille d'un seul écran — si bien que tout autre écran
   client affichant un formulaire partagé se retrouvait sans marge entre ses
   groupes et sans intitulé dessiné : les champs se touchaient. Relevé le 28/09
   sur le formulaire de complétion de la carte publique. Leur place est ici,
   avec le reste des champs, pour tout l'espace client. */
.c-body .app-form-group { margin-bottom: var(--c-spacer); }
.c-body .app-form-group:last-child { margin-bottom: 0; }
.c-body .app-form-label {
    display: block;
    margin-bottom: var(--c-spacer-xs);
    color: var(--c-ink);
    font-size: var(--c-font-size-sm);
    font-weight: 600;
}
/* L'astérisque des champs obligatoires. */
.c-body .app-required { color: var(--c-danger); }

/* Une mention DANS un intitulé — « Rang (optionnel) » — reste sur sa ligne.
   `app-text-muted` est rendu en bloc par le socle (c'est aussi la classe des
   phrases d'aide) : le « (optionnel) » tombait sous son propre libellé. */
.c-body .app-form-label .app-text-muted,
.c-body .app-form-label small {
    display: inline;
    margin: 0;
    font-weight: 400;
}

/* ---------- Champs -------------------------------------------------------- */
/* `.app-form-input` / `.app-form-select` : les champs des partials partagés
   (le filtre déroulant des listes). Ajoutés aux MÊMES règles que les champs
   Tabler — un seul dessin de champ pour tout l'espace client. */
/* BORDURE EN PROPRIÉTÉS LONGUES, et ce n'est pas une coquetterie : dans le
   raccourci `border: 1px solid var(--x)`, un jeton manquant rend la
   déclaration ENTIÈRE invalide, `border-style` retombe à `none` et le champ
   perd toute bordure — sans le moindre message. En propriétés séparées, seule
   la couleur tomberait. */
.c-input,
.c-select,
.c-textarea,
.c-body .form-control,
.c-body .form-select,
.c-body .app-form-input,
.c-body .app-form-select,
/* `.app-form-textarea` manquait : un <textarea> des partials partagés tombait
   au rendu natif du navigateur — fond blanc, bordure grise — au milieu d'un
   formulaire sombre (vu le 28/09 sur « Demander ma photo »). */
.c-body .app-form-textarea {
    display: block;
    width: 100%;
    padding: 8px 12px;
    background-color: var(--c-field-bg);
    background-clip: padding-box;   /* liseré net sous un fond translucide */
    border-width: 1px;
    border-style: solid;
    border-color: var(--c-field-border);
    border-radius: var(--c-radius);
    color: var(--c-ink);
    line-height: 1.5;
    transition: border-color var(--c-transition), box-shadow var(--c-transition);
}

.c-input::placeholder,
.c-textarea::placeholder,
.c-body .form-control::placeholder,
.c-body .app-form-input::placeholder,
.c-body .app-form-textarea::placeholder { color: var(--c-placeholder); }

.c-input:hover,
.c-select:hover,
.c-textarea:hover,
.c-body .form-control:hover,
.c-body .form-select:hover,
.c-body .app-form-input:hover,
.c-body .app-form-select:hover,
.c-body .app-form-textarea:hover { border-color: var(--c-field-border-hover); }

/* L'anneau de focus des champs est plus doux que le contour global de
   base.css : sur un rectangle déjà bordé, un contour de 2 px se lit comme une
   seconde bordure. On garde le contour pour tout le reste. */
.c-input:focus-visible,
.c-select:focus-visible,
.c-textarea:focus-visible,
.c-body .form-control:focus-visible,
.c-body .form-select:focus-visible,
.c-body .app-form-input:focus-visible,
.c-body .app-form-select:focus-visible,
.c-body .app-form-textarea:focus-visible {
    outline: none;
    border-color: var(--c-accent);
    box-shadow: 0 0 0 3px var(--c-field-ring);
}

.c-input:disabled,
.c-select:disabled,
.c-body .form-control:disabled,
.c-body .form-select:disabled,
.c-body .app-form-input:disabled,
.c-body .app-form-select:disabled {
    background-color: var(--c-field-bg-disabled);
    color: var(--c-ink-faint);
    cursor: not-allowed;
}

/* L'icône du sélecteur de date : le gabarit déclare `color-scheme: dark`, le
   navigateur la dessine donc déjà en CLAIR. Le `filter: invert(1)` d'origine la
   repassait en noir, presque invisible (audit du 15/10) : retiré. */
.c-body input[type="date"]::-webkit-calendar-picker-indicator {
    opacity: .65;
    cursor: pointer;
}
.c-body input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* ---------- Le libellé d'une ligne de formulaire partagée -------------------
   `shared/form-row` et les fiches partagées écrivent `col-3 col-form-label` :
   le libellé à gauche, le champ à droite (la grille elle-même est portée dans
   client/components.css). Au téléphone, il repasse au-dessus du champ. */
.c-body .col-form-label {
    padding-top: 9px;
    color: var(--c-ink-dim);
    font-size: var(--c-font-size-sm);
    font-weight: 500;
}
@media (max-width: 768px) {
    .c-body .col-form-label { padding-top: 0; }
}

/* ---------- Le champ mot de passe (shared/password-field) -------------------
   L'œil qui révèle, le bouton qui propose un mot de passe, et la jauge de
   solidité. Porté de root.css (23/09, avec les pages annexes). */
.c-body .app-password-wrapper { position: relative; }
.c-body .app-password-wrapper > .form-control { padding-right: 2.5rem; }
.c-body .app-password-wrapper:has(.app-password-generate) > .form-control { padding-right: 4.5rem; }
.c-body .app-password-toggle,
.c-body .app-password-generate {
    position: absolute;
    top: 50%;
    display: flex;
    align-items: center;
    padding: .25rem;
    border: 0;
    background: none;
    color: var(--c-ink-faint);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    transform: translateY(-50%);
    transition: color var(--c-transition);
}
.c-body .app-password-toggle { right: .625rem; }
.c-body .app-password-generate { right: 2.5rem; }
.c-body .app-password-toggle:hover { color: var(--c-ink); }
.c-body .app-password-generate:hover { color: var(--c-accent); }
.c-body .app-password-generate.is-copied::after {
    content: 'Copié !';
    position: absolute;
    left: 50%;
    bottom: calc(100% + 4px);
    padding: 2px 8px;
    border-radius: var(--c-radius-sm);
    background: var(--c-elev-3);
    color: var(--c-ink);
    font-size: .7rem;
    white-space: nowrap;
    transform: translateX(-50%);
    pointer-events: none;
}
.c-body .app-password-strength { margin-top: var(--c-spacer-xs); }
.c-body .app-password-strength__track {
    height: 4px;
    border-radius: 2px;
    background: var(--c-elev-3);
    overflow: hidden;
}
.c-body .app-password-strength__bar {
    width: var(--c-force, 0);
    height: 100%;
    border-radius: 2px;
    background: var(--c-danger);
    transition: width .3s ease, background .3s ease;
}
.c-body .app-password-strength__bar.is-force-1 { background: var(--c-danger); }
.c-body .app-password-strength__bar.is-force-2 { background: var(--c-warning); }
.c-body .app-password-strength__bar.is-force-3 { background: var(--c-warning); }
.c-body .app-password-strength__bar.is-force-4 { background: var(--c-accent); }
.c-body .app-password-strength__bar.is-force-5 { background: var(--c-success); }
.c-body .app-password-strength__label { margin-top: var(--c-spacer-xs); color: var(--c-ink-dim); font-size: var(--c-font-size-xs); }

/* ---------- Aides et messages -------------------------------------------- */
.c-hint,
.c-body .form-hint,
.c-body .app-text-muted {
    display: block;
    margin-top: var(--c-spacer-xs);
    font-size: var(--c-font-size-xs);
    line-height: var(--c-line-height-prose);
    color: var(--c-ink-dim);
}
/* Une aide posée dans une boîte de couleur reprend un fond à elle, sinon elle
   se confond avec la boîte. */
.c-hint--boxed,
.c-body .form-hint {
    padding: var(--c-spacer-sm) var(--c-spacer);
    background: var(--c-elev-1);
    border: 1px solid var(--c-line-soft);
    border-radius: var(--c-radius);
    color: var(--c-ink-dim);
}
.c-body .form-hint strong { color: var(--c-ink); }

/* ---------- Groupe de pilules (radios) -----------------------------------
   `form-selectgroup` est le nom Tabler du groupe de boutons-radios. Il arrive
   ici par DEUX chemins : le partial de catégories l'écrit en PHP, et
   card-create.js le RECONSTRUIT à l'exécution pour les classifications. Le
   placage est donc obligatoire — il n'y a pas de markup à renommer dans le
   second cas. */
.c-pills,
.c-body .form-selectgroup {
    display: flex;
    flex-wrap: wrap;
    gap: var(--c-spacer-sm);
    margin: 0;
    padding: 0;
}

.c-pill,
.c-body .form-selectgroup-item {
    position: relative;
    display: inline-flex;
    margin: 0;
    cursor: pointer;
}

/* Le radio réel reste dans le flux mais invisible : le retirer du DOM ou le
   passer en `display:none` le sortirait de la navigation au clavier. */
.c-body .form-selectgroup-input {
    position: absolute;
    width: 1px; height: 1px;
    margin: 0;
    opacity: 0;
    pointer-events: none;
}

.c-pill__label,
.c-body .form-selectgroup-label {
    display: inline-flex;
    align-items: center;
    gap: var(--c-spacer-xs);
    padding: 6px 14px;
    border-radius: var(--c-radius-pill);
    border: 1px solid var(--c-line);
    background: var(--c-elev-2);
    background-clip: padding-box;
    color: var(--c-ink-dim);
    font-size: var(--c-font-size-sm);
    line-height: 1.4;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--c-transition), border-color var(--c-transition), color var(--c-transition);
}
.c-pill__label:hover,
.c-body .form-selectgroup-label:hover {
    border-color: var(--c-field-border-hover);
    color: var(--c-ink);
}

/* La pilule cochée. `:checked + label` est la structure que produisent Tabler
   ET le partial de catégories : l'un et l'autre posent l'input AVANT son
   libellé, dans la même étiquette parente. */
.c-body .form-selectgroup-input:checked + .form-selectgroup-label,
.c-pill__input:checked + .c-pill__label {
    background: var(--c-accent);
    border-color: transparent;
    color: var(--c-on-accent);
    font-weight: 600;
}
/* Le focus clavier doit rester visible même quand la pilule est cochée :
   sans cela, on ne sait plus où l'on est dans le groupe. */
.c-body .form-selectgroup-input:focus-visible + .form-selectgroup-label {
    outline: 2px solid var(--c-accent);
    outline-offset: 2px;
}

/* ---------- Boîte de champ ------------------------------------------------
   Le conteneur gris qui regroupe plusieurs lignes de choix (les
   classifications). Deux noms pour un seul objet, là encore. */
.c-fieldbox,
.c-body .app-field-box {
    padding: var(--c-spacer);
    background: var(--c-elev-1);
    border: 1px solid var(--c-line-soft);
    border-radius: var(--c-radius);
}

/* ---------- Compteur −/+ --------------------------------------------------
   Le partial de compteur écrit `app-bulk-counter` en dur et son script lit ces
   mêmes classes. On le plaque, on ne le réécrit pas. */
.c-counter,
.c-body .app-bulk-counter {
    display: inline-flex;
    align-items: center;
    gap: var(--c-spacer-sm);
}
.c-body .app-bulk-counter__btn {
    display: grid;
    place-items: center;
    width: 36px; height: 36px;
    border-radius: var(--c-radius);
    border: 1px solid var(--c-line);
    background: var(--c-elev-2);
    background-clip: padding-box;
    color: var(--c-ink);
    cursor: pointer;
    transition: background var(--c-transition), border-color var(--c-transition);
}
.c-body .app-bulk-counter__btn:hover {
    background: var(--c-elev-3);
    border-color: var(--c-field-border-hover);
}
.c-body .app-bulk-counter__btn:disabled {
    opacity: .4;
    cursor: not-allowed;
}
.c-body .app-bulk-counter__input {
    width: 64px;
    padding: 6px 8px;
    background-color: var(--c-field-bg);
    background-clip: padding-box;
    border-width: 1px;
    border-style: solid;
    border-color: var(--c-field-border);
    border-radius: var(--c-radius);
    color: var(--c-ink);
    font-weight: 650;
    font-size: var(--c-font-size-lg);
    text-align: center;
    font-variant-numeric: tabular-nums;   /* le nombre ne tremble pas */
    /* Les flèches natives du champ numérique doublonnent les deux boutons. */
    -moz-appearance: textfield;
    appearance: textfield;
}
.c-body .app-bulk-counter__input::-webkit-outer-spin-button,
.c-body .app-bulk-counter__input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

/* ---------- Les cases à cocher et les interrupteurs -------------------------
   `form-check`, `form-switch`, `form-check-input` sont les noms Tabler : les
   vues partagées les écrivent, et le gabarit client ne charge pas Tabler — la
   case tombait donc au rendu natif du navigateur, BLEUE. Ici : la ligne
   (case + libellé), et la case prise à la teinte du socle par `accent-color`.
   Même dessin que les cases de l'aperçu d'une carte (`.c-case`).

   Sert « Mon club » (adresse de livraison identique, interrupteurs) et, depuis
   le 23/09, la modale de création d'un sous-compte (envoi des identifiants).
   Un vrai interrupteur à bascule demanderait de redessiner la case : la
   différence ne vaut pas la pièce, la case dit déjà oui ou non. */
.c-body .form-check {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    margin: 0;
    padding: 0;
    color: var(--c-ink);
    font-size: var(--c-font-size-sm);
    line-height: var(--c-line-height-prose);
    cursor: pointer;
}
.c-body .form-check-input {
    flex: none;
    width: 18px;
    height: 18px;
    margin: 2px 0 0;
    accent-color: var(--c-accent);
    cursor: pointer;
}
.c-body .form-check-input:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }
.c-body .form-check-label { cursor: pointer; }

/* ---------- Suggestions Code postal / Ville (address-autocomplete.js) ------
   Le menu est posé sur <body>, en position fixe sous le champ actif. La feuille
   claire de l'administration (address-autocomplete.css) n'est pas chargée dans
   l'espace club : sans ces règles complètes, « Mon club » affichait une liste
   de boutons nus (16/10, avec l'inscription passée en sombre). `hidden` reste
   l'interrupteur du script : aucune règle `display` ici. */
.c-body .app-addr-ac-menu {
    position: fixed;
    z-index: var(--c-z-pop);
    max-height: 15rem;
    overflow-y: auto;
    padding: var(--c-spacer-xs);
    background: var(--c-elev-2);
    border: 1px solid var(--c-glass-line);
    border-radius: var(--c-radius);
    box-shadow: var(--c-shadow-lg);
}
.c-body .app-addr-ac-item {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--c-spacer-sm);
    width: 100%;
    padding: .5rem .65rem;
    border: 0;
    border-radius: var(--c-radius-sm);
    background: transparent;
    font-family: inherit;
    font-size: var(--c-font-size-sm);
    color: var(--c-ink);
    text-align: left;
    cursor: pointer;
}
.c-body .app-addr-ac-item.is-active,
.c-body .app-addr-ac-item:hover { background: var(--c-elev-3); }
.c-body .app-addr-ac-item__name {
    font-weight: 500;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.c-body .app-addr-ac-item__cp {
    flex-shrink: 0;
    color: var(--c-ink-dim);
    font-size: var(--c-font-size-xs);
}
@keyframes c-addr-ac-flash {
    0%   { box-shadow: 0 0 0 3px var(--c-field-ring); }
    100% { box-shadow: 0 0 0 0 transparent; }
}
.c-body .app-addr-ac-filled { animation: c-addr-ac-flash .9s ease; }
