/* ============================================================================
   DockedCRM - couche PRODUIT du design système (F10 socle, portage T4).
   Consomme les tokens de marque de prysmial-tokens.css (copie canonique, shasum
   épinglé par tests/design-socle.test.mjs). Règles transverses de la charte :
     1. AUCUNE couleur en dur ici : tout passe par var(--pr-*) ou un color-mix()
        documenté avec son ratio mesuré (les ratios appartiennent au COUPLE
        teinte+fond papier chaud : changer un fond invalide les pourcentages).
     2. UN SEUL accent d'action (iris). Azur/mint = décor et sémantique.
        Les dégradés = filets/halos, jamais le fond d'une zone de lecture.
     3. DEUX valeurs par état : --X (non-texte, 3:1), --X-text (texte, 4.5:1).
        --pr-ink-faint jamais en texte (2.84:1, échoue AA).
     4. Focus en OUTLINE, jamais en box-shadow, jamais retiré sans remplacement.
     5. Serif = signature (wordmark, nom d'espace, heroes), jamais un paragraphe.
     6. Pas de carte dans une carte : sous-blocs séparés par un filet, rangées
        posées sur --pr-mist-soft (blanc sur blanc ne se voit pas).
     7. font-family: inherit sur TOUS les contrôles (sans lui Chrome rend les
        boutons en Arial, bug mesuré en prod amont).
   Cette feuille est GLOBALE : les panels sont injectés par innerHTML dans
   #zone-panel, un <style> de panel ferait FOUC et doublons a chaque navigation.
   ============================================================================ */

@import url("prysmial-tokens.css"); /* DOIT rester la première règle */

/* ---- Fontes auto-hébergées (CSP font-src 'self', zéro CDN, hors-ligne) --------
   Les 8 woff2 sont des VARIABLE FONTS (table fvar vérifiée au portage). La source
   amont déclarait Inter « 300 600 » et employait 620-750 : le navigateur
   SYNTHÉTISAIT ces graisses. Ici : 300 800, l'axe réel couvre. */
@font-face{font-family:"Inter";font-style:normal;font-weight:300 800;font-display:swap;src:url("fonts/inter-latin.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Inter";font-style:normal;font-weight:300 800;font-display:swap;src:url("fonts/inter-latin-ext.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:"Playfair Display";font-style:normal;font-weight:400 700;font-display:swap;src:url("fonts/playfair-latin.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Playfair Display";font-style:normal;font-weight:400 700;font-display:swap;src:url("fonts/playfair-latin-ext.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:"Playfair Display";font-style:italic;font-weight:400 600;font-display:swap;src:url("fonts/playfair-latin-italic.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Playfair Display";font-style:italic;font-weight:400 600;font-display:swap;src:url("fonts/playfair-latin-ext-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:"JetBrains Mono";font-style:normal;font-weight:400 500;font-display:swap;src:url("fonts/jetbrainsmono-latin.woff2") format("woff2");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"JetBrains Mono";font-style:normal;font-weight:400 500;font-display:swap;src:url("fonts/jetbrainsmono-latin-ext.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}

/* ---- Tokens sémantiques du produit (ne font que POINTER vers --pr-*) ---------- */
:root {
  /* Accent d'ACTION : iris seul. azur/mint décoratifs. */
  --accent: var(--pr-iris);
  --accent-ink: var(--pr-white);
  --accent-text: var(--pr-iris-ink);
  --accent-wash: var(--pr-iris-wash);
  --solid: var(--pr-ink);          /* bouton plein encre : blanc dessus = 19:1 */
  --solid-ink: var(--pr-white);
  --grad: var(--pr-gradient-iris); /* accents décoratifs uniquement */

  /* Fonds et lignes */
  --bg: var(--pr-paper);
  --bg-2: var(--pr-mist-soft);
  --surface: var(--pr-white);
  --surface-2: var(--pr-mist-soft);
  --border: var(--pr-mist);
  --border-2: color-mix(in srgb, var(--pr-mist) 84%, var(--pr-ink-faint));
  /* Bordure de CHAMP : 86 % et pas 88 (3.01:1 mesuré au pire des trois fonds, WCAG 1.4.11) */
  --border-field: color-mix(in srgb, var(--pr-ink-faint) 86%, var(--pr-ink));
  --border-card: color-mix(in srgb, var(--pr-ink) 9%, transparent);
  --border-card-2: color-mix(in srgb, var(--pr-ink) 10%, transparent);

  /* Texte */
  --text: var(--pr-ink);
  --text-2: var(--pr-ink-muted);
  --text-3: var(--pr-ink-tertiary); /* PAS ink-faint : échoue AA */

  /* États : version texte dérivée (ratios mesurés sur papier chaud, ne pas retoucher
     les pourcentages sans re-mesurer) */
  --ok: var(--pr-ok);     --ok-text:   color-mix(in srgb, var(--pr-ok) 62%, var(--pr-ink));
  --warn: var(--pr-warn); --warn-text: color-mix(in srgb, var(--pr-warn) 68%, var(--pr-ink));
  --err: var(--pr-err);   --err-text:  color-mix(in srgb, var(--pr-err) 90%, var(--pr-ink));

  /* Rayons : comble les trous de la source amont (--r-md/--r-xl y étaient consommés
     mais jamais définis, les coins des heroes tombaient à 0) */
  --r-sm: var(--pr-r-sm);   /* 10px */
  --r: var(--pr-r);         /* 14px */
  --r-md: 12px;
  --r-lg: var(--pr-r-lg);   /* 20px */
  --r-xl: 24px;
  --r-slab: 8px;            /* grandes dalles : hero, workspace, shell */
  --r-pill: var(--pr-r-pill);

  /* Ombres : idem, --shadow-md manquait amont. Teintées encre FROIDE (#0b0f19),
     jamais noires (sur un papier froid, une ombre neutre paraît grise et sale). */
  --shadow-sm: var(--pr-shadow-sm);
  --shadow-md: 0 1px 2px rgb(11 15 25 / 0.05), 0 10px 24px -14px rgb(11 15 25 / 0.2);
  --shadow: var(--pr-shadow);
  --shadow-lg: var(--pr-shadow-lg);
  --shadow-primary: 0 1px 2px rgb(11 15 25 / 0.07), 0 12px 24px -16px rgb(106 71 255 / 0.8);
  --shadow-inset-field: inset 0 1px 0 rgb(11 15 25 / 0.025);

  /* Typo : Inter porte tout le texte, Playfair signe les titres. Le produit
     consomme désormais le TOKEN au lieu de redéclarer la pile : jusqu'à la révision
     du 2026-08-20, --pr-sans nommait « Instrument Sans », que ce produit n'embarque
     pas, et la couche produit contournait le token en silence. */
  --sans: var(--pr-sans);
  --serif: var(--pr-serif);
  --mono: var(--pr-mono);
  --ring: color-mix(in srgb, var(--accent) 26%, transparent);

  /* Filet de marque : le dégradé irisé du site à SIX arrêts, pas une tricolore
     approchée. Le magenta d'ouverture et le cyan avant le vert sont ce que réfracte
     réellement le prisme du hero : les retirer donne un dégradé, pas CELUI-LÀ. */
  --dk-prism: var(--pr-gradient-iris);
  --dk-prism-wash: var(--pr-gradient-prism-wash);
}

/* ---- Base ---------------------------------------------------------------------- */
body {
  margin: 0; font-family: var(--sans); font-size: 14px;
  color: var(--text);
  background: var(--pr-gradient-prism-wash), var(--bg);
  -webkit-font-smoothing: antialiased;
}
::selection { background: var(--accent-wash); color: var(--pr-ink); }
a:focus-visible, button:focus-visible, select:focus-visible, input:focus-visible,
textarea:focus-visible, [tabindex]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
[x-cloak] { display: none !important; }
a { color: var(--accent-text); }

h2 { font-size: 22px; font-weight: 650; letter-spacing: -0.03em; margin: 0 0 8px; }
h3 { font-size: 15px; font-weight: 650; letter-spacing: -0.015em; margin: 0 0 6px; }
h4 { font-size: 13px; font-weight: 650; margin: 0 0 6px; }
small { color: var(--text-2); }
code, pre, .mono { font-family: var(--mono); }
.tabular { font-variant-numeric: tabular-nums; }

/* ---- Contrôles de formulaire ----------------------------------------------------- */
button {
  font-family: inherit; font-size: 13px; font-weight: 500;
  padding: 11px 14px; border-radius: 11px;
  border: 1px solid var(--border-2); background: var(--surface-2); color: var(--text);
  cursor: pointer;
  transition: background var(--pr-dur-fast) var(--pr-ease-glide),
              border-color var(--pr-dur-fast) var(--pr-ease-glide),
              transform var(--pr-dur-fast) var(--pr-ease-glide);
}
button:hover { background: var(--surface); }
button.primary {
  background: var(--accent); color: var(--accent-ink); font-weight: 600;
  border-color: transparent; box-shadow: var(--shadow-primary);
}
button.primary:hover { background: var(--pr-iris-ink); transform: translateY(-1px); }
button:disabled { opacity: 0.45; cursor: default; }
button:disabled:hover { transform: none; background: var(--surface-2); }
button.primary:disabled:hover { background: var(--accent); }
button.ghost { background: var(--surface); }
button.danger {
  color: var(--err-text); background: var(--surface);
  border-color: color-mix(in srgb, var(--err-text) 28%, var(--border));
}
button.danger:hover { background: color-mix(in srgb, var(--err) 8%, var(--surface)); }
button.btn-mini { padding: 4px 10px; font-size: 11.5px; border-radius: 9px; }
button.link, button.linkish {
  background: none; border: none; padding: 0; border-radius: 4px;
  color: var(--accent-text); text-decoration: underline; font-size: inherit;
}

input, textarea, select {
  font-family: inherit; font-size: 14px; color: var(--text);
  padding: 12px 13px; border-radius: 11px;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--pr-ink-faint) 55%, var(--pr-mist));
  box-shadow: var(--shadow-inset-field);
}
input::placeholder, textarea::placeholder { color: var(--text-3); }
/* Bague de CHAMP en box-shadow (esthétique) : elle s'AJOUTE à la bague outline globale
   de :focus-visible, elle ne la remplace jamais (règle n°4 de la charte). */
input:focus, textarea:focus, select:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--ring);
}
select { min-height: 42px; }

.field { margin-bottom: 14px; }
.field .label, .label {
  display: block; font-size: 10px; font-weight: 700; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--text-3); margin-bottom: 6px;
}
.field input, .field textarea, .field select { width: 100%; box-sizing: border-box; }
.value { font-size: 14px; }
label.field { display: block; }

/* Cases à cocher / radios : PAS des champs texte. Sans ce reset elles héritent du
   padding 12px et de la bordure des inputs et se déforment. accent-color = le seul
   accent d'action (iris), via token. */
input[type="checkbox"], input[type="radio"] {
  width: 16px; height: 16px; padding: 0; margin: 0;
  accent-color: var(--accent); box-shadow: none; flex: none;
}
input[type="file"] { padding: 8px 0; border: none; background: none; box-shadow: none; }
/* étiquette à case : texte 13px secondaire, case alignée */
.check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-2); cursor: pointer; }

/* rangée de création compacte (multi-champs + bouton, remplace les formulaires nus) */
.form-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.form-row input, .form-row select { flex: 1 1 150px; min-width: 0; }
.form-row button { flex: none; }

/* grille de champs pour les fiches longues ; .pleine étale un champ (textarea) */
.form-cols { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); column-gap: 14px; }
.field.pleine { grid-column: 1 / -1; }
/* UNE CASE DANS UNE GRILLE DE CHAMPS EST UN CHAMP (revue 2026-08-25). Elle n'a pas de
   .label au-dessus d'elle, contrairement aux .field voisins : posée nue, elle flottait
   dans sa cellule, decalee d'environ 22 px de la ligne des inputs, et une grille mixte
   « trois champs + deux cases » donnait un damier -- c'est ce que la revue a appele
   « pas harmonieux ».

   Le calage seul (align-self + padding) alignait les BAS mais laissait deux objets de
   nature visuelle differente cote a cote : un rectangle borde et un texte nu. On lui
   donne donc la MEME boite que les champs voisins -- meme hauteur (42 px, celle d'un
   input : 14 px de texte + 2x12 px de padding + bordures), meme rayon, meme bordure,
   meme marge basse -- et la case s'y pose au milieu. La grille redevient une grille.

   `margin-bottom: 14px` et non un padding : c'est la valeur de .field, et deux facons
   d'espacer la meme grille finiraient par diverger. */
.form-cols .check {
  align-self: end; margin-bottom: 14px;
  min-height: 42px; padding: 0 13px; box-sizing: border-box;
  border: 1px solid color-mix(in srgb, var(--pr-ink-faint) 55%, var(--pr-mist));
  border-radius: 11px; background: var(--surface);
}
/* Les lignes d'une grille de champs ne se touchent pas : `.field` porte 14 px de marge
   basse, mais une cellule qui n'est pas un .field (bloc d'aide, bouton) n'en a pas. */
.form-cols { row-gap: 2px; }

/* barre de filtres au-dessus d'une liste */
.toolbar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.toolbar .field { margin-bottom: 0; }

/* ---- Shell : bandeau + sidebar + zone de contenu --------------------------------- */
.app-shell {
  display: grid;
  grid-template-columns: 236px minmax(0, 1fr);
  grid-template-rows: auto 1fr;
  min-height: 100vh;
}
.top {
  grid-column: 1 / -1;
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 10px;
  min-height: 64px; padding: 0 24px; box-sizing: border-box;
  background: color-mix(in srgb, var(--pr-panel) 92%, transparent);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border-bottom: 1px solid var(--border);
}
.logo { display: block; flex: none; }
.lg-iris { stop-color: var(--pr-iris); }
.lg-azur { stop-color: var(--pr-azur); }
.lg-mint { stop-color: var(--pr-mint); }
.wordmark {
  font-family: var(--serif); font-size: 21px; font-weight: 500;
  letter-spacing: -0.005em; color: var(--text);
}
.top .deconnexion { margin-left: auto; display: flex; gap: 8px; }

.nav {
  display: flex; flex-direction: column; gap: 2px;
  position: sticky; top: 64px; height: calc(100vh - 64px); box-sizing: border-box;
  overflow-y: auto;
  padding: 24px 14px 18px;
  border-right: 1px solid var(--border);
  background: color-mix(in srgb, var(--pr-panel) 72%, transparent);
}
.nav-espace {
  font-family: var(--serif); font-size: 21px; font-weight: 500;
  letter-spacing: -0.01em; margin: 0 0 2px; padding: 0 12px;
}
.nav-titre {
  font-size: 11.5px; color: var(--text-3); margin: 0 0 10px; padding: 0 12px;
}
/* ---- Nav groupée (chantier UX, lot A) -------------------------------------------
   .nav-bloc = UN groupe (en-tête + items) : la nav reste un rail à gap 2px, le
   souffle entre groupes vit sur la marge haute du bloc. Le x-for laisse son
   <template> dans le DOM comme ancre : seul le PREMIER bloc le suit directement,
   et il tombe déjà sous .nav-titre (margée à 10px) ; sans l'ajustement il
   doublerait le souffle (24px au lieu de 12). */
.nav-bloc { display: flex; flex-direction: column; gap: 2px; margin-top: 12px; }
.nav > template + .nav-bloc { margin-top: 0; }
/* En-tête de groupe : la voix des étiquettes du design system (10px, 700,
   uppercase, letter-spacing 0.11em, text-3 ; cf .label et .entreprise-titre),
   alignée sur le rail de 12px des items. Marge basse seule : le souffle haut est
   porté par .nav-bloc. */
.nav-groupe {
  margin: 0 0 4px; padding: 0 12px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.11em;
  text-transform: uppercase; color: var(--text-3);
}
.nav-item {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  min-height: 41px; padding: 0 12px 0 14px;
  border-radius: 11px; border: 1px solid transparent;
  background: transparent; box-shadow: none;
  font-size: 13px; font-weight: 520; color: var(--text-2);
  text-align: left; width: 100%; box-sizing: border-box;
}
.nav-item:hover { color: var(--text); background: var(--pr-mist-soft); }
/* Pastille d'urgences (T-D2) : compte ce qui appelle un geste. margin-right laisse la
   place au point iris de l'item actif (::after, right: 12px). */
.nav-badge {
  margin-left: auto; margin-right: 10px; flex: none;
  min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  font-size: 10.5px; font-weight: 640; font-variant-numeric: tabular-nums;
  background: var(--accent); color: var(--surface);
}
.nav-icon {
  width: 21px; height: 21px; display: grid; place-items: center; flex: none;
  font-size: 14px; color: var(--pr-ink-faint); /* décoratif : faint autorisé */
}
/* Actif, la signature de l'UI : fond blanc + DEUX repères iris (filet gauche, point droit) */
.nav-item.actif {
  color: var(--text); background: var(--surface);
  border-color: color-mix(in srgb, var(--pr-ink) 7%, transparent);
  box-shadow: var(--shadow-sm);
}
.nav-item.actif .nav-icon { color: var(--accent); }
.nav-item.actif::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 19px; border-radius: 0 3px 3px 0;
  background: var(--accent);
}
.nav-item.actif::after {
  content: ""; position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  width: 5px; height: 5px; border-radius: var(--r-pill);
  background: var(--accent);
}
main#zone-panel {
  padding: 32px clamp(20px, 4vw, 56px) 56px;
  min-width: 0;
}

/* ---- Login ------------------------------------------------------------------------ */
#login {
  min-height: 100vh; display: grid; place-items: center;
  padding: 24px; box-sizing: border-box;
}
.login-carte {
  width: min(100%, 470px); box-sizing: border-box;
  padding: 32px; border-radius: var(--r-lg);
  background: var(--pr-panel); border: 1px solid var(--border-card);
  box-shadow: var(--shadow-lg);
}
/* ── Selecteur d'entreprise (bandeau) ────────────────────────────────────────────────
   Un aiguilleur entre instances : chaque entreprise garde sa base et son conteneur.
   Pose au CENTRE du bandeau (`margin-inline: auto`) : c'est le repere qui dit « ou
   suis-je », il ne se cherche pas dans un coin. */
.entreprise-sel { position: relative; margin-inline: auto; }
.entreprise-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px; border-radius: var(--r-pill);
  background: var(--surface); border: 1px solid var(--border);
  font-family: inherit; font-size: 13px; font-weight: 500; color: var(--text);
  cursor: pointer;
}
.entreprise-btn:hover { background: var(--surface-2); border-color: var(--border-2); }
.entreprise-btn .chevron { color: var(--text-2); font-size: 11px; }
.entreprise-menu {
  position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  z-index: 40; min-width: 240px; padding: 6px;
  background: var(--pr-panel); border: 1px solid var(--border-card);
  border-radius: var(--r); box-shadow: var(--shadow-lg);
}
.entreprise-titre {
  margin: 4px 10px 6px; font-size: 10px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-3);
}
/* Un `<a>` pour les instances (ca NAVIGUE vraiment), un `<button>` pour l'ajout (ca ne
   navigue pas). Ne pas intervertir : un lien qui ne mene nulle part ment au lecteur
   d'ecran et au clic du milieu. */
.entreprise-item {
  display: block; width: 100%; box-sizing: border-box; text-align: left;
  padding: 9px 10px; border: 0; border-radius: var(--r-sm);
  background: none; font-family: inherit; font-size: 13px; color: var(--text);
  text-decoration: none; cursor: pointer;
}
.entreprise-item:hover { background: var(--accent-wash); color: var(--accent-text); }
.entreprise-item.ajout { color: var(--text-2); }
.entreprise-sep { height: 1px; margin: 6px 4px; background: var(--border); }

/* ── Fenetre modale ─────────────────────────────────────────────────────────────── */
html.modale-ouverte,
html.modale-ouverte body {
  overflow: hidden;
  overscroll-behavior: none;
}
.modale-fond {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center;
  padding: 20px; overflow-y: auto; overscroll-behavior: contain;
  background: color-mix(in srgb, var(--pr-ink) 42%, transparent);
}
.modale {
  width: min(100%, 460px); padding: 26px; box-sizing: border-box; border-radius: var(--r-lg);
  background: var(--pr-panel); border: 1px solid var(--border-card);
  box-shadow: var(--shadow-lg);
}
/* Variante LARGE : pour un contenu qu'on vient LIRE (brief de préparation, corps d'un
   mail archivé) et non une question à laquelle répondre. Elle défile DANS la fenêtre
   (max-height + overflow) : sans ça, un brief long pousse la modale hors de l'écran et
   son bouton « Fermer » devient inatteignable -- exactement le piège qu'on répare en
   sortant ces contenus du bas de page. */
.modale.large { width: min(100%, 820px); max-height: 82vh; overflow-y: auto; }
.modale-tete { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.modale-tete h2 { margin: 0; }
.modale h2 { margin: 0 0 10px; font-family: var(--serif); font-size: 21px; font-weight: 500; }
.modale .sub { margin: 0 0 14px; font-size: 13px; color: var(--text-2); line-height: 1.55; }

/* ── Onboarding guidé ─────────────────────────────────────────────────────────────
   Le voile ne reçoit aucun clic : seuls le coach et la vraie cible restent dans les
   branches non inertes posées par le shell. Pas de cadre gris autour des icônes : la
   cible se distingue par un filet d'accent et une lumière courte. */
html.onboarding-ouvert,
html.onboarding-ouvert body { overflow: hidden; overscroll-behavior: none; }
.onboarding-layer {
  position: fixed; inset: 0; z-index: 80; display: grid; place-items: center;
  box-sizing: border-box; padding: 24px; overflow-y: auto; pointer-events: none;
}
.onboarding-voile {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background: color-mix(in srgb, var(--pr-ink) 64%, transparent);
  backdrop-filter: blur(1px);
}
.onboarding-coach {
  position: relative; z-index: 2; width: min(100%, 620px); max-height: calc(100dvh - 48px);
  overflow-y: auto; box-sizing: border-box; padding: 28px; pointer-events: auto;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border-card));
  border-radius: var(--r-lg); background: var(--pr-panel); box-shadow: var(--shadow-lg);
}
.onboarding-coach h2 {
  margin: 0 0 8px; font-family: var(--serif); font-size: 26px; font-weight: 500;
  letter-spacing: -.015em;
}
.onboarding-coach .sub { margin: 0 0 20px; color: var(--text-2); line-height: 1.55; }
.onboarding-etape {
  margin: 0 0 7px; color: var(--accent-text); font-size: 11px; font-weight: 750;
  letter-spacing: .08em; text-transform: uppercase;
}
.onboarding-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }
.onboarding-form { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.onboarding-form label { display: grid; gap: 6px; min-width: 0; font-size: 13px; font-weight: 650; }
.onboarding-form label:has(textarea),
.onboarding-form .onboarding-actions,
.onboarding-form .hint { grid-column: 1 / -1; }
.onboarding-form input,
.onboarding-form select,
.onboarding-form textarea { width: 100%; box-sizing: border-box; }
.onboarding-form textarea { resize: vertical; min-height: 72px; }
.onboarding-form small {
  justify-self: end; color: var(--text-3); font-size: 11px; font-weight: 500;
}
.onboarding-cible {
  position: relative !important; z-index: 81 !important;
  outline: 3px solid var(--accent) !important; outline-offset: 5px;
  border-radius: var(--r-sm); box-shadow: 0 0 0 10px color-mix(in srgb, var(--accent) 18%, transparent);
}
.onboarding-reprendre { white-space: nowrap; }

@media (max-width: 640px) {
  .onboarding-layer { align-items: start; padding: 12px; }
  .onboarding-coach {
    width: 100%; max-height: calc(100dvh - 24px); margin: 0; padding: 20px;
    border-radius: var(--r);
  }
  .onboarding-coach h2 { font-size: 23px; }
  .onboarding-form { grid-template-columns: 1fr; }
  .onboarding-form label { grid-column: 1; }
  .onboarding-actions { display: grid; grid-template-columns: 1fr; }
  .onboarding-actions button { width: 100%; }
}

/* Bascule entre les deux formes de connexion (token d'instance / compte). Un BOUTON,
   pas un <a> : il ne navigue pas, il change l'ecran. Un lien qui ne mene nulle part
   ment au lecteur d'ecran et au clic du milieu. Le focus reste en `outline` : c'est une
   propriete distincte, qu'aucune ombre decorative posee plus tard ne peut ecraser. */
.lien-bas {
  display: block; width: 100%; margin-top: 14px; padding: 8px;
  background: none; border: 0; border-radius: var(--r-sm);
  font-family: inherit; font-size: 13px; color: var(--text-2);
  text-decoration: underline; cursor: pointer;
}
.lien-bas:hover { color: var(--text); background: var(--surface-2); }

.login-carte h1 {
  font-family: var(--serif); font-size: 32px; font-weight: 500;
  letter-spacing: -0.02em; margin: 0 0 4px;
}
.login-carte .sub { margin: 0 0 22px; }
.login-carte button.primary { width: 100%; margin-top: 4px; }

/* ---- Bandeau mode dégradé (recette deux-valeurs : fond lavis, filet 3px, texte -text) */
.bandeau-degrade {
  padding: 10px 16px; font-weight: 600; font-size: 13px;
  background: color-mix(in srgb, var(--pr-err) 8%, var(--pr-panel));
  border-left: 3px solid var(--pr-err);
  color: var(--err-text);
}

/* ---- Bandeau canal de mise à jour (portage delta T-D8) : même recette deux-valeurs
   que le mode dégradé ci-dessus, teinte ACCENT (annonce, pas une panne) ; .securite
   bascule sur la teinte -err (non reportable, elle mérite l'alerte). */
.bandeau-maj {
  padding: 10px 16px; font-size: 13px; display: flex; align-items: center;
  flex-wrap: wrap; gap: 4px 6px;
  background: color-mix(in srgb, var(--accent) 8%, var(--pr-panel));
  border-left: 3px solid var(--accent);
  color: var(--accent-text);
}
.bandeau-maj.securite {
  background: color-mix(in srgb, var(--pr-err) 8%, var(--pr-panel));
  border-left-color: var(--pr-err);
  color: var(--err-text);
}
.bandeau-maj .maj-sub { opacity: .78; }
.bandeau-maj .maj-actions { display: inline-flex; align-items: center; gap: 6px; margin-left: 8px; }
.bandeau-maj .maj-msg { width: 100%; font-size: 12px; opacity: .85; }

/* ---- Gabarit de VUE (le pattern central de chaque panel) --------------------------
   <section class="view">
     <header class="view-hero"> kicker + h2 + .sub </header>
     <div class="view-workspace"> toolbar / split / listes / detail-shell </div>
   </section> */
/* ── LES VOLETS DENSES PRENNENT LA LARGEUR (demande 2026-08-27) ──────────────────────
   `.view` reste à 1120px : c'est une largeur de LECTURE, juste pour un formulaire ou un
   écran d'explication -- au-delà d'environ 90 caractères une ligne devient pénible, et un
   libellé à un mètre de son champ n'aide personne.
   `.view.large` est posée VOLET PAR VOLET sur ceux qui montrent beaucoup de lignes ou de
   colonnes (kanban, prospects, référentiel, factures, pipeline, campagnes, heures,
   recherche). `min(100% - 48px, 1800px)` : on prend l'écran, sans coller aux bords, et
   sans partir à 3000px sur un ultra-large où plus rien ne se lit d'un coup d'œil.
   ⚠ On ne touche QUE `max-width` : pendant l'entrée, l'opacité appartient à
   l'animation ; après sa fin, le fill-mode `none` rend bien la main. */
.view.large { max-width: min(100% - 48px, 1800px); }

.view {
  max-width: 1120px; margin: 0 auto;
  display: flex; flex-direction: column; gap: 16px;
  /* Entrée de vue à l'injection innerHTML (mouvement T4b). Durées/easing par tokens :
     prefers-reduced-motion les met à 0 dans prysmial-tokens.css, rien à refaire ici.
     Le mouvement reste volontairement un FONDU : même temporaire, un `transform` sur
     `.view` en ferait le bloc contenant des fenêtres `position: fixed` et les sortirait
     du viewport si l'utilisateur en ouvre une pendant les 420 ms d'entrée. */
  animation: view-in var(--pr-dur-slow) var(--pr-ease-prism);
}
@keyframes view-in { from { opacity: 0; } }
.view-hero {
  position: relative; overflow: hidden;
  padding: 26px 28px 24px; border-radius: var(--r-slab);
  background: var(--dk-prism-wash), var(--pr-panel);
  border: 1px solid var(--border-card);
  box-shadow: var(--shadow-sm);
}
.view-hero::before { /* filet prisme 3px, la marque */
  content: ""; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--dk-prism);
}
.view-hero::after { /* chevron du sigle en filigrane */
  content: "\203A"; position: absolute; right: 18px; top: 50%;
  transform: translateY(-58%);
  font-size: 104px; line-height: 1; font-weight: 700; opacity: 0.13;
  color: var(--accent); pointer-events: none;
}
.view-hero h2 {
  font-size: clamp(28px, 3vw, 38px); font-weight: 620;
  letter-spacing: -0.045em; line-height: 1.05; margin: 10px 0 6px;
}
.section-kicker {
  display: inline-block; margin: 0;
  padding: 4px 10px; border-radius: var(--r-pill);
  background: var(--surface);
  font-size: 10px; font-weight: 750; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--accent-text);
}
.sub { font-size: 14px; color: var(--text-2); line-height: 1.55; max-width: 670px; margin: 0; }
.view-workspace {
  display: flex; flex-direction: column; gap: 14px;
  padding: clamp(16px, 2vw, 22px); border-radius: var(--r-slab);
  background: var(--surface);
  border: 1px solid var(--border-card-2);
  box-shadow: var(--shadow-sm);
}
.view-workspace .msg:empty { display: none; }

/* Contenu d'un onglet INTERNE de volet (réglages, 2026-08-24) ou d'une vue de la
   bascule Campagnes (chantier UX, lot B) : un template x-if n'a qu'un seul noeud
   racine, donc les sections d'un même onglet sont regroupées sous le wrapper nommé
   .vue-onglet ; les vues de Campagnes, elles, sont des <div> nus portés par leur
   x-show, sans classe. Dans les deux cas les blocs perdaient le rythme vertical
   (gap 14px) qu'ils tenaient en enfants directs de .view-workspace : deux grilles
   .kpis se touchaient, la barre de filtres collait la première carte de la liste
   Brouillons. Ce flex reproduit le rythme à l'identique, et son gap ne joue
   qu'entre éléments VISIBLES (un x-show faux ne laisse pas de trou, contrairement
   à une marge). Le sélecteur d'attribut s'adosse à la MÉCANIQUE de bascule
   (x-show="vue === ..."), jamais à un data-role de test : le style suit le
   comportement. */
.vue-onglet,
.view-workspace > div[x-show^="vue ==="] { display: flex; flex-direction: column; gap: 14px; }

/* ---- Cartes ------------------------------------------------------------------------ */
.section-card {
  background: var(--surface); border-radius: var(--r-lg);
  border: 1px solid var(--border-card); box-shadow: var(--shadow-sm);
  padding: clamp(17px, 2.2vw, 24px);
}
.section-head { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.section-head p { font-size: 13px; color: var(--text-2); margin: 0; }
.detail-shell {
  border-radius: var(--r-slab); border: 1px solid var(--border-card-2);
  background: var(--surface); box-shadow: var(--shadow-sm);
  overflow: hidden; padding: 0;
}
.detail-shell-head {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 18px; background: var(--pr-mist-soft);
  border-bottom: 1px solid color-mix(in srgb, var(--pr-ink) 8%, transparent);
}
.detail-shell-head h3 { font-size: 14.5px; margin: 0; }
.detail-shell-head .btn-mini { margin-left: auto; }
.detail-shell-body {
  display: flex; flex-direction: column; gap: 16px;
  padding: clamp(16px, 2vw, 22px);
}
/* Pied du detail-shell, jumeau du head (même filet, mêmes paddings) : il accueille la
   barre de saisie qui vit DANS la fenêtre (assistant, 2026-08-24). Avant, la barre
   flottait en bas du workspace, détachée de la fenêtre de chat, et se lisait comme
   absente. */
.detail-shell-foot {
  padding: 13px 18px;
  border-top: 1px solid color-mix(in srgb, var(--pr-ink) 8%, transparent);
}
/* Pas de carte dans une carte : les sous-blocs deviennent des sections à filet */
.detail-card.flat + .detail-card.flat { border-top: 1px solid var(--border); padding-top: 16px; }
/* Rythme INTERNE d'une carte de détail (chantier UX, lot B) : seul le filet ENTRE
   cartes était réglé (règle ci-dessus), rien ne rythmait l'intérieur : guide-notes,
   barres d'outils, lecteurs audio, champs et listes s'y collaient (mesuré dans le
   volet Dictée : trois .guide-note, puis .toolbar, puis .field sans le moindre
   souffle). Marge haute sur tout enfant non premier : elle FUSIONNE avec les marges
   existantes (h3 6px, .field 14px) par margin collapsing, et pose donc un PLANCHER
   de 12px entre blocs frères sans jamais doubler le compte. Pas de flex+gap ici :
   le gap s'ADDITIONNERAIT à ces marges au lieu de les absorber. */
.detail-card > * + * { margin-top: 12px; }

/* ---- Split liste / fiche + rangées -------------------------------------------------- */
.split { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 22px; }
/* variante deux colonnes égales (formulaire | liste) : rdv, time, todos, invoicing */
.split-egal { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 22px; }
.split-egal > .pleine { grid-column: 1 / -1; }
/* LA LISTE DÉFILE DANS SON PROPRE CADRE (revue 2026-08-25). Le carnet réel porte
   plusieurs centaines de fiches : sans hauteur maximale, la liste pousse la page sur
   des mètres, la fiche ouverte à droite sort de l'écran dès qu'on cherche un nom, et
   le pied de page devient inatteignable. `min-height: 0` sur la piste de gauche du
   .split est indispensable : sans lui, un élément de grille refuse de rétrécir sous
   son contenu et l'overflow ne s'arme jamais (la barre de défilement n'apparaît pas,
   et rien ne le dit). */
.client-list {
  display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none;
  max-height: min(64vh, 640px); overflow-y: auto; overscroll-behavior: contain;
  min-height: 0; padding-right: 4px;
}
.client-list::-webkit-scrollbar { width: 8px; }
.client-list::-webkit-scrollbar-thumb {
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--pr-ink) 14%, transparent);
}
.client-list::-webkit-scrollbar-track { background: transparent; }

/* TROIS COLONNES ALIGNÉES D'UNE LIGNE À L'AUTRE, et c'est le point de la grille : en
   flex, chaque cellule se dimensionne sur SON contenu, donc « Société » et « prochaine
   touche » tombaient à une abscisse différente à chaque ligne -- mesuré à l'œil sur le
   carnet, illisible en diagonale. Les largeurs sont les MÊMES pour toutes les lignes de
   la liste (fractions fixes), donc les colonnes s'alignent.

   LE PLACEMENT EST EXPLICITE (.nom / .sec / .fin), jamais l'auto-placement, et ce
   détail est tout : `x-show` masque en `display: none`, ce qui RETIRE l'élément du flux
   de grille. Une fiche sans société ferait alors remonter sa date en colonne 2, sous
   les sociétés des autres lignes -- le désalignement qu'on vient de corriger,
   reconstruit par la première fiche incomplète. Une ligne à un seul enfant (volet
   clients) reste correcte : l'auto-placement la met en colonne 1. */
.client-row {
  position: relative; display: grid; align-items: center;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto; column-gap: 10px;
  width: 100%; min-height: 44px; padding: 0 12px; box-sizing: border-box;
  border-radius: 10px; border: 1px solid transparent; background: transparent;
  box-shadow: none; font-size: 13px; text-align: left; color: var(--text);
}
.client-row > .nom, .client-row > .sec {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.client-row > .nom { grid-column: 1; }
.client-row > .sec { grid-column: 2; color: var(--text-2); }
.client-row > .fin { grid-column: 3; justify-self: end; white-space: nowrap; color: var(--text-3); }

/* LIGNE D'ENTREPRISE (volet prospects) : la maison, et ses contacts dépliés dessous.
   Elle ne porte PAS .client-row, et c'est délibéré : les bancs comptent les
   `.client-row` d'une liste pour vérifier qu'aucune fiche ne disparaît. Si l'en-tête de
   groupe portait la même classe, ce compte mélangerait des maisons et des contacts, et
   « le compte est bon » cesserait de vouloir dire quoi que ce soit. */
/* En-tête de colonnes d'une liste : MÊME grille que .client-row (mêmes fractions, même
   gouttière, même padding), sinon l'en-tête et les lignes ne tomberaient pas d'accord --
   ce qui serait pire que pas d'en-tête du tout. Il vit HORS de la liste défilante, pour
   rester visible quand on fait défiler. */
.liste-entete {
  display: grid; align-items: center;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto; column-gap: 10px;
  padding: 0 12px 6px; box-sizing: border-box;
  font-size: 11px; letter-spacing: 0.02em; text-transform: uppercase; color: var(--text-3);
}
.liste-entete > .fin { justify-self: end; }

.groupe-societe { display: flex; flex-direction: column; gap: 2px; }
.societe-row {
  position: relative; display: grid; align-items: center;
  grid-template-columns: 14px minmax(0, 1fr) auto; column-gap: 8px;
  width: 100%; min-height: 40px; padding: 0 12px; box-sizing: border-box;
  border-radius: 10px; border: 1px solid transparent; background: transparent;
  box-shadow: none; font-size: 13px; font-weight: 600; text-align: left; color: var(--text);
}
.societe-row:hover {
  border-color: color-mix(in srgb, var(--pr-ink) 8%, transparent);
  background: color-mix(in srgb, var(--pr-white) 65%, transparent);
}
.societe-row.actif { background: var(--surface); box-shadow: var(--shadow-sm); }
.societe-row .chevron { color: var(--text-3); font-size: 10px; }
.societe-row .nom { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Les contacts d'une maison : décalés sous elle, et c'est le seul indice de hiérarchie
   dont la liste a besoin (pas de trait, pas de fond : la liste reste calme). */
.sous-contacts { list-style: none; margin: 0; padding: 0 0 4px 14px; display: flex; flex-direction: column; gap: 2px; }
.client-row:hover {
  border-color: color-mix(in srgb, var(--pr-ink) 8%, transparent);
  background: color-mix(in srgb, var(--pr-white) 65%, transparent);
}
.client-row.actif {
  background: var(--surface); box-shadow: var(--shadow-sm);
  border-color: color-mix(in srgb, var(--pr-ink) 7%, transparent);
}
.client-row.actif::before {
  content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 19px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.liste-rangs { display: flex; flex-direction: column; gap: 6px; }
.read-row, .doc-row {
  display: flex; align-items: center; gap: 10px; justify-content: space-between;
  padding: 10px 12px; border-radius: var(--r-md);
  background: var(--pr-mist-soft); /* posées DANS une carte blanche */
  border: 1px solid var(--border-card);
  font-size: 13px;
}
/* rangée multi-lignes (briefs, messages de fil) : même peau, contenu empilé */
.read-row.bloc { flex-direction: column; align-items: stretch; gap: 6px; }
.titre-rang { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; flex: 1 1 auto; }
/* LES ACTIONS D'UNE RANGEE, TOUTES A LA MEME ABSCISSE. La classe existait dans quatre
   volets et n'avait AUCUNE regle : les boutons se rangeaient donc a la suite du titre,
   donc a une abscisse differente a chaque ligne selon la longueur du nom de societe --
   « Voir le dernier mail » dessinait un escalier dans la vue Suivi. `margin-left: auto`
   les colle a droite ; comme toutes les lignes d'une meme liste portent les memes
   boutons, elles s'alignent. `flex: 0 0 auto` : le bloc d'actions ne se comprime jamais,
   c'est le titre qui cede (min-width: 0 + ellipsis). */
.actions-rang {
  display: flex; align-items: center; justify-content: flex-end; gap: 8px;
  margin-left: auto; flex: 0 0 auto;
}
.linkedin-invitation-row { align-items: flex-start; }
.linkedin-invitation-row .titre-rang small {
  flex-basis: 100%; color: var(--text-2); line-height: 1.45; overflow-wrap: anywhere;
}
/* Pagination d'une liste : dix lignes par page par defaut. Une liste de plusieurs
   centaines d'envois ne se lit pas, et surtout elle rend le contenu qu'on cherche
   inatteignable sans defiler un ecran entier. */
.pagination {
  display: flex; align-items: center; gap: 10px; justify-content: flex-end;
  padding-top: 10px; font-size: 12px; color: var(--text-2);
}
.pagination .compte { margin-right: auto; }
.read-row p { margin: 0; font-size: 13px; color: var(--text-2); }

/* ---- Chips et badges ----------------------------------------------------------------- */
.status-chip {
  display: inline-block; padding: 5px 9px; border-radius: var(--r-pill);
  background: var(--accent-wash); color: var(--accent-text);
  font-size: 11px; font-weight: 700;
}
.cstatut {
  display: inline-block; padding: 3px 7px; border-radius: var(--r-pill);
  background: var(--pr-mist-soft); color: var(--text-2);
  font-size: 9.5px; font-weight: 650;
}
/* Variantes sémantiques : le fond reste mist-soft, PLUS CLAIR que le papier chaud des
   ratios mesurés (--X-text y tient 4.5:1) : assombrir le fond invaliderait la mesure,
   l'éclaircir ne fait que monter le contraste (règle n°4 de la charte : un ratio
   appartient au couple teinte+fond, ici on reste du côté sûr du couple). */
.cstatut.ok { color: var(--ok-text); }
.cstatut.warn { color: var(--warn-text); }
.cstatut.err { color: var(--err-text); }
.doc-badge {
  display: inline-block; padding: 3px 8px; border-radius: var(--r-pill);
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  background: var(--accent-wash); color: var(--accent-text);
}
.doc-badge.neutre { background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border); }

/* ---- Messages et états ----------------------------------------------------------------
   .msg est le canal de feedback inline (.msg.err / .msg.ok). L'alias .erreur de la
   migration T4 a été retiré en T4b : les 13 volets sont tous passés à .msg.err
   (tests/design-panels.test.mjs le garantit pour tout volet futur). */
.msg { font-size: 12px; min-height: 15px; margin: 0; }
.msg.err { color: var(--err-text); }
.msg.ok { color: var(--ok-text); }
.guide-note {
  padding: 12px 14px; border-radius: var(--r-slab);
  background: var(--pr-mist-soft); border: 1px solid var(--pr-mist);
  font-size: 13px; color: var(--text-2);
}
.guide-note .label { color: var(--accent-text); margin-bottom: 4px; }
.empty {
  display: grid; place-content: center; gap: 8px; text-align: center;
  min-height: 380px; border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--border-card);
  color: var(--text-3); font-size: 12.5px;
}
.empty .glyphe { font-size: 26px; opacity: 0.5; }
/* Les puces d'un état vide (exemples de questions, volet assistant) : .empty centre
   son texte mais laissait ses puces collées à gauche du bloc (flex-start par défaut).
   Le groupe se centre lui aussi, sur la même ligne médiane que le texte au-dessus. */
.empty .toolbar { justify-content: center; }
.empty-compact { color: var(--text-3); font-size: 12.5px; margin: 0; }
li.empty-compact { list-style: none; }
/* Diagnostic lego de l'accueil : utile quand on cherche pourquoi une fonction manque,
   mais secondaire dans l'usage quotidien. Le detail natif reste clavier/lecteur d'ecran
   et evite qu'une longue formule de modules ressemble a une panne au premier regard. */
.modules-inactifs { color: var(--text-2); font-size: 12px; }
.modules-inactifs summary { width: fit-content; cursor: pointer; }
.modules-inactifs .hint { margin: 8px 0 0; line-height: 1.5; }
/* Sur bureau, la creation reste directement visible. Le bouton ne prend le relais
   qu'en vue etroite, ou le formulaire repousse sinon la liste utile sous la ligne de
   flottaison. L'etat ouvert reste une classe Alpine : le media query continue donc a
   reagir correctement si la fenetre change de largeur. */
.creation-client-bascule { display: none; }
/* aide discrète sous un titre ou un contrôle */
.hint { font-size: 12px; color: var(--text-2); margin: 0; }
/* tâche faite, texte barré (remplace le :style inline du volet todos) */
.raye { text-decoration: line-through; color: var(--text-3); }

/* ---- Table de données (réglages) -------------------------------------------------------
   Tête en étiquette 10px uppercase, rangées sur mist-soft à coins arrondis : la table vit
   DANS la carte blanche du workspace, des rangées blanches ne se verraient pas (règle n°6). */
table.donnees { width: 100%; border-collapse: separate; border-spacing: 0 6px; }
table.donnees th {
  font-size: 10px; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--text-3); text-align: left; padding: 0 12px;
}
table.donnees td {
  background: var(--pr-mist-soft); font-size: 13px; padding: 10px 12px;
  border-top: 1px solid var(--border-card); border-bottom: 1px solid var(--border-card);
}
table.donnees td:first-child { border-left: 1px solid var(--border-card); border-radius: var(--r-md) 0 0 var(--r-md); }
table.donnees td:last-child { border-right: 1px solid var(--border-card); border-radius: 0 var(--r-md) var(--r-md) 0; }

/* lecteur audio du volet dictée : jamais plus large que sa rangée */
audio { display: block; width: 100%; max-width: 420px; }

/* ---- Rangée de saisie du gabarit (formulaire inline champ + bouton) ------------------- */
.barre-saisie { display: flex; gap: 8px; align-items: stretch; }
.barre-saisie input { flex: 1; min-width: 0; }
/* une question tient sur deux lignes : meme rangee, champ multiligne (volet assistant) */
.barre-saisie textarea { flex: 1; min-width: 0; resize: vertical; }

/* ---- Tuiles KPI (finances) : un chiffre, son étiquette, son aide --------------------------
   Recette GÉNÉRIQUE de la feuille globale (aucun CSS de module dans le shell, décision
   lego n°15) : tout panel qui veut une rangée de chiffres la réutilise telle quelle.
   .ok / .danger colorent le CHIFFRE seulement : deux tuiles voisines peuvent porter des
   verdicts opposés sans que la rangée crie. */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; }
.kpi {
  padding: 12px 14px; border-radius: var(--r-md);
  background: var(--pr-mist-soft); border: 1px solid var(--border-card);
}
/* Les cartes qui changent de sous-vue sont de vrais boutons. Cette remise à zéro
   conserve exactement la métrique des KPI statiques ; l'interactivité vient de la
   sémantique clavier et de la bague focus-visible globale, pas d'un second style. */
button.kpi.cliquable {
  width: 100%; text-align: left; appearance: none;
  font: inherit; line-height: inherit; color: inherit; box-shadow: none;
}
button.kpi.cliquable:hover {
  background: var(--pr-mist-soft); border-color: var(--border-card); transform: none;
}
.kpi strong { display: block; font-size: 20px; font-variant-numeric: tabular-nums; }
.kpi.ok strong { color: var(--ok-text); }
.kpi.danger strong { color: var(--err-text); }

/* ---- Mini-historique en barres (volet campagnes) --------------------------------------
   La hauteur d'une barre est posee par CLASSE (:class cote volet), jamais par style
   inline : les volets n'ont pas le droit au style, tout le CSS vit ici. Cinq niveaux,
   le jour le plus charge faisant h4 ; h0 garde un liseret visible : un jour creux est
   une information, pas une case vide. */
.barres { display: flex; align-items: flex-end; gap: 2px; height: 48px; margin: 8px 0; }
.barres .bar { flex: 1 1 0; min-width: 0; border-radius: 2px 2px 0 0; background: var(--accent); }
.barres .h0 { height: 6%; opacity: 0.35; }
.barres .h1 { height: 30%; }
.barres .h2 { height: 55%; }
.barres .h3 { height: 80%; }
.barres .h4 { height: 100%; }

/* Corps d'un mail relu ou archive : les retours a la ligne FONT PARTIE de la donnee. */
.pre-line { white-space: pre-line; }
/* Rangee qui s'ouvre au clic (table des envoyes du volet campagnes). */
.cliquable { cursor: pointer; }

/* ---- Kanban : colonnes, cartes, glisser-deposer ------------------------------------------
   Recette de la feuille GLOBALE, comme tout le reste : les volets sont injectés par
   innerHTML, une balise style de volet ferait FOUC et doublons. Zéro couleur en dur, tout
   par tokens (règle n°1 de la charte).

   La cible de dépôt est la COLONNE, pas une zone fantôme entre les cartes : .kan-col.cible
   est le seul retour visuel du survol, et .kan-carte.envol grise la carte prise. Les deux
   états sont posés par des classes Alpine, jamais par un :style dynamique.

   LA SURFACE DE DÉPÔT EST LE VRAI SUJET, et elle se voit à l'oeil avant de se mesurer.
   Deux règles la tiennent : `align-items: stretch` sur .kan-board (toutes les colonnes
   prennent la hauteur de la plus haute, sinon une colonne presque vide devient une cible
   minuscule, et c'est justement celle vers laquelle on déplace) et `flex: 1` sur .kan-pile
   (la zone qui reçoit le drop remplit la colonne au lieu de s'arrêter sous la dernière
   carte). Le min-height reste pour le cas limite : une colonne VIDE dans un tableau où
   toutes les colonnes le sont. Défaut classique du glisser-déposer, invisible tant qu'on
   ne regarde pas un tableau déséquilibré. */
.kan-board {
  display: flex; align-items: stretch; gap: 12px;
  overflow-x: auto; padding-bottom: 6px;
  overscroll-behavior-inline: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--pr-ink) 22%, transparent) transparent;
}
.kan-col {
  flex: 0 0 262px; box-sizing: border-box;
  scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 9px;
  padding: 12px; border-radius: var(--r-md);
  background: var(--pr-mist-soft); border: 1px solid var(--border-card);
  transition: background var(--pr-dur-fast) var(--pr-ease-glide),
              border-color var(--pr-dur-fast) var(--pr-ease-glide);
}
.mobile-scroll-hint { display: none; }
.kan-col.cible { background: var(--accent-wash); border-color: var(--accent); }
.kan-col.ajout { background: transparent; border-style: dashed; }
.kan-col-tete { display: flex; align-items: baseline; gap: 8px; }
.kan-col-tete h3 { margin: 0; font-size: 13px; font-weight: 600; }
/* Gestes de colonne : ils vivent A DROITE de l'en-tete, et n'apparaissent qu'a qui peut
   structurer. Boutons compacts : quatre gestes ne doivent pas peser plus lourd que le
   titre de la colonne qu'ils servent. */
.kan-col-gestes { display: flex; align-items: center; gap: 2px; margin-left: auto; }

/* ---- Voyants de sante (Reglages > Connexions) -----------------------------------------
   TROIS ETATS, jamais deux : vert (teste, ca repond), rouge (teste, ca refuse), gris
   (jamais teste, ou pas configure). Le gris est le plus important -- « je ne sais pas »
   n'est pas « ca marche », et un voyant a deux etats afficherait vert sur une connexion
   jamais eprouvee. La couleur ne porte JAMAIS l'information seule : chaque voyant dit sa
   phrase en toutes lettres a cote de sa pastille (daltonisme, capture en noir et blanc,
   lecteur d'ecran). */
.voyants { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; margin-bottom: 14px; }
.voyant {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 13px; border-radius: var(--r-md);
  background: var(--pr-mist-soft); border: 1px solid var(--border-card);
}
.voyant .pastille {
  width: 11px; height: 11px; margin-top: 5px; border-radius: 50%; flex: none;
  background: var(--text-3);
}
/* UNE PASTILLE VERTE DOIT SE VOIR DE L'AUTRE BOUT DE LA PIECE (revue 2026-08-25 : « les
   voyants verts sont tres discrets »). Le vert dense (--pr-ok) tenait le contraste mais
   ne se DETACHAIT pas : sur une carte grise, un disque de 10 px de la meme valeur
   tonale que le texte passe inapercu.

   Trois couches, et aucune ne porte l'information seule : le halo (--pr-ok-vivid, le
   token vif prevu pour ca) donne l'effet « LED allumee », la carte prend une teinte et
   une bordure vertes, et la phrase reste ecrite en toutes lettres a cote -- daltonisme,
   capture en noir et blanc, lecteur d'ecran. Le ROUGE recoit le meme traitement : un
   voyant en panne qui se voit moins que celui qui va bien serait un comble.

   Le GRIS, lui, reste volontairement discret : « jamais teste » n'appelle pas l'oeil de
   la meme facon, il appelle un clic sur « Tester ». */
.voyant.ok {
  border-color: color-mix(in srgb, var(--pr-ok) 42%, var(--border-card));
  background: color-mix(in srgb, var(--pr-ok) 9%, var(--pr-mist-soft));
}
.voyant.ok .pastille {
  background: var(--pr-ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pr-ok-vivid) 45%, transparent);
}
.voyant.ok .voyant-corps small { color: var(--ok-text); }
.voyant.err {
  border-color: color-mix(in srgb, var(--pr-err) 38%, var(--border-card));
  background: color-mix(in srgb, var(--pr-err) 7%, var(--pr-mist-soft));
}
.voyant.err .pastille {
  background: var(--pr-err);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pr-err-vivid) 30%, transparent);
}
.voyant.err .voyant-corps small { color: var(--err-text); }
.voyant-corps { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.voyant-corps strong { font-size: 13px; }
.voyant-corps small { font-size: 12px; color: var(--text-2); overflow-wrap: anywhere; }

/* ---- Mode d'emploi (fenetre d'aide, Reglages) ------------------------------------------
   Un texte long se lit a une largeur de LIGNE, pas de fenetre : au-dela de ~72 caracteres
   l'oeil perd le debut de la ligne suivante. La fenetre reste large (.modale.large) pour
   les titres et l'aeration, la colonne de texte, elle, est bornee. */
.modale.aide .aide-bloc { margin-top: 22px; }
.modale.aide h3 {
  margin: 0 0 8px; font-family: var(--serif); font-size: 17px; font-weight: 500;
}
.modale.aide p {
  margin: 0 0 10px; max-width: 68ch;
  font-size: 13.5px; line-height: 1.62; color: var(--text-2);
}
.modale.aide strong { color: var(--text); }
.modale.aide em { font-style: normal; font-weight: 600; color: var(--text); }
.kan-col-gestes .btn-mini { padding: 2px 6px; font-size: 11px; }
.kan-col-gestes .btn-mini[disabled] { opacity: .35; cursor: default; }
.kan-pile { display: flex; flex-direction: column; gap: 8px; flex: 1; min-height: 52px; }
.kan-carte {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--border-card);
  box-shadow: var(--shadow-sm);
}
.kan-carte[draggable="true"] { cursor: grab; }
.kan-carte[draggable="true"]:active { cursor: grabbing; }
.kan-carte.envol { opacity: 0.45; }
.kan-carte.valide { border-left: 3px solid var(--ok); }
/* EN RETARD : même forme que `.valide` (un liseré, pas un fond) -- un fond rouge sur une
   colonne entière rend le tableau illisible dès que trois cartes glissent. La couleur
   n'est pas le SEUL signal : le badge de date passe en `.cstatut.err` et porte le mot
   « en retard », lisible par qui ne distingue pas le rouge. */
.kan-carte.retard { border-left: 3px solid var(--err); }
.kan-carte-tete { display: flex; align-items: center; gap: 8px; }
.kan-carte-tete h4 { margin: 0; font-size: 13.5px; font-weight: 600; }
.kan-poignee { color: var(--text-3); font-size: 12px; line-height: 1; cursor: grab; }
.kan-carte-pied { display: flex; align-items: center; gap: 8px; justify-content: flex-end; }
.kan-notes {
  margin: 0; padding: 6px 9px; border-radius: var(--r-sm);
  background: var(--pr-mist-soft); border-left: 2px solid var(--pr-mist);
  font-size: 12.5px; color: var(--text-2);
}
.kan-fil { display: flex; flex-direction: column; gap: 8px; }
/* commentaire du canal interne : jamais servi au client, mais repérable d'un coup d'oeil
   par l'équipe qui écrit dans les deux canaux depuis le même fil */
.kan-fil .read-row.interne { border-left: 3px solid var(--warn); }

/* ---- Dossier client 360 ---------------------------------------------------------------
   Le rail reste une navigation compacte dans la fiche : aucune tuile grise autour des
   libellés, seulement un filet et l'accent de la marque pour l'onglet courant. */
.fiche-360 { min-width: 0; overflow: hidden; }
.fiche-360-head {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
}
.fiche-360-head .section-kicker { margin: 0 0 4px; }
.fiche-360-head h3 { margin: 0; }
.fiche-tabs {
  display: flex; gap: 4px; max-width: 100%; overflow-x: auto; overscroll-behavior-x: contain;
  padding: 2px 2px 7px; border-bottom: 1px solid var(--border); scrollbar-width: thin;
}
.fiche-tabs::-webkit-scrollbar { height: 6px; }
.fiche-tabs::-webkit-scrollbar-thumb {
  border-radius: var(--r-pill); background: color-mix(in srgb, var(--pr-ink) 14%, transparent);
}
.fiche-tab {
  flex: 0 0 auto; min-height: 40px; padding: 8px 11px; border: 0; border-radius: var(--r-sm);
  background: transparent; box-shadow: none; color: var(--text-2); font-size: 12px;
  font-weight: 650; white-space: nowrap;
}
.fiche-tab:hover { background: var(--accent-wash); color: var(--accent-text); transform: none; }
.fiche-tab.actif {
  background: var(--accent-wash); color: var(--accent-text);
  box-shadow: inset 0 -2px 0 var(--accent);
}
.fiche-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.fiche-tab-panel { display: grid; gap: 16px; padding-top: 4px; min-width: 0; }
.fiche-section { min-width: 0; }
.fiche-section + .fiche-section { padding-top: 14px; border-top: 1px solid var(--border); }
.fiche-section h4, .fiche-acces h4 { margin: 0 0 8px; font-size: 13px; }
.fiche-360-row { align-items: flex-start; }
.fiche-360-row .titre-rang { display: grid; gap: 3px; }
.fiche-360-row .titre-rang strong,
.fiche-360-row .titre-rang small { min-width: 0; overflow-wrap: anywhere; }
.fiche-360-row .titre-rang small { color: var(--text-2); line-height: 1.45; }
.partage-saisie textarea { min-height: 78px; }
.partage-lien {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: end; gap: 8px;
  padding: 12px; border: 1px solid var(--border-card); border-radius: var(--r-md);
  background: var(--surface);
}
.partage-lien .field { margin: 0; min-width: 0; }
.partage-lien input { font-size: 12px; }
.fiche-acces { padding-top: 14px; border-top: 1px solid var(--border); }
.fiche-acces .titre-rang { display: grid; gap: 2px; }
.fiche-acces .titre-rang small { color: var(--text-2); overflow-wrap: anywhere; }
.portail-publication { align-items: stretch; }
.portail-publication .portail-meta {
  color: var(--text-3); font-size: 11px; font-variant-numeric: tabular-nums;
}
.portail-publication .portail-texte {
  color: var(--text); font-size: 14px; line-height: 1.58; white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.portail-liens { display: flex; flex-wrap: wrap; gap: 8px; }
.portail-liens a {
  padding: 7px 10px; border: 1px solid var(--accent); border-radius: var(--r-pill);
  color: var(--accent-text); font-size: 12px; font-weight: 650; text-decoration: none;
}
.portail-liens a:hover { background: var(--accent-wash); }
.portail-liens a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- Responsive ------------------------------------------------------------------------ */
@media (max-width: 920px) {
  .app-shell { display: block; }
  .nav {
    position: sticky; top: 64px; z-index: 15;
    flex-direction: row; align-items: center; gap: 4px;
    height: auto; padding: 8px 12px; overflow-x: auto;
    border-right: none; border-bottom: 1px solid var(--border);
    background: color-mix(in srgb, var(--pr-panel) 92%, transparent);
    backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  }
  .nav-espace, .nav-titre, .nav-groupe { display: none; }
  /* En rangée mobile, les blocs de groupe s'effacent (display: contents) : les
     items défilent à plat, sans en-têtes, dans le même ordre groupé. */
  .nav-bloc { display: contents; }
  .nav-item { width: auto; white-space: nowrap; min-height: 38px; }
  .nav-item.actif::after { display: none; }
  .split, .split-egal { grid-template-columns: 1fr; }
}
@media (max-width: 680px) {
  .btn-mini { min-width: 44px; min-height: 44px; }
  .creation-client > h3 { display: none; }
  .creation-client-bascule {
    display: flex; align-items: center; justify-content: space-between;
    width: 100%; min-height: 44px; padding: 10px 12px;
  }
  .creation-client-signe {
    margin-left: 12px; color: var(--text-2); font-size: 18px;
  }
  .creation-client-form { display: none; }
  .creation-client-form.ouverte-mobile { display: grid; }
  .top {
    position: relative; min-height: auto; padding: 10px 14px;
    flex-wrap: wrap;
  }
  .top .deconnexion {
    width: 100%; margin-left: 0; display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px;
  }
  .top .deconnexion .onboarding-reprendre { grid-column: 1 / -1; }
  .top .deconnexion button { white-space: normal; line-height: 1.2; }
  .nav { top: 0; scroll-snap-type: x proximity; }
  .nav-item { scroll-snap-align: start; }
  main#zone-panel { padding: 18px 14px 40px; }
  .view-hero { padding: 20px 18px; }
  .view-hero::after { display: none; }
  .mobile-scroll-hint {
    display: flex; justify-content: center; margin: 0 0 8px;
    font-size: 11.5px; color: var(--text-2);
  }
  .kan-col { flex-basis: min(82vw, 300px); }
  .fiche-tab { min-height: 44px; }
  .fiche-360-row { align-items: stretch; flex-direction: column; }
  .fiche-360-row .actions-rang { width: 100%; }
  .fiche-360-row .actions-rang .btn-mini { width: 100%; }
  .linkedin-invitation-row { align-items: stretch; flex-direction: column; }
  .linkedin-invitation-row .actions-rang {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%; margin-left: 0;
  }
  .linkedin-invitation-row .actions-rang .btn-mini { width: 100%; }
  .partage-saisie, .fiche-acces .barre-saisie { flex-direction: column; }
  .partage-lien { grid-template-columns: 1fr; }
  .partage-lien .btn-mini { width: 100%; }
}
