/* Direction artistique "salle de rédaction" : fond encre neutre, texte blanc
   papier, un seul accent rouge éditorial (actions, direct, progression).
   Space Grotesk pour les titres, Inter pour le texte. */
:root {
  --bg-0: #0b0c0e;
  --bg-1: #16171a;
  --bg-top: #121316;           /* départ du dégradé ci-dessous */
  /* Teinte RÉELLE du haut de l'écran : le départ du dégradé, éclairci par le
     halo. Mesurée (de #19191c à gauche à #1c1d20 à droite, identique sur toutes
     les pages depuis que le fond est calé sur l'écran, cf. body::before). Elle
     teinte la barre d'état du téléphone : cf. `html` plus bas, et la balise
     theme-color des gabarits, qui la répète en dur. */
  --barre-etat: #1b1c1f;
  --bg-grad: radial-gradient(1200px 700px at 78% -10%, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0) 55%),
             linear-gradient(180deg, var(--bg-top) 0%, #0b0c0e 100%);
  --surface: rgba(255, 255, 255, 0.045);
  --surface-strong: rgba(255, 255, 255, 0.075);
  --border: rgba(255, 255, 255, 0.10);
  --accent: #e5383b;
  --accent-hover: #c92c2f;
  --accent-2: #ff8a3d;
  --accent-rgb: 229, 56, 59;
  --focus: rgba(243, 241, 236, 0.42);
  --menu-bg: #18191c;
  --placeholder: #6f6e6a;
  --text: #f3f1ec;
  --text-dim: #a19f99;
  --danger: #ff6b6b;
  --sidebar-w: 288px;
}

* { box-sizing: border-box; }

/* l'attribut hidden doit toujours gagner, même face à display:flex des .panel */
[hidden] { display: none !important; }

/* Carlito : substitut libre métrique-compatible de Calibri, pour que le
   visionneur affiche les fiches comme Word (Calibri n'est pas une police
   système/web sur macOS). On l'aliase sur "Calibri" ET "Carlito". */
@font-face { font-family: "Carlito"; font-weight: 400; font-style: normal;
  src: url("../vendor/fonts/carlito-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,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: "Carlito"; font-weight: 700; font-style: normal;
  src: url("../vendor/fonts/carlito-700-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,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: "Carlito"; font-weight: 400; font-style: italic;
  src: url("../vendor/fonts/carlito-400-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,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: "Carlito"; font-weight: 700; font-style: italic;
  src: url("../vendor/fonts/carlito-700-italic.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,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: "Carlito"; font-weight: 400; font-style: normal;
  src: url("../vendor/fonts/carlito-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: "Carlito"; font-weight: 700; font-style: normal;
  src: url("../vendor/fonts/carlito-ext-700-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: "Carlito"; font-weight: 400; font-style: italic;
  src: url("../vendor/fonts/carlito-ext-400-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: "Carlito"; font-weight: 700; font-style: italic;
  src: url("../vendor/fonts/carlito-ext-700-italic.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }

html, body { min-height: 100%; }
/* Safari sur iPhone GROSSIT d'office le texte qu'il juge trop petit, sans
   toucher aux interlignes ni aux cadres. L'aperçu de fiche, réduit par `zoom`
   pour tenir dans l'écran, en devenait illisible : lignes superposées, texte
   débordant des bandeaux. Pas de grossissement : la fiche se lit à l'échelle,
   et le pincement pour zoomer reste possible. */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* Safari sur iPhone teinte la barre d'état (heure, réseau, batterie) avec la
   couleur de fond de la page. Sans couleur ici, il prenait celle de `body`,
   #0b0c0e — le BAS du dégradé, presque noir —, plus sombre que le haut de la
   page juste sous la barre. Le document prend donc la teinte du haut ; le
   fond visible, lui, est dessiné par-dessus (body::before). */
html { background-color: var(--barre-etat); }
/* Safari sur iPhone masque un mot de passe avec « ● » (U+25CF), et non « • »
   comme sur ordinateur. Le découpage d'Inter par Google Fonts ne le contient
   pas : il retombait sur la police système, dont le « ● » est énorme — des
   ronds qui se touchaient d'un bord à l'autre du champ. Verdana, présente sur
   iOS, le prend en charge à une taille normale. Sur ordinateur, « • » est
   dans Inter : rien ne change. */
input[type="password"] { font-family: Inter, Verdana, sans-serif; }

body {
  margin: 0;
  font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
  color: var(--text);
  /* Le fond est porté par body::before, calque FIXÉ à l'écran : `body` reste
     transparent pour le laisser voir. */
  line-height: 1.55;
  transition: padding-left 0.25s ease;
}

/* Le fond (dégradé + halo en haut à droite) sur un calque fixé à l'ÉCRAN, et
   non sur la page. Safari sur iPhone ignore `background-attachment: fixed` :
   le dégradé s'étirait sur toute la hauteur de la page, si bien que le haut
   n'avait pas la même teinte sur une page courte (connexion, accueil : le halo
   l'éclaire) et sur une longue (mentions, admin : il remonte hors de vue).
   Calé sur l'écran, le fond est le même partout et sur tous les appareils —
   c'est ce que faisait déjà `fixed` sur ordinateur —, et la barre d'état peut
   en reprendre exactement la teinte (cf. `html`). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--bg-0);
  background-image: var(--bg-grad);
  pointer-events: none;
}

.bg-accent {
  position: fixed;
  inset: auto -160px -220px auto;
  width: 520px;
  height: 520px;
  background: radial-gradient(circle at 30% 30%, rgba(var(--accent-rgb), 0.10), rgba(var(--accent-rgb), 0) 62%);
  filter: blur(30px);
  pointer-events: none;
  z-index: 0;
}

.shell {
  position: relative;
  z-index: 1;
  max-width: 660px;
  margin: 0 auto;
  /* padding-bottom > padding-top → le bloc centré remonte un peu */
  padding: 40px 22px 17vh;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* la vue "accueil" est centrée verticalement ; le visionneur, non.
   La hauteur minimale reste celle de l'écran : le lien des mentions légales
   s'ancre au bas de .shell, et un contenu court (génération en cours, dossier
   vide) le ferait sinon remonter au milieu de la page. */
body.viewing .shell,
body.browsing .shell {
  max-width: 1000px;
  min-height: 100vh;
  display: block;
  padding: 16px 22px 96px;
}

/* --- historique (sidebar) --- */
.sidebar-toggle {
  position: fixed;
  top: 18px;
  left: 18px;
  z-index: 30;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
  color: var(--text-dim);
  background: none;
  border: none;
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.sidebar-toggle:hover { color: var(--text); background: var(--surface); }
body.sidebar-open .sidebar-toggle { display: none; }

.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: var(--sidebar-w);
  z-index: 25;
  display: flex;
  flex-direction: column;
  /* droite resserrée (6px) : juste l'écart nécessaire au passage du curseur
     de la scrollbar, façon Claude. Gauche à 8px : les lignes ajoutent déjà
     leur propre retrait (10px sur .history__item / .folder__head), un bord
     large en plus rognait la place du titre pour rien. */
  padding: 16px 6px 16px 8px;
  background: rgba(11, 12, 14, 0.96);
  border-right: 1px solid var(--border);
  backdrop-filter: blur(10px);
  transform: translateX(-100%);
  /* Fermé, le volet est INVISIBLE, et pas seulement glissé hors de l'écran.
     Safari sur iPhone teinte la barre d'état d'après l'élément fixé en haut
     de l'écran : le volet ouvert (plein écran, fond #0b0c0e) la noircissait,
     et une fois refermé il restait sa référence — la barre gardait la teinte
     du volet sur la fiche ouverte depuis lui. `visibility` bascule APRÈS le
     glissement (délai de 0,25 s), sans quoi on ne le verrait pas se refermer ;
     à l'ouverture, elle bascule tout de suite. Au passage, la touche Tab
     n'atteint plus les liens d'un volet fermé. */
  visibility: hidden;
  transition: transform 0.25s ease, visibility 0s linear 0.25s;
}
body.sidebar-open .sidebar {
  transform: translateX(0);
  visibility: visible;
  transition: transform 0.25s ease, visibility 0s;
}
body.sidebar-resizing .sidebar { transition: none; }

/* poignée de redimensionnement, superposée sur la bordure droite du volet */
/* --- pied du volet : qui est connecté, et ce qu'il lui reste ---
   Posé sous la zone défilante, donc toujours visible : c'est un repère, pas
   une entrée d'historique. */
.sidebar__pied {
  position: relative;
  display: flex;
  align-items: center;
  /* padding-left de 10px, comme .sidebar__grouphead : le nom du compte tombe
     alors sur le même axe que « DOSSIERS » et « FICHES ». */
  /* paddings SYMÉTRIQUES : le bouton est centré sur la boîte entière
     (top:50%), le texte sur sa propre ligne. Les deux ne coïncident que si le
     haut et le bas sont égaux — à 12/6, le bouton montait de 3 px. */
  /* 50 px à droite : DEUX boutons de 20 px y flottent en absolu (mot de passe
     puis déconnexion), et le nom du compte ne doit pas passer dessous. */
  padding: 12px 50px 12px 10px;
  border-top: 1px solid var(--border);
  flex: none;
}
/* Le nom du compte devenu commande : un <button> traîne ses styles par défaut
   (fond, bordure, police, texte centré), il faut les défaire pour qu'il reste
   exactement ce qu'il était à l'œil. Seul le survol le distingue d'un texte. */
.sidebar__compte--bouton {
  font: inherit;
  text-align: left;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  border-radius: 8px;
  transition: opacity 0.15s ease;
}
.sidebar__compte--bouton:hover { opacity: 0.72; }
.sidebar__compte--bouton:focus-visible { outline: 1px solid var(--focus); outline-offset: 3px; }
.sidebar__pied form { margin: 0; }
/* Deux lignes : le nom, le solde en dessous. Le bloc entier est centré face au
   bouton de déconnexion — ce que garantissent les paddings symétriques du pied
   (le bouton est centré sur la boîte, le bloc l'occupe entièrement). */
.sidebar__compte {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  flex: 1;
}
.sidebar__nom {
  font-size: 0.86rem;
  color: var(--text);
  font-weight: 500;
  /* un identifiant long ne doit pas pousser le bouton de déconnexion dehors */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.sidebar__solde {
  font-size: 0.75rem;
  color: var(--text-dim);
  white-space: nowrap;
}
/* Bouton de sortie. Le MÊME objet sert dans le pied du volet et dans
   l'en-tête du panneau d'administration : son aspect vit donc ici, dans la
   feuille que les deux pages chargent, et chaque page n'ajoute que le
   placement. Deux copies auraient fini par diverger. */
.sortir {
  width: 20px;
  height: 20px;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 5px;
  color: var(--text-dim);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: color 0.15s ease, background 0.15s ease;
}
.sortir:hover { color: var(--text); background: var(--surface-strong); }

/* Même formule que .sidebar__mini (le +) et .sidebar__close (la croix) :
   right:7px sur une boîte de 20px, donc un centre au même endroit qu'eux. En
   flux normal, le bouton tombait 6px plus à gauche — assez pour se voir. */
.sidebar__sortir {
  position: absolute;
  top: 50%;
  right: 7px;
  transform: translateY(-50%);
}

.sidebar__resize {
  position: absolute;
  top: 0;
  bottom: 0;
  right: -3px;
  width: 6px;
  cursor: col-resize;
  z-index: 26;
}
/* pendant le glisser, le décalage du contenu doit suivre sans délai */
body.sidebar-resizing { cursor: col-resize; user-select: none; transition: none; }
body.sidebar-resizing * { user-select: none; }

.sidebar-backdrop {
  position: fixed;
  inset: 0;
  z-index: 24;
  background: rgba(0, 0, 0, 0.45);
}

.sidebar__head {
  position: relative;
  display: flex;
  align-items: center;
  padding: 6px 4px 4px 10px;
}
.sidebar__logo {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  opacity: 0.95;
  cursor: pointer;
  user-select: none;
}
.sidebar__logo:hover { opacity: 1; }
.sidebar__logo-mark { height: 20px; width: auto; flex: none; }
.sidebar__logo-text {
  font-family: "Space Grotesk", Inter, sans-serif;
  font-weight: 600;
  font-size: 1.1rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text);
}
.sidebar__close {
  /* même formule que .folder__kebab / .history__kebab (right:4px, centre à
     17px du bord) pour tomber exactement sur le même axe vertical qu'eux */
  position: absolute;
  right: 3px;
  top: 50%;
  transform: translateY(-50%);
  width: 28px; height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  background: none;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
}
.sidebar__close:hover { color: var(--text); background: var(--surface); }

/* zones "Dossiers" / "Fiches" */
.sidebar__scroll {
  flex: 1;
  overflow-y: auto;
  /* arrivé en bout de liste, le reste du geste (inertie du trackpad) ne doit
     pas "fuir" vers la page derrière : sans ça, la colonne s'arrête net et
     c'est la fiche ouverte qui se met à défiler à sa place — d'où un scroll
     saccadé. contain garde aussi le rebond élastique de macOS dans le volet. */
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  margin: 4px -6px 0 -14px;
  padding: 0 6px 0 14px;
  scrollbar-color: rgba(255, 255, 255, 0.28) transparent;
  scrollbar-width: thin;
}
.sidebar__scroll::-webkit-scrollbar { width: 1px; }
.sidebar__scroll::-webkit-scrollbar-track { background: transparent; }
.sidebar__scroll::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.28);
  border-radius: 999px;
}
.sidebar__scroll::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.42);
  background-clip: padding-box;
}
/* fondu au sommet de la liste : les items s'estompent sous le bouton "Nouvelle
   fiche" plutôt que d'être coupés net (façon Claude). position:sticky reste
   collé en haut du scroll sans jamais défiler lui-même ; margin-bottom négatif
   pour qu'il chevauche le contenu au lieu de lui prendre de la place. Invisible
   tant qu'on n'a pas scrollé (rien à cacher au repos, cf. .is-scrolled en JS) —
   sinon le tout premier item ("Dossiers") est à moitié caché dès le départ. */
.sidebar__fade-top {
  position: sticky;
  top: 0;
  z-index: 3;
  flex-shrink: 0;
  height: 20px;
  margin-bottom: -20px;
  background: linear-gradient(to bottom, rgba(11, 12, 14, 0.96), rgba(11, 12, 14, 0));
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.sidebar__scroll.is-scrolled .sidebar__fade-top { opacity: 1; }
/* l'écart entre "Épinglés" et "Fiches" est aussi la zone où l'on vient poser
   une fiche SOUS la dernière épinglée : trop serré, on n'a pas la place de
   viser et le curseur remonte aussitôt dans la liste. */
.sidebar__group { margin-bottom: 28px; }
.sidebar__group:last-child { margin-bottom: 0; }
.sidebar__grouphead {
  position: relative;
  display: flex;
  align-items: center;
  padding: 6px 8px 4px 10px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.sidebar__mini {
  /* même formule que .folder__kebab / .history__kebab (right:4px, centre à
     17px du bord) pour tomber exactement sur le même axe vertical qu'eux */
  position: absolute;
  right: 7px;
  top: 50%;
  transform: translateY(-50%);
  width: 20px; height: 20px;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.95rem; line-height: 1;
  color: var(--text-dim);
  background: none;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
.sidebar__mini:hover { color: var(--text); background: var(--surface); }

.sidebar__grouptoggle {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  background: none;
  border: none;
  padding: 2px 4px 2px 0;
  margin: -2px 0 -2px -4px;
  border-radius: 5px;
  cursor: pointer;
}
/* .is-hovering (calculé par app.js à chaque mousemove) plutôt que :hover :
   après un glisser-déposer, le navigateur garde un :hover figé sur ce qui se
   trouve sous l'endroit où la fiche a été saisie. La liste s'étant
   réorganisée entre-temps (trou refermé, "Déposer ici"…), c'est parfois ce
   bouton qui s'y retrouve : "Fiches" s'éclairait au dépôt sans être survolé. */
.sidebar__grouptoggle.is-hovering { color: var(--text); }
.sidebar__chevron {
  flex: none;
  opacity: 0;
  transition: transform 0.15s ease;
  /* évite le léger "saut" juste après la rotation : sans ça, le navigateur
     promeut l'élément sur sa propre couche graphique pendant la transition
     puis le rétrograde une fois finie, ce qui peut décaler le rendu
     (anticrénelage/sous-pixel) d'une fraction de pixel au moment du retour
     au rendu normal. */
  will-change: transform;
}
.sidebar__group.zone-hover .sidebar__chevron { opacity: 1; }
.sidebar__grouptoggle.is-hovering .sidebar__chevron { opacity: 1; }
.sidebar__group.collapsed .sidebar__chevron { opacity: 1; transform: rotate(-90deg); }
.sidebar__group.collapsed > *:not(.sidebar__grouphead) { display: none; }
/* glisser une fiche sur "Épinglés" replié : dossiers et fiches déjà
   épinglées restent masqués, mais "Déposer ici" (pin-drop-hint, cf. HTML)
   réapparaît exceptionnellement sous le titre tant qu'on la survole (classe
   ajoutée par app.js) — même ligne, punaise comprise, que pour épingler la
   toute première fiche section dépliée. #pin-drop-zone (id) l'emporte sur
   la règle générique ci-dessus (classes) quel que soit l'ordre. */
.sidebar__group.collapsed.collapsed--drag-preview > #pin-drop-zone { display: block; }

.folders, .history, .folder__fiches {
  list-style: none;
  margin: 0;
  padding: 0;
}
.history__empty { margin: 8px 10px; font-size: 0.82rem; color: var(--text-dim); line-height: 1.35; }
/* seul le dossier lui-même (sa ligne, pas la liste de ses fiches dépliée en
   dessous) est une zone d'atterrissage mise en avant : déposer une fiche
   ailleurs (fiches, dans un dossier ouvert) reste possible mais
   sans surbrillance — seul le survol D'UN dossier doit se voir. */
.folder__head.drop-target {
  outline: 1px dashed var(--accent);
  outline-offset: -2px;
  background: rgba(var(--accent-rgb), 0.08);
  border-radius: 8px;
}

/* dépose directement dans "Fiches" (hors dossier) : pas de mise en valeur
   au survol (cf. app.js pour la logique de dépose elle-même). */

/* ligne "Déposer ici" (épingler une fiche hors de tout dossier) : visible
   uniquement pendant le glissement d'une fiche (cf. app.js), comme le
   comportement de la section "Épinglés" dans l'app Claude. Pas de fond/
   contour au survol direct — seuls l'icône et le texte s'éclaircissent (et
   le texte devient "Relâcher", cf. app.js) pour indiquer qu'on est
   précisément dessus. */
/* "Déposer ici" doit tenir EXACTEMENT la place que prendra la fiche une fois
   épinglée, sans quoi tout se décale d'un cran au moment où l'une remplace
   l'autre. Or les deux lignes n'ont pas le même contenu (icône + texte ici,
   pastille + bouton là) et leur hauteur dépend donc des métriques de la
   police installée : aucune valeur écrite ici ne peut coïncider partout. La
   hauteur est donc mesurée sur une vraie ligne de fiche et imposée en JS
   (cf. syncPinHintSize) ; ce `height: 100%` fait remplir cette hauteur par
   l'en-tête, dont le `align-items: center` recentre alors le texte au même
   niveau que celui de la fiche. */
.folder--pindrop .folder__head { height: 100%; cursor: default; }
.folder--pindrop .folder__head.is-hover { background: transparent; }
.folder--pindrop .folder__icon { color: var(--text-dim); transform: rotate(-40deg); transition: color 0.12s ease; }
.folder--pindrop .folder__name { color: var(--text-dim); transition: color 0.12s ease; }
.folder--pindrop.drop-target .folder__icon,
.folder--pindrop.drop-target .folder__name { color: var(--text); }

/* espace réservé pendant un réordonnancement dans "Épinglés" : aucune
   mise en forme visible, comme .folder--placeholder — c'est le décalage
   (FLIP) des autres fiches autour de lui qui montre où la fiche atterrira. */
.pin-placeholder { list-style: none; pointer-events: none; }
/* la fiche réordonnée dans "Épinglés" (pas une nouvelle qu'on y glisse
   depuis ailleurs) s'efface complètement le temps du survol — c'est
   .pin-placeholder qui prend sa place dans le flux — comme .folder.drag-
   source-hidden pour "Dossiers". */
.history__item.pin-drag-collapsed {
  opacity: 0;
  height: 0;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  pointer-events: none;
}

/* la zone "Fiches" occupe tout l'espace restant → on peut y déposer même
   bien en dessous de la dernière fiche */
#fiches-group { flex: 1 1 auto; min-height: 90px; }

/* flow-root : le <li> devient son propre contexte de formatage de bloc, donc
   le margin-bottom de la dernière fiche d'un dossier ouvert (.history__item,
   plus bas) ne "fuit" plus sous ce <li> par fusion de marges. Sans ça, la
   hauteur mesurée via getBoundingClientRect() (utilisée pour dimensionner
   l'espace réservé au glisser-déposer, cf. app.js) est 2px trop courte pour
   un dossier ouvert et rempli, d'où un léger saut du reste de la colonne au
   moment de la prise. flow-root (pas overflow:hidden) ne rogne rien : les
   fiches gardent leur débord horizontal (marge négative, cf. plus bas). */
.folder { display: flow-root; }
/* même raison que ci-dessus, appliquée à la liste des fiches épinglées
   elle-même (pas juste à chaque ligne) : sans ça, le margin-bottom de la
   DERNIÈRE fiche épinglée fuit sous #pinned-list par fusion de marges dès
   qu'on retire l'espace réservé du réordonnancement (cf. app.js) — la
   hauteur mesurée de la liste change de 2px pile à ce moment-là, ce qui
   décale d'un coup tout ce qui suit dans la colonne ("Fiches" compris). */
#pinned-list { display: flow-root; }
/* cette règle (sélecteur d'ID) l'emporterait sinon en spécificité sur
   ".sidebar__group.collapsed > *:not(.sidebar__grouphead) { display: none; }"
   ci-dessus (classes seulement) : #pinned-list resterait visible même
   section "Épinglés" repliée. En reprenant l'id dans le sélecteur, cette
   règle gagne à son tour en spécificité et rétablit le repli normal. */
.sidebar__group.collapsed > #pinned-list { display: none; }

/* Marqueurs (icône dossier / point fiche) : même gabarit, même axe.
   axe gauche = 10px (padding des titres de groupe) · boîte marqueur = 16px ·
   écart marqueur→texte = 6px → texte à 32px pour dossiers ET fiches. */
.folder__head {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  /* .history__open est un <button> : le reset UA lui donne line-height:normal,
     plus compact que le line-height:1.55 hérité du body. .folder__name est un
     <span> ordinaire qui hérite ce 1.55 → dossier plus haut que fiche à
     padding identique. On aligne ici pour garder la même hauteur de ligne. */
  line-height: normal;
  /* même padding vertical que .history__open et le kebab sorti du flux (comme
     .history__kebab) : la hauteur de la ligne dépend alors uniquement du même
     texte 0.86rem + padding que les fiches, garantissant la même hauteur. */
  /* droite minimale : le kebab est en position absolue (ne prend pas de
     place dans le flux), c'est le fondu de .folder__name qui crée l'espace
     visuel avant lui, pas ce padding — sinon les deux se cumulent */
  padding: 8px 4px 8px 10px;
  border-radius: 8px;
  cursor: pointer;
}
.folder__head.is-hover { background: var(--surface); }
/* dossier mis en évidence au clic (ouverture ou fermeture), comme une fiche
   active (cf. .history__item--active) */
.folder--active .folder__head,
.folder--active .folder__head.is-hover { background: var(--surface-strong); }
.folder--active .folder__name { color: #fff; }
/* glissement d'un dossier (réordonner "Dossiers") : comme dans l'appli Claude,
   le geste lui-même n'ajoute pas de mise en évidence — seul un dossier déjà
   actif avant la prise garde son fond (et le garde après le dépôt). Pas de
   box-shadow/border ici : ça grandirait la ligne de quelques px (hauteur
   auto) par rapport à une fiche glissée, qui elle ne change jamais de
   taille — cf. .history__item.dragging plus bas, simple opacité. */
.folder.dragging:not(.folder--active) .folder__head,
.folder.dragging:not(.folder--active) .folder__head.is-hover {
  background: transparent;
  opacity: 0.75;
}
/* le dossier qu'on tient ne doit pas montrer ses "trois points" (options) :
   sans ça, l'image qui suit le curseur les affiche puisque le survol est
   encore actif au moment où elle est capturée. */
.folder.dragging .folder__head .folder__kebab { opacity: 0; }
/* la ligne ci-dessus (dragging) façonne l'image fantôme que le navigateur
   capture au tout début du glissement ; une fois cette capture faite, la
   source encore présente dans le DOM doit disparaître complètement et ne
   plus occuper de place (c'est l'espace réservé .folder--placeholder juste
   à côté qui prend le relai) — sinon on voit le dossier "en double" (figé à
   sa place ET sous le curseur). Elle reste dans le DOM (jamais déplacée
   tant que le glissement natif est en cours) pour ne pas le perturber. */
.folder.drag-source-hidden {
  opacity: 0;
  height: 0;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  overflow: hidden;
  pointer-events: none;
}
/* espace réservé qui prend la place du dossier glissé le temps du survol :
   aucun contenu, juste la hauteur qu'il occupait pour que le décalage des
   autres dossiers reflète où il atterrira. */
.folder--placeholder { list-style: none; pointer-events: none; }
/* Pendant TOUT glissement (fiche ou dossier), le survol CSS ne veut plus rien
   dire et doit rester muet — sinon des lignes paraissent "cliquées" (fond mis
   en évidence, trois points révélés) sans qu'on les survole vraiment. Deux
   raisons à cela :
   - le curseur traverse des lignes qu'on décale sur son passage, sans jamais
     les viser ;
   - le navigateur ne rafraîchit pas :hover pendant un glissement natif : il
     le garde figé là où le curseur était à la prise en main. Quand la liste
     se réorganise (le trou de la fiche épinglée qui se referme), c'est la
     ligne qui vient prendre cette place-là qui hérite du survol — une fiche
     mise en valeur au hasard, loin du curseur.
   On neutralise donc le survol — mais pas l'état actif d'un élément
   réellement sélectionné, qui doit rester visible. */
body.dnd-active .folder:not(.folder--active) .folder__head.is-hover {
  background: transparent;
}
body.dnd-active .folder:not(.folder--active) .folder__head.is-hover .folder__kebab {
  opacity: 0;
}
body.dnd-active .history__item:not(.history__item--active).is-hover {
  background: transparent;
}
body.dnd-active .history__item.is-hover .history__kebab {
  opacity: 0;
}
/* Curseur "main fermée" dès qu'on appuie sur une fiche ou un dossier, c'est-
   à-dire pendant tout le temps où le curseur nous appartient encore. Posé sur
   les descendants aussi (le titre, les trois points… réimposeraient sinon
   leur propre `pointer` via leur spécificité).

   ATTENTION — dès que le glisser-déposer NATIF démarre, le curseur cesse de
   dépendre du CSS : c'est le système qui dessine le retour visuel du
   glissement, à partir du seul `dropEffect` (move → flèche simple, copy →
   flèche + « + », none → sens interdit). La règle ci-dessous continue d'être
   calculée pendant le glissement (`getComputedStyle` renvoie bien
   "grabbing"), elle n'est simplement plus regardée. Obtenir une vraie main
   fermée d'un bout à l'autre supposerait d'abandonner le glisser-déposer
   natif au profit d'un glissement piloté aux événements pointeur. */
.history__item:active,
.history__item:active *,
.folder__head:active,
.folder__head:active * {
  cursor: grabbing;
}
body.dnd-active,
body.dnd-active * {
  cursor: grabbing !important;
}
.folder__icon {
  flex: none;
  width: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
}
.folder__name {
  flex: 1; min-width: 0;
  font-size: 0.86rem;
  white-space: nowrap; overflow: hidden; text-overflow: clip;
  /* fondu plutôt que "…", comme .history__theme pour les fiches ; le
     conteneur va maintenant presque jusqu'à la bordure (padding-right:4px),
     donc ce fondu est ce qui crée l'espace avant le kebab (right:4px,
     largeur 26px → occupe 4-30px depuis le bord) */
  --title-fade: 0px;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--title-fade) - 32px),
                                      transparent calc(100% - var(--title-fade)));
  mask-image: linear-gradient(to right, #000 calc(100% - var(--title-fade) - 32px),
                              transparent calc(100% - var(--title-fade)));
  transition: --title-fade 0.12s ease;
}
/* même fondu qu'au survol d'une fiche : les trois points apparaissent
   par-dessus la fin du nom, qui s'efface donc juste avant eux. Pendant un
   glissement, ni survol ni kebab : rien ne bouge — et "Déposer ici", qui
   emprunte .folder__name, garde son libellé entier. */
body:not(.dnd-active) .folder__head.is-hover .folder__name,
.folder__head:has(.folder__kebab.is-active) .folder__name {
  --title-fade: 30px;
}
.folder__kebab {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  background: none; border: none; cursor: pointer;
  border-radius: 7px;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.folder__head.is-hover .folder__kebab,
.folder__kebab.is-active { opacity: 1; }
.folder__kebab:hover,
.folder__kebab.is-active { color: var(--text); background: var(--surface-strong); }
/* dossier ouvert : les fiches qu'il contient pendent d'un trait vertical sous
   l'icône du dossier, à la façon des projets Claude. */
.folder__fiches {
  margin-left: 17px;
  padding-left: 9px;
  border-left: 1px solid var(--border);
}
.folder:not(.open) .folder__fiches,
.folder--empty .folder__fiches { display: none; }
/* la mise en évidence (survol/actif) d'une fiche dans un dossier doit
   déborder jusqu'à l'aplomb de l'en-tête du dossier (comme les projets
   Claude), pas s'arrêter à l'indentation de la fiche. On étend la boîte vers
   la gauche (marge négative = 17+9+1 de .folder__fiches) et on compense par
   un padding équivalent pour que le point et le texte gardent leur position. */
.folder__fiches > .history__item {
  margin-left: -27px;
  padding-left: 37px;
}

/* item de fiche (dans "Fiches" ou dans un dossier) */
.history__item {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 6px;
  padding-left: 10px;
  border-radius: 9px;
  margin-bottom: 2px;
}
/* .is-hover (fiches ET en-têtes de dossier) : survol calculé par app.js à
   chaque mousemove, jamais :hover. Après un glisser-déposer, Safari garde le
   :hover natif collé à la ligne qui se trouvait sous le point de prise en
   main — même une fois la souris repartie ailleurs — et une fiche de
   "Fiches" restait allumée sans être survolée. */
.history__item.is-hover { background: var(--surface); }
.history__item.dragging { opacity: 0.6; }
/* la fiche qu'on tient ne doit pas montrer ses "trois points" (options) :
   sans ça, l'image qui suit le curseur les affiche puisque le survol est
   encore actif au moment où elle est capturée. Spécificité augmentée
   (classe répétée) pour l'emporter sur ".history__item.is-hover .history__kebab"
   plus bas, quel que soit l'ordre dans le fichier. */
.history__item.history__item.dragging .history__kebab { opacity: 0; }
/* la ligne ci-dessus (dragging) façonne l'image fantôme que le navigateur
   capture au tout début du glissement ; une fois cette capture faite, la
   source encore présente dans la liste doit disparaître complètement —
   sinon on voit la fiche "en double" (figée à sa place ET sous le
   curseur). Seule celle qu'on tient doit rester visible. */
.history__item.drag-source-hidden { opacity: 0; }

/* fantôme suivi à la main (toute fiche glissée, cf. startDragGhost dans
   app.js) : l'image de glissement native est effacée et remplacée par cet
   élément, seul moyen de changer ce qu'on "tient" en plein glissement.
   pointer-events: none est indispensable — posé pile sous le curseur, il
   masquerait sinon la vraie zone survolée à chaque "dragover". */
.dragghost {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 60;
  pointer-events: none;
}
/* les deux couches partent du même point — l'origine du conteneur, c'est-à-
   dire le curseur — et s'en décalent chacune à leur façon : la fiche reste
   tenue là où on l'a attrapée (--grab-x/y), la pastille se centre sur le
   curseur (--label-x/y, la moitié de sa taille, mesurée par app.js). Les
   deux couches restent toujours dans le document : c'est ce qui permet au
   passage de l'une à l'autre de s'animer (un display:none ne se transitionne
   pas). */
.dragghost__fiche,
.dragghost__label {
  position: absolute;
  top: 0;
  left: 0;
  transform: translate(var(--grab-x), var(--grab-y));
  transition: transform 0.16s cubic-bezier(0.2, 0.8, 0.3, 1), opacity 0.14s ease;
}
/* la fiche tenue : mêmes règles que l'image native qu'elle remplace
   (.history__item.dragging), la marge de liste en moins. Elle ne se déplace
   pas, elle s'efface simplement. */
.dragghost__fiche { margin-bottom: 0; }
.dragghost--unpin > .dragghost__fiche { opacity: 0; }
/* survol de "Fiches" : la pastille glisse depuis la position de la fiche
   jusqu'au curseur, sur lequel elle se centre. */
.dragghost--unpin > .dragghost__label {
  opacity: 1;
  transform: translate(var(--label-x), var(--label-y)) scale(1);
}
.dragghost__label {
  display: inline-flex;
  opacity: 0;
  transform: translate(var(--grab-x), var(--grab-y)) scale(0.92);
  align-items: center;
  gap: 7px;
  /* hauteur imposée (celle de la fiche remplacée, mesurée par app.js) plutôt
     qu'un padding vertical : c'est la hauteur qui doit correspondre, pas la
     marge autour du texte. */
  height: var(--label-h, auto);
  padding: 0 11px;
  border-radius: 9px;
  background: var(--accent);
  color: #fff;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.45);
}
.dragghost__label svg { flex: none; }
/* dépôt dans un dossier (cf. sinkDragGhost dans app.js) : le conteneur glisse
   jusqu'à l'icône du dossier pendant que la fiche rétrécit vers le point où
   on la tient et que l'ensemble s'efface — elle "entre" dans le dossier. */
.dragghost--sink {
  transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.18s ease;
  opacity: 0;
}
.dragghost--sink > .dragghost__fiche {
  transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
  transform: translate(var(--grab-x), var(--grab-y)) scale(0.3);
}

/* fiche actuellement ouverte dans le visionneur */
.history__item--active,
.history__item--active.is-hover { background: var(--surface-strong); }
.history__item--active .history__theme { color: #fff; }
.history__item--active .history__dot::before { background: var(--accent); }

/* fiche en cours de génération (placeholder) — cliquable : revient sur le suivi */
.history__item--pending .history__open { cursor: pointer; }
.history__item--pending .history__meta { color: var(--accent); }
.history__item--pending .history__dot::before {
  background: var(--accent);
  animation: dotPulse 1.2s ease-in-out infinite;
}
@keyframes dotPulse { 50% { opacity: 0.25; } }
.history__dot {
  flex: none;
  width: 16px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: 15px;
}
.history__dot::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-dim);
}
.history__open {
  flex: 1;
  min-width: 0;
  display: block;
  /* droite minimale : le kebab est en position absolue (ne prend pas de
     place dans le flux), c'est le fondu de .history__theme qui crée
     l'espace visuel avant lui, pas ce padding — sinon les deux se cumulent */
  padding: 8px 4px 8px 0;
  text-align: left;
  text-decoration: none;
  color: var(--text);
  background: none;
  border: none;
  cursor: pointer;
  border-radius: 9px;
}
/* --title-fade : à quelle distance du bord droit le titre a FINI de
   disparaître. Déclarée en @property pour être une vraie longueur, donc
   animable — sans ça le fondu sauterait d'un état à l'autre au survol.
   Navigateur sans @property : la variable vaut quand même ses valeurs
   ci-dessous, seule la transition est perdue. */
@property --title-fade {
  syntax: "<length>";
  inherits: false;
  initial-value: 0px;
}
.history__theme {
  display: block;
  font-size: 0.86rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: clip;
  /* fondu tardif : le conteneur va maintenant presque jusqu'à la bordure
     (padding-right:4px), donc ce fondu est ce qui crée l'espace avant le
     kebab (right:4px, largeur 26px → occupe 4-30px depuis le bord) */
  --title-fade: 0px;
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - var(--title-fade) - 32px),
                                      transparent calc(100% - var(--title-fade)));
  mask-image: linear-gradient(to right, #000 calc(100% - var(--title-fade) - 32px),
                              transparent calc(100% - var(--title-fade)));
  transition: --title-fade 0.12s ease;
}
/* Au survol, les trois points apparaissent PAR-DESSUS la fin du titre : ils
   s'y noyaient, les lettres étant encore presque opaques à cet endroit. On
   recule donc le fondu pour qu'il soit terminé juste avant eux (30px = leur
   bord gauche), en même temps qu'ils apparaissent. Pas pendant un glissement,
   où le survol ne veut rien dire et où le kebab reste masqué. */
body:not(.dnd-active) .history__item.is-hover .history__theme,
.history__item:has(.history__kebab.is-active) .history__theme {
  --title-fade: 30px;
}
.history__meta {
  display: block;
  margin-top: 1px;
  font-size: 0.72rem;
  color: var(--text-dim);
}
/* dans le volet, la date n'est plus affichée (juste le titre, tronqué en fondu) */
.sidebar .history__meta { display: none; }
/* modèle utilisé : uniquement affiché dans "Toutes les fiches" (colonne dédiée,
   cf. .history--full .history__model plus bas) — trop de bruit dans le volet */
.history__model { display: none; }
/* superposé par-dessus la fin (fondue) du titre, pas dans le flux */
.history__kebab {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-dim);
  background: none;
  border: none;
  border-radius: 7px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.history__item.is-hover .history__kebab,
.history__kebab.is-active { opacity: 1; }
.history__kebab:hover,
.history__kebab.is-active { color: var(--text); background: var(--surface-strong); }

@media (min-width: 934px) {
  /* grand écran : le volet pousse tout le contenu vers la droite (recentré
     dans l'espace restant) au lieu de rétrécir la carte contre la marge
     droite ; la page A4 se réduit si besoin pour tenir dans la place restante
     (cf. fitViewerDoc dans app.js). En dessous (même seuil que NARROW_MQ),
     il se pose PAR-DESSUS, avec voile : ouvrir/fermer ne remet pas toute la
     page en forme. */
  body.sidebar-open { padding-left: var(--sidebar-w); }
  body.sidebar-open .sidebar-backdrop { display: none !important; }
}

/* petit écran : le volet n'est plus un tiroir latéral mais occupe tout
   l'écran ; il se referme dès qu'on choisit une fiche / une vue (cf.
   FULLSCREEN_SIDEBAR_MQ + isNarrow dans app.js) */
@media (max-width: 600px) {
  .sidebar {
    width: 100%;
    padding: 14px 10px 16px;
    border-right: none;
    /* Plein écran : le volet prend le FOND DU SITE, et déclare comme couleur
       celle de la barre d'état. Safari teinte cette barre d'après l'élément
       fixé en haut de l'écran, et lit sa couleur de fond, pas son dégradé :
       avec l'aplat #0b0c0e d'avant, la barre noircissait à l'ouverture et le
       restait pendant le glissement de fermeture. Le dégradé, opaque, couvre
       entièrement cette couleur à l'écran ; calé sur le volet qui fait la
       taille de l'écran, il est identique à celui de la page. */
    background-color: var(--barre-etat);
    background-image: var(--bg-grad);
    backdrop-filter: none;
  }
  .sidebar__resize { display: none; }
  .sidebar-backdrop { display: none !important; }
  /* la page dessous ne défile plus tant que le volet la couvre */
  body.sidebar-open { overflow: hidden; }
  /* un peu plus d'air pour le doigt */
  .sidebar__close { width: 36px; height: 36px; font-size: 1rem; }
  /* le bouton ☰ fixe en haut à gauche ne doit pas chevaucher le contenu */
  body.viewing .shell,
  body.browsing .shell { padding-top: 66px; }
}

/* fenêtre assez étroite pour que la page A4 (794px + marges) atteigne le
   bouton ☰ fixe : on la descend sous le bouton, comme sur mobile, et on la
   rétrécit d'un couloir de chaque côté (bouton : 18px + 40px) pour qu'il ne
   la chevauche pas non plus quand on fait défiler. 70px = la marge qu'avait
   déjà la page à 934px : pas de saut au passage du seuil. Y compris volet
   ouvert : il se pose alors par-dessus, la fiche dessous ne doit pas bouger. */
@media (min-width: 601px) and (max-width: 933px) {
  body.viewing .shell { padding: 66px 70px 96px; }
}

/* --- accueil : titre + zone de saisie directe (façon Claude) --- */
/* largeur FIXE, indépendante de la longueur du titre (qui change) */
#view-form { width: min(620px, 100%); margin: 0 auto; }

.head { text-align: center; margin-bottom: 22px; }
.head__logo {
  display: block;
  height: 38px;
  width: auto;
  margin: 0 auto 18px;
  opacity: 0.92;
}

/* petit éclat du logo au lancement d'une génération (cf. .zap dans app.js) */
.head__logo.zap { animation: logoFlash 0.55s ease-out; }
@keyframes logoFlash {
  0%   { filter: brightness(1) drop-shadow(0 0 0 rgba(255, 255, 255, 0)); }
  35%  { filter: brightness(1.9) drop-shadow(0 0 14px rgba(255, 255, 255, 0.85)); }
  100% { filter: brightness(1) drop-shadow(0 0 0 rgba(255, 255, 255, 0)); }
}
@media (prefers-reduced-motion: reduce) {
  .head__logo.zap { animation: none !important; }
}
.head h1 {
  font-family: "Space Grotesk", Inter, sans-serif;
  font-weight: 600;
  font-size: 1.85rem;
  line-height: 1.25;
  letter-spacing: -0.015em;
  margin: 0;
  color: #fff;
}

/* la "box" EST la zone de saisie (pas de textarea dans une carte) */
.composer {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  backdrop-filter: blur(6px);
  transition: border-color 0.15s ease;
}
/* encadré clair au survol comme pendant la saisie — et rien d'autre : un halo
   supplémentaire au focus faisait doublon avec la bordure, qui suffit à dire
   où l'on écrit. */
.composer:hover,
.composer:focus-within { border-color: var(--focus); }
.composer textarea {
  width: 100%;
  min-height: 52px;
  max-height: 40vh;
  overflow-y: hidden;   /* app.js bascule sur "auto" seulement quand le contenu dépasse max-height */
  padding: 20px 20px 8px;
  font: inherit;
  color: var(--text);
  background: transparent;
  border: none;
  outline: none;
  resize: none;
  display: block;
}
.composer textarea::placeholder { color: var(--placeholder); }
.composer__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 46px;
  padding: 8px 20px 14px;
}
/* sélecteur de modèle façon Claude : un déclencheur + un petit menu qui liste
   les modèles disponibles (config.MODEL_CHOICES). */
.model-picker { position: relative; }
.composer__model {
  display: flex;
  /* baseline et non center : « MODÈLE » et le nom n'ont pas la même taille,
     et centrer leurs boîtes posait le nom un demi-pixel plus bas (mesuré). */
  align-items: baseline;
  gap: 6px;
  /* « Mistral Medium 3.5 » passait sur deux lignes à 320 px de large */
  white-space: nowrap;
  background: none;
  border: none;
  padding: 4px 6px;
  margin: -4px -6px;
  border-radius: 8px;
  cursor: pointer;
  color: var(--text-dim);
  transition: background 0.12s ease, color 0.12s ease;
}
.composer__model:hover,
.model-picker.open .composer__model { background: var(--surface); color: var(--text); }
.composer__model:disabled {
  cursor: default;
  opacity: 0.7;
}
.composer__model:disabled:hover { background: none; }
.composer__model-tag {
  font-family: Inter, system-ui, sans-serif;
  font-weight: 500;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.75;
  user-select: none;
}
.composer__model-value {
  font-family: Inter, system-ui, sans-serif;
  font-weight: 500;
  font-size: 0.82rem;
  user-select: none;
}

.model-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  min-width: min(270px, calc(100vw - 48px));
  background: var(--menu-bg);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 6px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5);
  z-index: 20;
}
/* Ouvert VERS LE HAUT quand la place manque dessous (petit écran, téléphone
   en paysage) : vers le bas, il sortait de l'écran et le second modèle
   devenait inaccessible. Décidé à l'ouverture, cf. setupModelPicker. */
.model-menu--haut { top: auto; bottom: calc(100% + 8px); }
.model-menu__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  background: none;
  border: none;
  border-radius: 9px;
  text-align: left;
  cursor: pointer;
  color: var(--text);
}
.model-menu__item:hover { background: var(--surface-strong); }
.model-menu__text { display: flex; flex-direction: column; gap: 1px; flex: 1; min-width: 0; }
.model-menu__name {
  font-family: Inter, system-ui, sans-serif;
  font-weight: 500;
  font-size: 0.88rem;
}
.model-menu__desc { font-size: 0.78rem; color: var(--text-dim); }
.model-menu__check { flex: none; color: var(--accent); opacity: 0; }
.model-menu__item.is-selected .model-menu__check { opacity: 1; }

/* le bouton n'apparaît que si l'utilisateur a écrit quelque chose (cf. app.js) :
   il s'efface en opacité/échelle plutôt qu'en display, pour que la barre — et
   donc la zone de texte au-dessus — garde toujours la même hauteur. Même
   gabarit que le déclencheur du modèle (padding/hauteur identiques) — seule la
   forme est alignée, les couleurs du bouton restent celles de .btn. */
.btn.composer__submit {
  font-family: Inter, system-ui, sans-serif;
  font-size: 0.82rem;
  padding: 4px 8px;
  border-radius: 8px;
  opacity: 0;
  transform: translateY(4px) scale(0.96);
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease, background 0.15s ease;
}
.btn.composer__submit:active { transform: translateY(1px) scale(1); }
/* désactivé juste après le clic (anti double-envoi, pas un refus) : la souris
   est justement dessus à cet instant — pas de curseur "interdit" trompeur */
#submit-btn:disabled { cursor: default; }
.composer__bar.has-text .composer__submit {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

/* --- buttons --- */
.btn {
  display: inline-block;
  padding: 12px 26px;
  font-family: Inter, system-ui, sans-serif;
  font-weight: 500;
  font-size: 0.98rem;
  color: #fff;
  background: var(--accent);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, transform 0.15s ease;
}
.btn:hover { background: var(--accent-hover); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* --- panels --- */
.panel {
  margin-top: 22px;
  padding: 18px 20px;
  border-radius: 14px;
  border: 1px solid var(--border);
  background: var(--surface-strong);
}
/* barre de chargement (dans la vue fiche, plus large) : même largeur que la
   zone de saisie, pas toute la largeur du visionneur */
.panel--status {
  display: block;
  width: min(620px, 100%);
  margin-left: auto;
  margin-right: auto;
}
.status__row { display: flex; align-items: center; gap: 14px; }
.status__row p { margin: 0; font-family: Inter, system-ui, sans-serif; font-weight: 500; }
.status__sub { margin: 10px 0 0; font-size: 0.84rem; color: var(--text-dim); }
.status__sub:empty { display: none; }
.status__cancel {
  display: block;
  margin: 14px 0 0;
  padding: 6px 10px;
  margin-left: -10px;
  font-family: Inter, system-ui, sans-serif;
  font-weight: 500;
  font-size: 0.8rem;
  color: var(--text-dim);
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.status__cancel:hover { background: var(--surface); color: var(--danger); }
.status__cancel:disabled { opacity: 0.5; cursor: default; pointer-events: none; }

.progress {
  margin-top: 12px;
  height: 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
}
.progress__bar {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width 0.6s ease;
}
/* Suivi section par section (une ligne par appel de rédaction). */
.sections {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  gap: 2px;
}
.sections__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 5px 0;
  font-size: 0.85rem;
  color: var(--text-dim);
  transition: color 0.2s ease;
}
.sections__item::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1px solid var(--border);
  transition: background 0.2s ease, border-color 0.2s ease;
}
/* en cours : le point bat, pour distinguer « en vol » de « en attente » */
.sections__item--live::before {
  border-color: var(--accent);
  animation: sectionPulse 1.4s ease-in-out infinite;
}
.sections__item--done { color: var(--text); }
.sections__item--done::before {
  background: var(--accent);
  border-color: var(--accent);
}
.sections__item--failed { color: var(--danger); }
.sections__item--failed::before {
  background: var(--danger);
  border-color: var(--danger);
}
@keyframes sectionPulse {
  0%, 100% { background: transparent; }
  50%      { background: rgba(var(--accent-rgb), 0.55); }
}
@media (prefers-reduced-motion: reduce) {
  .sections__item--live::before { animation: none; background: rgba(var(--accent-rgb), 0.4); }
}

.panel--error {
  border-color: rgba(255, 107, 107, 0.4);
  background: rgba(255, 107, 107, 0.08);
  color: #ffc9c9;
  white-space: pre-wrap;
}

.spinner {
  width: 20px; height: 20px; flex: none;
  border: 3px solid rgba(var(--accent-rgb), 0.25);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

@media (max-width: 520px) {
  .shell { padding: 40px 16px 72px; }
  .head h1 { font-size: 1.6rem; }
}

/* ---------- bouton "Nouvelle fiche" (volet) ---------- */
.sidebar__new {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 4px 0 10px;
  padding: 9px 11px;
  font-family: inherit;
  font-size: 0.86rem;          /* aligné sur le reste du volet */
  font-weight: 500;
  color: var(--text);
  background: none;
  border: 1px solid transparent;
  border-radius: 9px;
  cursor: pointer;
  text-align: left;
}
.sidebar__new span { font-size: 1rem; line-height: 1; color: var(--text-dim); }
.sidebar__new:hover { background: var(--surface); }

/* dans .sidebar__scroll (donc dans la zone qui défile), juste après la liste
   des fiches : n'apparaît qu'en scrollant jusqu'au bout des 20 fiches visibles */
.sidebar__showall {
  flex: none;
  display: block;
  width: 100%;
  margin-top: 2px;
  padding: 8px 10px;
  font: inherit;
  font-size: 0.82rem;
  color: var(--text-dim);
  background: none;
  border: none;
  border-radius: 8px;
  text-align: left;
  cursor: pointer;
}
.sidebar__showall:hover { color: var(--text); background: var(--surface); }
/* variante dans un dossier (> 10 fiches) : même débord négatif que
   .folder__fiches > .history__item, mais porté par le bouton lui-même (et
   non son <li>) puisque c'est lui qui reçoit le fond au survol. */
.folder__showall-wrap { margin-top: 2px; }
.folder__showall-wrap .sidebar__showall {
  margin-left: -27px;
  width: calc(100% + 27px);
  padding: 6px 8px 6px 37px;
  font-size: 0.78rem;
}

/* état "sélectionné" quand on est sur l'accueil (= nouvelle fiche) */
body:not(.viewing):not(.browsing) .sidebar__new {
  background: var(--surface-strong);
  border-color: rgba(255, 255, 255, 0.16);
  color: #fff;
}
body:not(.viewing):not(.browsing) .sidebar__new span { color: var(--text); }

/* ---------- visionneur de fiche ---------- */

/* transition douce depuis le formulaire : le contenu descend en place */
@keyframes ficheSlideDown {
  from { opacity: 0; transform: translateY(-18px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes docFadeUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
body.viewing #view-fiche > * { animation: ficheSlideDown 0.4s ease both; }
body.viewing #status { animation-delay: 0.06s; }
body.viewing .viewer__doc { animation-delay: 0.12s; }
.viewer__doc .docx-wrapper { animation: docFadeUp 0.5s ease both; }
/* le bouton de téléchargement n'arrive qu'une fois la fiche quasi en place */
body.viewing #view-fiche > .viewer__footer { animation: docFadeUp 0.4s ease 0.35s both; }

/* sortie du formulaire vers le haut */
@keyframes formLeaveUp {
  to { opacity: 0; transform: translateY(-22px); }
}
#view-form.view--leaving { animation: formLeaveUp 0.24s ease forwards; }

@media (prefers-reduced-motion: reduce) {
  body.viewing #view-fiche > *,
  body.viewing #view-fiche > .viewer__footer,
  .viewer__doc .docx-wrapper,
  #view-form.view--leaving { animation: none; }
}

/* rappel de la requête, au-dessus de la fiche — même largeur que la zone de saisie */
.viewer__prompt {
  width: min(620px, 100%);
  margin: 32px auto 18px;
  padding: 10px 15px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.viewer__prompt-text {
  margin: 0;
  font-size: 0.82rem;
  font-style: italic;
  line-height: 1.5;
  color: var(--text-dim);
}
.viewer__prompt-text::before { content: "« "; }
.viewer__prompt-text::after { content: " »"; }

/* petit repère du modèle ayant généré la fiche, en bas à gauche de la bulle
   de rappel du prompt */
.viewer__model {
  margin: 0;
  font-size: 0.74rem;
  color: var(--text-dim);
  opacity: 0.75;
  text-align: left;
}
/* pied de la bulle : le modèle à gauche, le bouton « copier » à droite —
   seul, le bouton garde sa place à droite (margin-left: auto) */
.viewer__prompt-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 6px;
}
.viewer__prompt-foot:not(:has(> :not([hidden]))) { display: none; }
.viewer__copy {
  margin: -5px -6px -5px auto;
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  padding: 0;
  color: var(--text-dim);
  opacity: 0.75;
  background: none;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease;
}
.viewer__copy[hidden] { display: none; }
.viewer__copy:hover { opacity: 1; color: var(--text); background: var(--surface); }
.viewer__copy:focus-visible { outline: 1px solid var(--focus); outline-offset: 1px; }
/* une fois copié : coche le temps d'un battement, puis retour à l'icône */
.viewer__copy-done { display: none; }
.viewer__copy.is-copied .viewer__copy-icon { display: none; }
.viewer__copy.is-copied .viewer__copy-done { display: block; }
.viewer__copy.is-copied { opacity: 1; color: var(--text); }

.viewer__doc {
  overflow-x: auto;
  padding-bottom: 24px;
}

/* pied de page du visionneur : bouton de téléchargement — même largeur que la zone de saisie */
.viewer__footer {
  width: min(620px, 100%);
  margin: 0 auto;
  padding: 20px 2px 60px;
  border-top: 1px solid var(--border);
}
.viewer__actions {
  display: flex;
  justify-content: center;
}
.viewer__dl { text-decoration: none; }
.viewer__doc .docx-wrapper {
  background: transparent;
  padding: 0;
  gap: 22px;
}
.viewer__doc .docx-wrapper > section.docx {
  margin: 0 auto;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.45);
  border-radius: 2px;
}
/* Calibri absente de macOS/navigateur → on rend la fiche en Carlito
   (métrique-compatible, aspect quasi identique) */
.viewer__doc .docx,
.viewer__doc .docx * {
  font-family: "Carlito", "Calibri", system-ui, sans-serif !important;
}

.viewer__state {
  margin: 40px auto;
  max-width: 420px;
  text-align: center;
  font-size: 0.9rem;
  color: var(--text-dim);
}
.viewer__state--err { color: #ffc9c9; }

/* ---------- "Toutes les fiches" ---------- */
#view-history { width: min(920px, 100%); margin: 0 auto; }

/* décalé pour aligner avec le texte des noms de fiches en dessous (padding
   cumulé de .history--full .history__item + .history__open = 12px) */
.allfiches__head { margin: 32px 0 18px; padding-left: 12px; }
.allfiches__head h1 {
  font-family: "Space Grotesk", Inter, sans-serif;
  font-weight: 600;
  font-size: 1.4rem;
  letter-spacing: -0.01em;
  margin: 0;
  color: #fff;
}

.allfiches__search {
  display: block;
  width: 100%;
  margin-bottom: 18px;
  padding: 11px 14px;
  font: inherit;
  color: var(--text);
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid var(--border);
  border-radius: 12px;
  outline: none;
  transition: border-color 0.15s ease;
}
/* bordure seule, au survol comme au focus (cf. .composer) */
.allfiches__search:hover,
.allfiches__search:focus { border-color: var(--focus); }
.allfiches__search::placeholder { color: var(--placeholder); }

.history--full { padding-bottom: 60px; }
/* liste vide (recherche sans résultat) : ce padding-bottom ne doit pas
   pousser "aucune fiche ne correspond" vers le bas, elle doit rester au
   niveau où la 1ʳᵉ fiche serait apparue — cf. #allfiches-empty plus bas. */
.history--full:empty { padding-bottom: 0; }
.history--full .history__dot { display: none; }
.history--full .history__item {
  margin-bottom: 0;
  border-radius: 0;
  padding-left: 2px;
  border-bottom: 1px solid var(--border);
}
.history--full .history__item:last-child { border-bottom: none; }
.history--full .history__open {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 10px;
}
.history--full .history__theme {
  font-size: 0.92rem;
  white-space: normal;
  flex: 1;
  min-width: 0;
  -webkit-mask-image: none;
  mask-image: none;
}
/* colonnes "modèle" et date : largeur fixe (et pas juste "flex: none", qui se
   dimensionne au contenu) pour que les deux colonnes restent alignées d'une
   ligne à l'autre même quand l'une des deux est vide (fiches générées avant
   qu'on enregistre le modèle utilisé) — sinon la colonne suivante se décale. */
.history--full .history__model {
  display: block;
  flex: none;
  width: 130px;
  text-align: left;
  font-size: 0.76rem;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.history--full .history__meta {
  flex: none;
  width: 96px;
  margin-top: 0;
  margin-left: 0;
  text-align: right;
  font-size: 0.76rem;
  white-space: nowrap;
}
/* liste large : la date reste visible, donc le "⋮" ne se superpose pas dessus */
.history--full .history__kebab {
  position: static;
  transform: none;
  flex: none;
  margin: auto 4px auto 0;
}
/* recherche sans résultat : aligné avec le texte qu'aurait la 1ʳᵉ fiche —
   .allfiches__search margin-bottom (18px) + .history--full .history__open
   padding-top (14px). Remplace le margin-top de .history__empty (8px,
   pensé pour le volet), collapse avec celui de la liste (vide, cf. ci-dessus)
   pour donner ce total plutôt que de s'y ajouter. */
#allfiches-empty { margin-top: 32px; }

/* ---------- menu contextuel d'une fiche (épingler / renommer / supprimer) ---------- */
.fichemenu {
  position: fixed;
  z-index: 45;
  width: 190px;
  padding: 6px;
  background: var(--menu-bg);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
}
.fichemenu__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  font: inherit;
  font-size: 0.86rem;
  color: var(--text);
  background: none;
  border: none;
  border-radius: 8px;
  text-align: left;
  cursor: pointer;
}
.fichemenu__item svg { flex: none; opacity: 0.85; }
.fichemenu__item:hover { background: var(--surface-strong); }
.fichemenu__item--danger { color: var(--danger); }
.fichemenu__item--danger:hover { background: rgba(255, 107, 107, 0.14); }
/* entrée "Épingler" / "Désépingler" : icône punaise ou punaise barrée */
.fichemenu__item .fichemenu__unpin-icon,
.fichemenu__item.is-pinned .fichemenu__pin-icon { display: none; }
.fichemenu__item.is-pinned .fichemenu__unpin-icon { display: block; }

/* ---------- modale ---------- */
.modal {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  /* Le cadre DÉFILE quand la fenêtre est plus haute que l'écran (téléphone en
     paysage : ~340 px utiles). Centrée par `align-items: center`, elle perdait
     son haut — titre et premiers champs — hors d'atteinte. Le centrage passe
     donc par des marges automatiques (cf. `.modal > *`), qui centrent quand la
     place suffit et se réduisent à zéro sinon. */
  align-items: flex-start;
  overflow-y: auto;
  overscroll-behavior: contain;
  justify-content: center;
  padding: 20px;
  background: rgba(0, 0, 0, 0.62);
  backdrop-filter: blur(2px);
}
/* La pile porte la largeur ; la boîte et le compte rendu s'y alignent. Même
   construction que .porte__pile sur l'écran de connexion. */
.modal > * { margin-block: auto; }
.modal__pile {
  width: 100%;
  max-width: 380px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* COMPTE RENDU DU SERVEUR, sous la boîte (cf. le commentaire du gabarit).

   Caché par défaut : les modes « saisie » et « confirmation » ne parlent à
   personne, et une place réservée sous eux ne serait que du vide. Les modes qui
   INTERROGENT LE SERVEUR — mot de passe, demande de suppression — l'affichent
   en permanence, vide il est seulement invisible —
   parce que la modale est centrée verticalement : une boîte qui apparaîtrait
   sous elle la ferait remonter d'un demi-encart au moment précis où l'on
   s'apprête à corriger sa saisie.

   Deux lignes réservées, le pire cas courant (« Mot de passe trop simple »
   suivi de la règle entière). Un message qui en demanderait trois ferait
   bouger la boîte : c'est ce min-height qu'il faudrait alors revoir, pas le
   laisser pousser. Le texte est centré VERTICALEMENT, sans quoi une seule
   ligne se poserait en haut d'un encart réservé pour deux. */
.modal__retour { display: none; }
.modal__pile--retour .modal__retour {
  display: flex;
  align-items: center;
  box-sizing: border-box;
  margin: 0;
  padding: 13px 16px;
  font-size: 0.9rem;
  line-height: 1.5;
  min-height: calc(2 * 1.5em + 28px);   /* 2 lignes, paddings compris */
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface-strong);
  color: var(--text-dim);
}
/* `visibility` et non `display` : c'est ce qui garde la place. */
.modal__pile--retour .modal__retour--vide { visibility: hidden; }
/* Les deux classes sur le MÊME sélecteur, pour peser autant que
   `.modal__pile--retour .modal__retour` ci-dessus — qui pose les couleurs neutres
   et, à spécificité supérieure, les gardait : l'encart d'erreur restait gris. */
.modal__retour.modal__retour--erreur {
  border-color: rgba(255, 107, 107, 0.4);
  background: rgba(255, 107, 107, 0.08);
  color: #ffc9c9;
}
/* le vert du compte rendu réussi, déjà employé par .modal__message--ok */
.modal__retour.modal__retour--ok {
  border-color: rgba(143, 214, 148, 0.38);
  background: rgba(143, 214, 148, 0.08);
  color: #cdebcf;
}

.modal__box {
  width: 100%;
  max-width: 380px;
  padding: 22px;
  background: var(--bg-1);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}
.modal__title {
  margin: 0 0 12px;
  font-family: "Space Grotesk", Inter, sans-serif;
  font-weight: 600;
  font-size: 1.05rem;
  color: #fff;
}
.modal__message {
  margin: 0 0 4px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--text-dim);
}
.modal__input {
  width: 100%;
  padding: 11px 13px;
  font: inherit;
  color: var(--text);
  background: rgba(0, 0, 0, 0.32);
  border: 1px solid var(--border);
  border-radius: 10px;
  transition: border-color 0.15s ease;
}
/* même comportement que la zone de saisie du prompt (.composer) : encadré
   clair dès le survol, pas seulement une fois le focus posé, et bordure
   seule — pas de halo par-dessus. */
.modal__input:hover,
.modal__input:focus { border-color: var(--focus); }
.modal__input:focus { outline: none; }
/* Mode mot de passe : trois champs étiquetés, empilés. Un `gap` plutôt que des
   marges, pour que l'étiquette reste collée à son champ et que la respiration
   soit la même partout. */
.modal__mdp { display: flex; flex-direction: column; }
/* Quand un message explique POURQUOI cet écran s'ouvre (mot de passe posé par
   l'administrateur), il tombait contre l'étiquette du premier champ et se
   lisait comme son intitulé. Le combinateur `~` et non `+` : #modal-input
   s'intercale entre les deux, simplement masqué dans ce mode. */
#modal-message:not([hidden]) ~ .modal__formes .modal__mdp { margin-top: 14px; }
/* Mot de passe et demande de suppression superposés dans la même cellule de
   grille (cf. index.html) : la cellule prend la hauteur du plus grand. Celui
   qu'on ne montre pas y reste, invisible — `visibility` le retire aussi de la
   tabulation et des lecteurs d'écran. */
.modal__formes { display: grid; }
.modal__formes > * { grid-area: 1 / 1; }
.modal__fantome { visibility: hidden; }
.modal__mdp .modal__input { margin-bottom: 14px; }
.modal__mdp .modal__input:last-child { margin-bottom: 0; }
.modal__label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  margin-bottom: 6px;
}
.modal__aide {
  margin: 0 0 9px;
  font-size: 0.72rem;
  line-height: 1.35;
  color: var(--text-dim);
}
/* Le message de la modale sert aussi de compte rendu : rouge quand le serveur
   refuse, vert quand il a accepté. */
.modal__message--erreur { color: var(--danger); }
.modal__message--ok { color: #8fd694; }

.modal__actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 18px;
}
.modal__btn {
  padding: 9px 18px;
  font: inherit;
  font-weight: 500;
  color: #fff;
  background: var(--accent);
  border: none;
  border-radius: 9px;
  cursor: pointer;
}
.modal__btn:hover { background: var(--accent-hover); }
.modal__btn--ghost {
  color: var(--text-dim);
  background: none;
  border: 1px solid var(--border);
}
.modal__btn--ghost:hover { color: var(--text); background: var(--surface); }
/* Un bouton de modale peut désormais attendre une saisie (la confirmation de
   suppression du panneau) : sans cet état, il gardait l'aspect d'un bouton
   prêt à être cliqué alors qu'il ne répondait pas. */
.modal__btn:disabled { opacity: 0.4; cursor: not-allowed; }
.modal__btn:disabled:hover { background: var(--accent); }
.modal__btn--danger { background: var(--danger); }
.modal__btn--danger:disabled:hover { background: var(--danger); filter: none; }
.modal__btn--danger:hover { background: var(--danger); filter: brightness(1.08); }

/* --- lien des mentions légales, en bas de page et centré ---

   Posé en ABSOLU dans son écran, et non dans le flux : les trois pages qui le
   portent centrent leur contenu verticalement (grille pour les écrans
   d'entrée, colonne flexible pour l'application), et un lien ajouté au flux
   décalerait ce centrage d'une demi-ligne. Hors flux, il ne coûte rien à la
   mise en page.

   Il se lit à mi-voix — c'est une obligation légale, pas une invitation : on
   le trouve quand on le cherche, sans qu'il tire l'œil au moment d'écrire une
   demande ou de taper un mot de passe. */
.pied-legal {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 16px;
  z-index: 2;
  text-align: center;
  font-family: Inter, system-ui, sans-serif;
  font-size: 0.76rem;
  color: var(--placeholder);
  text-decoration: none;
  transition: color 0.15s ease;
}
.pied-legal:hover { color: var(--text-dim); }

/* --- « Mon compte » : le sommaire des gestes du titulaire ---

   Des lignes pleine largeur plutôt que des boutons alignés : ce sont deux
   destinations, pas deux actions qu'on comparerait. Chacune porte sa
   conséquence à mi-voix, sous son intitulé — on la lit avant de cliquer, pas
   dans l'écran suivant. */
.modal__compte { display: flex; flex-direction: column; gap: 10px; }
.modal__geste {
  font: inherit;
  text-align: left;
  width: 100%;
  padding: 13px 15px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.32);
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.modal__geste:hover:not(:disabled) { border-color: var(--focus); background: var(--surface-strong); }
.modal__geste:disabled { cursor: default; opacity: 0.5; }
.modal__geste-nom { display: block; font-size: 0.92rem; font-weight: 500; }
.modal__geste-note {
  display: block;
  margin-top: 3px;
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--text-dim);
}
/* Le geste qui engage : reconnaissable au repos, franc au survol — sans
   crier, il n'efface rien par lui-même. */
.modal__geste--danger .modal__geste-nom { color: var(--danger); }
.modal__geste--danger:hover {
  border-color: rgba(255, 107, 107, 0.5);
  background: rgba(255, 107, 107, 0.08);
}
.modal__suppr .modal__label { display: block; margin: 16px 0 6px; }
/* Le texte d'avertissement de la demande de suppression : la mise en forme
   des messages de la fenêtre, avec seulement la marge basse qui manquait —
   deux étiquettes de champ le suivent. */
#suppr-demande-note { margin: 0 0 4px; }
/* Case à cocher sous les champs : celle de « Se souvenir de moi » (login.html),
   alignée à gauche comme les étiquettes au-dessus d'elle. */
.modal__case {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-top: 16px;
  font-size: 0.82rem;
  color: var(--text-dim);
  cursor: pointer;
  user-select: none;
  transition: color 0.15s ease;
}
.modal__case[hidden] { display: none; }
.modal__case:hover { color: var(--text); }
.modal__case input {
  color-scheme: dark;
  accent-color: var(--accent);
  width: 15px;
  height: 15px;
  margin: 0;
  flex: none;
  cursor: inherit;
}
