# #114 — Configuration — refonte mobile-responsive de la section Settings > **Statut :** 🟢 · **Impact :** 🟡 · **Zone :** frontend (mobile, ≤ 768 px) > **Fichiers :** `frontend/index.html`, `frontend/js/config.js`, `frontend/style.css`, > `frontend/locales/{fr,en}.json`, `tests/frontend/config-mobile.test.mjs`, > `tests/e2e/config-mobile.spec.js`. ## Contexte La page **Configurations** (`#config-modal`) était utilisable en mobile seulement partiellement (correctifs BUG-071) : le sommaire s'ouvrait en bloc haut, la modale n'était pas plein écran, les cibles tactiles étaient sous 44 px, le clavier virtuel iOS zoomait les champs, la rangée « Sauvegarder » disparaissait au scroll et plusieurs dettes HTML/i18n étaient restées en place. ## Ce qui a été livré ### A. Sommaire en drawer coulissant - `#config-nav` devient un **panneau coulissant gauche** (`position: fixed`, `width: min(320px, 88vw)`, `z-index: 40`) sous un fond assombri (`#config-modal.config-toc-open::before`, `z-index: 35`). - Ouverture/fermeture pilotée par la classe **`.config-toc-open`** sur `#config-modal` (JS `_setConfigNav`) + un `display` inline conservé pour le contrat de reset. - Bouton **`#config-toc-close`** (classe `.help-toc-close`, `aria-label` `config.toc_close`) dans l'en-tête du drawer ; visible uniquement dans le drawer de la config (masqué sur desktop où la nav est toujours visible). - **Backdrop** : un tap hors du drawer ferme d'abord le drawer, pas la modale (`e.target === modal` → `config-toc-open` présent → `_setConfigNav(false)`). - **Échap** : ferme le drawer d'abord, puis la modale. - Fermeture de la modale (`closeConfigModal`) nettoie toujours la classe `config-toc-open` et le `display` inline (aucun fond ne subsiste). - Animation `config-toc-slide-in` (translateX) à l'ouverture. ### B. Modale plein écran - `#config-modal` : `padding: 0`, `.editor-container` en `100vw × 100dvh` (`100dvh` = hauteur du viewport dynamique, tient compte de la barre du navigateur mobile), `border-radius: 0`, `border: none`. - Le contenu (`#config-scroll`) garde son scroll propre ; le sous-bloc `.config-content` reçoit un `padding-bottom: 80 px` pour ne jamais passer sous la rangée sticky. ### C. Cibles tactiles ≥ 44 px & anti-zoom iOS - **Champs** : `.config-input`, `.config-select`, `.help-nav-search`, `.profile-field .config-input/.config-select` → `min-height: 44px` + `font-size: 16px` (**anti-zoom iOS** : un `font-size < 16px` déclenche le zoom automatique au focus). La règle est **scoppée `#config-modal`** pour ne pas écraser `.mfa-code-input` (qui a sa propre typographie). - **Boutons** : `.config-btn-save`, `.config-btn-secondary`, `.config-btn-primary`, `.config-btn-danger`, `.config-btn-add`, `.config-btn-sm`, `.mfa-link-btn`, `.theme-action-btn`, `.profile-avatar-actions .config-btn-secondary`, `.editor-btn` (fermer), `#config-hamburger`, `#config-toc-close`, `.help-search-clear` → `min-height/min-width: 44px`. - **Liens du sommaire** : `.help-nav-link` → `min-height: 44px` (ligne tactile confortable). - `.help-hamburger` passe de 36 px à **44 px** en mobile (règle partagée avec le modal d'aide). ### D. Rangée « Sauvegarder » sticky - `.config-actions-row` (dans `#cfg-backend-settings`) → `position: sticky; bottom: 0`, empilée verticalement (`flex-direction: column`), boutons pleine largeur 44 px, fond opaque + bordure, `padding-bottom` avec `env(safe-area-inset-bottom)` (barre home iOS). - La rangée reste visible pendant le scroll de la section backend ; le `padding-bottom: 80px` de `.config-content` garantit qu'elle ne masque jamais les derniers contrôles. ### E. Formulaires 1 colonne & grilles - `.config-row` → 1 colonne (`grid-template-columns: 1fr`), `.config-input--num` pleine largeur, `text-align: left`. - `.ai-default-grid` / `.ai-provider-fields` → 1 colonne. - Add-rows (`.config-add-row`, `.config-add-pattern`) → wrap + largeurs inline (`180/140/100px`) neutralisées (`width: auto !important`). - Items webhook/token/share → wrap ; URLs/méta sur leur propre ligne (`overflow-wrap: anywhere`) ; boutons de suppression 44 px. - `.hidden-files-add-row` → wrap, input pleine largeur. - `.config-diag-row` → wrap. - `.profile-avatar-row` → wrap ; `.profile-form` → `max-width: 100%`. - `.webauthn-key-item` → wrap ; `.webauthn-key-label` → pleine largeur. - `.theme-grid` reste en `auto-fill minmax(160px, 1fr)` (déjà responsive). ### F. MFA & sécurité - `.mfa-recovery-list` → **1 colonne** en mobile (2 colonnes illisibles à 360 px). - `.mfa-verify-section`, `.mfa-recovery-actions`, `.mfa-disable-actions` → wrap ; champs/boutons enfants en pleine largeur. - `.mfa-code-input` → `width: 100%`, `max-width: 320px`, `letter-spacing: 6px` (au lieu de 12 px qui débordait), `min-height: 52px`. - `.mfa-secret-code` → `word-break: break-all` (secret TOTP long). - `.mfa-code-input-group` → wrap. - Règle morte **`.mfa-recovery-input`** supprimée (auth.js utilise `mfa-code-input recovery-input`). ### G. Dettes HTML corrigées - `.config-actions-row` (Sauvegarder / Réindexer / Réinitialiser) déplacée **dans** `#cfg-backend-settings` (elle était hors de toute section → le sticky n'avait pas de conteneur de scroll fiable) ; `` orphelin supprimé. - Id dupliqué **`cfg-partages-publics`** retiré du `