:root[data-theme="dark"] {
    --bg: #1b1d22;
    --bg-elevated: #23262d;
    --bg-hover: #2c2f38;
    --border: #33363f;
    --text: #e4e5ea;
    --text-muted: #8b8f9c;
    --accent: #6f8bff;
    --accent-contrast: #10121a;
    --danger: #e5675f;
    /* Éclairci et réchauffé vers le jaune (v5.71.0) — l'orange
       précédent (#e8a33d) se distinguait mal du rouge ci-dessus, trop
       proche en luminosité et en saturation pour un simple badge ou
       point de couleur. Même changement pour le thème "ardoise", qui
       partage ces teintes. */
    --warning: #ffc266;
    --success: #6fcf7a;
    --inherited: #b389f0;
    --code-bg: #14161b;
    --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-head: var(--font-body);
    --shadow: 0 4px 16px rgba(0,0,0,.3);
}

:root[data-theme="light"] {
    --bg: #f7f7f5;
    --bg-elevated: #ffffff;
    --bg-hover: #ececea;
    --border: #dcdcd8;
    --text: #1e1f22;
    --text-muted: #6a6d78;
    --accent: #3955d8;
    --accent-contrast: #ffffff;
    --danger: #c53a32;
    /* Éclairci et réchauffé vers le jaune (v5.71.0) — même raison que
       le thème sombre ci-dessus. Même changement pour "ceruleen" et
       "sauge", qui partagent ces teintes. */
    --warning: #ffaa00;
    --success: #2e7d32;
    --inherited: #7b3fd4;
    --code-bg: #eeeeec;
    --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-head: var(--font-body);
    --shadow: 0 2px 10px rgba(0,0,0,.08);
}

/* Céruléen — inspiré du bleu profond et de la sérif élégante de
   CAP2030. Jamais de police chargée depuis un service externe (aucune
   dépendance hors du serveur lui-même, y compris pour les polices) :
   une pile de sérifs déjà présentes sur la quasi-totalité des systèmes
   suffit à retrouver cette même élégance. */
:root[data-theme="ceruleen"] {
    --bg: #f4f7fc;
    --bg-elevated: #ffffff;
    --bg-hover: #e8eff9;
    --border: #d3def2;
    --text: #14213d;
    --text-muted: #5b6b8c;
    --accent: #2563b8;
    --accent-contrast: #ffffff;
    --danger: #c0392b;
    --warning: #ffaa00;
    --success: #1e7b4d;
    --inherited: #7b3fd4;
    --code-bg: #eaf1fc;
    --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-head: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
    --shadow: 0 8px 30px rgba(20,33,61,.12);
}

/* Ardoise — moderne et très lisible : gris froids neutres, un seul
   accent vif à haut contraste, typographie géométrique système. */
:root[data-theme="ardoise"] {
    --bg: #14161a;
    --bg-elevated: #1c1f24;
    --bg-hover: #262a31;
    --border: #333841;
    --text: #f0f2f5;
    --text-muted: #9aa3b0;
    --accent: #00c2a8;
    --accent-contrast: #002420;
    --danger: #ff6b6b;
    --warning: #ffc266;
    --success: #4ade80;
    --inherited: #a78bfa;
    --code-bg: #0d0f12;
    --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-head: var(--font-body);
    --shadow: 0 4px 20px rgba(0,0,0,.4);
}

/* Sauge — moderne et très lisible : verts neutres chauds, ambiance
   calme, même typographie géométrique que l'Ardoise. */
:root[data-theme="sauge"] {
    --bg: #f6f7f2;
    --bg-elevated: #ffffff;
    --bg-hover: #ebeee3;
    --border: #d7dcc9;
    --text: #2a3328;
    --text-muted: #5e6b58;
    --accent: #4c7a54;
    --accent-contrast: #ffffff;
    --danger: #c0392b;
    --warning: #ffaa00;
    --success: #3a7d44;
    --inherited: #8a5fbf;
    --code-bg: #edefe5;
    --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    --font-head: var(--font-body);
    --shadow: 0 6px 24px rgba(42,51,40,.1);
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: var(--font-body);
    background: var(--bg);
    color: var(--text);
}

/* Masque visuellement un contenu tout en le gardant lisible par les
   technologies d'assistance (v5.26.0) — jamais display:none ni
   visibility:hidden, qui le retireraient aussi de l'arbre
   d'accessibilité. Technique standard, utilisée pour les titres de
   structure (h1/h2) de pages qui n'ont pas besoin de les afficher
   visuellement, l'apparence ayant déjà sa propre hiérarchie visuelle. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

h1, h2, h3 { font-family: var(--font-head); }

/* ---------- Login ---------- */
.login-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
}
.login-card {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 2.5rem;
    width: 100%;
    max-width: 340px;
}
/* Avec un logo personnalisé (v4.96.0) : les deux logos doivent tenir
   côte à côte, jamais l'un sous l'autre — 340px ne suffit pas pour ça,
   d'où cette largeur dédiée. flex-wrap reste un filet de sécurité sur
   les très petits écrans où même cette largeur ne tiendrait pas. */
.login-card.login-card-with-branding { max-width: 480px; }
.login-card h1 { margin: 0 0 0.25rem; font-size: 1.6rem; }
.login-logo-wrap {
    display: flex; justify-content: center; align-items: center; gap: 1rem; margin: 0 0 1.2rem; flex-wrap: wrap;
}
/* Nouveau logo (v4.56.7) : déjà pourvu de son propre fond mauve arrondi,
   contrairement à l'ancien — plus besoin d'une enveloppe blanche autour,
   qui le faisait paraître minuscule et perdu au milieu d'une grande zone
   vide. Affiché directement, à une taille généreuse. */
.login-logo { display: block; height: 128px; width: auto; border-radius: 20px; }
/* Logo personnalisé de l'instance (v4.96.0) : contrairement au logo
   ObsiWeb ci-dessus, jamais garanti avoir un fond déjà travaillé — sa
   propre enveloppe blanche arrondie évite qu'un fond transparent ou
   clair ne se fonde dans la page. Bordure reprenant exactement la
   couleur de fond du logo ObsiWeb (#e0caf1, mesurée dans le fichier),
   pour rester visuellement cohérent avec lui plutôt qu'un simple gris
   neutre. */
.login-custom-logo-frame {
    display: flex; align-items: center; justify-content: center;
    background: #fff; border: 2px solid #e0caf1; border-radius: 20px;
    height: 128px; padding: 0.6rem 1rem; box-sizing: border-box;
}
.login-custom-logo { display: block; height: 100%; width: auto; max-width: 220px; object-fit: contain; }
.login-card .subtitle { margin: 0 0 1.5rem; color: var(--text-muted); font-size: 0.9rem; }
.login-card form { display: flex; flex-direction: column; gap: 0.4rem; }
.login-card label { font-size: 0.85rem; color: var(--text-muted); margin-top: 0.5rem; }
.login-card input {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--ctl-r, 8px);
    color: var(--text);
    box-sizing: border-box;
    min-height: var(--ctl-h, 40px);
    padding: 0 0.75rem;
    font-size: var(--ctl-font, 0.95rem);
}
.login-card input:focus, button:focus-visible, textarea:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}
.login-card button {
    margin-top: 1.2rem;
    background: var(--accent);
    color: var(--accent-contrast);
    border: none;
    border-radius: var(--ctl-r, 8px);
    min-height: var(--ctl-h, 40px);
    padding: 0 0.75rem;
    font-size: var(--ctl-font, 0.95rem);
    cursor: pointer;
}
.login-card .error {
    background: rgba(229, 103, 95, 0.15);
    color: var(--danger);
    padding: 0.5rem 0.7rem;
    border-radius: 6px;
    font-size: 0.85rem;
}

/* Aide "mot de passe perdu" (v5.09.0) : jamais un envoi automatique,
   seulement les coordonnées saisies par un administrateur — voir
   l'onglet Utilisateurs de l'Administration. */
.login-help-link {
    display: block; text-align: center; color: var(--text-muted);
    font-size: 0.82rem; text-decoration: underline; cursor: pointer;
    margin-top: 1rem;
}
.login-help-panel {
    margin-top: 0.8rem; padding: 0.7rem 0.9rem; border-radius: 6px;
    background: var(--bg-subtle, rgba(0,0,0,0.04)); font-size: 0.85rem;
}
.login-help-panel p { margin: 0 0 0.4rem; }
.login-help-contacts { margin: 0; padding-left: 1.1rem; }
.login-help-contacts li { margin-bottom: 0.3rem; }
.login-help-contacts strong { margin-right: 0.4rem; }

/* ---------- App shell ---------- */
.app-shell {
    display: flex;
    height: 100vh;
}

.sidebar {
    background: var(--bg-elevated);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    width: 280px;
    min-width: 180px;
    max-width: 480px;
    flex-shrink: 0;
}
.sidebar-resizer {
    width: 6px;
    flex-shrink: 0;
    cursor: col-resize;
    background: transparent;
    position: relative;
}
.sidebar-resizer:hover, .sidebar-resizer.resizing { background: var(--accent); opacity: 0.4; }
.editor-area { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }
.sidebar-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: wrap;
    row-gap: 0.4rem;
    padding: 0.9rem 1rem;
    border-bottom: 1px solid var(--border);
}
.brand-block { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.sidebar-header-actions { display: flex; align-items: center; flex-wrap: wrap; justify-content: flex-end; gap: 0.4rem; flex-shrink: 0; }
.version { font-weight: 400; font-size: 0.75rem; color: var(--text-muted); }
.sidebar-header .session-info { margin: 0; font-size: 0.75rem; color: var(--text-muted); }
.vault-switcher { display: flex; align-items: center; gap: 0.4rem; padding: 0.6rem 1rem; border-bottom: 1px solid var(--border); }
/* Capture rapide (v4.56.2) : réduite à une icône, positionnée dans la
   rangée +Nouveau/···, jamais reléguée dans un menu qui exigerait un
   second clic — voir .sidebar-actions plus bas. Le raccourci Alt+I
   fonctionne toujours indépendamment de la position visuelle du bouton. */
.quick-capture-wrap { display: flex; flex-direction: column; gap: 0.6rem; }
.quick-capture-textarea {
    width: 100%; padding: 0.6rem; border-radius: 6px; border: 1px solid var(--border);
    background: var(--bg); color: var(--text); font-family: inherit; font-size: 0.95rem;
    resize: vertical;
}
@media (hover: none), (pointer: coarse) {
    /* Même correctif que .filterable-list-input plus bas dans ce fichier
       (v5.53.0) : sous 16px, Safari/iOS zoome automatiquement à la mise
       au point d'un champ de saisie, décalant la modale (position: fixed)
       par rapport à ce que le doigt vient de toucher — jamais un simple
       détail visuel. Placé ICI, juste après la règle de base : la
       cascade CSS tranche par ordre d'apparition à spécificité égale,
       jamais par la seule présence d'une media query (déjà rencontré à
       plusieurs reprises dans ce projet). Capture rapide (v4.55.0),
       modale la plus utilisée au clavier sur mobile. */
    .quick-capture-textarea { font-size: 16px; }
}
.vault-switcher select {
    flex: 1; min-width: 0; background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 6px; padding: 0.35rem 0.5rem; font-size: 0.85rem;
}
.readonly-banner {
    margin: 0; padding: 0.5rem 1rem; background: rgba(229, 103, 95, 0.12);
    color: var(--danger); font-size: 0.82rem; border-bottom: 1px solid var(--border);
}
.brand { font-weight: 600; letter-spacing: 0.02em; }
/* Nom cliquable de l'application, ouvrant la popup d'identification de
   l'instance (v5.76.0) — un vrai <button> pour l'accessibilité, mais
   sans rien de sa mise en forme par défaut, pour rester visuellement
   identique au simple texte qu'il remplace. */
.brand-btn {
    background: none; border: none; padding: 0; margin: 0; cursor: pointer;
    color: inherit; font: inherit;
}
.brand-btn:hover, .brand-btn:focus-visible { text-decoration: underline; }
/* Popup d'identification de l'instance (v5.76.0). */
.instance-info-line { margin: 0.3rem 0; }
.icon-btn {
    background: none; border: none; color: var(--text-muted);
    cursor: pointer; font-size: 1rem; display: inline-flex; align-items: center; justify-content: center;
}
.icon-btn[hidden] { display: none; }
.icon-btn svg { display: block; }
.theme-select {
    background: var(--bg); color: var(--text); border: 1px solid var(--border);
    border-radius: 6px; padding: 0.3rem 0.5rem; font-size: 0.85rem; cursor: pointer;
}
@media (hover: none), (pointer: coarse) {
    /* Même correctif que .filterable-list-input (v5.53.0) — dans "Mon
       compte" (modale). */
    .theme-select { font-size: 16px; }
}
.notif-bell-btn { position: relative; }
.kanban-icon-link { position: relative; }
.notif-bell-badge {
    position: absolute; top: -2px; right: -4px; background: var(--danger); color: #fff;
    font-size: 0.62rem; font-weight: bold; line-height: 1; padding: 0.15rem 0.32rem;
    border-radius: 999px; min-width: 1.1rem; text-align: center;
}
.notif-bell-badge[hidden] { display: none; }

/* ---------------- Messagerie ---------------- */
.conversation-view { display: flex; flex-direction: column; gap: 0.6rem; }
.conversation-thread {
    max-height: 50vh; overflow-y: auto; display: flex; flex-direction: column; gap: 0.5rem;
    padding: 0.4rem; background: var(--bg); border-radius: 6px; border: 1px solid var(--border);
}
.message-bubble {
    align-self: flex-start; max-width: 85%; background: var(--bg-hover); border-radius: 8px;
    padding: 0.5rem 0.7rem; border: 1px solid var(--border);
}
.message-bubble.message-mine { align-self: flex-end; background: var(--accent); color: var(--accent-contrast); }
.message-bubble.message-mine .message-meta { color: var(--accent-contrast); opacity: 0.75; }
.message-text { white-space: pre-wrap; word-break: break-word; font-size: 0.88rem; }
.message-note-ref {
    display: inline-block; margin-top: 0.3rem; font-size: 0.78rem; color: inherit;
    text-decoration: underline; opacity: 0.85;
}
.message-meta { margin-top: 0.25rem; font-size: 0.7rem; color: var(--text-muted); }
.conversation-resolved-row { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; cursor: pointer; }
.conversation-reply-box {
    width: 100%; background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 6px; padding: 0.5rem; font-size: 0.85rem; font-family: inherit; resize: vertical;
}
@media (hover: none), (pointer: coarse) {
    /* Même correctif que .filterable-list-input (v5.53.0) — messagerie
       interne (modale). */
    .conversation-reply-box { font-size: 16px; }
}
.conversation-list-row { display: block; cursor: pointer; }
.announce-picker-box { max-height: 30vh; overflow-y: auto; margin: 0.3rem 0; padding-left: 0.3rem; }
.announcement-item {
    border: 1px solid var(--border); border-radius: 6px; padding: 0.6rem; margin-bottom: 0.5rem; background: var(--bg);
}
.announcement-item.announcement-retracted { opacity: 0.55; }

/* ---------------- Diffusion (broadcast) ---------------- */
.broadcast-modal-content { display: flex; flex-direction: column; gap: 0.6rem; }
.broadcast-body { max-height: 55vh; overflow-y: auto; padding: 0.6rem; background: var(--bg); border-radius: 6px; border: 1px solid var(--border); }
.broadcast-ack-btn { align-self: center; margin-top: 0.4rem; }
.broadcast-user-list { list-style: none; margin: 0 0 0.8rem; padding: 0; font-size: 0.85rem; }
.broadcast-user-list li { padding: 0.15rem 0; }
.search-box { padding: 0.7rem 1rem 0; }
.search-box input {
    width: 100%; background: var(--bg); border: 1px solid var(--border);
    border-radius: 6px; padding: 0.45rem 0.6rem; color: var(--text); font-size: 0.85rem;
}
.sidebar-actions { display: flex; align-items: center; gap: 0.5rem; padding: 0.7rem 1rem; }
/* "+ Nouveau" resserré (v4.56.2) : partage désormais sa rangée avec la
   capture rapide et "···", plus besoin d'occuper toute la largeur
   disponible comme lorsqu'il était seul sur sa ligne. */
.sidebar-actions-main { flex: 1 1 auto; padding-left: 0.5rem; padding-right: 0.5rem; min-width: 0; }
.sidebar-actions .btn-icon-only { flex: 0 0 auto; }
.sidebar-actions #quick-actions-menu-btn { flex: 0 0 auto; }
#create-menu-btn { flex: 1; }
#quick-actions-menu-btn { flex: 0 0 auto; min-width: 2.6rem; }
.display-mode-row { display: flex; gap: 0.4rem; padding: 0 1rem 0.6rem; align-items: center; }
.display-mode-row select {
    flex: 1; min-width: 0; background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 6px; padding: 0.3rem 0.4rem; font-size: 0.78rem;
}
#display-org-select { flex: 1; }
.btn-small {
    background: var(--bg-hover); border: 1px solid var(--border); color: var(--text);
    border-radius: 6px; padding: 0.35rem 0.6rem; font-size: 0.8rem; cursor: pointer;
}
.btn-small:hover { background: var(--border); }
.btn-primary { background: var(--accent); color: var(--accent-contrast); border-color: transparent; }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-danger { background: var(--danger); color: #fff; border-color: transparent; }
.btn-danger:hover { filter: brightness(1.1); }
.btn-icon-danger {
    background: transparent; border: 1px solid var(--danger); color: var(--danger);
    padding: 0.25rem 0.55rem; border-radius: 6px; cursor: pointer; font-size: 0.95rem; line-height: 1.2;
}
.btn-icon-danger:hover { background: var(--danger); color: #fff; }
.btn-small:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-ghost { background: none; }

.file-tree { flex: 1; overflow-y: auto; padding: 0.4rem 0.5rem; font-size: 0.87rem; }

.smart-folders-section { padding: 0.3rem 0.5rem 0; font-size: 0.87rem; flex-shrink: 0; }
.smart-folders-header {
    display: flex; align-items: center; justify-content: space-between;
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em;
    color: var(--text-muted); padding: 0.3rem 0.3rem 0.2rem;
}
.smart-folders-header .icon-btn { width: 1.3rem; height: 1.3rem; font-size: 0.9rem; line-height: 1; }
.smart-folder-item { border-bottom: 1px dashed var(--border); }
.smart-folder-item:last-child { border-bottom: none; margin-bottom: 0.3rem; }
.smart-folder-row { display: flex; align-items: center; }
.smart-folder-label { flex: 1; color: var(--accent); font-style: italic; }
.smart-folder-results { padding: 0.1rem 0 0.3rem 1.1rem; }
.smart-folder-result { font-style: normal; }
.tree-folder > .tree-label { font-weight: 500; }
.tree-row { display: flex; align-items: center; gap: 0.15rem; border-radius: 5px; }
.tree-row:hover { background: var(--bg-hover); }
.tree-label {
    display: flex; align-items: center; gap: 0.35rem; flex: 1; min-width: 0;
    padding: 0.3rem 0.4rem; border-radius: 5px; cursor: pointer;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tree-label.active { background: var(--accent); color: var(--accent-contrast); }
/* Acronymes à documenter (v5.73.0) — un simple repère visuel, jamais
   une couleur alarmante : ce n'est ni une erreur ni un avertissement,
   juste une suggestion. */
.tree-acrodico-badge { flex-shrink: 0; margin-left: 0.15rem; font-size: 0.85rem; }
/* Dossiers fonctionnels (v5.75.0) — ligne bien visible séparant
   "Acrodicos"/"Templates" du reste de l'arborescence, en fin de liste. */
.tree-functional-separator { height: 2px; background: var(--accent); margin: 0.6rem 0.3rem; opacity: 0.5; border-radius: 1px; }
.tree-label.dragging { opacity: 0.4; }
.tree-label.drop-target { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--bg-hover); }
.tree-label.drop-target-before { box-shadow: inset 0 2px 0 0 var(--accent); }
.tree-label.drop-target-after { box-shadow: inset 0 -2px 0 0 var(--accent); }
.tree-label.flash-highlight { animation: tree-flash 1.2s ease-out; }
.tree-label.has-broken-links { text-decoration: underline dotted var(--danger); text-underline-offset: 2px; }
@keyframes tree-flash {
    0% { background: var(--accent); color: var(--accent-contrast); }
    100% { background: transparent; }
}
.tree-item-actions { display: flex; gap: 0.15rem; padding-right: 0.3rem; }
/* Le bouton "⋮" est toujours visible (PC et tactile) : un menu contextuel
   par ligne, plutôt que des icônes dépendant du survol — inatteignables au
   doigt de toute façon, et encombrantes en permanence sur petit écran. */
@media (hover: none), (pointer: coarse) {
    .tree-row { min-height: 44px; }
    .btn-small { min-height: 40px; }
    .icon-btn { min-width: 40px; min-height: 40px; }
    /* L'œil de visibilité du mot de passe (connexion, première
       configuration, "Mon compte"…) ne mesurait que 34×34px — sous le
       minimum de 44×44px recommandé pour une cible tactile, un défaut
       jamais remarqué jusqu'ici car ce bouton n'avait encore jamais
       été vérifié sur l'écran de première configuration. Même
       correctif que .tree-row/.btn-small/.icon-btn juste au-dessus :
       une capacité de l'appareil, jamais une largeur d'écran (voir
       docs/ARCHITECTURE.md, §9) — un agrandissement du bouton
       lui-même, jamais seulement de sa zone cliquable invisible, pour
       ne pas déborder du champ de saisie sur un écran étroit. */
    .password-toggle-btn { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; font-size: 1.15rem; }
}
.tree-menu-btn {
    background: none; border: none; color: var(--text-muted); cursor: pointer;
    font-size: 1.1rem; line-height: 1; padding: 0.35rem 0.55rem; border-radius: 4px;
    min-width: 32px; min-height: 32px;
}
.tree-menu-btn:hover { background: var(--border); color: var(--text); }
.tree-children { margin-left: 0.9rem; border-left: 1px dashed var(--border); padding-left: 0.5rem; }
.tree-empty { color: var(--text-muted); font-size: 0.82rem; padding: 0.4rem; }

.sidebar-footer { padding: 0.7rem 1rem; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 0.5rem; }
.sidebar-footer-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.sidebar-footer-full { display: block; text-align: center; }

/* ---------- Editor ---------- */
.editor-toolbar {
    display: flex; align-items: center; justify-content: space-between;
    padding: 0.6rem 1rem; border-bottom: 1px solid var(--border);
    background: var(--bg-elevated);
}
.current-note-title { font-weight: 600; font-size: 0.95rem; }
.mobile-menu-btn { display: none; }
.mobile-menu-btn[hidden] { display: none; } /* [hidden] seul perdrait face à la règle mobile ci-dessous */
.sidebar-close-btn { display: none; }
.toolbar-actions { display: flex; align-items: center; gap: 0.6rem; }
.mode-switch { display: flex; }
.mode-switch[hidden] { display: none; }
.mode-btn {
    background: none; color: var(--text-muted); border: none;
    padding: 0.15rem; cursor: pointer; display: flex; align-items: center; justify-content: center;
}
.attach-btn { display: inline-flex; align-items: center; cursor: pointer; }
.attach-btn[hidden] { display: none; }

/* Icônes fournies par l'utilisateur (v4.51.0, découpées et harmonisées à
   110x110px en v4.51.1) remplaçant le texte des boutons de la barre
   d'outils de l'éditeur — objectif explicite : gagner la largeur perdue
   sur mobile au détriment de la source/l'aperçu. Chaque image porte déjà
   son propre habillage visuel (carré arrondi, couleur active/inactive) —
   le bouton qui la contient reste donc volontairement sans fond ni
   bordure propres (voir .btn-icon-only et .mode-btn ci-dessus) : un
   double encadrement écraserait la lisibilité au lieu de l'aider. */
.btn-icon-only {
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: none; border-radius: 0;
    padding: 0.15rem; min-width: 2rem;
}

.editor-panes { flex: 1; display: grid; overflow: hidden; min-height: 0; }
.editor-panes[hidden] { display: none; }
.editor-panes.mode-split { grid-template-columns: var(--split-left, 50%) 6px 1fr; grid-template-rows: 1fr; }
.editor-panes.mode-source { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.editor-panes.mode-live { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.editor-panes.mode-source .preview-pane, .editor-panes.mode-source .pane-resize-handle { display: none; }
.editor-panes.mode-live .source-pane, .editor-panes.mode-live .pane-resize-handle { display: none; }

.pane-resize-handle {
    cursor: col-resize; background: var(--border); touch-action: none;
    position: relative;
}
.pane-resize-handle::after {
    content: ''; position: absolute; top: 0; bottom: 0; left: -4px; right: -4px; /* zone de préhension élargie, invisible */
}
.pane-resize-handle:hover, .pane-resize-handle.dragging { background: var(--accent); }

.source-pane {
    display: flex; overflow: hidden; min-height: 0; height: 100%;
    border-right: 1px solid var(--border); background: var(--bg);
}
.source-pane-inner { display: flex; flex-direction: column; flex: 1; min-height: 0; height: 100%; }
.source-pane-body { display: flex; flex: 1; min-height: 0; overflow: hidden; }
.line-numbers {
    flex-shrink: 0; overflow: hidden; user-select: none; text-align: right;
    color: var(--text-muted); background: var(--bg);
    padding: 1.2rem 0.6rem 1.2rem 0.8rem; font-size: 0.95rem; line-height: 1.6;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    border-right: 1px solid var(--border);
}
.line-numbers[hidden] { display: none; }
.line-numbers div {
    white-space: nowrap;
    /* Une div VIDE (ligne sans numéro) n'a aucun contenu pour établir sa
       propre hauteur de ligne : sans cette hauteur minimale explicite,
       elle s'effondre à 0 pixel, décalant vers le haut toutes les divs
       suivantes d'une hauteur de ligne par ligne vide rencontrée — les
       numéros finissent alors en face de la MAUVAISE ligne du texte
       source. Doit correspondre exactement au line-height du texte
       source lui-même (voir .source-editor), jamais une valeur
       approximative. */
    min-height: 1.6em;
}

.source-editor {
    background: transparent; color: var(--text); border: none;
    padding: 1.2rem; font-size: 0.95rem; line-height: 1.6;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    resize: none; height: 100%; width: 100%; min-height: 0;
    overflow-y: auto; position: relative; z-index: 1;
    /* Doit correspondre EXACTEMENT à .source-highlight-layer ci-dessous
       (même règle déjà en place là-bas) : un mot sans espace assez long
       débordait sinon horizontalement dans le textarea (accessible d'un
       glissement latéral, mais sans le moindre indice qu'il fallait le
       faire) tout en étant renvoyé à la ligne dans le calque de
       surlignage superposé — les rectangles <mark> d'un résultat de
       recherche tombaient alors décalés par rapport au texte réellement
       visible dès qu'une correspondance suivait un tel mot. */
    overflow-wrap: break-word;
}
.source-editor-wrap { position: relative; flex: 1; min-height: 0; height: 100%; }

/* Calque de surlignage, superposé pile sous le textarea (devenu
   transparent) : même police, même remplissage au caractère près, pour
   que les rectangles <mark> tombent exactement sous le texte visible du
   textarea. Défile en JS de façon synchronisée avec lui. */
.source-highlight-layer {
    position: absolute; inset: 0; padding: 1.2rem; font-size: 0.95rem; line-height: 1.6;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    white-space: pre-wrap; word-wrap: break-word; overflow: hidden;
    color: transparent; pointer-events: none; margin: 0; z-index: 0;
}
.source-highlight-layer mark.find-match { background: rgba(255, 214, 0, 0.38); border-radius: 2px; }
.source-highlight-layer mark.find-match-current { background: rgba(255, 140, 0, 0.65); }
.source-highlight-layer mark.list-numbering-warning { background: rgba(229, 103, 95, 0.28); border-bottom: 2px wavy var(--danger); border-radius: 2px; }

.find-replace-bar {
    flex-shrink: 0; z-index: 2;
    background: var(--bg-elevated); border-bottom: 1px solid var(--border);
    padding: 0.5rem 0.7rem;
    display: flex; flex-direction: column; gap: 0.4rem;
}
.find-replace-bar[hidden] { display: none; }
.find-replace-row { display: flex; align-items: center; gap: 0.35rem; }
.find-replace-input {
    flex: 1; min-width: 6rem; background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 5px; padding: 0.3rem 0.5rem; font-size: 0.85rem;
}
.find-match-count { font-size: 0.75rem; color: var(--text-muted); white-space: nowrap; flex-shrink: 0; }
.find-option-row {
    display: flex; align-items: center; gap: 0.2rem; font-size: 0.78rem; color: var(--text-muted);
    cursor: pointer; flex-shrink: 0; white-space: nowrap;
}
.preview-pane {
    padding: 1.2rem 1.6rem; overflow-y: auto; line-height: 1.65; min-height: 0;
    /* Un mot ou un jeton sans espace (URL longue, identifiant…) ne doit
       jamais dépasser silencieusement de ce panneau : .editor-panes,
       son parent, masque tout débordement horizontal (overflow: hidden,
       nécessaire pour ne pas casser toute la mise en page) — sans ce
       retour à la ligne forcé, ce texte devient invisible, sans la
       moindre barre de défilement pour s'en rendre compte. Jamais
       appliqué aux blocs de code ci-dessous (voir .preview-pane pre),
       qui doivent au contraire défiler horizontalement. */
    overflow-wrap: anywhere;
}
.preview-pane h1, .preview-pane h2, .preview-pane h3 { line-height: 1.3; }
.preview-pane code { background: var(--code-bg); padding: 0.1rem 0.3rem; border-radius: 4px; }
.preview-pane pre {
    background: var(--code-bg); padding: 0.8rem; border-radius: 6px; overflow-x: auto;
    overflow-wrap: normal; -webkit-overflow-scrolling: touch;
}
.preview-pane pre code { background: none; padding: 0; }
.preview-pane blockquote {
    border-left: 3px solid var(--accent); margin: 0.6rem 0; padding: 0.2rem 0.9rem;
    color: var(--text-muted);
}
.callout {
    border-left: 4px solid var(--accent); background: var(--bg-hover);
    border-radius: 6px; margin: 0.8rem 0; padding: 0.6rem 0.9rem;
}
.callout-suggest {
    position: fixed; z-index: 60; background: var(--bg-elevated); border: 1px solid var(--border);
    border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.35); max-height: 260px; overflow-y: auto;
    min-width: 220px;
}
.callout-suggest-item { padding: 0.4rem 0.7rem; font-size: 0.85rem; cursor: pointer; }
.callout-suggest-item.highlighted, .callout-suggest-item:hover { background: var(--bg-hover); }
.callout-suggest-path { color: var(--text-muted); font-size: 0.78rem; margin-left: 0.3rem; }

.attachment-picker-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 0.6rem;
    max-height: 60vh; overflow-y: auto;
}
.attachment-picker-cell {
    cursor: pointer; border: 1px solid var(--border); border-radius: 6px; overflow: hidden;
    background: var(--bg); display: flex; flex-direction: column;
}
.attachment-picker-cell:hover { border-color: var(--accent); }
.attachment-picker-cell img { width: 100%; height: 70px; object-fit: cover; display: block; }
.attachment-picker-icon { width: 100%; height: 70px; display: flex; align-items: center; justify-content: center; font-size: 1.8rem; position: relative; }
.attachment-picker-icon-pdf { background: #d94b3a1a; color: #d94b3a; }
.attachment-picker-ext-badge {
    position: absolute; bottom: 4px; right: 6px; font-size: 0.62rem; font-weight: 700;
    letter-spacing: 0.02em; color: var(--text-muted); background: var(--bg-elevated);
    border: 1px solid var(--border); border-radius: 3px; padding: 0.05rem 0.3rem;
}
.attachment-picker-icon-pdf .attachment-picker-ext-badge { color: #d94b3a; border-color: #d94b3a55; }
.attachment-picker-open-link {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
    font-size: 0.68rem; color: var(--accent); text-align: center;
    padding: 0.3rem 0.5rem; border-top: 1px solid var(--border); line-height: 1.3;
}
.attachment-picker-open-link:hover { background: var(--bg-hover); text-decoration: underline; }
.attachment-picker-name {
    font-size: 0.78rem; font-weight: 600; padding: 0.3rem 0.4rem 0; text-align: center;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.attachment-picker-caption { font-size: 0.7rem; color: var(--text-muted); text-align: center; padding: 0.15rem 0.4rem; }
.attachment-picker-used-in {
    font-size: 0.68rem; color: var(--text-muted); text-align: center; padding: 0 0.4rem 0.35rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.callout-title { font-weight: 600; margin-bottom: 0.2rem; }
.callout p { margin: 0.2rem 0 0; color: var(--text); }
.callout-note, .callout-example { border-left-color: var(--accent); }
.callout-info, .callout-abstract { border-left-color: #4c9be8; }
.callout-tip, .callout-question { border-left-color: #2fb673; }
.callout-success { border-left-color: #2fb673; }
.callout-warning, .callout-todo { border-left-color: #e0a30d; }
.callout-danger { border-left-color: var(--danger); }
.callout-quote { border-left-color: #9b7fd4; }
.callout-default { border-left-color: var(--text-muted); }
.diff-view {
    max-height: 320px; overflow-y: auto; font-family: ui-monospace, Consolas, monospace;
    font-size: 0.82rem; border: 1px solid var(--border); border-radius: 6px; padding: 0.4rem 0;
    background: var(--bg);
}
.diff-line { padding: 0.05rem 0.7rem; white-space: pre-wrap; word-break: break-word; }
.diff-line.diff-added { background: rgba(47, 182, 115, 0.15); color: #2fb673; }
.diff-line.diff-removed { background: rgba(224, 90, 90, 0.15); color: var(--danger); }
.diff-line.diff-same { color: var(--text-muted); }
.preview-pane .footnotes { margin-top: 1.5rem; font-size: 0.85rem; color: var(--text-muted); }
.preview-pane .footnotes hr { border: none; border-top: 1px solid var(--border); margin-bottom: 0.6rem; }
.preview-pane .footnotes ol { padding-left: 1.2rem; }
.preview-pane .footnote-ref, .preview-pane .footnote-backref { color: var(--accent); text-decoration: none; }
.preview-pane .footnote-ref:hover, .preview-pane .footnote-backref:hover { text-decoration: underline; }
/* Renvoi de note de bas de page dans un titre (v6.32.3) : il garde l'apparence qu'il a dans un paragraphe (taille, graisse,
   police du texte courant) au lieu d'hériter de celle du titre — énorme, en gras et, selon le thème, en empattement.
   1rem / 1,2 = la taille d'un renvoi dans un paragraphe (« smaller » du navigateur, mais calculé sur le texte courant et non sur le titre) ; line-height: 0 : il n'agrandit jamais la ligne
   du titre ; vertical-align: super (inchangé) le place en haut des lettres, proportionnellement au titre. */
.preview-pane :is(h1, h2, h3, h4, h5, h6) sup { font-family: var(--font-body); font-size: calc(1rem / 1.2); font-weight: 400; font-style: normal; letter-spacing: normal; line-height: 0; }
.preview-pane img { max-width: 100%; border-radius: 6px; }
.preview-pane table {
    border-collapse: collapse; width: 100%; margin: 0.8rem 0; font-size: 0.9rem;
    overflow-x: auto; display: block;
}
.preview-pane table thead { background: var(--bg-hover); }
.preview-pane table th, .preview-pane table td {
    border: 1px solid var(--border); padding: 0.45rem 0.7rem; text-align: left;
}
.preview-pane table th { font-weight: 600; }
.preview-pane table tbody tr:nth-child(even) { background: var(--bg-hover); }
.preview-pane a.wikilink { color: var(--accent); text-decoration: none; border-bottom: 1px dotted var(--accent); }
.preview-pane a.tag-link { color: var(--accent); text-decoration: none; font-size: 0.85em; }
.preview-pane .broken-embed,
.preview-pane a.wikilink.broken-link { color: var(--danger); font-style: italic; }
.preview-pane a.wikilink.broken-link { border-bottom-color: var(--danger); }
.preview-pane .attachment-link { color: var(--accent); text-decoration: none; }
.preview-pane .attachment-link:hover { text-decoration: underline; }

/* Liens de mise en évidence d'interface (v4.65.0) — jamais confondus
   visuellement avec un lien vers une note, puisqu'ils ne mènent jamais
   à une autre note mais désignent un élément réel de l'écran. */
.preview-pane a.ui-pointer-link {
    color: #b5540a; text-decoration: none; border-bottom: 1px dashed #b5540a;
}
.preview-pane a.ui-pointer-link .ui-link-icon { width: 1em; height: 1em; margin-right: 0.3em; vertical-align: -0.14em; }

/* Encadré épais et vif, volontairement voyant — le but est d'attirer
   immédiatement l'œil vers l'élément désigné, pas de rester discret.
   outline (pas border) : ne modifie jamais la taille ni la position de
   l'élément encadré, quel qu'il soit (champ, bouton, item de menu). */
@keyframes ui-highlight-pulse {
    0%, 100% { outline-color: #ff0000; }
    50% { outline-color: #ff6666; }
}
.ui-highlight-target {
    outline: 4px solid #ff0000 !important;
    outline-offset: 2px;
    border-radius: 4px;
    animation: ui-highlight-pulse 1.2s ease-in-out infinite;
}
.preview-pane li.task-list-item { list-style: none; margin-left: -1.3em; }
.preview-pane input.task-checkbox { margin-right: 0.4em; cursor: pointer; vertical-align: middle; }

.lightbox-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,0.88); z-index: 90;
    display: flex; align-items: center; justify-content: center; cursor: zoom-out;
}
.lightbox-image { max-width: 92vw; max-height: 92vh; object-fit: contain; box-shadow: 0 8px 40px rgba(0,0,0,0.5); }
.lightbox-counter { position: absolute; bottom: 1.2rem; left: 50%; transform: translateX(-50%); color: #fff; font-size: 0.85rem; opacity: 0.8; }
.lightbox-close { position: absolute; top: 1rem; right: 1.2rem; background: none; border: none; color: #fff; font-size: 1.4rem; cursor: pointer; opacity: 0.8; }
.lightbox-close:hover { opacity: 1; }
.preview-pane mark.search-highlight {
    border-radius: 2px; padding: 0 1px; color: #1e1f22;
}
/* Une couleur distincte par mot recherché (dans l'ordre d'apparition dans
   la requête), lisible dans les deux thèmes grâce à un fond clair et un
   texte sombre fixe — boucle au-delà de 6 mots. */
.preview-pane mark.search-highlight-0 { background: #ffe066; }
.preview-pane mark.search-highlight-1 { background: #8ce99a; }
.preview-pane mark.search-highlight-2 { background: #74c0fc; }
.preview-pane mark.search-highlight-3 { background: #f783ac; }
.preview-pane mark.search-highlight-4 { background: #ffa94d; }
.preview-pane mark.search-highlight-5 { background: #b197fc; }
.preview-pane mark.search-highlight.current {
    /* Un simple contour plutôt qu'un remplissage : reste visible et net
       par-dessus n'importe laquelle des couleurs ci-dessus, sans jamais
       la masquer. */
    outline: 3px solid #1e1f22; outline-offset: 1px;
}

.status-line {
    margin: 0; padding: 0.3rem 1rem; font-size: 0.78rem; color: var(--text-muted);
    min-height: 1.4em;
}
.status-bar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; }

/* Suggestions de liens (v4.56.1) : bannière discrète après
   enregistrement, jamais bloquante — l'utilisateur choisit lui-même de
   les voir ou non. Fond teinté par la couleur d'accent (pas juste une
   bordure) pour vraiment attirer l'œil, un simple texte gris passait
   inaperçu selon le retour de l'utilisateur. */
.link-suggestions-banner {
    display: flex; align-items: center; gap: 0.6rem; padding: 0.6rem 0.8rem;
    background: color-mix(in srgb, var(--accent) 18%, var(--bg-elevated));
    border-bottom: 2px solid var(--accent); font-size: 0.85rem;
}
/* Bug réel corrigé (v4.56.2) : "display: flex" ci-dessus a exactement
   la même spécificité que la règle native du navigateur pour l'attribut
   "hidden" — sans cette redéfinition explicite, la bannière restait
   visible quoi que fasse le JavaScript sur cet attribut, puisque la
   règle de CE fichier CSS (chargé après la feuille de style native du
   navigateur) l'emportait silencieusement. */
.link-suggestions-banner[hidden] { display: none; }
.link-suggestions-banner span { flex: 1; color: var(--text); font-weight: 500; }
.source-highlight-layer mark.link-suggestion {
    background: rgba(120, 170, 255, 0.28); border-radius: 2px;
    /* Seule exception au "pointer-events: none" du calque parent : le clic
       doit atteindre CETTE surbrillance précise pour ouvrir sa popup,
       sans jamais gêner la frappe normale ailleurs dans le texte. */
    pointer-events: auto; cursor: pointer;
}
.source-highlight-layer mark.link-suggestion:hover { background: rgba(120, 170, 255, 0.5); }

/* Popup de suggestion (v4.56.1) : grande, redimensionnable (poignée
   classique en coin, comme un <textarea>), avec ascenseur — remplace la
   petite infobulle automatique au survol et la barre de sélection
   multiple, jugées peu compréhensibles par l'utilisateur. */
.link-suggestion-popup {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    z-index: 20; width: 380px; height: 320px;
    min-width: 260px; min-height: 200px; max-width: 90%; max-height: 80%;
    resize: both; overflow: auto;
    padding: 1rem; border-radius: 8px; border: 1px solid var(--border);
    background: var(--bg-elevated); box-shadow: 0 8px 28px rgba(0,0,0,0.4);
    font-size: 0.9rem; line-height: 1.5;
    display: flex; flex-direction: column; gap: 0.6rem;
}
/* Même correctif que .link-suggestions-banner ci-dessus (v4.56.2) :
   "display: flex" doit être explicitement neutralisé pour l'état caché,
   sinon l'attribut "hidden" natif n'a plus aucun effet sur cet élément. */
.link-suggestion-popup[hidden] { display: none; }
.link-suggestion-popup h3 { margin: 0; font-size: 1rem; }
.link-suggestion-popup-body { flex: 1; overflow-y: auto; white-space: pre-wrap; color: var(--text-muted); }
.link-suggestion-popup-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.status-line { justify-self: start; }
.clock-display { justify-self: center; font-size: 0.78rem; color: var(--text-muted); white-space: nowrap; padding: 0.3rem 1rem; }
.word-count { justify-self: end; }
.word-count { font-size: 0.78rem; color: var(--text-muted); padding: 0.3rem 1rem; white-space: nowrap; }
.word-count[hidden] { display: none; }

/* ---------- Backlinks ---------- */
.backlinks-toggle {
    background: var(--bg-elevated); border: none; border-top: 1px solid var(--border);
    color: var(--text-muted); text-align: left; padding: 0.4rem 1.2rem;
    font-size: 0.8rem; cursor: pointer;
}
.backlinks-toggle:hover { color: var(--text); }
.backlinks-panel {
    border-top: 1px solid var(--border); background: var(--bg-elevated);
    max-height: 160px; overflow-y: auto; padding: 0.5rem 1.2rem;
}
.backlinks-panel a {
    display: block; padding: 0.25rem 0; color: var(--accent); text-decoration: none;
    font-size: 0.85rem; cursor: pointer;
}
.backlinks-panel a:hover { text-decoration: underline; }
.backlinks-panel a.outlink-broken { color: var(--danger); font-style: italic; }

/* ---------- Canvas ---------- */
.canvas-view { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.canvas-view[hidden] { display: none; }
.canvas-toolbar {
    padding: 0.4rem 1rem; border-bottom: 1px solid var(--border);
    display: flex; align-items: center; justify-content: space-between; gap: 0.6rem;
}
.canvas-hint { font-size: 0.78rem; color: var(--text-muted); }
.canvas-surface {
    flex: 1; position: relative; overflow: auto; background: var(--bg);
    background-image: radial-gradient(var(--border) 1px, transparent 1px);
    background-size: 22px 22px;
    cursor: default;
}
.canvas-edges { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 0; }
.canvas-edge-line { stroke: var(--edge-color, var(--accent)); stroke-width: var(--edge-w, 2px); pointer-events: none; }
.canvas-edge-hit { stroke: transparent; stroke-width: 16; pointer-events: stroke; cursor: pointer; }
@media (pointer: coarse) { .canvas-edge-hit { stroke-width: 28; } }
/* Un clic SÉLECTIONNE le lien (il ne le supprime plus) : survol et sélection l'épaississent, sans passer au rouge. */
.canvas-edge-hit:hover + .canvas-edge-line { stroke-width: calc(var(--edge-w, 2px) + 1px); }
.canvas-edge-line.selected { stroke-width: calc(var(--edge-w, 2px) + 1.5px); filter: drop-shadow(0 0 3px var(--edge-color, var(--accent))); }
/* Couche au-dessus des cartes : poignées du lien sélectionné et points d'ancrage (v6.45.0). */
.canvas-edges-top { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 6; }
.canvas-edge-handle-group { pointer-events: auto; cursor: grab; touch-action: none; }
.canvas-edge-handle-hit { fill: transparent; }
.canvas-edge-handle { fill: var(--accent); stroke: #fff; stroke-width: 2; }
.canvas-anchor-dot { fill: var(--accent); opacity: 0.55; pointer-events: none; }
.canvas-anchor-dot.near { opacity: 1; stroke: #fff; stroke-width: 2; }
/* Les commandes des liens sélectionnés forment un bandeau placé SOUS la surface, dans le flux de la vue Canvas. Insérées dans la barre d'outils, elles la faisaient passer sur deux
   lignes et décalaient toute la surface sous le pointeur à chaque sélection ; flottantes par-dessus, elles recouvraient le bas du Canvas — liens compris : au doigt, les appuis tombaient
   sur le bandeau. Ici le HAUT de la surface ne bouge jamais ; elle se raccourcit et reste défilable, donc rien n'est inaccessible. */
.canvas-edge-tools {
    flex: none; display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 0.4rem 0.75rem;
    padding: 0.45rem 0.75rem; background: var(--bg-elevated); border-top: 1px solid var(--border);
}
.canvas-edge-tools[hidden] { display: none; }
/* L'aide « double-cliquez… » décrit des gestes de souris et occupait près de 40 % de l'écran d'un téléphone : masquée au doigt (le bouton d'aide du menu la reprend). */
@media (pointer: coarse) { .canvas-hint { display: none; } .canvas-toolbar { justify-content: flex-end; flex-wrap: wrap; } }
.canvas-edge-count { font-size: 0.8rem; color: var(--text-muted); }
.canvas-edge-arrow { fill: var(--accent); }
.canvas-temp-edge { stroke: var(--accent); stroke-width: 2; stroke-dasharray: 5 4; pointer-events: none; }
.canvas-card {
    position: absolute; min-width: 160px; min-height: 90px;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.15); display: flex; flex-direction: column;
    resize: both; overflow: hidden; z-index: 1;
}
.canvas-card.note-card { border-color: var(--accent); }
.canvas-card.canvas-card-search-match { border-color: #ff9f1c; border-width: 2px; box-shadow: 0 0 0 2px #ff9f1c33, 0 2px 6px rgba(0,0,0,0.15); }
/* --canvas-header-h : distance du HAUT de la carte à la limite BASSE du bandeau (bordure de 1 px + bandeau de 24 px, MESURÉS sur ordinateur et sur téléphone avant de les figer).
   Le tracé des liens s'en sert pour placer les deux ancrages « sous le bandeau » (lus par JavaScript : voir canvasHeaderH dans app.js). */
:root { --canvas-header-h: 25px; }
.canvas-card-header {
    height: calc(var(--canvas-header-h) - 1px); box-sizing: border-box;
    padding: 0.25rem 0.5rem;
    font-size: 0.72rem; display: flex; align-items: center; gap: 0.4rem;
    user-select: none;
}
.canvas-drag-zone {
    cursor: move; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; touch-action: none;
    background: none; border: none; font: inherit; color: inherit; text-align: left; padding: 0.1rem 0.2rem;
    border-radius: 3px;
}
.canvas-drag-zone:focus { outline: 1px solid currentColor; background: rgba(255,255,255,0.15); }
.canvas-connector-handle { cursor: crosshair; padding: 0 0.2rem; touch-action: none; }
.canvas-card-header button { background: none; border: none; color: inherit; cursor: pointer; font-size: 0.8rem; opacity: 0.85; }
.canvas-card-header button:hover { opacity: 1; }
.canvas-color-swatch {
    width: 16px; height: 16px; border-radius: 50%; border: 1px solid rgba(0,0,0,0.25);
    padding: 0; cursor: pointer; flex-shrink: 0; position: relative; overflow: hidden;
}
.canvas-color-swatch input[type="color"] {
    position: absolute; inset: -4px; width: 200%; height: 200%; border: none; padding: 0; cursor: pointer;
    opacity: 0; /* le rond coloré (background inline) sert de rendu visuel ; l'input reste invisible mais cliquable */
}
.canvas-title-edit {
    flex: 1; min-width: 0; background: rgba(255,255,255,0.25); border: 1px solid rgba(0,0,0,0.2);
    border-radius: 3px; font: inherit; color: #1a1a1a; padding: 0.05rem 0.3rem;
}
.canvas-card textarea {
    flex: 1; border: none; background: transparent; color: var(--text); resize: none;
    padding: 0.5rem; font-size: 0.85rem; font-family: inherit;
}
.canvas-note-card-body {
    flex: 1; display: flex; align-items: center; padding: 0.6rem;
    cursor: pointer; color: var(--accent); font-size: 0.88rem;
    overflow: hidden; text-overflow: ellipsis;
}
.canvas-note-card-body:hover { text-decoration: underline; }
.modal-filter-input {
    width: 100%; margin-bottom: 0.6rem; background: var(--bg); border: 1px solid var(--border);
    border-radius: 6px; padding: 0.4rem 0.6rem; color: var(--text); font-size: 0.85rem;
}
@media (hover: none), (pointer: coarse) {
    /* Même correctif que .filterable-list-input (v5.53.0) — sélecteur de
       note existante à lier (modale). */
    .modal-filter-input { font-size: 16px; }
}

/* ---------- Modale générique ---------- */
.modal-overlay {
    position: fixed; inset: 0; background: rgba(0,0,0,0.5);
    display: flex; align-items: center; justify-content: center; z-index: 50;
}
.modal-overlay[hidden] { display: none; }
.modal-box {
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 10px;
    width: 100%; max-width: 480px; max-height: 80vh; display: flex; flex-direction: column;
    min-width: 0;
    /* min-width: 0 (v5.02.3) : sans cette ligne, la modale est un enfant
       flex de .modal-overlay et hérite donc de min-width: auto par
       défaut — une valeur qui l'empêche de jamais rétrécir en dessous
       de la taille intrinsèque de son propre contenu, l'emportant sur
       max-width dans ce contexte précis. Un contenu suffisamment large
       (comme le recadrage d'image, dont l'image affichée peut faire
       plusieurs centaines de pixels de large) forçait alors TOUTE
       modale de ce type à déborder largement d'un petit écran mobile,
       max-width n'ayant plus le moindre effet réel. Bug général de
       toutes les modales de l'application, jamais révélé avant l'ajout
       d'un contenu assez large pour le déclencher. */
}
.modal-box.graph-modal {
    max-width: 94vw; width: 1100px; height: 85vh; max-height: 85vh;
}
.modal-box.graph-modal .modal-body { padding: 0; overflow: hidden; flex: 1; }
/* Contenu riche (listes/tableaux à plusieurs colonnes ou métadonnées) —
   exploite une bien plus grande partie de l'écran disponible plutôt que
   de forcer un défilement horizontal sur des informations qui
   pourraient tenir à l'écran (v4.59.6, suite à une remarque d'ergonomie
   générale). Redimensionnable manuellement (coin bas-droit) pour
   s'adapter davantage encore si besoin. */
.modal-box.wide-modal {
    max-width: 96vw; width: 1400px; max-height: 90vh;
    resize: both; overflow: auto; min-width: 480px; min-height: 300px;
}
@media (hover: none), (pointer: coarse) {
    /* Le redimensionnement manuel par glisser du coin (resize: both,
       v4.59.6) n'a de sens que là où une souris permet ce geste
       précis — jamais une question de largeur d'écran à proprement
       parler (une tablette tactile large a beau avoir de la place,
       elle n'a pas de souris) : exprimé ici par capacité de l'appareil
       plutôt que par un seuil de largeur arbitraire, contrairement à
       l'ancienne version de ce correctif. Sa contrainte min-width:
       480px, nécessaire pour garder cette poignée utilisable ailleurs,
       devenait sinon la vraie cause d'un débordement systématique de
       toute modale large sur un appareil tactile (v5.02.3) : elle
       empêchait purement et simplement max-width de jamais
       s'appliquer, quel que soit le contenu réel de la modale.
       Placé ICI, juste après la règle de base, et non dans le bloc
       hover/pointer partagé plus haut dans ce fichier : la cascade CSS
       tranche par ordre d'apparition à spécificité égale — un bloc
       plus tôt dans le fichier perd toujours face à une règle de même
       spécificité déclarée plus loin, quelle que soit la media query
       qui l'entoure. */
    .modal-box.wide-modal { resize: none; min-width: 0; }
}
.modal-header {
    display: flex; justify-content: space-between; align-items: center;
    padding: 0.8rem 1rem; border-bottom: 1px solid var(--border); font-weight: 600;
}
.modal-body { padding: 1rem; overflow-y: auto; }
.modal-list-item {
    padding: 0.5rem 0.6rem; border-radius: 6px; cursor: pointer; font-size: 0.9rem;
    display: flex; justify-content: space-between; align-items: center;
    touch-action: manipulation; /* évite que le tap soit retardé/absorbé par la détection de double-tap-zoom */
}
.modal-list-item:hover { background: var(--bg-hover); }
.directory-entry { cursor: default; gap: 0.6rem; }
.directory-toolbar-row { display: flex; gap: 0.6rem; align-items: center; margin-bottom: 0.6rem; }
.directory-toolbar-row .modal-filter-input { flex: 1 1 auto; margin-bottom: 0; }
.directory-stats-line { margin-bottom: 0.4rem; font-size: 0.82rem; }
.directory-entry-actions { display: flex; flex-direction: column; gap: 0.3rem; flex-shrink: 0; align-items: flex-end; }
.directory-entry-actions a, .directory-entry-actions button { text-align: center; text-decoration: none; }
.directory-letter-heading {
    margin: 1rem 0 0.3rem; padding-bottom: 0.2rem; border-bottom: 1px solid var(--border);
    font-size: 0.85rem; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.04em;
}
.directory-letter-heading:first-child { margin-top: 0; }
.modal-list-item .count { color: var(--text-muted); font-size: 0.78rem; }
.filterable-list-input {
    width: 100%; box-sizing: border-box; background: var(--bg); border: 1px solid var(--border);
    color: var(--text); border-radius: 6px; padding: 0.5rem 0.6rem; font-size: 0.9rem; margin-bottom: 0.6rem;
}
@media (hover: none), (pointer: coarse) {
    /* Placé ICI, juste après la règle de base, et non dans le bloc
       hover/pointer partagé plus haut dans ce fichier : à spécificité
       égale (une seule classe de chaque côté), la cascade CSS tranche
       par ordre d'apparition — un bloc plus tôt dans le fichier perd
       toujours face à une règle de même spécificité déclarée plus
       loin, quelle que soit la media query qui l'entoure (déjà
       rencontré à plusieurs reprises dans ce projet : .modal-box.wide-modal,
       .cal-year-day.cal-day-school-holiday...). Signalé sur la
       recherche étendue : un champ de saisie à moins de 16px déclenche
       sur Safari/iOS un zoom automatique à la mise au point — jamais
       un simple détail visuel, la modale (position: fixed par rapport
       à la fenêtre) se retrouve alors décalée par rapport à ce que le
       zoom donne réellement à voir, et déborde à droite de l'écran.
       Corrigé à la source (empêcher le zoom), jamais en tentant de
       rattraper la modale après coup. Bénéficie aussi bien au
       sélecteur rapide, qui partage ce même champ, qu'à la recherche
       étendue. */
    .filterable-list-input { font-size: 16px; }
}
.filterable-list-items { max-height: 320px; overflow-y: auto; }
.filterable-list-row.highlighted { background: var(--bg-hover); }
/* Recherche étendue (v5.50.0) — résultats groupés par catégorie,
   chacun avec son origine (vault/tableau/agenda) affichée à droite,
   jamais mélangée au titre lui-même : l'origine est une information
   secondaire de repérage, pas le résultat en tant que tel. */
.global-search-modal-box { max-width: 640px; }
.global-search-results { max-height: 55vh; overflow-y: auto; }
.global-search-category-header {
    font-size: 0.78rem; font-weight: 600; color: var(--text-muted); text-transform: uppercase;
    letter-spacing: 0.03em; padding: 0.7rem 0.2rem 0.3rem;
}
.global-search-category-header:first-child { padding-top: 0.2rem; }
.global-search-result-row { display: flex; align-items: center; justify-content: space-between; gap: 0.4rem 0.8rem; flex-wrap: wrap; }
.global-search-result-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.global-search-result-origin { color: var(--text-muted); font-size: 0.78rem; flex-shrink: 0; }
.special-char-row { display: flex; align-items: center; gap: 0.8rem; }
.special-char-glyph {
    font-size: 1.6rem; min-width: 2.2rem; text-align: center; flex-shrink: 0;
}
.special-char-info { color: var(--text-muted); font-size: 0.85rem; }

/* Mes images (v4.60.0) */
.my-images-toolbar {
    display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center;
    margin-bottom: 1rem; padding-bottom: 0.8rem; border-bottom: 1px solid var(--border);
}
.my-images-search { flex: 1; min-width: 200px; }
.my-images-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 1rem; max-height: 60vh; overflow-y: auto; padding: 0.2rem;
}
.my-images-cell {
    position: relative; border: 1px solid var(--border); border-radius: 8px;
    overflow: hidden; cursor: pointer; background: var(--bg-elevated);
    transition: border-color 0.15s;
}
.my-images-cell:hover { border-color: var(--accent); }
.my-images-checkbox {
    position: absolute; top: 0.4rem; left: 0.4rem; z-index: 2;
    width: 1.2rem; height: 1.2rem; cursor: pointer;
}
.my-images-thumb { width: 100%; height: 120px; object-fit: cover; display: block; background: var(--bg); }
.my-images-badge {
    position: absolute; top: 0.4rem; right: 0.4rem; background: var(--accent);
    color: #fff; font-size: 0.7rem; padding: 0.1rem 0.4rem; border-radius: 4px;
}
.my-images-cell-info { padding: 0.5rem; }
.my-images-cell-name { font-size: 0.85rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.my-images-cell-meta { font-size: 0.75rem; color: var(--text-muted); margin-top: 0.2rem; }
.my-images-cell-tags { font-size: 0.75rem; color: var(--accent); margin-top: 0.2rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.my-images-detail-preview { max-width: 100%; max-height: 40vh; object-fit: contain; display: block; margin: 0 auto 1rem; border-radius: 6px; }

/* Éditeur d'import d'image (v4.60.0) : recadrage, rognage, filigrane —
   un seul aperçu unifié depuis v5.04.0 (voir .img-cropper plus bas),
   jamais plus une image dupliquée séparément pour chacun. */
.image-import-section { margin: 1rem 0; padding-top: 0.8rem; border-top: 1px solid var(--border); }
.image-import-section h4 { margin: 0 0 0.4rem; font-size: 0.9rem; }
.image-import-size-info { font-size: 0.82rem; color: var(--text-muted); margin: 0.3rem 0; }

/* Composant de recadrage réutilisable (v5.02.0) — remplace l'ancien
   recadrage à la souris uniquement, sans poignées. */
.img-cropper { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; min-width: 0; }
.img-cropper-viewport {
    position: relative; max-width: 100%; overflow: hidden; box-sizing: border-box;
    /* Marge égale au rayon d'une poignée (voir .img-cropper-handle,
       22px de diamètre) : sans cet espace, une poignée sur un cadre qui
       touche déjà le bord de l'image serait tronquée par overflow.
       box-sizing: border-box pour que ce padding ne dépasse jamais la
       largeur totale de 100% du parent (autrement 22px de trop).
       Jamais width: 100% ici (v5.02.4, retour en arrière sur un essai
       raté) : avec align-items: center sur .img-cropper, un enfant flex
       sans width explicite prend sa taille de contenu (le stage, lui-
       même dimensionné en JS sur la vraie taille affichée de l'image) —
       lui donner width: 100% le fait au contraire s'étirer sur toute la
       largeur disponible de la modale, bien plus grande que l'image
       elle-même, cassant tout calcul de coordonnées du recadrage. */
    padding: 11px;
}
.img-cropper-stage {
    position: relative;
    /* overflow: hidden vit sur .img-cropper-viewport (ci-dessus), pas
       ici : sans lui quelque part, l'assombrissement du cadre
       (box-shadow géant, voir .img-cropper-rect) déborderait sur toute
       la page visible au lieu de rester contenu à cette zone — sinon le
       résultat masque tout le reste de la modale, y compris le bouton
       de validation situé en dessous.
       AUCUN touch-action ici, volontairement (v5.02.3) : il vit
       uniquement sur .img-cropper-rect et .img-cropper-handle, les
       seuls éléments réellement glissables. Le mettre ici aussi
       bloquait TOUT geste tactile commençant sur l'image, y compris en
       dehors du cadre — sur mobile, où l'image occupe l'essentiel de
       l'écran, cela empêchait purement et simplement de faire défiler
       la modale jusqu'au bouton de validation, plus bas. */
}
.img-cropper-image {
    display: block; max-width: 100%; max-height: 55vh; -webkit-user-drag: none;
    min-width: 0; min-height: 0;
    /* Protection défensive sans effet connu à ce jour dans ce contexte
       précis (align-items: center sur .img-cropper, voir plus haut) —
       la vraie cause d'un débordement de modale sur mobile observée en
       v5.02.3 s'est révélée être ailleurs (min-width: 480px explicite
       sur .modal-box.wide-modal, corrigé séparément par une media
       query). Gardé par prudence : min-width/min-height: auto est la
       valeur par défaut d'un enfant flex et peut, dans d'autres
       contextes d'intégration futurs de ce composant, faire remonter la
       taille intrinsèque de l'image comme minimum le long de la chaîne
       de parents malgré max-width: 100%. */
}
.img-cropper-rect {
    position: absolute; border: 2px solid #fff;
    box-shadow: 0 0 0 2000px rgba(0,0,0,0.55);
    cursor: move; touch-action: none;
}
/* Cadre qui couvre TOUTE l'image (v6.34.9) : aucun recadrage n'est choisi, son corps n'a rien à déplacer. Il laisse passer les gestes : sur mobile l'image
   occupe l'essentiel de l'écran, et un cadre plein y bloquait le défilement tactile de la fenêtre (le défaut que v5.02.3 avait corrigé hors du cadre).
   Les poignées et le marqueur de filigrane restent actifs. */
.img-cropper-rect.img-cropper-rect-full { pointer-events: none; touch-action: auto; }
.img-cropper-rect.img-cropper-rect-full .img-cropper-handle,
.img-cropper-rect.img-cropper-rect-full .img-cropper-watermark-marker { pointer-events: auto; }
.img-cropper-handle {
    position: absolute; width: 22px; height: 22px; margin: -11px;
    background: #fff; border: 2px solid var(--accent); border-radius: 50%;
    touch-action: none;
    /* 22px et non la taille visuelle habituelle d'une poignée desktop :
       une cible tactile confortable au doigt reste le facteur limitant
       ici, jamais l'esthétique seule. */
}
.img-cropper-handle-n  { top: 0; left: 50%; cursor: ns-resize; }
.img-cropper-handle-s  { top: 100%; left: 50%; cursor: ns-resize; }
.img-cropper-handle-e  { top: 50%; left: 100%; cursor: ew-resize; }
.img-cropper-handle-w  { top: 50%; left: 0; cursor: ew-resize; }
.img-cropper-handle-nw { top: 0; left: 0; cursor: nwse-resize; }
.img-cropper-handle-se { top: 100%; left: 100%; cursor: nwse-resize; }
.img-cropper-handle-ne { top: 0; left: 100%; cursor: nesw-resize; }
.img-cropper-handle-sw { top: 100%; left: 0; cursor: nesw-resize; }
.img-cropper-controls { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }


/* Filigrane (v5.04.0) : enfant du cadre de recadrage lui-même (jamais
   du stage), en pourcentage — reste donc toujours correctement
   positionné, même quand le cadre est déplacé ou redimensionné, sans
   le moindre recalcul depuis l'extérieur du composant. */
.img-cropper-watermark-marker {
    position: absolute; transform: translate(-50%, -50%); cursor: move;
    background: rgba(0,0,0,0.6); color: #fff; padding: 0.25rem 0.6rem;
    border-radius: 4px; font-size: 0.85rem; border: 1px dashed #fff;
    white-space: nowrap; touch-action: none; z-index: 3;
}
.image-import-trim-inputs { display: flex; gap: 0.8rem; flex-wrap: wrap; }
.modal-box.markdown-help-modal { max-width: 620px; width: 90vw; }
.about-content p { margin: 0.5rem 0 0.9rem; line-height: 1.65; }
.about-content a { color: var(--accent); }
.about-content .about-title { margin: 0 0 0.2rem; font-size: 1.2rem; line-height: 1.3; }
.about-content hr { border: 0; border-top: 1px solid var(--border); margin: 1rem 0; }
.about-content .about-credit { font-style: italic; }
.modal-box.about-modal-box { max-height: 92vh; }
.audit-log-view {
    background: var(--bg); border: 1px solid var(--border); border-radius: 6px;
    padding: 0.8rem; max-height: 65vh; overflow-y: auto; font-size: 0.8rem;
    font-family: ui-monospace, Consolas, monospace; white-space: pre-wrap; word-break: break-word;
    color: var(--text);
}
.audit-filters { display: flex; gap: 0.5rem; margin: 0.6rem 0 0.3rem; flex-wrap: wrap; }
.audit-filters input { flex: 1; padding: 0.4rem 0.6rem; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text); }
.audit-filters select { padding: 0.4rem 0.6rem; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text); }
.password-field-wrap { position: relative; display: flex; }
.password-field-wrap input { flex: 1; padding-right: 2.2rem; }
.password-toggle-btn {
    position: absolute; right: 0.4rem; top: 50%; transform: translateY(-50%);
    background: none; border: none; cursor: pointer; font-size: 0.95rem; padding: 0.2rem;
    color: var(--text-muted); line-height: 1;
}
.password-toggle-btn:hover { color: var(--text); }
.admin-default-password-row {
    display: flex; align-items: flex-end; gap: 0.6rem; margin: 0.6rem 0 1.2rem;
    padding: 0.8rem; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
}
.admin-default-password-field { flex: 1; margin: 0; }
.admin-password-policy-row {
    display: flex; align-items: flex-end; gap: 0.6rem; margin: 0.6rem 0 1.2rem; flex-wrap: wrap;
    padding: 0.8rem; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
}
.admin-password-policy-row .admin-field { min-width: 140px; }

/* Compteur d'utilisateurs, mis en avant (v5.11.0) — l'essentiel de la
   page reste la liste des comptes, mais ce chiffre doit rester la
   première chose vue en arrivant sur l'onglet. */
.admin-user-count-banner {
    font-size: 1.1rem; font-weight: 600; margin: 0.4rem 0 1rem;
}

/* Sections repliables (v5.11.0) — regroupe les réglages secondaires
   (mot de passe par défaut, politique, contacts) hors du champ de
   vision par défaut, pour que l'essentiel de la page reste la liste
   des utilisateurs. <details>/<summary> natifs : accessibles au
   clavier et au lecteur d'écran sans le moindre JavaScript à écrire
   ni maintenir pour ce seul comportement. */
.admin-collapsible-section {
    margin: 0.6rem 0 1rem; border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg-elevated);
}
.admin-collapsible-section summary {
    padding: 0.7rem 1rem; cursor: pointer; font-weight: 600; font-size: 0.92rem;
    list-style: none; user-select: none;
}
.admin-collapsible-section summary::-webkit-details-marker { display: none; }
.admin-collapsible-section summary .section-chevron { display: inline-flex; vertical-align: -3px; margin-right: 0.5rem; transition: transform 0.15s ease; }
.admin-collapsible-section[open] summary .section-chevron { transform: rotate(90deg); }
.admin-collapsible-section > *:not(summary) { padding: 0 1rem 1rem; }
.admin-collapsible-section .admin-default-password-row,
.admin-collapsible-section .admin-password-policy-row,
.admin-collapsible-section .admin-help-contacts-section {
    margin: 0; border: none; padding: 0 1rem 1rem; background: none;
}
.admin-collapsible-section .admin-help-contacts-section { padding-top: 0.2rem; }

/* Contacts "mot de passe perdu" (v5.09.0) */
.admin-help-contacts-section {
    margin: 0.6rem 0 1.2rem; padding: 0.8rem;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
}
/* Auto-inscription (v5.95.0) — même habillage que la section ci-dessus,
   pour une cohérence visuelle entre les deux blocs de cette même zone
   repliable. */
.admin-collapsible-section .admin-signup-settings-section {
    margin: 0.6rem 0 0; padding: 0.8rem;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
}
.admin-signup-settings-section .admin-checkbox-row { margin: 0.5rem 0; }
.admin-signup-settings-section .admin-field { margin: 0.6rem 0; max-width: 320px; }
.admin-help-contact-row { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.5rem; }
.admin-help-contact-row .admin-help-contact-name { flex: 0 0 220px; }
.admin-help-contact-row .admin-help-contact-info { flex: 1; }
.admin-help-contact-row input {
    padding: 0.4rem 0.6rem; border: 1px solid var(--border); border-radius: 6px;
    background: var(--bg); color: var(--text);
}
.admin-checkbox-field { display: flex; align-items: center; gap: 0.35rem; font-size: 0.85rem; cursor: pointer; margin: 0 0 0.5rem; }
.admin-checkbox-field input { cursor: pointer; }
.admin-groups-checkbox-list { display: flex; flex-direction: column; gap: 0.2rem; max-height: 220px; overflow-y: auto; padding: 0.5rem; border: 1px solid var(--border); border-radius: 6px; }
.admin-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.admin-sortable:hover { color: var(--text); }
.admin-sort-active { color: var(--accent); }
.admin-path-cell { font-family: ui-monospace, Consolas, monospace; font-size: 0.78rem; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attachment-usage-link { display: block; color: var(--accent); text-decoration: none; margin-top: 0.1rem; }
.attachment-usage-link:hover { text-decoration: underline; }

.format-toolbar {
    display: flex; align-items: center; gap: 0.3rem; padding: 0.3rem 0.7rem;
    border-bottom: 1px solid var(--border); background: var(--bg-elevated); flex-wrap: wrap;
}
.format-toolbar[hidden] { display: none; }
.fmt-btn {
    background: none; border: 1px solid transparent; border-radius: 5px; color: var(--text);
    padding: 0.25rem 0.55rem; font-size: 0.82rem; cursor: pointer; line-height: 1.2;
}
.fmt-btn:hover { background: var(--bg-hover); border-color: var(--border); }
.fmt-btn-menu { font-size: 0.78rem; color: var(--text-muted); }
.fmt-btn-active { background: var(--accent); color: var(--accent-contrast); border-color: transparent; }
.fmt-btn-disabled, .fmt-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.fmt-sep { width: 1px; height: 1.2rem; background: var(--border); margin: 0 0.2rem; }
.preview-pane .attachment-link.attachment-highlighted {
    background: rgba(224, 163, 13, 0.25); outline: 2px solid #e0a30d; border-radius: 4px; padding: 0.1rem 0.3rem;
}
.dropdown-menu {
    position: fixed; z-index: 70; background: var(--bg-elevated); border: 1px solid var(--border);
    border-radius: 8px; box-shadow: 0 6px 20px rgba(0,0,0,0.35); min-width: 180px; padding: 0.3rem;
    display: flex; flex-direction: column; gap: 0.1rem;
}
.dropdown-menu-item {
    display: block; width: 100%; box-sizing: border-box; text-align: left; background: none; border: none;
    color: var(--text); font-size: 0.85rem; padding: 0.5rem 0.6rem; border-radius: 5px; cursor: pointer;
    text-decoration: none; font: inherit;
}
.dropdown-menu-item:hover { background: var(--bg-hover); }
.dropdown-menu-separator { height: 1px; background: var(--border); margin: 0.25rem 0.2rem; }
.dropdown-menu-item.popularity-badge { font-size: 0.8rem; color: var(--text-muted); }
.dropdown-menu-item.popularity-badge:hover { color: var(--text); }
.modal-box.account-modal-box { max-width: 560px; width: 90vw; max-height: 85vh; overflow-y: auto; }
.modal-box.inbox-modal-box {
    max-width: 96vw; width: 900px; height: 640px; max-height: 90vh; min-width: 560px; min-height: 380px;
    resize: both; overflow: auto;
}
.modal-box.inbox-modal-box .modal-body { overflow: visible; display: flex; flex-direction: column; height: 100%; }
.inbox-table-scroll { flex: 1; max-height: none; min-height: 120px; }
.account-section-title { margin: 1.1rem 0 0.4rem; font-size: 0.95rem; border-top: 1px solid var(--border); padding-top: 0.9rem; }
.account-section-title:first-child { margin-top: 0; border-top: none; padding-top: 0; }
/* Encart RGPD visuellement distinct (v5.94.0) — signalé par l'analyse
   ergonomique du 26 septembre 2026 : ce texte réglementaire se lit
   désormais comme un aparté encadré plutôt que comme une simple case
   à cocher qui cassait le rythme de saisie entre les champs
   d'identité et les coordonnées. */
.account-consent-box {
    margin: 0.8rem 0; padding: 0.7rem 0.9rem; border: 1px solid var(--border);
    border-radius: 8px; background: var(--bg-hover);
}
.account-consent-box .admin-checkbox-row { margin: 0; }
.trash-item { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.8rem; flex-wrap: wrap; }
.trash-item-info { flex: 1 1 220px; min-width: 0; }
.trash-item-meta { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.15rem; }
.trash-item-meta.trash-item-alert { color: var(--danger); font-weight: 600; }
.trash-item-actions { display: flex; gap: 0.3rem; flex-wrap: wrap; flex-shrink: 0; }
.trash-preview-textarea {
    width: 100%; min-height: 300px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.85rem; padding: 0.6rem; border: 1px solid var(--border); border-radius: 6px;
    background: var(--bg); color: var(--text); resize: vertical;
}
.account-sort-row { display: flex; align-items: center; gap: 0.4rem; margin: 0.3rem 0 0.4rem; font-size: 0.8rem; color: var(--text-muted); }
.markdown-help-category {
    font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted);
    padding: 0.6rem 0.6rem 0.2rem;
}
.markdown-help-row { display: grid; grid-template-columns: 1fr 1fr; gap: 0.6rem; align-items: center; }
.markdown-help-label { font-size: 0.72rem; color: var(--text-muted); margin-bottom: 0.1rem; }
.markdown-help-code {
    font-family: ui-monospace, Consolas, monospace; font-size: 0.8rem; color: var(--text);
    white-space: pre-wrap; word-break: break-word;
}
.markdown-help-preview { font-size: 0.88rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 560px) {
    .markdown-help-row { grid-template-columns: 1fr; gap: 0.15rem; }
}

/* ---------- Vue graphique interactive ---------- */
.local-graph-outer { display: flex; flex-direction: column; height: 100%; }
.graph-breadcrumb {
    flex-shrink: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 0.3rem;
    padding: 0.4rem 0.8rem; border-bottom: 1px solid var(--border); background: var(--bg-elevated);
    font-size: 0.8rem;
}
.graph-breadcrumb-item { background: none; border: none; padding: 0; font: inherit; cursor: pointer; color: var(--accent); text-decoration: underline; }
.graph-breadcrumb-item.graph-breadcrumb-current { color: var(--text); text-decoration: none; cursor: default; font-weight: 600; }
.graph-breadcrumb-sep { color: var(--text-muted); }
.graph-path-tooltip {
    position: absolute; z-index: 5; pointer-events: none; background: var(--bg-elevated);
    border: 1px solid var(--border); border-radius: 5px; padding: 0.2rem 0.5rem; font-size: 0.78rem;
    color: var(--text); white-space: nowrap; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}
.graph-proximity-control {
    flex-shrink: 0; display: flex; align-items: center; gap: 0.6rem;
    padding: 0.5rem 0.8rem; border-bottom: 1px solid var(--border); background: var(--bg-elevated);
}
.graph-proximity-text { font-size: 0.82rem; color: var(--text-muted); white-space: nowrap; min-width: 9rem; }
.graph-proximity-control input[type="range"] { flex: 1; accent-color: var(--accent); }
.local-graph-canvas-holder { flex: 1; min-height: 0; position: relative; }
.graph-canvas-wrap {
    position: relative; width: 100%; height: 100%; overflow: hidden;
    background: var(--bg); cursor: grab; touch-action: none;
}
.graph-canvas-wrap.panning { cursor: grabbing; }
.graph-svg-full { width: 100%; height: 100%; display: block; }
.graph-node-circle { fill: var(--accent); cursor: pointer; stroke: var(--bg-elevated); stroke-width: 2px; touch-action: none; }
.graph-node:hover .graph-node-circle { fill: #ff9f1c; }
.graph-node-circle-kanban { fill: #5b4bc4; }
.graph-node:hover .graph-node-circle-kanban { fill: #6c5ce7; }
.graph-node-kanban-mark { fill: #fff; font-size: 11px; font-weight: 700; pointer-events: none; user-select: none; }
.graph-node-task-mark { fill: #fff; font-size: 11px; font-weight: 700; pointer-events: none; user-select: none; }
.graph-node-label { fill: var(--text); font-size: 12px; pointer-events: none; user-select: none; }
/* Nœud sur lequel le graphe local est actuellement centré : un anneau
   distinctif permanent (pas la même couleur que le survol, pour ne
   jamais confondre « c'est le centre » et « je le survole en ce
   moment ») ; le survol du centre lui-même se comporte normalement. */
.graph-node-circle-center { stroke: #ff9f1c; stroke-width: 3px; }
.graph-node-center:hover .graph-node-circle-center { fill: #ff9f1c; }
.graph-node-label-center { font-weight: 700; }
.graph-edge { stroke: var(--border); stroke-width: 1.2; }
.graph-hint {
    position: absolute; left: 12px; right: 12px; bottom: 10px; font-size: 11px;
    /* Texte et fond fixes, jamais liés aux couleurs du thème actif :
       calculé et vérifié pour rester lisible quel que soit le thème
       (RGAA/WCAG AA, contraste ≥ 4,5:1 — mesuré ≥ 8,8:1 dans les 5
       thèmes). Avec l'ancien fond à 35% d'opacité, un texte de couleur
       variable (var(--text-muted)) tombait à un contraste réel d'à
       peine 2:1 sur les trois thèmes clairs — gris sur gris,
       proprement illisible, quel que soit le thème actif au moment de
       la mesure. */
    color: #ffffff; background: rgba(0,0,0,0.75);
    pointer-events: none;
    padding: 0.2rem 0.5rem; border-radius: 4px;
}
.graph-zoom-controls {
    position: absolute; right: 12px; bottom: 10px; display: flex; flex-direction: column; gap: 0.3rem;
}
.graph-zoom-controls button {
    width: 30px; height: 30px; border-radius: 6px; border: 1px solid var(--border);
    background: var(--bg-elevated); color: var(--text); cursor: pointer; font-size: 1rem;
    display: flex; align-items: center; justify-content: center;
}
.graph-zoom-controls button:hover { background: var(--bg-hover); }
.graph-size-mode-controls {
    position: absolute; right: 12px; top: 10px; display: flex; gap: 0.3rem;
}
.graph-size-mode-controls button {
    padding: 0.25rem 0.5rem; border-radius: 6px; border: 1px solid var(--border);
    background: var(--bg-elevated); color: var(--text); cursor: pointer; font-size: 0.8rem;
}
.graph-size-mode-controls button:hover { background: var(--bg-hover); }
.graph-size-mode-controls button.active { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }
.graph-kanban-filter-control {
    position: absolute; right: 12px; top: 46px; display: flex; align-items: center; gap: 0.35rem;
    font-size: 0.8rem; color: var(--text); background: var(--bg-elevated); border: 1px solid var(--border);
    border-radius: 6px; padding: 0.25rem 0.5rem; cursor: pointer; user-select: none;
}
.graph-kanban-filter-control input { cursor: pointer; }

/* ---------- Administration ---------- */
.admin-shell { max-width: 1000px; margin: 0 auto; padding: 1.5rem; }
/* Élargie uniquement pour la page Administration (v5.30.0), qui seule
   porte la barre latérale ci-dessous — jamais .admin-shell elle-même,
   partagée avec Kanban : l'élargir directement y avait laissé un vide
   disgracieux entre le titre et les actions, cette page n'ayant pas de
   sidebar pour occuper l'espace gagné. */
.admin-shell-with-sidebar { max-width: 1300px; }
.admin-header {
    display: flex; align-items: flex-start; justify-content: space-between;
    margin-bottom: 1.2rem;
}
.admin-back { color: var(--text-muted); text-decoration: none; font-size: 0.85rem; }
.admin-back:hover { color: var(--accent); }
.admin-header h1 { margin: 0.3rem 0 0; font-size: 1.4rem; }
.admin-header .session-info { display: flex; align-items: center; gap: 0.7rem; font-size: 0.85rem; color: var(--text-muted); }

/* Barre latérale groupée par thème (v5.30.0) — remplace l'ancienne
   barre horizontale de 13 onglets, qui passait déjà sur plusieurs
   lignes avant même d'atteindre le contenu. sticky : reste visible
   même en faisant défiler un long panneau (ex. une longue liste
   d'utilisateurs), jamais perdue de vue. */
.admin-body { display: flex; gap: 2rem; align-items: flex-start; }
/* Enveloppe le bouton de bascule mobile et la vraie barre latérale
   (v5.31.0) — jamais .admin-body elle-même comme parent positionné du
   menu déroulant mobile : elle contient aussi tout le contenu de la
   page, ce qui aurait fait apparaître ce menu tout en bas de la page
   plutôt que juste sous le bouton qui l'ouvre. */
.admin-sidebar-wrap { flex-shrink: 0; }
.admin-sidebar {
    width: 210px; flex-shrink: 0; position: sticky; top: 1.5rem;
    display: flex; flex-direction: column; gap: 1.1rem;
}
.admin-nav-group-title {
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
    color: var(--text-muted); font-weight: 600; margin: 0 0 0.35rem; padding: 0 0.6rem;
}
.admin-tab {
    display: block; width: 100%; text-align: left; background: none; border: none;
    border-left: 2px solid transparent; padding: 0.45rem 0.6rem; color: var(--text-muted);
    cursor: pointer; font-size: 0.9rem; border-radius: 0 6px 6px 0;
}
.admin-tab:hover { background: var(--bg-elevated); color: var(--text); }
.admin-tab.active { color: var(--accent); border-left-color: var(--accent); background: var(--bg-elevated); font-weight: 600; }
.admin-content { flex: 1; min-width: 0; }
/* Bouton de bascule mobile (v5.31.0) — jamais affiché sur bureau, la
   vraie barre latérale y est déjà visible en permanence. */
.admin-sidebar-toggle-btn { display: none; }
.admin-panel-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }

/* Illustrations partagées du vault-modèle (v4.64.0) */
.admin-subsection-title { margin: 1.5rem 0 0.4rem; font-size: 1rem; }
.onboarding-assets-list { display: flex; flex-direction: column; gap: 0.6rem; margin-top: 1rem; }
.branding-logo-preview-wrap { display: flex; flex-direction: column; gap: 0.4rem; margin: 0.8rem 0; }
.branding-logo-preview-frame {
    display: inline-flex; align-items: center; justify-content: center;
    background: #fff; border: 2px solid #e0caf1; border-radius: 16px;
    height: 100px; padding: 0.5rem 0.8rem; width: fit-content;
}
.branding-logo-preview-frame img { display: block; height: 100%; width: auto; max-width: 220px; object-fit: contain; }
.onboarding-asset-card {
    display: flex; align-items: center; gap: 0.8rem; padding: 0.6rem;
    border: 1px solid var(--border); border-radius: 8px; background: var(--bg-elevated);
}
.onboarding-asset-thumb { width: 64px; height: 64px; object-fit: cover; border-radius: 4px; background: var(--bg); flex-shrink: 0; }
.onboarding-asset-info { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; flex: 1; min-width: 0; }
.onboarding-asset-name { font-weight: 600; font-size: 0.9rem; }
.onboarding-asset-meta { font-size: 0.8rem; color: var(--text-muted); }
.onboarding-asset-snippet { flex: 1; min-width: 200px; font-family: monospace; font-size: 0.8rem; }

/* Liste des liens de mise en évidence d'interface (v4.66.0) */
.ui-highlight-registry-list { display: flex; flex-direction: column; gap: 0.5rem; }
.ui-highlight-registry-row { display: flex; align-items: center; gap: 0.6rem; padding: 0.4rem 0; border-bottom: 1px solid var(--border); }
.ui-highlight-registry-label { flex: 1; font-size: 0.9rem; }
.ui-highlight-registry-snippet { font-family: monospace; font-size: 0.8rem; width: 220px; }

/* Sélecteur de note d'ouverture automatique (v4.68.0) */
.opening-note-picker { display: flex; align-items: center; gap: 0.6rem; }
.opening-note-picker select { flex: 1; min-width: 200px; }

/* Export/import utilisateurs et groupes (v4.72.0) */
.ugt-selection-bar {
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 15;
    display: flex; align-items: center; gap: 0.8rem; padding: 0.7rem 1.2rem;
    background: var(--bg-elevated); border-top: 1px solid var(--border);
    box-shadow: 0 -4px 16px rgba(0,0,0,0.25);
}
.ugt-selection-bar[hidden] { display: none; }
.ugt-selection-bar span { flex: 1; font-weight: 500; }
.ugt-template-links { display: flex; gap: 1rem; margin: 0.6rem 0; }
.ugt-upload-fields { display: flex; flex-direction: column; gap: 0.8rem; margin: 0.8rem 0; }
.ugt-sync-checkbox { display: flex; flex-direction: row; align-items: center; gap: 0.5rem; margin-bottom: 1rem; }
.ugt-sync-checkbox input { width: auto; }
.ugt-preview-error-row { background: color-mix(in srgb, #c0392b 12%, transparent); }
#ugt-result-passwords-body code { font-size: 0.9rem; }


/* Sélecteur de lien de mise en évidence, dans le menu Insérer du vault-modèle (v4.69.0) */
.ui-link-picker { display: flex; flex-direction: column; gap: 0.6rem; }
.ui-link-picker-filter { width: 100%; }
.ui-link-picker-list { display: flex; flex-direction: column; max-height: 50vh; overflow-y: auto; }
.ui-link-picker-list .modal-list-item { display: flex; justify-content: space-between; gap: 0.6rem; cursor: pointer; }
.admin-panel-header h2 { margin: 0; font-size: 1.1rem; }
/* Titre repliable "Mes agendas" (v5.86.0) — un vrai <button>, mais
   visuellement identique au <h2> qu'il remplace ; la flèche pivote
   selon l'état, plutôt que de changer de glyphe, pour une transition
   visuelle plus douce. */
.cal-collapse-toggle {
    background: none; border: none; padding: 0; margin: 0; cursor: pointer;
    color: inherit; font: inherit; font-size: 1.1rem; font-weight: 600;
    display: flex; align-items: center; gap: 0.3rem;
}
.cal-collapse-arrow { display: inline-block; transition: transform 0.15s ease; font-size: 1.3em; font-weight: 700; }
.cal-collapse-toggle[aria-expanded="false"] .cal-collapse-arrow { transform: rotate(-90deg); }
.admin-panel-header .header-actions { display: flex; gap: 0.5rem; align-items: center; }
.backups-summary-detail { font-size: 0.9rem; font-weight: 400; color: var(--text-muted); }
.backups-help-content p { margin: 0 0 0.7rem; line-height: 1.5; }
.backups-help-content ul { margin: 0 0 0.7rem; padding-left: 1.3rem; }
.backups-help-content li { margin-bottom: 0.3rem; line-height: 1.4; }

.inbox-toolbar { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-bottom: 0.7rem; align-items: flex-end; }
/* [hidden] doit systématiquement l'emporter sur .inbox-toolbar : même
   spécificité (0,1,0) des deux côtés, la règle de la feuille de style
   gagnerait sinon sur celle, par défaut, du navigateur pour [hidden] —
   utilisé pour replier #users-extra-filters (v5.61.0). Un sélecteur
   d'attribut combiné à la classe (0,2,0) l'emporte sans ambiguïté. */
.inbox-toolbar[hidden] { display: none; }
.inbox-filter-field {
    display: flex; flex-direction: column; font-size: 0.75rem; color: var(--text-muted); gap: 0.15rem;
    /* Sans ceci, ce champ (item flex d'une rangée de filtres) refuse de
       se réduire en-dessous de la largeur intrinsèque de son <select>
       le plus large (min-width initiale d'un item flex = auto, pas 0)
       — rendant le max-width: 100% ci-dessous sans le moindre effet,
       puisqu'il ne fait alors que 100% d'une largeur déjà dictée par
       ce même select. */
    min-width: 0;
}
.inbox-filter-field input { font-size: 0.85rem; padding: 0.25rem 0.4rem; border: 1px solid var(--border); border-radius: 4px; background: var(--bg); color: var(--text); }
@media (hover: none), (pointer: coarse) {
    /* Même correctif que .filterable-list-input (v5.53.0) — messagerie
       interne, filtres (modale). */
    .inbox-filter-field input { font-size: 16px; }
}
/* Un <select> se dimensionne sinon sur son option la plus longue,
   quelle que soit la largeur réellement disponible (ici, le filtre
   d'action du journal d'audit débordait de 497px sur un écran de
   390px à cause d'un seul libellé long parmi ses options) — jamais un
   problème sur un écran large où cette largeur passe inaperçue. */
.inbox-filter-field select { max-width: 100%; }
.inbox-table-scroll { max-height: 360px; }
.stats-chart-section { margin-top: 1.2rem; }
.stats-chart-section select { margin-left: 0.5rem; }
#stats-chart-container { margin-top: 0.6rem; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px; padding: 0.8rem; }
.admin-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.admin-table th, .admin-table td { text-align: left; padding: 0.6rem 0.7rem; border-bottom: 1px solid var(--border); }
.admin-table th { color: var(--text-muted); font-weight: 600; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; }
.admin-inline-select {
    background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 5px; padding: 0.25rem 0.4rem; font-size: 0.85rem;
}
.admin-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.admin-danger { color: var(--danger); }
.admin-danger-text { color: var(--danger); font-weight: 600; }
.admin-warning-text { color: var(--warning); font-weight: 600; }
.backup-next-deadline {
    background: var(--bg-elevated); border: 1px solid var(--accent); border-left: 4px solid var(--accent);
    border-radius: 6px; padding: 0.7rem 1rem; margin: 0.6rem 0; font-size: 0.95rem; font-weight: 600;
}
.backup-next-deadline.overdue { border-color: var(--danger); border-left-color: var(--danger); color: var(--danger); }
.backup-protected-badge { cursor: help; }
.backup-actions-cell { display: flex; gap: 0.4rem; flex-wrap: wrap; }

.backup-synoptic-title { font-size: 1rem; margin: 0; flex: 1; }
.backup-synoptic-year { font-weight: 700; font-size: 1.05rem; min-width: 3.5rem; text-align: center; }
.backup-synoptic-legend { display: flex; gap: 1.2rem; flex-wrap: wrap; font-size: 0.8rem; color: var(--text-muted); margin: 0.3rem 0 0.6rem; }
.backup-synoptic-legend .dot-sample { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 0.3rem; vertical-align: middle; }
.dot-sample.dot-done { background: #00B050; }
.dot-sample.dot-missing { background: #fff; border: 2px solid #999; }
.dot-sample.dot-never { background: #FF0000; }
.dot-sample.dot-future { background: #5B9BD5; }
.backup-synoptic-scroll { overflow-x: auto; overflow-y: hidden; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-elevated); margin-bottom: 1rem; }
.backup-synoptic-scroll svg { display: block; }
.synoptic-dot { cursor: default; }
.synoptic-dot.clickable { cursor: pointer; }
.synoptic-dot.clickable:hover { stroke: var(--text); stroke-width: 2; }

.backups-table-scroll { max-height: 380px; overflow-y: auto; border: 1px solid var(--border); border-radius: 8px; margin-bottom: 1rem; }
.backups-table-scroll table { margin: 0; }
.backups-table-scroll thead th { position: sticky; background: var(--bg-elevated); z-index: 2; }
.backups-table-scroll thead tr:first-child th { top: 0; z-index: 3; }
.admin-filter-row th { padding: 0.3rem 0.5rem; }
.admin-filter-row input { width: 100%; box-sizing: border-box; font-size: 0.78rem; padding: 0.25rem 0.4rem; border: 1px solid var(--border); border-radius: 4px; background: var(--bg); color: var(--text); }
.admin-sortable { cursor: pointer; user-select: none; }
.admin-sortable:hover { color: var(--accent); }
.admin-sort-active { color: var(--accent); }
.admin-field { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.9rem; font-size: 0.85rem; color: var(--text-muted); }
.admin-field input[type="text"], .admin-field input[type="password"], .admin-field select {
    background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 6px; padding: 0.5rem 0.6rem; font-size: 0.9rem;
}
/* Distingue visuellement un champ non modifiable (v5.93.0) — signalé
   par l'analyse ergonomique du 26 septembre 2026 : jusqu'ici, un champ
   "disabled" (lecture seule en Configuration, ou verrouillé tant que
   la case RGPD n'est pas cochée dans "Mon compte") restait visuellement
   IDENTIQUE à un champ normal, rien n'indiquant qu'il ne sert à rien
   d'essayer d'y taper. Couvre tous les types de champ à la fois
   (":disabled" s'applique aussi bien à [type=email] et [type=tel],
   non listés dans le sélecteur ci-dessus, qu'aux champs texte). */
.admin-field input:disabled {
    background: var(--bg-hover); color: var(--text-muted); cursor: not-allowed;
}
@media (hover: none), (pointer: coarse) {
    /* Même correctif que .filterable-list-input (v5.53.0) — .admin-field
       est réutilisé dans un très grand nombre de modales de
       l'application (dossiers intelligents, dimensions Canvas, partage,
       pièces jointes, "Mon compte"...), jamais seulement dans
       l'Administration malgré son nom : le correctif profite donc à
       toutes ces modales à la fois, sans devoir le répéter ailleurs. */
    .admin-field input[type="text"], .admin-field input[type="password"], .admin-field select { font-size: 16px; }
}
.admin-member-list { display: flex; flex-direction: column; gap: 0.3rem; max-height: 200px; overflow-y: auto; }
.admin-checkbox-row { display: flex; align-items: center; gap: 0.4rem; font-size: 0.85rem; color: var(--text); font-weight: normal; }
.admin-modal-submit { margin-top: 0.4rem; }
/* Test d'envoi d'e-mail, onglet Configuration (v5.48.0) — flex-wrap
   dès la conception (jamais ajouté après coup sur mobile comme pour la
   barre de recherche/remplacement, voir docs/CHANGELOG.md v5.37.0) :
   ce champ + bouton + statut n'ont aucune raison de rester sur une
   seule ligne si l'écran est étroit. */
.admin-mail-test-row { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin: 0.8rem 0; }
.admin-mail-test-row input[type="email"] {
    background: var(--bg); border: 1px solid var(--border); color: var(--text);
    border-radius: 6px; padding: 0.5rem 0.6rem; font-size: 0.9rem; flex: 1; min-width: 0;
}
.admin-mail-test-status { font-size: 0.85rem; color: var(--text-muted); }

@media (max-width: 780px) {
    .app-shell { flex-direction: column; position: relative; overflow: hidden; }
    .mobile-menu-btn { display: inline-flex; font-size: 1.1rem; }
    .mobile-menu-btn[hidden] { display: none; }
    .sidebar-close-btn { display: inline-flex; }
    .sidebar {
        position: fixed;
        top: 0; bottom: 0; left: 0;
        width: 85vw;
        max-width: 340px;
        max-height: none;
        z-index: 40;
        border-right: 1px solid var(--border);
        border-bottom: none;
        box-shadow: 4px 0 16px rgba(0,0,0,0.3);
        transform: translateX(-100%);
        transition: transform 0.2s ease;
    }
    .sidebar.open { transform: translateX(0); }
    .sidebar-resizer { display: none; }
    .sidebar-scrim {
        display: none;
        position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 35;
    }
    .sidebar-scrim.visible { display: block; }
    .editor-toolbar { flex-wrap: wrap; gap: 0.5rem; }
    .current-note-title { order: -1; flex: 1 1 100%; }
    .toolbar-actions { flex-wrap: wrap; gap: 0.35rem; }
    .editor-panes.mode-split { grid-template-columns: 1fr; grid-template-rows: var(--split-left, 50%) 6px 1fr; }
    .source-pane { border-right: none; border-bottom: 1px solid var(--border); }
    .pane-resize-handle { cursor: row-resize; }
    .pane-resize-handle::after { top: -4px; bottom: -4px; left: 0; right: 0; }

    /* La barre de recherche/remplacement (7 éléments sur sa première
       ligne : champ, compteur, précédent/suivant, 2 cases à cocher,
       fermer) déborde purement et simplement de l'écran en restant sur
       une seule ligne — jusqu'à 457px de large pour un écran de 390px,
       le bouton "Tout remplacer" entièrement hors champ, sans la
       moindre barre de défilement pour s'en rendre compte. Le champ de
       saisie prend sa propre ligne pleine largeur ; tout le reste
       (nettement plus étroit une fois le champ retiré) se répartit sur
       la ou les lignes suivantes. */
    .find-replace-row { flex-wrap: wrap; }
    .find-replace-input { flex-basis: 100%; }

    /* Cibles tactiles de la barre de mise en forme (G, /, B, </>…) :
       0.25rem de remplissage vertical ne donne qu'une hauteur réelle
       d'environ 24px, bien en-dessous des 44px recommandés pour un
       doigt — 11 des 12 boutons mesurés en-dessous de ce seuil. Le
       retour à la ligne existant déjà (flex-wrap sur .format-toolbar)
       absorbe la hauteur supplémentaire sans rien casser. */
    .fmt-btn {
        min-height: 44px; min-width: 44px; padding: 0.5rem 0.7rem;
        display: inline-flex; align-items: center; justify-content: center;
    }

    /* La sidebar mobile a un espace bien plus limité qu'un écran de
       bureau pour un en-tête qui n'a jamais été pensé différemment
       jusqu'ici — resserré ici pour laisser le plus de place possible
       à l'arborescence du vault, le vrai contenu de cette panneau.
       Le passage à la ligne lui-même (flex-wrap) est désormais une
       règle permanente, pas seulement mobile — une sidebar réduite
       manuellement sur grand écran peut chevaucher exactement de la
       même façon si elle seule dépendait de la largeur de fenêtre. */
    .sidebar-header { padding: 0.6rem 0.7rem; }
    .vault-switcher { padding: 0.4rem 0.7rem; }
    .search-box { padding: 0.5rem 0.7rem 0; }
    .sidebar-actions { padding: 0.5rem 0.7rem; }
    .display-mode-row { padding: 0 0.7rem 0.4rem; }
}

/* ---------------- Arborescence des groupes (administration) ---------------- */
.groups-tree { margin-top: 0.8rem; }
.group-node { margin-bottom: 0.1rem; }
.group-row {
    display: flex; align-items: center; gap: 0.4rem; padding: 0.35rem 0.5rem;
    border-radius: 6px; cursor: pointer;
}
.group-row:hover { background: var(--bg-hover); }
.group-row.drop-target { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--bg-hover); }
.group-node .tree-children { margin-left: 1.4rem; border-left: 1px dashed var(--border); padding-left: 0.8rem; }
.group-multiparent-badge {
    font-size: 0.72rem; font-weight: bold; color: var(--accent); background: var(--bg-hover);
    border: 1px solid var(--accent); border-radius: 999px; padding: 0.1rem 0.5rem; margin-left: 0.5rem;
    cursor: pointer;
}
.group-multiparent-badge:hover { background: var(--accent); color: var(--accent-contrast); }
.group-stats-badge {
    font-size: 0.72rem; color: var(--text-muted); background: var(--bg-hover);
    border-radius: 999px; padding: 0.1rem 0.5rem; margin-left: 0.5rem; font-weight: normal;
}
.group-empty-hint { margin: 0.2rem 0 0.4rem; font-size: 0.8rem; }

/* Kanban (v4.74.0) */
.kb-boards-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 1rem; margin-top: 1rem; }
.kb-board-card {
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
    padding: 1rem; cursor: pointer; transition: border-color 0.15s;
}
.kb-board-card:hover { border-color: var(--accent); }
.kb-board-card h3 { margin: 0 0 0.4rem; }
.kb-board-card-has-assigned { border-color: var(--accent); border-width: 2px; }
.kb-board-card-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 0.6rem; }
.kb-board-card-header h3 { flex: 1 1 auto; min-width: 0; }
.kb-progress-ring { flex-shrink: 0; }
.kb-progress-ring-bg { fill: none; stroke: var(--border); stroke-width: 5; }
.kb-progress-ring-fg {
    fill: none; stroke: var(--success); stroke-width: 5; stroke-linecap: round;
    transform: rotate(-90deg); transform-box: fill-box; transform-origin: center;
}
/* Couleur de l'arc de progression, selon la situation de la personne sur ce tableau (v6.39.0). */
/* L'arc est en couleur PLEINE ; le cercle de fond prend la même couleur en transparence. À 0 % d'avancement l'arc se réduit à un point : sans cela la couleur serait presque
   invisible précisément quand elle compte (un retard survient surtout quand rien n'est commencé). */
.kb-ring-none .kb-progress-ring-fg { stroke: #3b82f6; }
.kb-ring-late .kb-progress-ring-fg { stroke: var(--danger); }
.kb-ring-soon .kb-progress-ring-fg { stroke: var(--warning); }
.kb-ring-ok .kb-progress-ring-fg { stroke: var(--success); }
.kb-ring-none .kb-progress-ring-bg { stroke: #3b82f6; stroke-opacity: 0.28; }
.kb-ring-late .kb-progress-ring-bg { stroke: var(--danger); stroke-opacity: 0.28; }
.kb-ring-soon .kb-progress-ring-bg { stroke: var(--warning); stroke-opacity: 0.28; }
.kb-ring-ok .kb-progress-ring-bg { stroke: var(--success); stroke-opacity: 0.28; }
.kb-progress-ring-text {
    font-size: 0.85rem; font-weight: 700; fill: var(--text); text-anchor: middle; dominant-baseline: central;
}
.kb-board-assigned-badge {
    display: inline-flex; align-items: center; justify-content: center; min-width: 1.3rem; height: 1.3rem;
    background: var(--accent); color: var(--accent-contrast); border-radius: 999px; font-size: 0.72rem;
    font-weight: 700; padding: 0 0.3rem; vertical-align: middle;
}
/* Couleur selon l'état des tâches assignées (v5.69.0) — combinée à la
   classe de base pour l'emporter sans ambiguïté (0,2,0), quel que soit
   l'ordre d'apparition dans ce fichier. */
.kb-board-assigned-badge.kb-board-assigned-badge--red { background: var(--danger); color: #fff; }
.kb-board-assigned-badge.kb-board-assigned-badge--green { background: var(--success); color: #fff; }
.kb-board-assigned-badge.kb-board-assigned-badge--orange { background: var(--warning); color: #fff; }
.kb-assigned-task-list { list-style: none; margin: 0.6rem 0 0; padding: 0.5rem 0 0; border-top: 1px solid var(--border); }
.kb-assigned-task-list li {
    display: flex; align-items: center; justify-content: space-between; gap: 0.5rem;
    padding: 0.3rem 0.2rem; border-radius: 5px; cursor: pointer; font-size: 0.85rem;
}
.kb-assigned-task-list li:hover { background: var(--bg-hover); }
.kb-assigned-task-dot {
    display: inline-block; width: 0.6rem; height: 0.6rem; border-radius: 50%; flex-shrink: 0;
}
.kb-assigned-task-dot--red { background: var(--danger); }
.kb-assigned-task-dot--green { background: var(--success); }
.kb-assigned-task-dot--orange { background: var(--warning); }
.kb-assigned-task-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-assigned-task-due { flex-shrink: 0; font-size: 0.78rem; color: var(--text-muted); }
.kb-columns-row { display: flex; gap: 1rem; overflow-x: auto; margin-top: 1rem; padding-bottom: 1rem; align-items: flex-start; }
/* Indice de défilement horizontal (v5.94.0) — une ombre sur le bord
   droit, visible uniquement tant qu'il reste du contenu à faire
   défiler (classe .has-more-right, posée/retirée par
   updateKanbanScrollHint() dans kanban.js). Jamais sur le bord gauche
   au départ (rien à y faire défiler avant la première colonne). */
.kb-columns-scroll-wrap { position: relative; }
.kb-columns-scroll-wrap::after {
    content: ''; position: absolute; top: 0; right: 0; bottom: 1rem; width: 2.5rem;
    background: linear-gradient(to right, transparent, var(--bg) 90%);
    pointer-events: none; opacity: 0; transition: opacity 0.15s ease;
}
.kb-columns-scroll-wrap.has-more-right::after { opacity: 1; }
.kb-column {
    background: var(--bg-elevated); border-radius: 8px; min-width: 260px; max-width: 260px;
    display: flex; flex-direction: column; padding: 0.6rem;
}
.kb-column-header {
    font-weight: 600; padding: 0.4rem 0.2rem; border-top: 4px solid; border-radius: 2px;
    margin-bottom: 0.5rem;
}
.kb-column-tasks { display: flex; flex-direction: column; gap: 0.5rem; min-height: 30px; }
.kb-task-card {
    background: var(--bg-base); border: 1px solid var(--border); border-radius: 6px;
    padding: 0.5rem 0.6rem; cursor: pointer;
}
.kb-task-card:hover { border-color: var(--accent); }
.kb-task-title { font-size: 0.9rem; }
.kb-task-assignee { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.3rem; }
.kb-task-row { display: flex; align-items: flex-start; gap: 0.4rem; }
.kb-task-handle { cursor: grab; color: var(--text-muted); user-select: none; line-height: 1.4; flex-shrink: 0; }
.kb-task-handle:active { cursor: grabbing; }
.kb-task-due { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.2rem; }
.kb-task-due-overdue { color: var(--danger, #c0392b); font-weight: 600; }
.kb-task-due-soon { color: var(--warning); font-weight: 600; }
.kb-task-notes-count { font-size: 0.78rem; color: var(--text-muted); margin-top: 0.2rem; }
.kb-task-progress-row { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.3rem; }
.kb-task-weather { font-size: 0.9rem; line-height: 1; flex-shrink: 0; }
.kb-task-progress-bar { flex: 1 1 auto; height: 6px; background: var(--bg-hover); border-radius: 999px; overflow: hidden; min-width: 30px; }
.kb-task-progress-fill { display: block; height: 100%; background: var(--accent); border-radius: 999px; }
.kb-task-progress-label { flex-shrink: 0; font-size: 0.75rem; color: var(--text-muted); }
#kb-task-progress { width: 100%; accent-color: var(--accent); }
.kb-task-order {
    flex-shrink: 0; font-size: 0.7rem; color: var(--text-muted); background: var(--bg-hover);
    border-radius: 50%; width: 16px; height: 16px; display: inline-flex; align-items: center;
    justify-content: center; line-height: 1;
}
.kb-task-order-buttons { flex-shrink: 0; margin-left: auto; display: flex; gap: 0.1rem; }
.kb-task-move-up, .kb-task-move-down {
    background: none; border: 1px solid var(--border); border-radius: 4px; color: var(--text-muted);
    cursor: pointer; font-size: 0.65rem; padding: 0.05rem 0.25rem; line-height: 1.4;
}
.kb-task-move-up:hover:not(:disabled), .kb-task-move-down:hover:not(:disabled) { color: var(--text); border-color: var(--text-muted); }
.kb-task-move-up:disabled, .kb-task-move-down:disabled { opacity: 0.3; cursor: not-allowed; }
.kb-wip-over { color: var(--danger, #c0392b); font-weight: 700; }
/* Repliée par défaut (v5.66.0) — universellement, bureau compris :
   utile, mais jamais prioritaire sur la vue des tâches elles-mêmes,
   sur aucune taille d'écran. Le sélecteur combiné avec la classe
   .kb-filters-open l'emporte par spécificité, quel que soit l'ordre
   d'apparition dans ce fichier. */
.kb-filters-bar { display: none; flex-wrap: wrap; gap: 1rem; align-items: flex-end; margin: 0.8rem 0; padding: 0.7rem 0.9rem; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px; }
.kb-filters-bar.kb-filters-open { display: flex; }
.kb-involved-panel.kb-filters-open { display: flex; flex-direction: column; align-items: stretch; gap: 0.6rem; }
.kb-involved-sort-row { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; color: var(--text-muted); }
.kb-involved-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.kb-involved-list li {
    display: flex; justify-content: space-between; align-items: center; gap: 0.6rem;
    padding: 0.3rem 0.1rem; border-bottom: 1px solid var(--border);
}
.kb-involved-list li:last-child { border-bottom: none; }
.kb-involved-count-btn {
    background: none; border: 1px solid var(--border); border-radius: 12px;
    padding: 0.15rem 0.6rem; font-size: 0.82rem; color: var(--accent); cursor: pointer;
}
.kb-involved-count-btn:hover { background: var(--bg-hover); }
.kb-involved-empty { color: var(--text-muted); font-size: 0.85rem; font-style: italic; }
.kb-involved-task-row {
    width: 100%; border: none; background: none; color: var(--text); font: inherit;
    text-align: left;
}
.kb-involved-task-row .count { color: var(--text-muted); font-size: 0.8rem; white-space: nowrap; }
.kb-filters-bar label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.78rem; color: var(--text-muted); }
.kb-filters-bar select, .kb-filters-bar input {
    padding: 0.4rem 0.6rem; background: var(--bg); border: 1px solid var(--border);
    border-radius: 6px; color: var(--text); font-size: 0.85rem;
}
.kb-filters-bar input[type="date"] { min-width: 140px; }
#kb-filters-reset-btn { align-self: flex-end; }
.kb-task-move-select { display: block; width: 100%; margin-top: 0.4rem; font-size: 0.78rem; }
.kb-board-title-inline { display: inline; margin-left: 0.8rem; }
.kb-add-task-btn { margin-top: 0.5rem; width: 100%; }
.kb-column-editor-row, .kb-col-head {
    display: grid; align-items: center; gap: 0.5rem; margin-bottom: 0.5rem;
    grid-template-columns: 28px 44px minmax(0, 1fr) 112px minmax(0, 250px) 40px;
    grid-template-areas: "order color title wip role remove";
}
.kb-column-editor-row--norole, .kb-col-head--norole {
    grid-template-columns: 28px 44px minmax(0, 1fr) 112px 40px; grid-template-areas: "order color title wip remove";
}
.kb-col-head { margin-bottom: 0.25rem; font-size: 0.75rem; color: var(--text-muted); grid-template-areas: none; }
.kb-col-head span { min-width: 0; }
/* Limite et rôle : un bloc TRANSPARENT sur ordinateur (ses enfants rejoignent la grille de la ligne) ; sur téléphone il devient une seconde ligne. */
.kb-col-extra { display: contents; }
.kb-col-order-buttons { grid-area: order; }
.kb-column-editor-row .kb-col-color { grid-area: color; }
.kb-column-editor-row .kb-col-title { grid-area: title; }
.kb-column-editor-row .kb-col-wip-limit { grid-area: wip; }
.kb-column-editor-row .kb-col-role { grid-area: role; }
.kb-column-editor-row .kb-col-remove { grid-area: remove; }
@media (max-width: 640px) {
    /* Téléphone : deux lignes par colonne — ordre, couleur, titre et retrait en haut ; limite et rôle dessous, à pleine largeur. */
    .kb-col-head { display: none; }
    .kb-column-editor-row { grid-template-columns: 28px 44px minmax(0, 1fr) 40px; grid-template-areas: "order color title remove" ". extra extra extra"; row-gap: 0.4rem; margin-bottom: 0.9rem; }
    .kb-col-extra { grid-area: extra; display: grid; grid-template-columns: 112px minmax(0, 1fr); gap: 0.5rem; }
    .kb-column-editor-row--norole .kb-col-extra { grid-template-columns: minmax(0, 1fr); }
    .kb-column-editor-row .kb-col-extra > .kb-col-wip-limit, .kb-column-editor-row .kb-col-extra > .kb-col-role { grid-area: auto; }
}
.kb-col-order-buttons { flex-shrink: 0; display: flex; flex-direction: column; gap: 0.05rem; }
.kb-col-order-buttons button {
    background: none; border: 1px solid var(--border); border-radius: 4px; color: var(--text-muted);
    cursor: pointer; font-size: 0.6rem; padding: 0.02rem 0.25rem; line-height: 1.3;
}
.kb-col-order-buttons button:hover:not(:disabled) { color: var(--text); border-color: var(--text-muted); }
.kb-col-order-buttons button:disabled { opacity: 0.3; cursor: not-allowed; }
/* Pastille de couleur : une taille FIXE qui ne peut jamais être écrasée par les autres champs de la ligne (elle l'était : 6 px de large sous Chromium) — mêmes dimensions
   et même rendu natif neutralisé sur Safari, Chrome et Firefox. */
.kb-column-editor-row input[type="color"].kb-col-color {
    -webkit-appearance: none; appearance: none; box-sizing: border-box; width: 44px; min-width: 44px; height: var(--ctl-h, 40px); padding: 3px;
    border: 1px solid var(--border); border-radius: var(--ctl-r, 8px); background: var(--bg); cursor: pointer;
}
.kb-col-color::-webkit-color-swatch-wrapper { padding: 0; }
.kb-col-color::-webkit-color-swatch { border: none; border-radius: 5px; }
.kb-col-color::-moz-color-swatch { border: none; border-radius: 5px; }
.kb-share-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.4rem 0; border-bottom: 1px solid var(--border); }
.kb-linked-note-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.35rem 0; border-bottom: 1px solid var(--border); font-size: 0.85rem; }
.kb-linked-note-row a { color: var(--text); text-decoration: none; }
.kb-linked-note-row a:hover { color: var(--accent); text-decoration: underline; }
.kb-linked-note-inactive { color: var(--text-muted); font-style: italic; }
#kb-link-note-select { width: 100%; margin-top: 0.5rem; }

/* Ces deux boutons de repli, autrefois réservés au mobile, gagnent à
   exister aussi sur grand écran (v5.66.0) : libérer de la place pour
   les colonnes elles-mêmes — le vrai contenu de cette page — reste
   utile même quand l'espace ne manque pas autant qu'au format mobile. */
.kb-actions-kebab-btn, .kb-filters-toggle-btn { display: inline-flex; margin-bottom: 0.5rem; }
/* [hidden] doit systématiquement l'emporter (v5.68.0) — même
   spécificité (0,1,0) des deux côtés, la règle ci-dessus gagnerait
   sinon sur celle, par défaut, du navigateur pour [hidden] : même piège
   déjà rencontré pour .inbox-toolbar (v5.61.0). Utilisé pour masquer le
   bouton "Utilisateurs impliqués" sur un tableau de type "Tri". */
.kb-filters-toggle-btn[hidden] { display: none; }
#kb-view-board .admin-panel-header { position: relative; }
#kb-header-actions.header-actions {
    display: none; position: absolute; top: 100%; right: 0; margin-top: 0.3rem;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
    box-shadow: 0 6px 20px rgba(0,0,0,0.35); padding: 0.4rem; z-index: 70;
    flex-direction: column; gap: 0.3rem; min-width: 160px;
}
#kb-header-actions.header-actions.kb-actions-open { display: flex; }
#kb-header-actions.header-actions .btn-small { width: 100%; text-align: left; }

@media (max-width: 780px) {
    /* 780px : LE seuil standard de bascule en mise en page mobile de
       toute l'application (voir docs/ARCHITECTURE.md, section 9) —
       auparavant 700px ici spécifiquement, un chiffre choisi
       indépendamment de celui déjà en vigueur pour l'éditeur
       principal. Les deux zones utilisent désormais exactement le
       même seuil : plus d'écart de 80px pendant lequel l'une bascule
       déjà en mobile et l'autre pas encore.
       La zone d'en-tête (titre, actions, filtres) ne doit jamais
       dévorer l'écran avant même d'atteindre les colonnes, le vrai
       contenu de la page — un espace bien plus limité sur mobile que
       sur un écran de bureau, jamais traité différemment jusqu'ici. */
    .admin-shell { padding: 0.8rem; }
    /* Barre latérale groupée (v5.30.0), corrigée en v5.31.0 : sur
       mobile, la disposition en groupes horizontaux jugée pire que
       l'ancienne barre plate (chaque titre de groupe ajoutant sa
       propre ligne) est abandonnée au profit d'un vrai menu repliable
       — la barre latérale reste identique à celle du bureau (une vraie
       liste verticale groupée), simplement masquée par défaut et
       affichée en recouvrement à la demande, jamais reproduite
       séparément pour mobile. */
    .admin-body { flex-direction: column; }
    /* align-items: flex-start (règle desktop) réduit sinon ce conteneur à
       la largeur de son contenu au lieu de la pleine largeur disponible —
       rétrécissant à la fois le bouton et le menu déroulant positionné
       par rapport à lui (left/right à 0 d'un parent déjà trop étroit). */
    .admin-sidebar-wrap { position: relative; width: 100%; }
    /* EXACTEMENT le même défaut, sur le conteneur du contenu cette
       fois : sans cette largeur explicite, .admin-content se réduit à
       la largeur de son contenu le plus large (un tableau, un
       graphique SVG) au lieu d'être limité à celle de l'écran — et
       comme cette largeur remonte à TOUS ses parents/enfants, aucun
       des conteneurs à défilement horizontal propre déjà en place
       (.backups-table-scroll, .backup-synoptic-scroll…) n'a jamais la
       moindre chance de les contenir : ils grandissent avec le reste
       de la page au lieu de faire défiler leur contenu. Découvert en
       mesurant un débordement de 1913px sur le panneau Sauvegardes à
       lui seul. */
    .admin-content { width: 100%; min-width: 0; }
    /* Un en-tête de panneau avec plusieurs boutons à libellé long (ex.
       Sauvegardes : "Sauvegarde complète", "Réparer les fichiers
       manquants", "Aide", "Actualiser") déborde sinon de l'écran —
       .header-actions n'autorise le retour à la ligne nulle part par
       défaut, correct sur bureau (une seule ligne y tient), jamais
       adapté au mobile jusqu'ici. */
    .admin-panel-header { flex-wrap: wrap; row-gap: 0.5rem; margin-bottom: 0.6rem; }
    .admin-panel-header .header-actions { flex-wrap: wrap; }
    /* Masque le titre du panneau sur mobile (v5.96.0) — signalé par
       l'utilisateur : le bouton de bascule juste au-dessus (voir
       #admin-sidebar-toggle-label ci-dessous) affiche déjà le nom de la
       section choisie, rendant ce second titre identique strictement
       redondant sur cette largeur. Jamais masqué sur bureau, où rien
       d'autre n'affiche ce nom de façon aussi visible (la barre latérale
       se contente de surligner l'onglet actif, moins immédiat à
       repérer) — et où plusieurs de ces mêmes titres cohabitent avec de
       vrais boutons d'action (Utilisateurs, Groupes, Sauvegardes...)
       dont la disposition dépend de cet en-tête, jamais touchée ici.
       Un sélecteur direct plutôt qu'une classe dédiée : jamais neuf
       endroits à modifier dans le template pour un seul changement de
       présentation. */
    .admin-panel-header > h2:first-child { display: none; }
    .admin-sidebar-toggle-btn {
        display: flex; width: 100%; align-items: center; justify-content: space-between;
        background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 6px;
        padding: 0.6rem 0.8rem; color: var(--text); font-size: 0.95rem; font-weight: 600; cursor: pointer;
        margin-bottom: 0.8rem;
    }
    .admin-sidebar {
        display: none; position: absolute; top: 100%; left: 0; right: 0; z-index: 10;
        width: auto; margin-top: -0.4rem; background: var(--bg); border: 1px solid var(--border);
        border-radius: 6px; padding: 0.8rem; box-shadow: 0 8px 24px rgba(0,0,0,0.35);
        max-height: 70vh; overflow-y: auto;
    }
    .admin-sidebar.open { display: flex; }
    .admin-header, #kb-view-board .admin-panel-header { margin-bottom: 0.6rem; position: relative; }
    #kb-board-title { font-size: 1.05rem; }

    /* Le mécanisme de repli des actions du tableau et de la barre de
       filtres/tri est désormais universel — voir plus haut, hors de
       cette media query (v5.66.0) : ne reste ici que ce qui est
       réellement propre au mobile. */

    /* Des colonnes un peu plus étroites : plus de colonnes visibles à
       la fois sans pour autant les rendre illisibles. */
    .kb-column { min-width: 220px; max-width: 220px; }

    /* Onglet Utilisateurs (v5.61.0) : la place laissée au tableau
       lui-même — le vrai contenu de cette page — était ridicule sur
       mobile, noyée sous l'en-tête, deux gros boutons empilés, deux
       encarts d'aide et quatre lignes de filtres avant même d'y
       arriver. Traité comme les autres pages ci-dessus : replier ce
       qui peut l'être, ne jamais afficher deux boutons pleine largeur
       quand un seul suffit visuellement. */
    #import-users-groups-btn .btn-label { display: none; }
    #import-users-groups-btn { padding-left: 0.5rem; padding-right: 0.5rem; }

    /* Recherche toujours visible (le filtre de loin le plus utilisé au
       quotidien), Rôle/Statut repliés derrière un simple bouton —
       jamais quatre lignes de filtres avant la moindre ligne du
       tableau. L'étiquette "Recherche" au-dessus du champ (comportement
       normal de .inbox-filter-field, en colonne) double inutilement sa
       hauteur ici : le placeholder du champ suffit déjà à s'expliquer,
       l'étiquette reste accessible via aria-label sur le label lui-même
       plutôt que par ce texte visible. */
    .admin-users-filter-bar { align-items: center; }
    .admin-users-search-field { flex: 1 1 auto; flex-direction: row; align-items: center; }
    .admin-users-search-field span { display: none; }
    .admin-users-search-field input { flex: 1 1 auto; min-width: 0; }

    /* Encart d'aide replié : ses marges verticales (conçues pour un
       écran large où l'espace ne manque pas) grignotent à elles seules
       près de 26px avant même d'atteindre son contenu, alors qu'il
       n'affiche jamais qu'une seule ligne de résumé une fois replié. */
    #tab-users .admin-collapsible-section { margin: 0.4rem 0 0.6rem; }
    #tab-users .admin-collapsible-section summary { padding: 0.5rem 0.8rem; }
    /* Bannière de comptage : une information utile, jamais prioritaire
       au point de justifier une taille de titre et une marge pensées
       pour un écran large. */
    .admin-user-count-banner { font-size: 0.92rem; margin: 0.3rem 0 0.6rem; }

    /* Le tableau lui-même devient une liste de fiches empilées,
       jamais un tableau à défiler horizontalement (8 colonnes, dont un
       menu déroulant, ne tiennent structurellement pas sur un écran de
       téléphone) — la technique classique consistant à transformer
       chaque <tr> en carte et chaque <td> en une ligne "étiquette :
       valeur" repose sur data-label, posé par admin.js au moment du
       rendu de chaque cellule. #users-table (identifiant) l'emporte
       sur .admin-table (classe) par spécificité, quel que soit l'ordre
       d'apparition dans ce fichier — jamais un pari sur la position,
       contrairement à d'autres correctifs de ce projet qui doivent
       composer avec une spécificité égale des deux côtés. */
    #users-table thead { display: none; }
    #users-table, #users-table tbody { display: block; width: 100%; }
    #users-table tr {
        display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem 0.6rem;
        border: 1px solid var(--border); border-radius: 8px;
        margin-bottom: 0.6rem; padding: 0.6rem 0.7rem 0.5rem;
        background: var(--bg-elevated);
    }
    #users-table td { border: none; padding: 0.15rem 0; }
    /* Case à cocher, identifiant et statut forment la ligne "titre" de
       la carte — jamais une ligne "étiquette : valeur" comme le reste,
       l'identifiant se suffisant à lui-même en tête de carte. */
    #users-table td.admin-table-header-cell { width: auto; }
    #users-table td.admin-table-primary-cell { font-weight: 600; font-size: 1rem; flex: 1 1 auto; }
    /* Chaque autre cellule prend toute la largeur (une ligne propre),
       avec son étiquette de colonne devant elle — perdue autrement une
       fois l'en-tête du tableau masqué juste au-dessus. */
    #users-table td:not(.admin-table-header-cell):not(.admin-actions) {
        width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 0.4rem;
    }
    #users-table td[data-label]:not(.admin-table-header-cell)::before {
        content: attr(data-label) " :"; font-weight: 600; color: var(--text-muted); font-size: 0.72rem;
        text-transform: uppercase; letter-spacing: 0.02em; flex-shrink: 0;
    }
    /* Boutons d'action : toujours en dernier, sur toute la largeur,
       séparés du reste par un simple filet plutôt qu'une bordure de
       cellule (déjà retirée juste au-dessus pour toutes les cellules
       de ce tableau). */
    #users-table td.admin-actions {
        width: 100%; margin-top: 0.3rem; padding-top: 0.4rem; border-top: 1px solid var(--border);
    }
}

/* ============ Agenda (v5.12.0) ============ */

/* Coquille propre à l'Agenda (v5.15.0), jamais .admin-shell partagée
   avec l'Administration et Kanban : une grille horaire (semaine, jour)
   a besoin de bien plus que les 1000px imposés là-bas, sans risquer la
   moindre régression sur ces autres pages en élargissant une classe
   commune. */
/* Les marges de sécurité de l'appareil (encoche, île dynamique, barre d'accueil) : nulles sur ordinateur, donc sans effet là ; sur iPhone, la page s'étend sous la barre
   d'état (viewport-fit=cover, voir calendar.php) et ces marges y gardent le contenu lisible. */
.cal-shell { margin: 0 auto; padding: calc(1.5rem + env(safe-area-inset-top, 0px)) calc(1.5rem + env(safe-area-inset-right, 0px)) calc(1.5rem + env(safe-area-inset-bottom, 0px)) calc(1.5rem + env(safe-area-inset-left, 0px)); }
/* Bande de la barre d'état : toujours opaque, au fond de la page, AU-DESSUS du contenu qui défile — sans elle, la liste défilait à la vue de tous sous l'heure et l'île
   dynamique. Hauteur nulle sans encoche. */
.cal-page::before { content: ''; position: fixed; top: 0; left: 0; right: 0; height: env(safe-area-inset-top, 0px); background: var(--bg); z-index: 6; pointer-events: none; }

.cal-header { display: flex; flex-direction: column; gap: 0.7rem; margin-bottom: 1.2rem; position: sticky; top: env(safe-area-inset-top, 0px); background: var(--bg); z-index: 5; padding-top: 0.4rem; }
.cal-header-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
/* Jamais la marge par défaut du <h1> (v5.90.0) — un ~1em non
   réinitialisé au-dessus et en dessous, jusqu'ici jamais remis à zéro,
   creusait un vide bien visible entre le titre et la ligne
   Aujourd'hui/date/vues juste en dessous, en particulier sur mobile où
   .cal-header-top passe à la ligne. */
.cal-header-top h1 { margin: 0; line-height: 1.2; }
/* Date et heure actuelles (v5.15.0), toujours affichées quelle que soit
   la vue active — jamais seulement déduites du jour mis en évidence
   dans une grille, qui n'existe même pas dans certaines vues. */
.cal-now-display { font-size: 1rem; font-weight: 700; color: var(--text-muted); text-align: right; white-space: nowrap; }
.cal-header-actions {
    display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
    padding-top: 0.6rem; border-top: 1px solid var(--border);
}
/* Bouton principal volontairement discret parmi les autres actions de
   cette même ligne (v5.15.0) — l'action la plus fréquente de la page
   reste la simple consultation, jamais la création. */
/* Réduit au seul "+" (v5.86.0) — le mot "Événement" prenait trop de
   place ; le signe grossi et mis en gras reste parfaitement clair
   grâce au titre/aria-label porté par le bouton lui-même. */
.cal-new-event-btn { padding: 0.35rem 0.7rem; font-size: 1.3rem; font-weight: 700; line-height: 1; margin-left: auto; }

.cal-layout { display: flex; gap: 1.2rem; align-items: flex-start; margin-top: 1rem; }
/* position: sticky (v5.93.0) — sans quoi le défilement automatique de
   la page vers l'heure actuelle en vues Semaine/Jour (voir
   renderTimeGrid() dans calendar.js) entraînait la barre latérale
   avec lui, poussant "Mes agendas" hors de l'écran. `top` fixé
   dynamiquement en JS (updateTimeGridStickyOffsets()), la hauteur de
   l'en-tête variant selon la largeur d'écran. `max-height` et
   `overflow-y` évitent qu'elle ne dépasse jamais le bas de la fenêtre
   sur un écran bas, avec son propre défilement interne le cas échéant. */
.cal-sidebar {
    flex: 0 0 220px; position: sticky; top: 0;
    max-height: calc(100vh - 1rem); overflow-y: auto;
}
.cal-main { flex: 1; min-width: 0; }

.cal-current-month { font-weight: 600; margin: 0 0.4rem; text-transform: capitalize; }

.cal-agenda-row { display: flex; align-items: center; gap: 0.4rem; padding: 0.3rem 0; }
.cal-agenda-color-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.cal-agenda-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.9rem; }
/* Vues enregistrées — liste déroulante + boutons d'action (v5.85.0). */
.cal-presets-controls { display: flex; flex-direction: column; gap: 0.5rem; }
.cal-presets-controls select { width: 100%; }
/* Boutons ne portant qu'une icône (v5.90.0, corrigé après un premier
   essai raté) — un gabarit FIXE (largeur ET hauteur), pour une taille
   réellement homogène quel que soit le glyphe affiché : un texte simple
   ("+", "✎") et un émoji couleur ne se dimensionnent jamais pareil
   à la même taille de police, un émoji débordant même largement sur
   mobile (iOS notamment) si on se contente d'augmenter font-size. Le
   gabarit fixe, avec le contenu centré et jamais autorisé à dépasser,
   règle ce problème à la racine plutôt que par un réglage de police
   qui ne pouvait qu'empirer les choses pour un émoji.
   -webkit-text-size-adjust: 100% neutralise un agrandissement d'iOS
   spécifique aux émoji, seule cause identifiée de leur taille démesurée
   sur la capture d'écran signalée. */
/* Boutons ne portant qu'une icône (v5.91.0, seconde tentative après un
   nouveau signalement) — cette fois de vraies icônes SVG monochromes,
   plutôt que des glyphes texte/émoji : "+" (gras), "✎" (fin, clair) et
   un émoji couleur n'ont jamais le même poids visuel à taille égale,
   quels que soient les réglages de police tentés jusqu'ici (v5.89.0,
   v5.90.0) — le crayon restait presque invisible malgré un gabarit fixe
   correct. Un tracé vectoriel avec stroke="currentColor" donne un
   contrôle total et identique sur les trois icônes : même épaisseur de
   trait, même couleur (héritée de "color" ci-dessous, jamais un gris
   clair par défaut), même taille. */
.cal-icon-btn {
    width: 2rem; height: 2rem; padding: 0; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--bg-hover); border: 1px solid var(--border); border-radius: 6px;
    color: var(--text); cursor: pointer;
}
.cal-icon-btn svg { width: 1.15rem; height: 1.15rem; display: block; }
.cal-icon-btn:disabled { opacity: 0.4; cursor: default; }
.cal-icon-btn:not(:disabled):hover { background: var(--bg-elevated); }
/* Regroupe les boutons-icônes sur UNE SEULE ligne, à côté du titre
   qu'ils concernent (v5.90.0) — jamais une ligne à eux seuls en
   dessous, qui gaspillait une hauteur d'écran considérable sur mobile
   pour un simple bouton "Modifier" ou "Supprimer". */
.cal-icon-btn-group { display: flex; gap: 0.35rem; flex-shrink: 0; }
.cal-agenda-menu-btn { width: 1.8rem; height: 1.8rem; padding: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 0.95rem; line-height: 1; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
/* Cases des jours fériés / vacances scolaires (v5.16.0) — jamais de
   vrais agendas, mais visuellement alignées sur le même patron
   qu'eux : chacune sur sa propre ligne, jamais côte à côte comme le
   ferait un <label> sans mise en page explicite. */
.cal-sidebar-divider { border-top: 1px solid var(--border); margin: 0.5rem 0; }
/* Intitulé de chaque groupe d'agendas — propriétaire, partagé en
   écriture, partagé en lecture (v5.87.0, texte ajouté en v5.88.0) :
   petit mais lisible, avec un trait fin en dessous qui sépare
   visuellement du groupe précédent sans avoir besoin d'un élément à
   part. */
.cal-agendas-group-label {
    font-size: 0.72rem; color: var(--text-muted); text-transform: uppercase;
    letter-spacing: 0.03em; margin: 0.6rem 0 0.3rem; padding-bottom: 0.25rem;
    border-bottom: 1px solid var(--border);
}
.cal-agendas-group-label:first-child { margin-top: 0; }
.cal-overlays-list { display: flex; flex-direction: column; gap: 0.2rem; }
/* Sans ceci, [hidden] (repli, v5.90.0) n'a aucun effet : une règle
   d'auteur (display: flex ci-dessus) l'emporte toujours sur la feuille
   de style par défaut du navigateur, quelle que soit la spécificité —
   un piège déjà rencontré ailleurs dans cette application. */
.cal-overlays-list[hidden] { display: none; }
.cal-overlay-row { display: flex; align-items: center; gap: 0.4rem; padding: 0.3rem 0; font-size: 0.9rem; cursor: pointer; }

/* Filet de sécurité (v5.23.0) : si un contenu imprévu déborde malgré
   min-width: 0 sur les cellules (ci-dessous), la grille défile
   horizontalement plutôt que de couper silencieusement une colonne
   entière (le dimanche, en bout de grille) sans aucun moyen d'y
   accéder. */
.cal-month-view-scroll { overflow-x: auto; }
.cal-weekday-header {
    display: grid; grid-template-columns: minmax(2.2rem, auto) repeat(7, 1fr);
    font-size: 0.8rem; color: var(--text-muted); text-align: center; margin-bottom: 0.3rem;
}
.cal-month-grid {
    display: grid; grid-template-columns: minmax(2.2rem, auto) repeat(7, 1fr); grid-auto-rows: minmax(90px, 1fr);
    gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: 6px; overflow: hidden;
}
/* Numéro de semaine ISO 8601 (v5.16.0) — toujours affiché, jamais un
   réglage à activer : une information discrète et rarement gênante,
   contrairement aux jours fériés ou aux vacances scolaires qui
   ajoutent, eux, un vrai contenu visuel supplémentaire. */
.cal-week-number-cell {
    background: var(--bg); display: flex; align-items: center; justify-content: center;
    font-size: 0.72rem; color: var(--text-muted); min-width: 0;
}
.cal-day-cell {
    background: var(--bg-elevated); padding: 0.3rem; cursor: pointer; display: flex; flex-direction: column; gap: 0.2rem;
    /* min-width: 0 rompt le piège classique de CSS Grid : sans cette
       ligne, une cellule ne se comprime jamais en dessous de la
       largeur de son contenu le plus large (ici, un chip d'événement
       au texte non replié) — ce qui étirait toute la grille au-delà
       du viewport, avec la colonne Dimanche purement et simplement
       coupée, sans le moindre moyen d'y accéder (v5.23.0). */
    min-width: 0; overflow: hidden;
}
.cal-day-cell:hover { background: var(--bg); }
/* Indicateur de focus clavier (v5.26.0) — .cal-day-cell est un <div>
   rendu focusable (tabindex), jamais couvert par la règle générique
   "button:focus-visible" qui ne cible que les vrais boutons. */
.cal-day-cell:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Contraste insuffisant avec la seule opacité réduite (v5.27.0) —
   un audit outillé (axe-core) a mesuré ~3.15:1 sur le thème sombre,
   sous le seuil minimal de 4.5:1 : réduire l'opacité assombrit
   uniformément texte ET fond, sans garantie de contraste résultant.
   var(--text-muted), déjà pensée pour un texte secondaire lisible,
   offre un contraste mesuré de 4.69:1 (sombre) et 5.16:1 (clair). */
.cal-day-outside-month { color: var(--text-muted); }
.cal-day-number { font-size: 0.8rem; font-weight: 600; }
.cal-day-today .cal-day-number {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.4rem; height: 1.4rem; border-radius: 50%; background: var(--accent); color: var(--accent-contrast);
}
.cal-day-events { display: flex; flex-direction: column; gap: 2px; overflow: hidden; }
.cal-event-chip {
    font-size: 0.72rem; color: #fff; padding: 1px 4px; border-radius: 4px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer;
}
/* Jours fériés et vacances scolaires (v5.16.0). */
.cal-holiday-chip {
    font-size: 0.72rem; color: #fff; padding: 1px 4px; border-radius: 4px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; background: #b23b3b;
}
/* Trois signaux indépendants, communs à toutes les vues — mois,
   semaine, jour, année (v5.44.0) : rouge pour un jour férié (couleur
   de texte seule, jamais un fond, pour ne jamais entrer en conflit
   avec un autre signal posé sur le même élément), fond gris neutre
   pour une période de vacances scolaires (jamais teinté de la couleur
   d'accent — plus simple à distinguer du bleu "aujourd'hui" ou de la
   couleur propre à chaque agenda), soulignement plus marqué réservé à
   la seule présence d'un événement réel — jamais un jour férié ou des
   vacances scolaires seuls, qui ont déjà leur propre signal ci-dessus
   et n'ont besoin de rien d'autre. Les trois se superposent sans le
   moindre conflit : aucun des trois ne touche aux mêmes propriétés
   qu'un autre. Contraste du fond gris mesuré à environ 1,4-1,6:1
   contre le fond dans les 5 thèmes (contre ~1,19:1 pour l'ancienne
   teinte à l'accent, jugée trop discrète sur mobile en v5.43.0 — cette
   version, universelle, n'a plus besoin d'un correctif séparé par
   appareil). */
.cal-day-holiday { color: #d95c5c; font-weight: 600; }
/* Sélecteur composé nécessaire pour la vue Année spécifiquement : à
   spécificité par ailleurs égale (une seule classe de chaque côté),
   .cal-year-day (son propre color: var(--text)) est déclarée plus loin
   dans le fichier et l'emportait donc sur .cal-day-holiday seule,
   rendant un jour férié invisible en rouge dans cette vue précise —
   le même piège de cascade CSS, une fois de plus, qui n'affecte ni
   .cal-day-number ni .cal-timegrid-day-header (aucun des deux ne fixe
   sa propre couleur de texte ailleurs, donc rien à emporter). */
.cal-year-day.cal-day-holiday { color: #d95c5c; font-weight: 600; }
.cal-day-has-events { text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
.cal-day-school-holiday { background: color-mix(in srgb, gray 35%, var(--bg-elevated)); }

/* Formulaire des vacances scolaires (v5.16.0), même patron que les
   contacts de mot de passe perdu mais avec un champ de plus (deux
   dates plutôt qu'un champ libre) — largeurs ajustées en conséquence. */
.admin-school-holiday-name { flex: 1 1 220px; }
.admin-school-holiday-start, .admin-school-holiday-end { flex: 0 0 160px; }

.cal-linked-notes-list { list-style: none; padding: 0; margin: 0.5rem 0; }
.cal-linked-notes-list li { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.2rem 0; font-size: 0.85rem; }

/* Récurrence des événements (v5.42.0). */
.cal-recurrence-section { margin: 0.8rem 0; padding-top: 0.6rem; border-top: 1px solid var(--border); }
.cal-recurrence-details { margin-top: 0.6rem; display: flex; flex-direction: column; gap: 0.6rem; }
/* Sans ceci, [hidden] (repli tant que "Répéter" n'est pas coché,
   v5.93.0 — signalé par l'analyse ergonomique du 26 septembre 2026)
   n'a aucun effet : une règle d'auteur (display: flex ci-dessus)
   l'emporte toujours sur la feuille de style par défaut du navigateur,
   quelle que soit la spécificité — le même piège déjà rencontré et
   corrigé pour .cal-overlays-list en v5.90.0. */
.cal-recurrence-details[hidden] { display: none; }
.cal-recurrence-row { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.cal-recurrence-interval { width: 4rem; }
.cal-recurrence-weekdays { gap: 0.6rem; }
.cal-recurrence-weekday { display: flex; align-items: center; gap: 0.2rem; font-size: 0.85rem; cursor: pointer; }
.cal-recurrence-end { display: flex; flex-direction: column; gap: 0.3rem; }
.cal-recurrence-end-row { display: flex; align-items: center; gap: 0.3rem; font-size: 0.88rem; cursor: pointer; }
.cal-recurrence-end-row input[type="date"], .cal-recurrence-end-row input[type="number"] { width: auto; }
.cal-recurrence-scope-btn { display: block; width: 100%; text-align: left; margin-top: 0.4rem; }
.cal-share-row { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.3rem 0; font-size: 0.85rem; }

/* Sélecteur de vue (v5.14.0) : Année / Mois / Semaine / Jour. */
.cal-view-switcher { display: inline-flex; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
.cal-view-btn {
    background: var(--bg-elevated); border: none; border-right: 1px solid var(--border);
    padding: 0.35rem 0.7rem; font-size: 0.85rem; cursor: pointer; color: var(--text);
}
.cal-view-btn:last-child { border-right: none; }
.cal-view-btn:hover { background: var(--bg); }
.cal-view-btn.active { background: var(--accent); color: var(--accent-contrast); }

/* Vue année : 12 mini-mois cliquables, un point sous les jours ayant au moins un événement visible. */
.cal-year-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 1rem; }
.cal-year-month { background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px; padding: 0.6rem; }
.cal-year-month-header {
    display: block; width: 100%; background: none; border: none; text-align: left;
    font-weight: 600; font-size: 0.95rem; text-transform: capitalize; cursor: pointer; color: var(--text);
    padding: 0 0 0.4rem; margin-bottom: 0.3rem; border-bottom: 1px solid var(--border);
}
.cal-year-month-header:hover { color: var(--accent); }
.cal-year-weekday-row { display: grid; grid-template-columns: repeat(7, 1fr); font-size: 0.65rem; color: var(--text-muted); text-align: center; margin-bottom: 0.2rem; }
.cal-year-mini-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
.cal-year-day {
    position: relative; background: none; border: none; font-size: 0.72rem; padding: 0.25rem 0;
    cursor: pointer; color: var(--text); border-radius: 4px;
}
.cal-year-day:hover { background: var(--bg); }
.cal-year-day-outside { opacity: 0.35; }
/* Sélecteur composé, jamais .cal-day-school-holiday seule : à
   spécificité égale (une seule classe de chaque côté), la cascade CSS
   tranche par ordre d'apparition dans le fichier — .cal-year-day (son
   propre background: none, ligne 1904) est déclarée APRÈS cette règle
   plus haut dans le fichier et l'emportait donc toujours, rendant la
   case à cocher "Vacances scolaires" sans le moindre effet visuel en
   vue Année alors qu'elle fonctionne dans toutes les autres vues.
   :not(.cal-day-today) plutôt qu'un simple ordre de déclaration
   (v5.44.0) : le jour du jour doit toujours rester visuellement
   prioritaire sur la simple teinte des vacances scolaires lorsqu'il
   en fait partie — :not() ajoute une classe à la spécificité (3 contre
   2 pour .cal-year-day.cal-day-today), une garantie qui ne dépend
   d'aucun ordre de fichier, contrairement à un correctif déjà tenté
   une première fois par simple position (v5.32.0, v5.36.0, v5.39.0,
   v5.41.0 : ce même piège de cascade CSS rencontré à répétition dans
   ce projet). */
.cal-year-day.cal-day-school-holiday:not(.cal-day-today) { background: color-mix(in srgb, gray 35%, var(--bg-elevated)); }

/* Vue Liste (v5.16.0). */
.cal-list-view { display: flex; flex-direction: column; gap: 1.5rem; }
.cal-list-section h3 { margin: 0 0 0.6rem; font-size: 1rem; }
.cal-list-day { margin-bottom: 0.8rem; }
.cal-list-day-label { font-size: 0.85rem; color: var(--text-muted); text-transform: capitalize; margin-bottom: 0.3rem; }
.cal-list-day-label.cal-day-today { color: var(--accent); font-weight: 600; }
.cal-list-item {
    display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0.4rem; border-radius: 6px; cursor: pointer;
}
.cal-list-item:hover { background: var(--bg-hover); }
.cal-list-item-time { flex: 0 0 3.5rem; font-size: 0.8rem; color: var(--text-muted); }
.cal-list-item-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Icône de confiance et pourcentage d'avancement d'une tâche (v5.20.0)
   — largeur fixe, jamais compressée par .cal-list-item-title qui
   occupe tout l'espace restant. */
.cal-list-item-task-meta { flex: 0 0 auto; font-size: 0.8rem; color: var(--text-muted); white-space: nowrap; }
.cal-list-item-holiday { color: #d95c5c; cursor: default; }
.cal-list-item-holiday:hover { background: none; }
.cal-list-empty { padding-left: 0.4rem; }
.cal-year-day.cal-day-today { background: var(--accent); color: var(--accent-contrast); font-weight: 600; }

/* Vues semaine / jour : grille horaire, heures en lignes, jours en colonnes. */
/* Jamais overflow: hidden ici (v5.83.0) — même destiné à arrondir
   proprement les coins contre la bordure, un ancêtre avec overflow
   différent de "visible" empêche position: sticky de fonctionner sur
   TOUT descendant, quelle que soit sa propre valeur : exactement ce qui
   empêchait l'en-tête (noms des jours) et la ligne "journée entière" de
   rester visibles au défilement. Les coins arrondis sont désormais
   portés directement par le premier et le dernier élément (voir
   .cal-timegrid-header ci-dessous et .cal-timegrid-body plus bas). */
.cal-timegrid { display: flex; flex-direction: column; border: 1px solid var(--border); border-radius: 6px; }
.cal-timegrid-header, .cal-timegrid-allday-row {
    display: grid; grid-template-columns: 3.5rem repeat(var(--cal-day-count, 7), 1fr);
    border-bottom: 1px solid var(--border);
    /* Figés au défilement (v5.83.0) — jamais une valeur fixe pour "top",
       la hauteur de l'en-tête général (.cal-header) variant selon la
       largeur d'écran : voir updateTimeGridStickyOffsets() côté JS, qui
       positionne chacun juste sous ce qui le précède. */
    position: sticky; z-index: 4; background: var(--bg);
}
/* Coin arrondis du haut portés directement ici (v5.83.0), .cal-timegrid
   n'ayant plus overflow: hidden pour les imposer (voir plus haut) —
   seul le PREMIER de ces deux éléments en a besoin visuellement. */
.cal-timegrid-header { border-radius: 6px 6px 0 0; }
.cal-timegrid-day-header { padding: 0.4rem; text-align: center; font-size: 0.82rem; text-transform: capitalize; border-left: 1px solid var(--border); }
.cal-timegrid-day-header.cal-day-today { color: var(--accent); font-weight: 600; }
.cal-timegrid-allday-cell { border-left: 1px solid var(--border); padding: 0.2rem; display: flex; flex-direction: column; gap: 2px; min-height: 1.6rem; }
/* Jamais un conteneur interne limité en hauteur avec sa propre barre de
   défilement (peu visible, et masque une bonne partie de la journée
   d'entrée de jeu) : la grille garde sa hauteur naturelle (24h), et
   c'est la page elle-même qui défile — l'en-tête reste collé en haut
   (voir .cal-header) pour ne jamais perdre la navigation de vue. */
.cal-timegrid-body { display: flex; position: relative; border-radius: 0 0 6px 6px; overflow: hidden; }
.cal-timegrid-hours-col { position: relative; flex: 0 0 3.5rem; }
.cal-timegrid-hour-label { position: absolute; right: 0.4rem; transform: translateY(-50%); font-size: 0.7rem; color: var(--text-muted); }
.cal-timegrid-day-col { position: relative; flex: 1; border-left: 1px solid var(--border); cursor: pointer; }
.cal-timegrid-hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border); opacity: 0.5; }
.cal-timegrid-event {
    position: absolute; color: #fff; border-radius: 4px; padding: 2px 4px; font-size: 0.72rem;
    overflow: hidden; cursor: pointer; box-sizing: border-box; border: 1px solid var(--bg-elevated);
}

@media (max-width: 780px) {
    /* 780px : LE seuil standard de bascule en mise en page mobile de
       toute l'application (voir docs/ARCHITECTURE.md, section 9) —
       auparavant 700px ici spécifiquement.
       align-items: flex-start (règle de base) est voulu en colonnes
       côte à côte (bureau) — jamais une fois flex-direction basculé en
       column ici : sans cette correction, .cal-main ne s'étire plus du
       tout sur la largeur et se réduit à son contenu le plus étroit,
       d'où une vue jour/semaine ridiculement comprimée sur mobile. */
    .cal-layout { flex-direction: column; align-items: stretch; }
    /* Téléphone (v6.42.1) : SEULE la barre de vues reste fixée (Aujourd'hui, période, Année…Liste, +) — environ 11 % de l'écran au lieu de 24 % ; le lien de retour, le titre
       et l'heure défilent avec la page. Le bloc .cal-header devient « transparent » (display: contents) : ses deux parties deviennent des enfants directs de .cal-shell, et la
       barre peut rester collée sur toute la hauteur de la page (collée DANS son parent, elle aurait lâché dès la fin du bloc). La barre se colle sous la bande de la barre
       d'état (voir .cal-page::before). Sur ordinateur, rien ne change. */
    /* Le CORPS défile, pas le document (v6.42.3). MESURÉ sur l'iPhone de l'éditeur (Safari, iOS 18.7, ?diag=1) : la marge de sécurité annoncée est NULLE (haut et bas), la zone
       de page ne fait que 714 px sur 874 et commence sous la barre d'état — mais le contenu qui défile continue d'être PEINT au-dessus de son bord, sous la barre d'état. Un élément
       fixe ne peut pas le recouvrir (Safari ne peint pas un élément fixe hors de la zone de page : la bande rouge du diagnostic n'apparaissait pas). Seule solution : que rien ne
       puisse défiler au-dessus de ce bord. Le document ne défile plus (html figé), le corps devient la zone de défilement : son contenu est COUPÉ à son bord supérieur. */
    .cal-root { height: 100%; overflow: hidden; }
    .cal-page { height: 100%; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; }
    .cal-header { display: contents; }
    .cal-header-top { margin-bottom: 0.6rem; }
    .cal-header-actions { position: sticky; top: env(safe-area-inset-top, 0px); z-index: 5; background: var(--bg); padding: 0.55rem 0; border-top: none; border-bottom: 1px solid var(--border); margin-bottom: 1rem; }
    /* Jamais sticky sur mobile (v5.93.0) — la barre latérale est ici
       EMPILÉE au-dessus de la grille (colonne unique), pas à côté :
       la figer resterait en permanence à l'écran et grignoterait la
       hauteur disponible pour la grille elle-même en dessous. */
    .cal-sidebar { flex: none; width: 100%; position: static; max-height: none; overflow-y: visible; }
    .cal-month-grid { grid-auto-rows: minmax(60px, 1fr); }
    .cal-event-chip { font-size: 0.65rem; }
    .cal-timegrid-day-header { font-size: 0.68rem; padding: 0.25rem; }
    .cal-timegrid-hours-col { flex-basis: 2.6rem; }
    .cal-timegrid-header, .cal-timegrid-allday-row { grid-template-columns: 2.6rem repeat(var(--cal-day-count, 7), 1fr); }
}

/* Affichage français des champs de date natifs (v5.92.0) — voir
   french-date-input.js pour le mécanisme complet. Le champ natif reste
   cliquable et éditable normalement (pointer-events: none sur la
   superposition, jamais sur le champ lui-même) ; seul son texte est
   rendu invisible pour laisser place au texte français superposé. */
.fr-date-wrap { position: relative; display: inline-block; }
.fr-date-wrap input[type="date"],
.fr-date-wrap input[type="datetime-local"] {
    color: transparent;
}
.fr-date-wrap input[type="date"]::-webkit-datetime-edit,
.fr-date-wrap input[type="datetime-local"]::-webkit-datetime-edit {
    color: transparent;
}
.fr-date-overlay {
    position: absolute; left: 0.7em; top: 50%; transform: translateY(-50%);
    pointer-events: none; color: var(--text); font: inherit; white-space: nowrap;
}
.fr-date-overlay.fr-date-empty { color: var(--text-muted); }

/* Menu "⋯" des actions moins fréquentes de l'éditeur (v5.94.0) — voir
   templates/app.php pour le détail de la demande. Positionné en
   superposition (jamais en ligne), pour ne jamais élargir ni faire
   déborder la barre d'outils elle-même quand il s'ouvre. */
.toolbar-more-wrap { position: relative; display: inline-flex; }
.toolbar-more-group {
    position: absolute; top: 100%; right: 0; margin-top: 0.3rem; z-index: 30;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px;
    padding: 0.3rem; display: flex; flex-direction: column; gap: 0.1rem;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25); min-width: 12rem;
}
.toolbar-more-group[hidden] { display: none; }
.toolbar-more-group button {
    justify-content: flex-start; width: 100%; gap: 0.6rem;
    padding: 0.45rem 0.6rem; border-radius: 6px; min-width: 0;
}
.toolbar-more-group button:hover { background: var(--bg-hover); }
.toolbar-more-group button span { font-size: 0.85rem; white-space: nowrap; }

/* Zone de texte principale d'un panneau d'Administration (v5.96.0) —
   signalé par l'utilisateur : un simple rows="14" laisse un vide
   important sous le bouton "Enregistrer" sur la plupart des écrans,
   la zone de saisie étant pourtant l'élément central de l'écran (le
   texte RGPD notamment peut être long). min-height plutôt qu'une
   hauteur fixe : resize:vertical (déjà en place) reste pleinement
   utilisable pour l'agrandir davantage si besoin, jamais entravé.
   width en !important (v5.97.0) — un <textarea> avec resize actif
   ignore silencieusement un width:100% posé en style EN LIGNE (même
   avec !important directement dans l'attribut HTML, qui n'y produit
   aucun effet : el.style.width reste vide une fois analysé par le
   navigateur, un comportement vérifié empiriquement plutôt que
   documenté) et retombe sur sa largeur intrinsèque par défaut
   (~180px, proche de cols="20") — un défaut resté longtemps invisible
   tant que la zone était courte, mais devenu flagrant une fois
   agrandie en hauteur par la règle ci-dessus (une colonne étroite et
   haute, signalée par l'utilisateur). Un !important posé ici, dans la
   feuille de style externe plutôt que dans l'attribut HTML, s'applique
   en revanche normalement et corrige le problème à la racine. */
.admin-fill-textarea { min-height: 55vh; width: 100% !important; }

/* Jauge de progression de l'import d'un vault (v6.02.0) — fichier
   externe, jamais un style en ligne : la CSP de l'application les
   refuse. La largeur de remplissage, elle, est posée par le script via
   l'API CSSOM (element.style.width), que la CSP autorise. */
.import-progress-title { margin: 0 0 0.8rem; font-weight: 600; overflow-wrap: anywhere; }
.import-progress-bar {
    position: relative; height: 14px; border-radius: 999px; overflow: hidden;
    background: var(--bg-hover); border: 1px solid var(--border);
}
.import-progress-fill {
    height: 100%; background: var(--accent); border-radius: 999px;
    transition: width 0.15s linear;
}
.import-progress-bar.failed .import-progress-fill { background: var(--danger); width: 100% !important; }
/* Traitement par le serveur : avancement interne inconnu du navigateur,
   d'où une barre animée plutôt qu'un pourcentage inventé. */
.import-progress-bar.indeterminate .import-progress-fill {
    width: 40% !important; transition: none;
    animation: import-progress-slide 1.2s ease-in-out infinite;
}
@keyframes import-progress-slide {
    0% { margin-left: -40%; }
    100% { margin-left: 100%; }
}
@media (prefers-reduced-motion: reduce) {
    .import-progress-bar.indeterminate .import-progress-fill { animation: none; margin-left: 30%; }
}
.import-progress-text { margin: 0.6rem 0 0.2rem; }
.import-progress-detail { margin: 0; min-height: 1.2em; }
.import-progress-error {
    margin: 0.8rem 0 0; padding: 0.6rem 0.8rem; border: 1px solid var(--danger);
    border-radius: 6px; color: var(--danger); overflow-wrap: anywhere;
}
.import-progress-error[hidden] { display: none; }

/* Transfert d'éléments entre vaults (v6.04.0) — fenêtre de choix, récapitulatif
   et sélecteur de vault de destination. Fichier externe : la CSP de
   l'application refuse tout style en ligne. */
.xfer-vault-field { margin-bottom: 0.6rem; }
.xfer-vault-select { width: 100%; max-width: 100%; }
.xfer-plan p, .xfer-result p { margin: 0 0 0.7rem; overflow-wrap: anywhere; }
.xfer-summary { font-weight: 600; }
.xfer-group {
    margin: 0 0 0.8rem; padding: 0.6rem 0.8rem; min-width: 0;
    border: 1px solid var(--border); border-radius: 8px;
}
.xfer-group legend { padding: 0 0.4rem; font-weight: 600; }
.xfer-group details { margin: 0 0 0.5rem; font-size: 0.85rem; color: var(--text-muted); }
.xfer-group summary { cursor: pointer; }
.xfer-group ul { margin: 0.3rem 0 0; padding-left: 1.2rem; max-height: 8rem; overflow-y: auto; overflow-wrap: anywhere; }
.xfer-radio { display: flex; align-items: flex-start; gap: 0.5rem; margin: 0.35rem 0; cursor: pointer; }
.xfer-radio input { margin-top: 0.25rem; flex: 0 0 auto; }
.xfer-radio.disabled { opacity: 0.5; cursor: not-allowed; }
.xfer-warning {
    padding: 0.5rem 0.7rem; border: 1px solid var(--warning, #d9a400);
    border-radius: 6px; font-size: 0.88rem; overflow-wrap: anywhere;
}
.xfer-error {
    padding: 0.6rem 0.8rem; border: 1px solid var(--danger); border-radius: 6px;
    color: var(--danger); overflow-wrap: anywhere;
}
.xfer-buttons { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1rem; }
.xfer-buttons .btn-small { margin: 0; }

/* Rôles fonctionnels (v6.05.0) — pastilles, onglet d'administration, filtre
   de listes de personnes. Fichier externe : la CSP refuse tout style en ligne. */
.role-badge {
    display: inline-block; margin: 0.1rem 0.3rem 0.1rem 0; padding: 0.05rem 0.55rem;
    border: 1px solid var(--border); border-left-width: 4px; border-radius: 999px;
    background: var(--bg-hover); color: var(--text);
    font-size: 0.78rem; line-height: 1.55; white-space: nowrap; vertical-align: middle;
}
.role-badge-rasci { font-weight: 600; }
/* Une couleur par lettre RASCI, en liseré : repérable d'un coup d'œil sans dépendre du thème. */
.role-badge-r { border-left-color: #2fb673; }
.role-badge-a { border-left-color: #e0a30d; }
.role-badge-s { border-left-color: #4c9be8; }
.role-badge-c { border-left-color: #9b7fd4; }
.role-badge-i { border-left-color: #8a8f9c; }
.admin-user-roles-cell { min-width: 9rem; }

.roles-list { margin-bottom: 1.5rem; }
.roles-group-title { margin: 1rem 0 0.4rem; font-weight: 600; color: var(--text-muted); font-size: 0.9rem; }
.roles-row {
    display: grid; grid-template-columns: minmax(12rem, 1.2fr) 2fr auto; gap: 0.4rem 1rem;
    align-items: center; padding: 0.55rem 0.8rem; margin-bottom: 0.4rem;
    border: 1px solid var(--border); border-radius: 8px;
}
.roles-row-system { background: var(--bg-hover); }
.roles-row-main { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; min-width: 0; }
.roles-row-desc { margin: 0; font-size: 0.88rem; color: var(--text-muted); overflow-wrap: anywhere; }
.roles-row-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; justify-content: flex-end; }
.roles-row-actions .btn-small { margin: 0; }
.roles-lock { font-size: 0.82rem; color: var(--text-muted); }
.roles-assign-title { margin: 1.2rem 0 0.5rem; }
.roles-assign-controls { display: flex; flex-wrap: wrap; gap: 0.8rem; align-items: flex-end; margin-bottom: 0.6rem; }
.roles-assign-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.6rem; }
.roles-assign-actions .btn-small { margin: 0; }
.roles-modal-buttons { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1rem; }
.roles-modal-buttons .btn-small { margin: 0; }
.roles-form-error {
    margin: 0.6rem 0 0; padding: 0.5rem 0.7rem; border: 1px solid var(--danger);
    border-radius: 6px; color: var(--danger); overflow-wrap: anywhere;
}
.roles-form-error[hidden] { display: none; }
@media (max-width: 780px) {
    .roles-row { grid-template-columns: 1fr; }
    .roles-row-actions { justify-content: flex-start; }
}

/* Filtre par rôle et tri ajoutés au-dessus d'une liste de personnes. */
.role-filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin: 0 0 0.5rem; }
.role-filter-select { max-width: 100%; }
.role-filter-bar .btn-small { margin: 0; }
/* display:flex/grid l'emporte sur [hidden] : piège connu de ce projet. */
[data-user-id][hidden] { display: none !important; }

/* Personnes concernées par une tâche (v6.05.0, refondu en v6.40.0) — formulaire de tâche du Kanban et des Canvas : en-tête avec le nombre, UNE liste triable et filtrable,
   ajout en dernier. Fichier externe : la CSP refuse tout style en ligne. */
.participants-editor { display: flex; flex-direction: column; gap: 0.5rem; min-width: 0; }
.participants-heading { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.2rem 0.5rem; }
.participants-count { font-weight: 700; color: var(--text); }
.participants-breakdown { font-size: 0.8rem; color: var(--text-muted); }
.participants-filters { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.participants-filter-text { flex: 1 1 11rem; min-width: 0; padding: 0.35rem 0.5rem; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 6px; font: inherit; font-size: 0.85rem; }
.participants-filter-role, .participants-add-person, .participants-add-role, .participants-role-select, .participants-sort-select {
    padding: 0.3rem 0.4rem; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 6px; font: inherit; font-size: 0.85rem; max-width: 100%;
}
.participants-sort-select { display: none; }
.participants-filter-clear[hidden] { display: none; }
.participants-list { min-width: 0; }   /* PAS d'overflow : ObsiWebTables y verrait un conteneur à défilement et le borne (défilement imbriqué dans la fenêtre) */
.participants-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.participants-th { text-align: left; padding: 0.25rem 0.4rem; border-bottom: 1px solid var(--border); white-space: nowrap; }
.participants-sort-btn { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.15rem 0.1rem; background: none; border: none; color: var(--text-muted); font: inherit; font-weight: 600; cursor: pointer; }
.participants-sort-btn:hover, .participants-sort-btn.is-active { color: var(--text); }
.participants-row { border-bottom: 1px solid var(--border); border-left: 4px solid var(--border); }
.participants-cell { padding: 0.3rem 0.4rem; vertical-align: middle; overflow-wrap: anywhere; }
.participants-cell-last { font-weight: 600; }
.participants-row-r { border-left-color: #2fb673; }
.participants-row-a { border-left-color: #e0a30d; }
.participants-row-s { border-left-color: #4c9be8; }
.participants-row-c { border-left-color: #9b7fd4; }
.participants-row-i { border-left-color: #8a8f9c; }
.participants-cell-actions { width: 1%; text-align: right; }
.participant-remove { display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; background: none; border: 1px solid transparent; border-radius: 6px; color: var(--text-muted); cursor: pointer; }
.participant-remove:hover, .participant-remove:focus-visible { color: var(--danger); border-color: var(--border); }
.participant-remove .ic { --ic-size: 14px; }
.participants-empty { margin: 0.2rem 0; }
.participants-notice { margin: 0; padding: 0.35rem 0.6rem; font-size: 0.82rem; border-left: 3px solid var(--warning); background: var(--bg-hover); border-radius: 4px; }
.participants-add { display: flex; flex-direction: column; gap: 0.35rem; padding-top: 0.5rem; border-top: 1px solid var(--border); }
.participants-add-row { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.participants-add-person { flex: 1 1 12rem; min-width: 0; }
.participants-add-hint { margin: 0; font-size: 0.78rem; }
.participants-add-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.participants-legend { font-size: 0.8rem; color: var(--text-muted); }
.participants-legend summary { cursor: pointer; }
.participants-legend-line { margin-top: 0.2rem; overflow-wrap: anywhere; }
.participants-desc { font-size: 0.74rem; color: var(--text-muted); overflow-wrap: anywhere; }
/* Téléphone : plus d'en-têtes de colonnes (un sélecteur de tri les remplace) ; chaque personne devient une petite carte — nom, prénom, puis rôle et retrait. */
@media (max-width: 780px) {
    .participants-sort-select { display: inline-block; min-height: 40px; }
    .participants-filter-text, .participants-filter-role, .participants-add-person, .participants-add-role, .participants-role-select { min-height: 40px; font-size: 16px; }
    .participants-table, .participants-table tbody { display: block; }
    .participants-table thead { display: none; }
    .participants-row { display: grid; grid-template-columns: auto 1fr auto; grid-template-areas: "last first remove" "role role remove"; gap: 0.1rem 0.5rem; padding: 0.3rem 0.4rem; align-items: center; }
    .participants-cell { padding: 0.1rem 0; display: block; }
    .participants-cell-last { grid-area: last; }
    .participants-cell-first { grid-area: first; }
    .participants-cell-role { grid-area: role; }
    .participants-cell-actions { grid-area: remove; width: auto; }
    .participant-remove { width: 40px; height: 40px; }
}
/* Responsables sur une carte de tâche : la lettre du rôle, discrète. */
.kb-resp-role {
    display: inline-block; min-width: 1.1rem; padding: 0 0.25rem; border-radius: 4px;
    background: var(--bg-hover); border: 1px solid var(--border); font-size: 0.68rem; font-weight: 700; text-align: center; color: var(--text);
}
.kb-involved-filter-row { display: flex; align-items: center; gap: 0.5rem; font-size: 0.85rem; color: var(--text-muted); }

/* « Mes rôles » du profil (v6.05.0). */
.my-roles-label { margin: 0.6rem 0 0.2rem; }
.my-roles-desc { margin: 0 0 0.3rem; font-size: 0.82rem; color: var(--text-muted); overflow-wrap: anywhere; }
.my-roles-rasci { padding: 0.4rem 0.7rem; margin: 0.5rem 0; border: 1px solid var(--border); border-left-width: 4px; border-radius: 8px; }
.my-roles-rasci-r { border-left-color: #2fb673; }
.my-roles-rasci-a { border-left-color: #e0a30d; }
.my-roles-rasci-s { border-left-color: #4c9be8; }
.my-roles-rasci-c { border-left-color: #9b7fd4; }
.my-roles-rasci-i { border-left-color: #8a8f9c; }
.my-roles-tasks { margin: 0.2rem 0 0; padding-left: 1.2rem; overflow-wrap: anywhere; }
.my-roles-tasks li { margin: 0.15rem 0; }

.directory-categories { margin: 0.15rem 0 0.2rem; }
.directory-category-filter { max-width: 100%; }
/* display:flex l'emporte sur l'attribut hidden : la barre de filtre doit pouvoir se masquer (partage d'un groupe). */
.role-filter-bar[hidden] { display: none; }

/* Canvas (v6.05.0) : poignée de redimensionnement, texte à liens, cartes-tâche. Fichier externe : la CSP refuse tout style en ligne. */
/* L'ancien `resize: both` (poignée native, taille jamais enregistrée, absente sur mobile) est remplacé par .canvas-resize-handle. */
.canvas-card { resize: none; }
.canvas-card.task-card { min-width: 200px; min-height: 120px; border-color: #2fb673; }
.canvas-resize-handle {
    position: absolute; right: 0; bottom: 0; width: 22px; height: 22px; z-index: 3;
    display: flex; align-items: flex-end; justify-content: flex-end; padding: 0 3px 1px 0;
    cursor: nwse-resize; touch-action: none; user-select: none;
    font-size: 0.8rem; line-height: 1; color: var(--text-muted); opacity: 0.8;
}
.canvas-resize-handle:hover { opacity: 1; color: var(--text); }
@media (pointer: coarse) { .canvas-resize-handle { width: 34px; height: 34px; font-size: 1.1rem; } }
.canvas-text-body { flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative; }
.canvas-text-view {
    flex: 1; min-height: 0; overflow: auto; padding: 0.5rem; font-size: 0.85rem; cursor: text;
    color: var(--text); overflow-wrap: anywhere; outline-offset: -2px;
}
.canvas-text-empty { color: var(--text-muted); font-style: italic; }
.canvas-text-body textarea { display: none; flex: 1; min-height: 0; width: 100%; box-sizing: border-box; }
.canvas-text-body.canvas-text-editing textarea { display: block; }
.canvas-text-body.canvas-text-editing .canvas-text-view { display: none; }
.canvas-text-tools { display: none; padding: 0 0.4rem 0.3rem; }
.canvas-text-body.canvas-text-editing .canvas-text-tools { display: block; }
.canvas-text-linkbtn {
    border: 1px solid var(--border); background: var(--bg-hover); color: var(--text); border-radius: 6px;
    font-size: 0.75rem; padding: 0.15rem 0.5rem; cursor: pointer; min-height: 1.6rem;
}
.canvas-link { text-decoration: none; border-bottom: 1px solid currentColor; }
.canvas-link-note, .canvas-link-task { color: var(--accent); cursor: pointer; }
.canvas-link.broken-link { color: var(--danger); border-bottom-style: dashed; cursor: help; }
.canvas-link-suggest {
    position: fixed; z-index: 2000; width: 290px; max-height: 180px; overflow: auto;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 4px 14px rgba(0,0,0,0.3);
}
.canvas-link-suggest[hidden] { display: none; }
.canvas-link-suggest-item { padding: 0.35rem 0.6rem; cursor: pointer; font-size: 0.85rem; overflow-wrap: anywhere; }
.canvas-link-suggest-item.active, .canvas-link-suggest-item:hover { background: var(--bg-hover); }
.canvas-link-suggest-hint { color: var(--text-muted); font-size: 0.75rem; }
.canvas-task-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 0.4rem 0.6rem; overflow: auto; gap: 0.15rem; }
.canvas-task-body { display: flex; flex-direction: column; gap: 0.15rem; }
.canvas-task-title { margin: 0; font-weight: 600; font-size: 0.9rem; overflow-wrap: anywhere; }
.canvas-task-line { margin: 0; font-size: 0.78rem; overflow-wrap: anywhere; }
.canvas-task-overdue { color: var(--danger); font-weight: 600; }
.canvas-task-unavailable { opacity: 0.7; }
.canvas-task-progress { display: block; margin: 0.2rem 0; }
.canvas-task-open { margin-top: auto; font-size: 0.78rem; color: var(--accent); padding-right: 1.6rem; }
.canvas-task-tabs { display: flex; gap: 0.5rem; margin-bottom: 0.8rem; }
.canvas-task-tabs .btn-small { margin: 0; }
.canvas-task-pick { display: flex; justify-content: space-between; gap: 0.6rem; }

/* Fenêtre « + Tâche » d'un Canvas : champs aux couleurs du thème (le fond blanc par défaut détonnait en thème sombre). */
.canvas-task-dialog textarea, .canvas-task-dialog input[type="text"], .canvas-task-dialog input[type="search"] {
    width: 100%; box-sizing: border-box; background: var(--bg); color: var(--text);
    border: 1px solid var(--border); border-radius: 6px; padding: 0.4rem 0.6rem; font: inherit;
}
.canvas-task-dialog input[type="date"] { background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 6px; padding: 0.35rem 0.5rem; font: inherit; max-width: 100%; }

/* Écran « Vaults » (v6.06.0) : liste triable et filtrable, description sous le nom en gras, menu contextuel.
   Fichier externe : la CSP refuse tout style en ligne. */
.vaults-manager { display: flex; flex-direction: column; gap: 0.5rem; }
.vaults-toolbar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.vaults-toolbar input[type="search"] {
    flex: 1 1 14rem; min-width: 0; background: var(--bg); color: var(--text); border: 1px solid var(--border);
    border-radius: 6px; padding: 0.4rem 0.6rem; font: inherit;
}
.vaults-toolbar select { background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 6px; padding: 0.35rem 0.5rem; font: inherit; max-width: 100%; }
.vaults-sort-wrap { display: none; gap: 0.4rem; align-items: center; }
.vaults-summary { margin: 0; }
.vaults-list-box { overflow-x: auto; }
.vaults-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.vaults-table th, .vaults-table td { padding: 0.5rem 0.55rem; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
.vaults-table .vaults-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.vaults-sort-btn {
    background: none; border: none; color: var(--text-muted); font: inherit; font-weight: 600; cursor: pointer;
    padding: 0.2rem 0; white-space: nowrap;
}
.vaults-sort-btn:hover, .vaults-sort-btn.active { color: var(--text); }
.vaults-row:hover { background: var(--bg-hover); }
.vaults-name-cell { min-width: 12rem; }
.vault-name { font-weight: 700; overflow-wrap: anywhere; }
.vault-desc { margin-top: 0.15rem; color: var(--text); font-size: 0.85rem; overflow-wrap: anywhere; }
.vault-sub { margin-top: 0.1rem; color: var(--text-muted); font-size: 0.78rem; }
.vault-badge { display: inline-block; padding: 0 0.4rem; border-radius: 999px; font-size: 0.7rem; font-weight: 600; border: 1px solid var(--border); background: var(--bg-hover); color: var(--text-muted); vertical-align: middle; }
.vault-badge-inherited { color: var(--inherited); border-color: var(--inherited); }
.vault-badge-public { color: var(--success); border-color: var(--success); }
.vaults-menu-col { width: 3rem; text-align: right; }
.vault-menu-btn {
    min-width: 2.5rem; min-height: 2.5rem; border: 1px solid var(--border); background: var(--bg-hover);
    color: var(--text); border-radius: 6px; font-size: 1.1rem; line-height: 1; cursor: pointer;
}
.vault-menu-btn:hover { background: var(--border); }
.vaults-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.vault-form-counter { margin: 0.2rem 0 0; text-align: right; }
.vault-form-counter-over { color: var(--danger); font-weight: 600; }
.account-vaults-summary { margin: 0.2rem 0 0.5rem; }
/* Fenêtre « Infos » */
.vault-info-title { margin: 1rem 0 0.3rem; font-size: 0.95rem; }
.vault-info-description { margin: 0 0 0.4rem; font-style: italic; overflow-wrap: anywhere; }
.vault-info-list { display: grid; grid-template-columns: minmax(9rem, 13rem) 1fr; gap: 0.25rem 0.9rem; margin: 0; }
.vault-info-list dt { color: var(--text-muted); }
.vault-info-list dd { margin: 0; overflow-wrap: anywhere; }
.vault-info-shares { margin: 0.2rem 0 0; padding-left: 1.2rem; }
.vault-info-foot { display: flex; justify-content: space-between; align-items: center; gap: 0.6rem; margin-top: 1rem; flex-wrap: wrap; }
/* Mobile : le tableau devient une liste de fiches, le tri passe par le sélecteur. Chaque fiche est une grille : le nom (avec description
   et pastilles) à gauche, le bouton ⋯ À SA DROITE DANS LE FLUX — il ne se superpose plus jamais au contenu, quelle que soit la
   longueur du nom ou de la description. Les détails sont repliés par défaut ; « ▸ Détails » les déplie fiche par fiche. */
.vaults-details-cell { display: none; }
.vaults-toggle-all { display: none; }
@media (max-width: 780px) {
    .vaults-sort-wrap { display: flex; }
    .vaults-toggle-all:not([hidden]) { display: inline-flex; }
    .vaults-table thead { display: none; }
    .vaults-table, .vaults-table tbody { display: block; width: 100%; box-sizing: border-box; }
    .vaults-table tr {
        display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 0.5rem; align-items: start;
        border: 1px solid var(--border); border-radius: 8px; padding: 0.5rem 0.6rem; margin-bottom: 0.6rem; box-sizing: border-box;
    }
    .vaults-table td { border-bottom: none; padding: 0.15rem 0; min-width: 0; }
    .vaults-table td.vaults-name-cell { grid-column: 1; grid-row: 1; padding-right: 0; }
    .vaults-table td.vaults-menu-col { grid-column: 2; grid-row: 1; width: auto; padding: 0; text-align: right; }
    .vaults-table td.vaults-details-cell { display: block; grid-column: 1 / -1; padding-top: 0.2rem; }
    .vaults-details-btn {
        background: none; border: none; color: var(--accent); font: inherit; font-size: 0.85rem; font-weight: 600; cursor: pointer;
        padding: 0.45rem 0; min-height: 2.5rem; width: 100%; text-align: left;
    }
    .vaults-table td[data-label] { grid-column: 1 / -1; display: flex; justify-content: space-between; gap: 0.6rem; font-size: 0.82rem; }
    .vaults-table tr:not(.vaults-expanded) td[data-label] { display: none; }
    .vaults-table td[data-label]::before { content: attr(data-label); color: var(--text-muted); }
    .vaults-table .vaults-num { text-align: left; }
    .vault-info-list { grid-template-columns: 1fr; gap: 0.05rem; }
    .vault-info-list dd { margin-bottom: 0.4rem; }
}

/* ===================== Jeux d'icônes (v6.07.0) =====================
   Une icône est un <span class="ic" data-icon="fonction"> (voir assets/js/shared-icons.js et
   src/Icons/IconSets.php). Elle hérite de la couleur du texte (donc de tous les thèmes) et sa taille vient de la
   variable --ic-size, réglée par zone : trois tailles seulement (menu 18, barre 22, mobile 24 px). */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.ic { display: inline-flex; align-items: center; justify-content: center; flex: none; line-height: 1; }
.ic-svg { display: block; width: var(--ic-size, 1.2em); height: var(--ic-size, 1.2em); }
.ic-empty { display: none; }
/* Libellés sous les icônes : « auto » = sur mobile seulement ; « on » = toujours ; « off » = jamais. */
.ic-label { display: none; font-size: 0.68rem; line-height: 1.1; color: var(--text-muted); white-space: nowrap; }
html[data-icon-labels="on"] .ic-label { display: block; }
@media (max-width: 780px) { html[data-icon-labels="auto"] .ic-label { display: block; } }
/* Icônes rapides de l'en-tête de la barre latérale */
.sidebar-header-actions .icon-btn { --ic-size: 22px; position: relative; flex-direction: column; gap: 2px; min-width: 40px; min-height: 40px; }
.sidebar-header-actions .icon-btn .ic-label { margin-top: 1px; }
.vault-switcher .icon-btn { --ic-size: 20px; }
.sidebar-actions .btn-small { --ic-size: 18px; }
.sidebar-actions .btn-small .ic { vertical-align: middle; }
.sidebar-footer-row .btn-small { --ic-size: 18px; display: inline-flex; align-items: center; gap: 0.35rem; }
/* Menus déroulants : une icône à gauche du libellé */
.dropdown-menu-item.has-icon { display: flex; align-items: center; gap: 0.6rem; --ic-size: 18px; }
.dropdown-menu-item.has-icon .ic { color: var(--text-muted); }
.dropdown-menu-item.has-icon:hover .ic { color: var(--text); }
.dropdown-menu-text { flex: 1; min-width: 0; }
/* Arborescence */
.tree-label .ic { --ic-size: 16px; margin-right: 0.15rem; }
.tree-menu-btn .ic { --ic-size: 18px; }
.maturity-badge .ic { --ic-size: 14px; }
/* Cibles tactiles d'au moins 44 × 44 px sur mobile (recommandation WCAG 2.5.5) */
@media (hover: none), (pointer: coarse), (max-width: 780px) {
    .sidebar-header-actions .icon-btn { min-width: 44px; min-height: 44px; --ic-size: 24px; }
    .vault-switcher .icon-btn { min-width: 44px; min-height: 44px; --ic-size: 22px; }
    .dropdown-menu-item { min-height: 44px; }
    .tree-menu-btn { min-width: 44px; min-height: 44px; }
}

.sidebar-actions .btn-icon-only .ic-svg { color: var(--accent, #6d8dff); }

/* Statut actif d'un menu à choix (maturité…) : icône de coche à droite (jeu d'icônes actif, ajoutée par openDropdownMenu). */
.dropdown-menu-item.is-current { font-weight: 600; }
.dropdown-menu-item .menu-current-mark { display: inline-flex; margin-left: auto; padding-left: 0.6rem; color: var(--accent); }
.dropdown-menu-item .menu-current-mark .ic { --ic-size: 16px; }

.account-icon-preview { display: flex; gap: 0.9rem; align-items: center; margin: 0.2rem 0 0.8rem; color: var(--text-muted); --ic-size: 22px; flex-wrap: wrap; }

/* ===================== Éditeur : barre d'outils vectorielle (v6.08.0) =====================
   Les anciens PNG portaient leur propre habillage (carré arrondi, couleur active/inactive). Une icône vectorielle n'a que
   la couleur du texte : le bouton fournit donc ici l'habillage — sauf en affichage sans icônes. */
html:not([data-icon-fallback]) .toolbar-actions .btn-icon-only,
html:not([data-icon-fallback]) .toolbar-actions .mode-btn {
    --ic-size: 22px; display: inline-flex; align-items: center; justify-content: center;
    min-width: 40px; min-height: 40px; padding: 0.25rem; border: none; border-radius: 8px;
    background: transparent; color: var(--text-muted); cursor: pointer;
}
html:not([data-icon-fallback]) .toolbar-actions .btn-icon-only:hover,
html:not([data-icon-fallback]) .toolbar-actions .mode-btn:hover { background: var(--bg-hover); color: var(--text); }
html:not([data-icon-fallback]) .toolbar-actions .is-active,
html:not([data-icon-fallback]) .toolbar-actions .mode-btn.active { color: var(--accent); background: var(--bg-hover); }
html:not([data-icon-fallback]) .toolbar-actions .mode-switch { gap: 0; }
/* Enregistrer : discret tant que rien n'est à enregistrer, bien visible dès qu'une modification attend */
html:not([data-icon-fallback]) #save-btn:disabled { opacity: 0.45; cursor: default; }
html:not([data-icon-fallback]) #save-btn.is-dirty { background: var(--accent); color: var(--accent-contrast); }
html:not([data-icon-fallback]) #save-btn.is-dirty:hover { background: var(--accent); filter: brightness(1.1); }
.toolbar-more-group .btn-icon-only .ic { --ic-size: 20px; }
html:not([data-icon-fallback]) .toolbar-more-group .btn-icon-only { width: 100%; justify-content: flex-start; gap: 0.5rem; }
.mobile-menu-btn .ic { --ic-size: 24px; }
#modal-close .ic { --ic-size: 20px; }
.readonly-banner .ic { --ic-size: 16px; vertical-align: -3px; margin-right: 0.2rem; }
.backlinks-toggle .ic { vertical-align: middle; --ic-size: 16px; }
.btn-small .ic { vertical-align: middle; }
.backlinks-toggle { display: inline-flex; align-items: center; gap: 0.3rem; }
@media (hover: none), (pointer: coarse), (max-width: 780px) {
    html:not([data-icon-fallback]) .toolbar-actions .btn-icon-only,
    html:not([data-icon-fallback]) .toolbar-actions .mode-btn { min-width: 36px; min-height: 44px; padding: 0.2rem; }
    /* La barre d'outils compte 9 boutons sur une seule ligne de 390 px : 36 px de large (au-delà du minimum de 24 px de
       WCAG 2.5.8) mais 44 px de haut ; l'en-tête, les menus et les entrées de la barre latérale gardent 44 × 44 px. */
    .mobile-menu-btn { min-width: 36px; min-height: 44px; }
    html:not([data-icon-fallback]) .toolbar-actions { gap: 0.1rem; }
    html:not([data-icon-fallback]) .editor-toolbar { gap: 0.25rem; }
}

.fmt-btn .ic { --ic-size: 16px; vertical-align: middle; margin-right: 0.15rem; }
#find-prev-btn .ic, #find-next-btn .ic, #find-close-btn .ic { --ic-size: 16px; }

/* ===================== Kanban et Agenda (v6.09.0) ===================== */
.btn-small { --ic-size: 16px; }
.admin-back .ic, h1 .ic { vertical-align: middle; }
h1 .ic { --ic-size: 1.1em; margin-right: 0.15rem; }
.kb-task-assignee .ic, .kb-task-due .ic, .kb-task-notes-count .ic, .kb-assigned-task-due .ic { --ic-size: 14px; vertical-align: -2px; margin-right: 0.1rem; }
.kb-task-handle .ic { --ic-size: 16px; }
.kb-task-move-up .ic, .kb-task-move-down .ic, .kb-col-move-up .ic, .kb-col-move-down .ic { --ic-size: 14px; }
.kb-task-handle { display: inline-flex; align-items: center; }
.cal-collapse-arrow .ic { --ic-size: 1.2em; }
.cal-agenda-name .ic, .cal-list-item .ic, .cal-holiday-chip .ic, .cal-event-chip .ic { --ic-size: 13px; vertical-align: -2px; margin-right: 0.1rem; }
.cal-agenda-menu-btn .ic, .cal-icon-btn .ic { --ic-size: 18px; }
#cal-prev-btn .ic, #cal-next-btn .ic { --ic-size: 18px; }
.modal-close .ic { --ic-size: 20px; }
/* Espace entre l'icône et le libellé d'un bouton (certains conteneurs flex suppriment l'espace du texte) — jeux vectoriels seulement. */
html:not([data-icon-fallback]) .btn-small > .ic:not(:only-child) { margin-right: 0.3rem; }

.kb-task-weather .ic { --ic-size: 18px; }
.kb-weather-select-row { display: inline-flex; align-items: center; gap: 0.5rem; }
.kb-weather-preview { display: inline-flex; min-width: 22px; --ic-size: 22px; color: var(--text-muted); }
.cal-list-item-task-meta .ic { --ic-size: 14px; vertical-align: -2px; }
/* Fermeture des fenêtres (Kanban, Agenda) : habillage discret comme sur la page principale — jeux vectoriels seulement. */
html:not([data-icon-fallback]) .modal-close { background: none; border: none; color: var(--text-muted); cursor: pointer; border-radius: 8px; min-width: 40px; min-height: 40px; display: inline-flex; align-items: center; justify-content: center; }
html:not([data-icon-fallback]) .modal-close:hover { background: var(--bg-hover); color: var(--text); }

/* ===================== Administration (v6.11.0) ===================== */
.admin-tab .ic { --ic-size: 18px; margin-right: 0.45rem; vertical-align: -4px; }
h2 .ic { --ic-size: 1.1em; vertical-align: -0.2em; margin-right: 0.25rem; }
.admin-table .ic, .tree-label .ic, .tree-empty .ic, .admin-panel .ic { vertical-align: -3px; }
.admin-table .ic, .tree-empty .ic { --ic-size: 14px; }
.admin-subtitle .ic { --ic-size: 1em; }
#admin-sidebar-toggle .ic { --ic-size: 20px; }
.btn-icon .ic { --ic-size: 16px; }
.admin-warning .ic, .admin-danger .ic { --ic-size: 16px; }

/* ===================== Fenêtres de contenu : messagerie, palette, sélecteurs, Canvas (v6.12.0) ===================== */
.modal-header h2 .ic, #modal-title .ic { --ic-size: 1.1em; vertical-align: -0.2em; }
.filterable-list-row .ic, .modal-list-item .ic { --ic-size: 16px; vertical-align: -3px; }
.callout-suggest-item .ic { --ic-size: 16px; vertical-align: -3px; }
.global-search-result-title .ic { --ic-size: 15px; vertical-align: -3px; }
.conversation-list-row .ic, .inbox-modal-box .ic { --ic-size: 15px; vertical-align: -3px; }
.canvas-drag-zone .ic, .canvas-task-line .ic, .canvas-task-wrap .ic { --ic-size: 14px; vertical-align: -2px; }
.canvas-suggest-item .ic, .canvas-suggest .ic { --ic-size: 15px; vertical-align: -3px; }
.attachment-picker-icon .ic { --ic-size: 28px; }
html:not([data-icon-fallback]) .ic[data-icon="unread-dot"] { color: var(--danger); --ic-size: 10px; }
html:not([data-icon-fallback]) .ic[data-icon="unread-dot"] svg { fill: currentColor; }

/* ===================== Images, corbeille, transferts, dossiers, vaults (v6.13.0) ===================== */
.trash-item-info .ic, .trash-item-meta .ic { --ic-size: 15px; vertical-align: -3px; }
.image-lightbox-close .ic, .canvas-card-close .ic, .canvas-close .ic { --ic-size: 18px; }
.canvas-connector .ic { --ic-size: 14px; }
.canvas-link .ic, .canvas-card-body .ic { --ic-size: 14px; vertical-align: -2px; }
.transfer-plan .ic, .modal-body li .ic { --ic-size: 14px; vertical-align: -2px; }
#modal-body p .ic, #modal-body strong .ic { --ic-size: 16px; vertical-align: -3px; }
.vault-share-status .ic { --ic-size: 16px; vertical-align: -3px; }
.directory-entry .ic { --ic-size: 15px; vertical-align: -3px; }
/* En-tête d'une carte de Canvas : l'icône (fermeture, connecteur) ne doit pas agrandir l'en-tête — la vue texte garde sa hauteur d'origine (jeux vectoriels seulement). */
html:not([data-icon-fallback]) .canvas-card-header .ic { --ic-size: 12px; vertical-align: middle; }
html:not([data-icon-fallback]) .canvas-card-header button { line-height: 1; padding-top: 0; padding-bottom: 0; display: inline-flex; align-items: center; }

/* ===================== Pages autonomes (v6.14.0) ===================== */
.password-toggle-btn .ic { --ic-size: 18px; vertical-align: middle; }
.login-help-link .ic, .guide-topbar .ic, .login-page a .ic, .login-page .btn-small .ic { --ic-size: 16px; vertical-align: -3px; }
.attachment-view-toolbar .ic { --ic-size: 16px; vertical-align: -3px; }
.attachment-view-toolbar .btn-small { display: inline-flex; align-items: center; gap: 0.3rem; }

/* ===================== Fenêtres sur mobile (v6.14.1) =====================
   Audit automatique de toutes les fenêtres en émulation mobile (390 × 800 et 360 × 640) : champs de 21 px de haut en police de
   13 px (iOS zoome au focus), rangées de cases à cocher de 19 px, fenêtre de messagerie de 560 px sur un écran de 390 px.
   Deux couches : valeurs par défaut « douces » pour l'apparence (:where, spécificité nulle : jamais au détriment d'un style
   existant) ; taille de police et hauteur STRICTES, car c'est ce qui compte au toucher. */
@media (hover: none), (pointer: coarse), (max-width: 780px) {
    :where(.modal-box) :where(input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]), select, textarea) {
        background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: 0.5rem 0.65rem; box-sizing: border-box; max-width: 100%;
    }
    .modal-box input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]),
    .modal-box select, .modal-box textarea { font-size: 16px; min-height: 44px; }
    .modal-box textarea { min-height: 96px; line-height: 1.4; }
    .modal-box input[type="file"] { font-size: 16px; min-height: 44px; padding: 0.55rem 0; max-width: 100%; }
    .modal-box input[type="color"] { min-width: 56px; min-height: 44px; padding: 2px; }
    .modal-box input[type="range"] { width: 100%; min-height: 32px; }
    .modal-box input[type="checkbox"], .modal-box input[type="radio"] { width: 22px; height: 22px; flex: none; }
    /* Rangées « case + libellé » : toute la rangée est la cible tactile */
    .modal-box label.admin-checkbox-field, .modal-box label.admin-checkbox-row, .modal-box label.cal-overlay-row, .modal-box label.cal-agenda-row,
    .modal-box label:has(> input[type="checkbox"]), .modal-box label:has(> input[type="radio"]) {
        display: flex; align-items: center; gap: 0.6rem; min-height: 44px;
    }
    /* Fenêtres de messagerie (Mes messages, Conversations, Annonces, Mes diffusions) : plus de largeur minimale de 560 px */
    .modal-box.inbox-modal-box { min-width: 0; width: 100%; max-width: 100vw; height: 92vh; max-height: 92vh; min-height: 0; resize: none; }
    .modal-box.inbox-modal-box .inbox-table-scroll { overflow: auto; -webkit-overflow-scrolling: touch; }
    .modal-box.inbox-modal-box .inbox-table-scroll table { min-width: 540px; }
    .modal-box.inbox-modal-box .inbox-toolbar { gap: 0.5rem; }
    .modal-box.inbox-modal-box .inbox-toolbar > * { flex: 1 1 140px; min-width: 0; }
    /* Annuaire : la barre d'outils passe à la ligne, le filtre prend toute la largeur */
    .directory-toolbar-row { flex-wrap: wrap; }
    .directory-toolbar-row .modal-filter-input { flex: 1 1 100%; min-width: 0; }
    .directory-toolbar-row select, .role-filter-select { max-width: 100%; }
    /* Mes images : filtres sur plusieurs lignes */
    .my-images-toolbar { flex-wrap: wrap; gap: 0.5rem; }
    .my-images-search { flex: 1 1 100%; min-width: 0; }
    .my-images-toolbar select { flex: 1 1 40%; min-width: 0; }
}
@media (hover: none), (pointer: coarse), (max-width: 780px) {
    /* Graphe des tâches et colonnes du Kanban : commandes à la taille d'un doigt */
    .graph-zoom-controls button { width: 44px; height: 44px; }
    .kb-col-move-up, .kb-col-move-down { min-width: 44px; min-height: 44px; }
}
@media (hover: none), (pointer: coarse), (max-width: 780px) {
    /* Cibles tactiles restantes */
    .modal-box .btn-icon-danger { min-width: 44px; min-height: 44px; }
    .modal-box table input[type="checkbox"], .modal-box input[type="checkbox"].my-images-checkbox { width: 28px; height: 28px; }
    .attachment-usage-link { padding: 0.65rem 0; }
    /* Quand c'est TOUTE la boîte qui défile, le titre et le bouton de fermeture disparaissaient dès qu'on descendait :
       l'en-tête reste fixe et seul le corps défile (« Mon compte », fenêtres de messagerie). */
    .modal-box.account-modal-box { overflow: hidden; }
    .modal-box.account-modal-box .modal-body { overflow-y: auto; min-height: 0; flex: 1 1 auto; }
    .modal-box.inbox-modal-box { overflow: hidden; }
    .modal-box.inbox-modal-box .modal-body { overflow-y: auto; min-height: 0; }
}
@media (hover: none), (pointer: coarse), (max-width: 780px) {
    /* Pages autonomes (connexion, inscription, mot de passe oublié, changement de mot de passe, profil) : sans cela, iOS zoomait la page
       dès qu'on touchait l'identifiant (police de 13 px). Liens d'aide à la taille d'un doigt. */
    .login-page input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]), .login-page select, .login-page textarea { font-size: 16px; min-height: 44px; }
    .login-help-link { display: inline-block; padding: 0.7rem 0.4rem; }
}

/* Bouton œil du mot de passe sur les pages de connexion : il recevait les styles du bouton « Se connecter » (fond plein et marge haute
   de 1,2 rem), donc il apparaissait décalé sous le champ. Et les liens sans classe dans les fenêtres gardaient le bleu par défaut du
   navigateur, illisible sur fond sombre. */
.login-card .password-toggle-btn { margin-top: 0; background: none; color: var(--text-muted); padding: 0.2rem; border-radius: 6px; }
.login-card .password-toggle-btn:hover { color: var(--text); }
.modal-box a:not([class]) { color: var(--accent); }

/* Icône d'un callout (SVG intégré par SafeMarkdown, v6.15.0) */
.callout-svg { width: 1.1em; height: 1.1em; vertical-align: -0.18em; flex: none; }

/* Affichage SANS icônes (sprite introuvable, v6.15.0) : les emplacements d'icônes sont masqués, les textes et libellés restent. Aucun émoji de remplacement. */
html[data-icon-fallback] .ic { display: none; }
html[data-icon-fallback] .ic-label { display: inline; }

.attachment-svg { width: 1em; height: 1em; vertical-align: -0.15em; }

/* ===== Page de guide (guide.php) — v6.16.0 =====
   Ces règles étaient dans un bloc <style> en ligne de la page : la politique de sécurité (default-src 'self') le bloquait, donc elles ne
   s'appliquaient jamais (bandeau non fixé, colonne non centrée, liens en bleu foncé sur fond sombre). Elles sont ici, dans la feuille externe. */
.guide-page { background: var(--bg); margin: 0; }
.guide-topbar {
    position: sticky; top: 0; z-index: 5; display: flex; align-items: center; justify-content: space-between;
    padding: 0.7rem 1.2rem; background: var(--bg-elevated); border-bottom: 1px solid var(--border);
}
.guide-topbar a { color: var(--accent); text-decoration: none; font-size: 0.9rem; }
.guide-topbar a:hover { text-decoration: underline; }
.guide-wrap { max-width: 860px; margin: 0 auto; padding: 1.5rem 1.6rem 4rem; }
.guide-wrap :is(h1, h2, h3) { scroll-margin-top: 4.5rem; }
.guide-wrap a { color: var(--accent); }
.guide-wrap .ic { --ic-size: 1.05em; vertical-align: -0.2em; margin-inline-end: 0.15em; }
.guide-wrap h1 { margin-top: 2.2rem; padding-top: 0.6rem; border-top: 2px solid var(--border); }
.guide-wrap > h1:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

.guide-topbar-links { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.4rem 1.3rem; }

/* ===== Pastille de défilement rapide (v6.18.0) =====
   Apparaît pendant le défilement d'une note longue (ou d'un guide), propose « début » / « fin », s'efface seule. Sous les fenêtres (50), le tiroir mobile (40) et son voile (35). */
.scroll-pill {
    position: fixed; z-index: 30; display: flex; flex-direction: column; gap: 2px; padding: 3px;
    background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 999px; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
    opacity: 0; transition: opacity 0.18s ease; pointer-events: none;
}
.scroll-pill.is-visible { opacity: 1; pointer-events: auto; }
.scroll-pill[hidden], .scroll-pill-btn[hidden] { display: none; }
.scroll-pill-btn {
    width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--text);
    display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.scroll-pill-btn .ic { --ic-size: 20px; }
.scroll-pill-btn:hover, .scroll-pill-btn:focus-visible { background: var(--bg-hover); color: var(--accent); outline: none; }
@media (hover: none), (pointer: coarse), (max-width: 780px) { .scroll-pill-btn { width: 44px; height: 44px; } }
@media (prefers-reduced-motion: reduce) { .scroll-pill { transition: none; } }
html[data-scroll-pill="off"] .scroll-pill { display: none !important; }

/* ----- Indicateur de position de la pastille (v6.19.0) : six styles, aux couleurs du thème ----- */
.scroll-pill-ind { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 30px; padding: 3px 0; color: var(--text); font-variant-numeric: tabular-nums; }
.scroll-pill-ind[hidden] { display: none; }
.spi-track { position: relative; width: 6px; height: 64px; border-radius: 3px; background: var(--border); background: color-mix(in srgb, var(--text) 28%, transparent); }
.spi-thumb { position: absolute; left: 0; width: 6px; border-radius: 3px; background: var(--accent); }
.spi-num { font-size: 13px; font-weight: 600; line-height: 1.1; white-space: nowrap; }
.spi-num-sm { font-size: 12px; margin-top: 3px; }
.spi-ring-bg { stroke: var(--border); stroke: color-mix(in srgb, var(--text) 28%, transparent); }
.spi-ring-fg { stroke: var(--accent); }
.spi-ring-txt { font-size: 12px; font-weight: 600; fill: var(--text); }
.spi-page { position: relative; box-sizing: border-box; width: 26px; height: 36px; border: 1.5px solid var(--text-muted); border-radius: 4px; }
.spi-band { position: absolute; left: 2px; right: 2px; border-radius: 2px; background: var(--accent); }
.spi-scr-n { font-size: 17px; font-weight: 600; line-height: 1; }
.spi-scr-of { font-size: 11px; color: var(--text-muted); margin-top: 2px; white-space: nowrap; }

/* ===== Tableaux (v6.20.0) — voir assets/js/shared-tables.js et docs/TABLES.md =====
   En-tête fixe pendant le défilement ; colonnes triables repérables (⇅ au repos, ▲ ▼ sur la colonne triée) ; conteneur borné quand il le faut. */
.data-table thead th { position: sticky; top: 0; z-index: 3; background: var(--bg-elevated); box-shadow: inset 0 -1px 0 var(--border); }
.table-scroll { overflow: auto; }
.data-table th.is-sortable { cursor: pointer; user-select: none; white-space: nowrap; }
.data-table th.is-sortable:hover { color: var(--accent); background: var(--bg-hover); }
.data-table th.is-sortable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.data-table th.is-sortable.is-sorted, .data-table th.is-sortable[aria-sort="ascending"], .data-table th.is-sortable[aria-sort="descending"] { color: var(--accent); }
/* Indicateur de tri (v6.33.0) : trois icônes du jeu actif ajoutées par shared-tables.js, une seule visible selon aria-sort. */
.data-table .sort-ind { display: inline-flex; vertical-align: -3px; margin-left: 0.4em; opacity: 0.4; transition: opacity 0.12s; }
.data-table .sort-ind > span { display: none; }
.data-table .sort-ind .ic { --ic-size: 14px; }
.data-table th[aria-sort="none"] .sort-ind-none, .data-table th[aria-sort="ascending"] .sort-ind-asc, .data-table th[aria-sort="descending"] .sort-ind-desc { display: inline-flex; }
.data-table th.is-sortable:hover .sort-ind { opacity: 0.9; }
.data-table th[aria-sort="ascending"] .sort-ind, .data-table th[aria-sort="descending"] .sort-ind { opacity: 1; }
.data-table th.has-sort-button > button { color: inherit; }
.data-table th.vaults-num.is-sortable { text-align: right; }
@media (prefers-reduced-motion: reduce) { .data-table .sort-ind { transition: none; } }

/* ===== Configuration : sections repliables (v6.21.0) — voir docs/SECTIONS.md =====
   Chaque thème est une section <details> repliée au départ ; barre d'outils (tout déplier, tout replier, enregistrer) fixe sur ordinateur. */
.config-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem; margin: 0 0 1rem; padding: 0.6rem 0; background: var(--bg); border-bottom: 1px solid var(--border); }
@media (min-width: 781px) { .config-toolbar { position: sticky; top: 0; z-index: 4; } }
.config-toolbar-group { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.config-collapsible { border: 1px solid var(--border); border-radius: 10px; background: var(--bg-elevated); margin: 0 0 0.55rem; }
.config-collapsible > summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; gap: 0.7rem; padding: 0.7rem 0.95rem; user-select: none; border-radius: 10px; }
.config-collapsible > summary::-webkit-details-marker { display: none; }
.config-collapsible > summary .section-chevron { flex: 0 0 auto; display: inline-flex; align-self: center; width: 1em; color: var(--text-muted); transition: transform 0.12s; }
.config-collapsible[open] > summary { border-bottom: 1px solid var(--border); border-radius: 10px 10px 0 0; }
.config-collapsible[open] > summary .section-chevron { transform: rotate(90deg); color: var(--accent); }
.config-collapsible > summary:hover { background: var(--bg-hover); }
.config-collapsible > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.config-sec-title { font-weight: 600; }
.config-sec-hint { flex: 1 1 auto; color: var(--text-muted); font-size: 0.85rem; }
.config-dirty { display: none; font-size: 0.78rem; padding: 0.05rem 0.55rem; border: 1px solid var(--accent); border-radius: 999px; color: var(--accent); }
.config-collapsible.is-dirty .config-dirty { display: inline-block; }
.config-body { padding: 0.8rem 0.95rem 0.95rem; }
@media (prefers-reduced-motion: reduce) { .config-collapsible > summary::before { transition: none; } }

/* ===== Configuration : réorganiser les sections (v6.22.0) — voir docs/SECTIONS.md ===== */
.config-reorder-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1rem; margin: 0 0 0.8rem; padding: 0.6rem 0.8rem; border: 1px dashed var(--accent); border-radius: 10px; background: var(--bg-elevated); }
.config-reorder-bar[hidden] { display: none; }
.config-reorder-help { margin: 0; flex: 1 1 320px; font-size: 0.88rem; color: var(--text-muted); }
.config-handle { display: inline-flex; align-self: center; cursor: grab; color: var(--text-muted); }
.config-move-controls { margin-left: auto; display: inline-flex; align-items: center; gap: 0.3rem; }
.config-pos { min-width: 3.4em; text-align: right; font-size: 0.8rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.config-reordering .config-collapsible > summary { cursor: grab; }
.config-reordering .config-collapsible > summary::before { content: none; }
.config-reordering .config-collapsible > .config-body { display: none; }
.config-collapsible.is-dragging { opacity: 0.45; border-style: dashed; }
.config-move-controls .btn-small:disabled { opacity: 0.3; cursor: default; }
@media (hover: none), (pointer: coarse), (max-width: 780px) { .config-move-controls .btn-small { min-width: 44px; min-height: 44px; } }

/* ===== Onglet « Mise à jour » en rouge quand une version plus récente est disponible (v6.24.0) =====
   Le rouge est celui du thème (--danger, défini dans les cinq thèmes) ; le texte masqué et le titre de l'onglet portent aussi l'information : jamais la couleur seule. */
.admin-tab.has-update, .admin-tab.has-update:hover, .admin-tab.has-update.active { color: var(--danger); }

/* ===== Mode démo (v6.27.0) ===== */
.demo-badge {
    display: inline-block; background: #b3261e; color: #fff; font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase;
    padding: 0.12rem 0.55rem; border-radius: 999px; line-height: 1.4; vertical-align: middle; white-space: nowrap;
}
.brand .demo-badge { margin: 0 0.15rem; }
.demo-banner { border: 1px solid #b3261e; border-radius: 8px; padding: 0.6rem 0.8rem; margin: 0.4rem 0 1rem; font-size: 0.9rem; line-height: 1.45; }
.demo-hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }   /* piège à robots : invisible pour une personne */
.demo-notice-overlay { z-index: 200; }
.demo-notice-box { max-width: 560px; max-height: 90vh; }
.demo-notice-markdown :first-child { margin-top: 0; }
.demo-notice-fixed { margin-top: 1rem; padding-top: 0.8rem; border-top: 1px solid var(--border); font-size: 0.92rem; line-height: 1.5; }
.demo-notice-fixed p { margin: 0.35rem 0; }
.demo-notice-deadline { font-weight: 700; color: var(--danger); }
.demo-notice-footer { padding: 0.8rem 1rem; border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: flex-end; gap: 0.8rem; flex-wrap: wrap; }
.demo-notice-error { margin: 0; color: var(--danger); font-size: 0.85rem; flex: 1 1 100%; }
.demo-notice-error:empty { display: none; }
.demo-notice-ok { min-height: 44px; padding: 0.5rem 1.2rem; font-weight: 600; cursor: pointer; }
body.demo-notice-open { overflow: hidden; }
.demo-badge-off { display: inline-block; border: 1px solid var(--border); color: var(--text-muted); font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; padding: 0.12rem 0.55rem; border-radius: 999px; line-height: 1.4; vertical-align: middle; }
.demo-status { margin: 0.4rem 0 0.8rem; }
.demo-toggle-box { border: 1px solid var(--border); border-radius: 8px; padding: 0.8rem 1rem; margin: 0.6rem 0 1rem; max-width: 640px; }
.demo-settings-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.8rem 1.2rem; max-width: 760px; margin: 0.6rem 0; }
.demo-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.demo-field input { width: 100%; box-sizing: border-box; }
.demo-notice-input { width: 100%; box-sizing: border-box; resize: vertical; max-width: 760px; }
.demo-notice-preview-box { border: 1px solid var(--border); border-radius: 8px; padding: 0.8rem 1rem; margin: 0.4rem 0 1rem; max-width: 760px; }
@media (max-width: 640px) { .demo-settings-grid { grid-template-columns: minmax(0, 1fr); } }
.demo-closed { opacity: 0.55; cursor: not-allowed; }

/* ===== Mode démo : repérage et tableau de bord (v6.28.0) ===== */
.demo-sev-forte { color: var(--danger); font-weight: 700; }
.demo-sev-faible { color: var(--text-muted); font-weight: 600; }
.demo-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.6rem; margin: 0.4rem 0 1rem; max-width: 980px; }
.demo-kpi { border: 1px solid var(--border); border-radius: 8px; padding: 0.6rem 0.8rem; min-width: 0; }
.demo-kpi-value { font-size: 1.5rem; font-weight: 700; line-height: 1.2; }
.demo-kpi-label { font-size: 0.8rem; color: var(--text-muted); }
.demo-stats-block { margin: 0 0 1.4rem; max-width: 980px; }
.demo-stats-table { width: 100%; }
.demo-progress { width: 100%; min-width: 80px; height: 0.8rem; }
.demo-chart { width: 100%; max-width: 760px; height: auto; display: block; margin: 0.3rem 0 0.8rem; }
.demo-bar { fill: var(--accent); }
.demo-chart-label { fill: var(--text-muted); font-size: 11px; }

/* L'attribut hidden doit TOUJOURS l'emporter (v6.29.0). Une règle `display: flex` sur la classe d'un élément l'annulait en silence : « 0 lien(s) sortant(s) » s'affichait sous chaque note
   sans lien sortant, l'aperçu du logo de connexion et la ligne de confirmation du mode démo s'affichaient alors qu'ils devaient rester cachés. tests/hidden-attribute-ui-test.js le vérifie. */
[hidden] { display: none !important; }

/* Classes utilitaires remplaçant d'anciens styles en ligne, que la politique de sécurité (style-src 'self') refusait en silence : leur effet n'a jamais été appliqué (v6.29.0). */
.text-center { text-align: center; }
.text-uppercase { text-transform: uppercase; }
.form-block-margin { margin: 0.8rem 0; }
.form-hint-tight { margin: -0.4rem 0 0.8rem; }
.form-policy-hint { margin: 0.2rem 0 0.8rem; }
.form-intro { margin-bottom: 1rem; }
.admin-wide-textarea { width: 100%; box-sizing: border-box; resize: vertical; }
.admin-code-textarea { width: 100%; box-sizing: border-box; resize: vertical; font-family: monospace; }

/* ---------- Débalisage sélectif (v6.31.0) ---------- */
.strip-dialog { display: flex; flex-direction: column; gap: 0.5rem; }
.strip-types { display: flex; flex-direction: column; gap: 0.25rem; max-height: 46vh; overflow: auto; }
.strip-type-row { display: flex; align-items: center; gap: 0.6rem; padding: 0.35rem 0.6rem; border: 1px solid var(--border); border-radius: 6px; cursor: pointer; }
.strip-type-row:hover { background: var(--bg-hover); }
.strip-type-row input[type="checkbox"] { flex: none; }
.strip-type-example { color: var(--text-muted); background: transparent; }
.strip-type-count { margin-left: auto; min-width: 2.2rem; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-muted); }
.strip-type-all { background: var(--bg-elevated); }
.strip-info { font-weight: 600; margin: 0; }
.strip-hint { color: var(--text-muted); margin: 0; font-size: 0.9em; }
.strip-preview { white-space: pre-wrap; overflow-wrap: anywhere; max-height: 46vh; overflow: auto; margin: 0; padding: 0.6rem; border: 1px solid var(--border); border-radius: 6px; background: var(--code-bg); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9em; }
.strip-mark { background: rgba(255, 200, 0, 0.55); color: inherit; border-radius: 2px; cursor: pointer; }
.strip-mark-excluded { background: transparent; outline: 1px dashed var(--text-muted); }
.strip-mark-current { outline: 2px solid var(--accent); }
.strip-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: flex-end; margin-top: 0.4rem; }
.strip-nav { justify-content: flex-start; margin-top: 0; }
.strip-confirm { border: 1px solid var(--warning); border-radius: 6px; padding: 0.7rem 0.9rem; }
.strip-confirm-title { font-weight: 700; margin: 0 0 0.4rem; }
.strip-confirm-list { margin: 0 0 0.5rem; padding-left: 1.3rem; }

/* ---------- Mode d'affichage unique et commandes (v6.32.0) ---------- */
.mode-icon { display: inline-flex; align-items: center; justify-content: center; }
.commands-widget { position: fixed; z-index: 45; width: 340px; max-height: min(70vh, 560px); display: flex; flex-direction: column; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow); }
.commands-widget.is-dragging { user-select: none; }
.commands-widget-header { display: flex; align-items: center; justify-content: space-between; padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--border); cursor: grab; touch-action: none; }
.commands-widget.is-dragging .commands-widget-header { cursor: grabbing; }
.commands-widget-title { font-weight: 600; font-size: 0.9rem; }
.commands-widget-close { display: inline-flex; background: none; border: none; color: var(--text-muted); cursor: pointer; padding: 0.2rem; border-radius: 6px; }
.commands-widget-close:hover { background: var(--bg-hover); color: var(--text); }
.commands-widget-close .ic { --ic-size: 16px; }
.commands-widget-filter { margin: 0.5rem 0.6rem 0.3rem; padding: 0.35rem 0.5rem; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); color: var(--text); font: inherit; font-size: 0.88rem; }
.commands-widget-list { overflow-y: auto; padding: 0 0.3rem 0.3rem; }
.commands-widget-row { display: flex; justify-content: space-between; align-items: center; gap: 0.6rem; padding: 0.4rem 0.5rem; border-radius: 6px; cursor: pointer; font-size: 0.88rem; }
.commands-widget-row:hover, .commands-widget-row.highlighted { background: var(--bg-hover); }
.commands-widget-row .ic { --ic-size: 16px; vertical-align: -3px; }
.commands-widget-footer { margin: 0; padding: 0.4rem 0.6rem; border-top: 1px solid var(--border); color: var(--text-muted); font-size: 0.8rem; }
.shortcut-hints { flex: none; white-space: nowrap; color: var(--text-muted); font-size: 0.78rem; }
.shortcut-hint { font-family: inherit; font-size: 0.78rem; padding: 0 0.3rem; border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 4px; background: var(--bg); color: var(--text); }
@media (hover: none), (pointer: coarse), (max-width: 780px) { .shortcut-hints { display: none; } .commands-widget { display: none; } }

/* ---------- Arborescence : nom raccourci avant les badges, et repère « acronymes à documenter » (v6.32.1) ---------- */
.tree-name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.tree-label > .maturity-badge, .tree-label > .tree-acrodico-badge { flex-shrink: 0; }
/* Pastille autour de l'icône de la note : forme (fond + liseré) ET couleur, jamais la couleur seule ; teinte douce, car
   beaucoup de notes peuvent être concernées à la fois — le plein accent reste réservé au bouton « Enregistrer ». */
.tree-label.has-acrodico > .ic:first-child { padding: 2px; border-radius: 5px; background: var(--bg-hover); color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
@supports (background: color-mix(in srgb, red 10%, blue)) {
    .tree-label.has-acrodico > .ic:first-child { background: color-mix(in srgb, var(--accent) 18%, transparent); }
}
/* Ligne sélectionnée (fond d'accent) : couleurs inversées, sinon l'icône d'accent disparaîtrait dans son propre fond. */
.tree-label.active.has-acrodico > .ic:first-child { background: var(--accent-contrast); color: var(--accent); box-shadow: none; }

/* ---------- Glyphes remplacés par des icônes du jeu actif (v6.33.0) ---------- */
.fmt-btn-menu .ic { --ic-size: 14px; vertical-align: -2px; }
.section-chevron .ic { --ic-size: 16px; }
.graph-zoom-controls button .ic, .graph-size-mode-controls button .ic { --ic-size: 18px; }

/* ---------- Classes qui remplacent les derniers styles en ligne des scripts (v6.34.5) ----------
   Un attribut style="..." écrit dans un innerHTML est REFUSÉ en silence par la politique de sécurité (style-src 'self') : l'effet voulu
   (le « Activée » en vert de la double authentification, les aperçus de l'aide-mémoire Markdown) n'apparaissait jamais. */
.plain-list { list-style: none; padding-left: 0; }
.status-on { color: var(--success, #2e7d32); }
.status-off { color: var(--text-muted); }
.mdh-h1 { margin: 0; font-size: 1.3em; }
.mdh-h2 { margin: 0; font-size: 1.15em; }
.mdh-h3 { margin: 0; font-size: 1.05em; }
.mdh-quote { border-left: 3px solid var(--accent); padding-left: 0.5rem; color: var(--text-muted); }
.mdh-callout { border-left: 3px solid #2fb673; background: var(--bg-hover); padding: 0.2rem 0.5rem; border-radius: 4px; }
.mdh-code { background: var(--code-bg); padding: 0.1rem 0.4rem; border-radius: 4px; }
.mdh-hr { border: none; border-top: 1px solid var(--border); margin: 0; }
.mdh-table { border-collapse: collapse; font-size: 0.85em; }
.mdh-cell { border: 1px solid var(--border); padding: 2px 6px; }
.mdh-accent { color: var(--accent); }
.mdh-muted { color: var(--text-muted); }

/* ---------- Fiches de tableaux : vault, outils (information, duplication) (v6.35.0) ---------- */
.kb-board-card { display: flex; flex-direction: column; }
.kb-board-card-vault { display: flex; align-items: center; gap: 0.35rem; margin: 0.15rem 0 0; min-width: 0; }
.kb-board-card-vault span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-board-card-tools { display: flex; justify-content: flex-end; gap: 0.3rem; margin-top: auto; padding-top: 0.5rem; }
.kb-card-tool-btn {
    display: inline-flex; align-items: center; justify-content: center; min-width: 32px; min-height: 32px;
    background: transparent; border: 1px solid transparent; border-radius: 6px; color: var(--text-muted); cursor: pointer;
}
.kb-card-tool-btn:hover, .kb-card-tool-btn:focus-visible, .kb-card-tool-btn[aria-expanded="true"] { color: var(--text); border-color: var(--accent); }
.kb-info-popover {
    position: fixed; z-index: 1000; max-width: min(22rem, calc(100vw - 16px)); padding: 0.7rem 0.85rem; font-size: 0.85rem;
    background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); border-radius: 8px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.25); pointer-events: none;
}
.kb-info-title { margin: 0 0 0.4rem; font-size: 0.95rem; }
.kb-info-list { display: grid; grid-template-columns: auto 1fr; gap: 0.2rem 0.7rem; margin: 0; }
.kb-info-list dt { color: var(--text-muted); }
.kb-info-list dd { margin: 0; overflow-wrap: anywhere; }
.kb-info-note { margin: 0.5rem 0 0; color: var(--text-muted); }

/* ---------- Recherche / remplacement (v6.36.0) ---------- */
/* Surbrillance dans l'APERÇU : API CSS Custom Highlight (aucune balise ajoutée au DOM de l'aperçu). */
::highlight(find-match) { background-color: rgba(255, 214, 0, 0.45); }
::highlight(find-match-current) { background-color: rgba(255, 140, 0, 0.75); }
/* Calque désaligné malgré la correction de largeur (navigateur qui replierait les lignes autrement) : un surlignage décalé serait pire que pas de
   surlignage — masqué ; la barre l'explique. Les autres surlignages (numérotation, suggestions de liens) ne sont PAS touchés. */
.source-highlight-layer.highlight-misaligned mark.find-match { background: transparent; }
.find-hint-row { align-items: center; }
.find-hint-row[hidden] { display: none; }
.find-hint { flex: 1; min-width: 0; font-size: 0.8rem; color: var(--text-muted); }
.find-replace-bar button:disabled, .find-replace-input:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---------- Messagerie unifiée (v6.37.0) ---------- */
/* Un type = une couleur ET une icône ET un libellé (jamais la couleur seule). Les couleurs servent de repère, pas de seule information. */
.inbox-panel, .inbox-scrim { --inbox-conversation: #3b82f6; --inbox-announcement: #8b5cf6; --inbox-direct: #10b981; --inbox-transfer: #f59e0b; --inbox-system: #64748b; --inbox-kanban: #0ea5e9; }
.inbox-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 60; }
.inbox-scrim[hidden], .inbox-panel[hidden] { display: none; }
.inbox-panel {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 61; width: min(1000px, 96vw); display: flex;
    background: var(--bg); color: var(--text); border-left: 1px solid var(--border); box-shadow: -8px 0 30px rgba(0, 0, 0, 0.35);
    padding-top: env(safe-area-inset-top, 0px); padding-bottom: env(safe-area-inset-bottom, 0px);
}
.inbox-panel *, .inbox-panel *::before, .inbox-panel *::after { box-sizing: border-box; min-width: 0; }
body.inbox-open { overflow: hidden; }
.inbox-list-pane { flex: 0 0 390px; display: flex; flex-direction: column; border-right: 1px solid var(--border); background: var(--bg-elevated); }
.inbox-detail-pane { flex: 1 1 auto; display: flex; flex-direction: column; background: var(--bg); position: relative; }
.inbox-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border); }
.inbox-title { display: flex; align-items: center; gap: 0.5rem; margin: 0; font-size: 1.05rem; }
.inbox-header-actions { display: flex; gap: 0.2rem; }
.inbox-header-actions .icon-btn.is-active { background: var(--bg-hover); outline: 1px solid var(--accent); }
.inbox-views { display: flex; gap: 0.25rem; padding: 0.5rem 0.8rem 0; }
.inbox-view-btn { flex: 1; display: flex; align-items: center; justify-content: center; gap: 0.35rem; padding: 0.4rem 0.3rem; background: none; color: var(--text-muted); border: 1px solid var(--border); border-radius: 6px; cursor: pointer; font: inherit; font-size: 0.82rem; min-height: 36px; }
.inbox-view-btn.is-active { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); font-weight: 600; }
.inbox-view-count { font-size: 0.72rem; opacity: 0.85; }
.inbox-types { display: flex; flex-wrap: wrap; gap: 0.3rem; padding: 0.5rem 0.8rem 0; }
.inbox-type-chip { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.25rem 0.5rem; background: none; color: var(--text); border: 1px solid var(--border); border-left: 4px solid var(--inbox-system); border-radius: 6px; cursor: pointer; font: inherit; font-size: 0.78rem; min-height: 32px; --ic-size: 15px; }
.inbox-type-chip.is-active { background: var(--bg-hover); outline: 1px solid var(--accent); font-weight: 600; }
.inbox-type-chip.is-empty { opacity: 0.55; }
.inbox-chip-count { font-size: 0.7rem; color: var(--text-muted); }
.inbox-search-row { display: flex; gap: 0.4rem; padding: 0.5rem 0.8rem; align-items: center; }
.inbox-search { flex: 1 1 auto; padding: 0.4rem 0.6rem; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 6px; font: inherit; font-size: 0.88rem; min-height: 36px; }
.inbox-advanced { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; padding: 0 0.8rem 0.5rem; }
.inbox-advanced[hidden] { display: none; }
.inbox-field { display: flex; flex-direction: column; gap: 0.15rem; font-size: 0.75rem; color: var(--text-muted); }
.inbox-field input, .inbox-field select { padding: 0.3rem 0.4rem; background: var(--bg); color: var(--text); border: 1px solid var(--border); border-radius: 5px; font: inherit; font-size: 0.85rem; min-height: 34px; }
.inbox-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; padding: 0 0.8rem 0.4rem; }
.inbox-bulk-count { font-size: 0.8rem; color: var(--text-muted); margin-right: auto; }
.inbox-list { list-style: none; margin: 0; padding: 0; flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; border-top: 1px solid var(--border); outline: none; -webkit-overflow-scrolling: touch; }
.inbox-row { position: relative; display: flex; align-items: flex-start; gap: 0.55rem; padding: 0.6rem 0.8rem 0.6rem 1rem; border-bottom: 1px solid var(--border); cursor: pointer; min-height: 64px; }
.inbox-row:hover { background: var(--bg-hover); }
.inbox-row.is-active { background: var(--bg-hover); }
.inbox-row.is-cursor { outline: 2px solid var(--accent); outline-offset: -2px; }
.inbox-row-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; background: var(--inbox-system); }
.inbox-row-icon { flex: 0 0 auto; color: var(--text-muted); padding-top: 0.15rem; --ic-size: 20px; }
.inbox-row-check { flex: 0 0 auto; width: 20px; height: 20px; margin-top: 0.1rem; }
.inbox-row-main { flex: 1 1 auto; display: flex; flex-direction: column; gap: 0.1rem; }
.inbox-row-top { display: flex; justify-content: space-between; gap: 0.5rem; align-items: baseline; }
.inbox-row-from { font-size: 0.9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox-row-date { flex: 0 0 auto; font-size: 0.72rem; color: var(--text-muted); }
.inbox-row-subject { font-size: 0.78rem; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.inbox-row-preview { font-size: 0.82rem; color: var(--text-muted); overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.inbox-row-tags { display: flex; flex-wrap: wrap; gap: 0.25rem; align-items: center; margin-top: 0.15rem; }
/* Lu : estompé (il RESTE dans la liste). Non lu : gras et pastille. */
.inbox-row:not(.is-unread) { opacity: 0.72; }
.inbox-row:not(.is-unread) .inbox-row-from { font-weight: 400; }
.inbox-row.is-unread .inbox-row-from, .inbox-row.is-unread .inbox-row-subject { font-weight: 700; color: var(--text); }
.inbox-row.is-unread .inbox-row-preview { color: var(--text); }
.inbox-tag { display: inline-block; padding: 0.05rem 0.4rem; font-size: 0.68rem; border: 1px solid var(--border); border-radius: 999px; color: var(--text-muted); }
.inbox-tag-action { background: var(--warning); color: #1a1a1a; border-color: var(--warning); font-weight: 700; }
.inbox-tag-warn { border-color: var(--warning); color: var(--warning); }
.inbox-unread-badge { display: inline-block; padding: 0.05rem 0.45rem; font-size: 0.68rem; font-weight: 700; background: var(--accent); color: var(--accent-contrast); border-radius: 999px; }
.inbox-row.is-action { background: rgba(245, 158, 11, 0.1); }
.inbox-type-chip.inbox-type-conversation { border-left-color: var(--inbox-conversation); }
.inbox-type-chip.inbox-type-announcement { border-left-color: var(--inbox-announcement); }
.inbox-type-chip.inbox-type-direct { border-left-color: var(--inbox-direct); }
.inbox-type-chip.inbox-type-transfer { border-left-color: var(--inbox-transfer); }
.inbox-type-chip.inbox-type-system { border-left-color: var(--inbox-system); }
.inbox-type-chip.inbox-type-kanban { border-left-color: var(--inbox-kanban); }
.inbox-row.inbox-type-conversation .inbox-row-bar { background: var(--inbox-conversation); }
.inbox-row.inbox-type-announcement .inbox-row-bar { background: var(--inbox-announcement); }
.inbox-row.inbox-type-direct .inbox-row-bar { background: var(--inbox-direct); }
.inbox-row.inbox-type-transfer .inbox-row-bar { background: var(--inbox-transfer); }
.inbox-row.inbox-type-system .inbox-row-bar { background: var(--inbox-system); }
.inbox-row.inbox-type-kanban .inbox-row-bar { background: var(--inbox-kanban); }
/* La couleur d'un message est celle de son TYPE (celle de sa pastille de filtre), toujours : la barre ET l'icône. Un message qui demande de l'attention (plan de
   sauvegarde, mise à jour, tâche en retard) ne change PAS de couleur — avant, sa barre passait à l'orange, qui est la couleur des transferts : sur la liste, des messages
   système ressemblaient à des transferts. L'urgence se dit par une pastille « Important ». */
.inbox-row.inbox-type-conversation .inbox-row-icon { color: var(--inbox-conversation); }
.inbox-row.inbox-type-announcement .inbox-row-icon { color: var(--inbox-announcement); }
.inbox-row.inbox-type-direct .inbox-row-icon { color: var(--inbox-direct); }
.inbox-row.inbox-type-transfer .inbox-row-icon { color: var(--inbox-transfer); }
.inbox-row.inbox-type-system .inbox-row-icon { color: var(--inbox-system); }
.inbox-row.inbox-type-kanban .inbox-row-icon { color: var(--inbox-kanban); }
.inbox-type-chip.inbox-type-conversation .ic, .inbox-type-chip.inbox-type-announcement .ic, .inbox-type-chip.inbox-type-direct .ic,
.inbox-type-chip.inbox-type-transfer .ic, .inbox-type-chip.inbox-type-system .ic, .inbox-type-chip.inbox-type-kanban .ic { color: inherit; }
.inbox-type-chip.inbox-type-conversation .ic { color: var(--inbox-conversation); }
.inbox-type-chip.inbox-type-announcement .ic { color: var(--inbox-announcement); }
.inbox-type-chip.inbox-type-direct .ic { color: var(--inbox-direct); }
.inbox-type-chip.inbox-type-transfer .ic { color: var(--inbox-transfer); }
.inbox-type-chip.inbox-type-system .ic { color: var(--inbox-system); }
.inbox-type-chip.inbox-type-kanban .ic { color: var(--inbox-kanban); }
.inbox-empty { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; padding: 1.5rem 1rem; color: var(--text-muted); text-align: center; }
.inbox-empty[hidden] { display: none; }
.inbox-more { padding: 0.4rem 0.8rem; text-align: center; }
.inbox-more button[hidden] { display: none; }
.inbox-detail-header { display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 0.8rem; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.inbox-detail-title { flex: 1 1 12rem; font-weight: 600; overflow-wrap: anywhere; }
.inbox-detail-actions { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.inbox-back-btn { display: none; }
.inbox-detail-body { flex: 1 1 auto; overflow-y: auto; overflow-x: hidden; padding: 0.8rem 1rem; display: flex; flex-direction: column; gap: 0.7rem; -webkit-overflow-scrolling: touch; }
.inbox-detail-body.is-thread { overflow: hidden; }
.inbox-detail-placeholder { color: var(--text-muted); text-align: center; margin: 2rem 0; }
.inbox-detail-meta { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; }
.inbox-detail-date, .inbox-detail-from { font-size: 0.8rem; color: var(--text-muted); margin: 0; }
.inbox-detail-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.5; }
.inbox-detail-links { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.inbox-resolved { font-size: 0.85rem; }
.inbox-thread { flex: 1 1 auto; overflow-y: auto; display: flex; flex-direction: column; gap: 0.5rem; padding: 0.3rem 0; }
.inbox-bubble { max-width: 85%; align-self: flex-start; padding: 0.5rem 0.7rem; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 10px; }
.inbox-bubble.is-mine { align-self: flex-end; background: var(--bg-hover); }
.inbox-bubble-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.inbox-bubble-meta { font-size: 0.68rem; color: var(--text-muted); margin-top: 0.2rem; }
.inbox-bubble-note { display: inline-block; font-size: 0.82rem; margin-top: 0.2rem; }
.inbox-composer { display: flex; flex-direction: column; gap: 0.3rem; padding-top: 0.5rem; border-top: 1px solid var(--border); background: var(--bg); }
.inbox-composer-text { width: 100%; resize: vertical; padding: 0.5rem; background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); border-radius: 6px; font: inherit; }
.inbox-composer-row { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
.inbox-composer-hint { font-size: 0.72rem; color: var(--text-muted); }
.inbox-recipient, .inbox-recipient-filter { width: 100%; padding: 0.4rem; background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); border-radius: 6px; font: inherit; }
.inbox-kanban-tasks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.inbox-kanban-task { padding: 0.5rem 0.6rem; border: 1px solid var(--border); border-left: 4px solid var(--inbox-kanban); border-radius: 6px; display: flex; flex-direction: column; gap: 0.2rem; }
.inbox-kanban-task.is-overdue { border-left-color: var(--warning); }
.inbox-kanban-title { overflow-wrap: anywhere; font-weight: 600; }
.inbox-kanban-due, .inbox-kanban-progress { font-size: 0.75rem; color: var(--text-muted); }
.inbox-toast { position: absolute; left: 0.8rem; right: 0.8rem; bottom: 0.8rem; z-index: 3; display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; padding: 0.55rem 0.8rem; background: var(--text); color: var(--bg); border-radius: 8px; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4); }
.inbox-toast[hidden] { display: none; }
.inbox-toast-undo { background: var(--bg); color: var(--text); border: 1px solid var(--border); min-height: 32px; }
.inbox-btn-label { margin-left: 0.25rem; }
.inbox-bulk-btn, .inbox-detail-btn, .inbox-toast-undo, .inbox-back-btn { align-items: center; gap: 0.3rem; }
.inbox-bulk-btn, .inbox-detail-btn, .inbox-toast-undo { display: inline-flex; }
.inbox-bulk { flex-wrap: nowrap; }
.inbox-bulk .inbox-bulk-btn { flex: 1 1 auto; justify-content: center; }
.inbox-bulk-count { flex: 0 0 auto; }
.notif-bell-badge--action { background: var(--warning); color: #1a1a1a; }

/* L'ordre visuel (haut en bas) est fixé ici, pas par l'ordre du DOM : en-tête, affichages, types, recherche, filtres avancés, actions, liste. Le DOM place les types APRÈS
   les filtres avancés pour que, sur téléphone, un simple sélecteur voisin (~) les révèle avec eux. */
.inbox-list-pane > .inbox-header { order: 0; } .inbox-list-pane > .inbox-views { order: 1; } .inbox-list-pane > .inbox-types { order: 2; }
.inbox-list-pane > .inbox-search-row { order: 3; } .inbox-list-pane > .inbox-advanced { order: 4; } .inbox-list-pane > .inbox-bulk { order: 5; }
.inbox-list-pane > .inbox-list { order: 6; } .inbox-list-pane > .inbox-empty { order: 7; } .inbox-list-pane > .inbox-more { order: 8; }
.inbox-filters-count { display: inline-block; margin-left: 0.3rem; padding: 0 0.4rem; min-width: 1.2rem; text-align: center; font-size: 0.7rem; font-weight: 700; background: var(--accent); color: var(--accent-contrast); border-radius: 999px; }
.inbox-filters-count[hidden] { display: none; }

/* Téléphone : un écran après l'autre — la liste, puis le message ; « Messages » ramène à la liste, qui n'a pas bougé (filtre et position conservés). */
@media (max-width: 780px) {
    .inbox-panel { width: 100vw; border-left: 0; }
    .inbox-list-pane { flex: 1 1 100%; width: 100%; border-right: 0; }
    .inbox-detail-pane { display: none; flex: 1 1 100%; width: 100%; }
    .inbox-panel.show-detail .inbox-list-pane { display: none; }
    .inbox-panel.show-detail .inbox-detail-pane { display: flex; }
    .inbox-back-btn { display: inline-flex; min-height: 44px; }
    /* Sur téléphone, la liste doit occuper l'écran : il ne reste visibles que l'en-tête, les trois affichages et la recherche (environ 20 % de la hauteur).
       Les types, la période, l'émetteur, le tri et les actions en bloc sont derrière « Filtres » (un compteur y indique les filtres actifs). */
    .inbox-header { padding: 0.35rem 0.6rem; }
    .inbox-header .icon-btn { min-height: 40px; min-width: 40px; }
    .inbox-views { padding: 0.35rem 0.6rem 0; gap: 0.2rem; }
    .inbox-view-btn { min-height: 36px; padding: 0.2rem 0.2rem; font-size: 0.8rem; }
    .inbox-search-row { padding: 0.35rem 0.6rem; gap: 0.3rem; }
    .inbox-search-row .btn-small { min-height: 40px; padding-left: 0.5rem; padding-right: 0.5rem; }
    .inbox-clear-text { display: none; }
    .inbox-types, .inbox-bulk { display: none; }
    .inbox-advanced:not([hidden]) ~ .inbox-types { display: flex; padding: 0.2rem 0.6rem 0.3rem; }
    .inbox-advanced:not([hidden]) ~ .inbox-bulk, .inbox-bulk.is-select { display: flex; padding: 0 0.6rem 0.4rem; }
    .inbox-type-chip { min-height: 36px; }
    .inbox-bulk-btn { min-height: 38px; font-size: 0.8rem; padding-left: 0.4rem; padding-right: 0.4rem; }
    .inbox-advanced { padding: 0 0.6rem 0.4rem; grid-template-columns: 1fr 1fr; }
    .inbox-row { min-height: 64px; padding: 0.5rem 0.6rem 0.5rem 0.9rem; }
    .inbox-bubble { max-width: 94%; }
    .inbox-composer-text { font-size: 16px; }   /* évite le zoom automatique de Safari sur téléphone */
    .inbox-search { font-size: 16px; min-height: 40px; }
    .inbox-field input, .inbox-field select, .inbox-recipient, .inbox-recipient-filter { font-size: 16px; min-height: 40px; }
}

/* ---------- Boutons-icônes avec infobulle (v6.38.0) ---------- */
[data-tip] { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; touch-action: manipulation; }
.tip-popover {
    position: fixed; z-index: 400; max-width: min(18rem, calc(100vw - 16px)); padding: 0.4rem 0.6rem;
    background: var(--text); color: var(--bg); border-radius: 6px; font-size: 0.8rem; line-height: 1.3;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); pointer-events: none;
}
.tip-popover-main { font-weight: 600; overflow-wrap: anywhere; }
.tip-popover-more { margin-top: 0.15rem; font-size: 0.72rem; opacity: 0.85; overflow-wrap: anywhere; }
/* Annuaire : des boutons-icônes carrés, à la place de boutons à libellé qui alourdissaient chaque ligne (surtout sur téléphone). */
.directory-entry-actions { flex-direction: row; align-items: center; gap: 0.3rem; }
.directory-icon-btn {
    display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 38px; height: 38px; padding: 0;
    background: none; color: var(--text); border: 1px solid var(--border); border-radius: 6px; cursor: pointer; --ic-size: 18px;
}
.directory-icon-btn:hover, .directory-icon-btn:focus-visible { background: var(--bg-hover); border-color: var(--accent); }
.directory-entry .directory-icon-btn .ic { --ic-size: 18px; vertical-align: 0; }

/* ---------- Kanban : propriétés, import (v6.41.0) ---------- */
.kb-list-actions { display: inline-flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.kb-import-preview { margin: 0.4rem 0 0.8rem; font-size: 0.9rem; }
.kb-import-preview div { margin-bottom: 0.2rem; }
.kb-import-preview.is-error { color: var(--danger); }
.kb-import-help { margin: 0.2rem 0 0.6rem; }
.kb-import-warnings { margin: 0.3rem 0 0.8rem; padding-left: 1.2rem; font-size: 0.88rem; }
.kb-import-warnings li { margin-bottom: 0.25rem; overflow-wrap: anywhere; }

/* =====================================================================================================================================
   Socle des formulaires et des fenêtres (v6.41.1) — un seul style de champ, de bouton et de fenêtre, au lieu d'un rendu natif différent
   selon le navigateur et le type de champ. S'applique aux conteneurs portant la classe « ui-form » (les écrans sont convertis un à un).
   ===================================================================================================================================== */
:root { --ctl-h: 40px; --ctl-r: 8px; --ui-gap: 1rem; --ctl-font: 0.95rem; }
/* 16 px minimum sur appareil tactile : en dessous, Safari sur iPhone agrandit la page au focus d'un champ. Une VARIABLE plutôt qu'une règle de remplacement : celle-ci
   aurait été moins spécifique que la règle de base (cinq :not()) et ne se serait jamais appliquée. */
@media (max-width: 640px), (pointer: coarse) { :root { --ctl-h: 44px; --ctl-font: 16px; } }

.ui-form .admin-field, .ui-form .ui-field { display: flex; flex-direction: column; gap: 0.35rem; margin: 0 0 var(--ui-gap); }
.ui-form .admin-field > span:first-child, .ui-form .ui-field > .ui-label { font-size: 0.85rem; font-weight: 600; color: var(--text); }
.ui-form input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="button"]):not([type="submit"]),
.ui-form select, .ui-form textarea {
    box-sizing: border-box; width: 100%; min-height: var(--ctl-h); padding: 0 0.75rem; margin: 0;
    border: 1px solid var(--border); border-radius: var(--ctl-r); background-color: var(--bg); color: var(--text);
    font: inherit; font-size: var(--ctl-font); line-height: 1.3;
}
.ui-form textarea { padding: 0.6rem 0.75rem; min-height: 5.5rem; resize: vertical; }
.ui-form select {
    -webkit-appearance: none; appearance: none; padding-right: 2.4rem; cursor: pointer; text-overflow: ellipsis;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 1.15rem) 50%, calc(100% - 0.8rem) 50%; background-size: 0.35rem 0.35rem; background-repeat: no-repeat;
}
.ui-form input::placeholder, .ui-form textarea::placeholder { color: var(--text-muted); opacity: 0.8; }
.ui-form input:focus-visible, .ui-form select:focus-visible, .ui-form textarea:focus-visible, .ui-form .btn-small:focus-visible,
.ui-form input[type="color"]:focus-visible, .ui-form input[type="range"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ui-form input:disabled, .ui-form select:disabled, .ui-form textarea:disabled { opacity: 0.6; cursor: not-allowed; }
.ui-form .btn-small { min-height: var(--ctl-h); padding: 0 1rem; border-radius: var(--ctl-r); display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem; font-size: 0.92rem; }
.ui-form .account-section-title { margin: 1.4rem 0 0.6rem; font-size: 1rem; }
.ui-form .tree-empty { margin: 0.2rem 0 0.8rem; padding-left: 0; padding-right: 0; font-size: 0.85rem; }   /* aligné sur le bord gauche des libellés */

/* Pied d'actions : collé en bas de la zone qui défile, séparé par un filet, bouton principal à droite ; sur téléphone, boutons pleine largeur. */
.ui-actions {
    position: sticky; bottom: 0; z-index: 2; display: flex; gap: 0.6rem; justify-content: flex-end; align-items: center; flex-wrap: wrap;
    margin: var(--ui-gap) -1.25rem 0; padding: 0.8rem 1.25rem; background: var(--bg-elevated); border-top: 1px solid var(--border);
}
.ui-actions > .ui-actions-start { margin-right: auto; }
@media (max-width: 640px) { .ui-actions > button { flex: 1 1 auto; } .ui-actions > .ui-actions-start { margin-right: 0; } }

/* Fenêtre de formulaire : largeur adaptée au contenu, REDIMENSIONNABLE à la souris (coin bas-droit), en-tête fixe et un SEUL défilement (celui du corps). */
.modal-box.form-modal {
    width: min(820px, 96vw); max-width: 96vw; max-height: 90vh; min-width: 420px; min-height: 320px; resize: both; overflow: hidden;
}
.modal-box.form-modal .modal-body { flex: 1 1 auto; min-height: 0; padding: 1.1rem 1.25rem 0; }
@media (max-width: 640px), (hover: none), (pointer: coarse) {
    .modal-box.form-modal { resize: none; min-width: 0; width: 100%; max-width: 100%; max-height: 92vh; border-radius: 14px; }
    .modal-box.form-modal .modal-body { padding: 1rem 1rem 0; }
    .ui-actions { margin-left: -1rem; margin-right: -1rem; padding-left: 1rem; padding-right: 1rem; }
}
.ui-form .kb-weather-row { display: grid; grid-template-columns: 28px minmax(0, 1fr); align-items: center; gap: 0.6rem; margin-bottom: 0.5rem; }
.ui-form .kb-weather-row > span:first-child { display: inline-flex; justify-content: center; font-weight: 400; }
.ui-form #kb-due-soon-days { max-width: 8rem; }

/* Description d'un tableau (v6.41.2) */
.kb-board-description { margin: 0.2rem 0 0.6rem; max-width: 70ch; font-size: 0.92rem; color: var(--text-muted); white-space: pre-line; overflow-wrap: anywhere; }
.kb-board-card-desc {
    margin: 0.3rem 0 0.4rem; font-size: 0.85rem; color: var(--text-muted); white-space: pre-line; overflow-wrap: anywhere;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ui-form .kb-field-hint { align-self: flex-end; font-size: 0.78rem; color: var(--text-muted); }

/* ---------- Sélecteur de date (v6.42.0) ---------- */
.dp-field { display: block; position: relative; min-width: 0; }
.dp-box { position: relative; display: block; }
.dp-text { padding-right: calc(var(--ctl-h, 40px) + 4px); }
.dp-btn {
    position: absolute; top: 50%; right: 4px; transform: translateY(-50%); width: calc(var(--ctl-h, 40px) - 10px); height: calc(var(--ctl-h, 40px) - 10px);
    display: inline-flex; align-items: center; justify-content: center; padding: 0; border: none; border-radius: 6px; background: transparent; color: var(--text-muted); cursor: pointer;
}
.dp-btn:hover, .dp-btn[aria-expanded="true"] { background: var(--bg-hover); color: var(--text); }
.dp-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Champ natif masqué mais PRÉSENT (source de vérité, valeur ISO) : !important car les règles de champ du socle sont très spécifiques. */
.dp-field input.dp-native { position: absolute !important; inset: 0; width: 100% !important; height: 100% !important; min-height: 0 !important; margin: 0 !important; padding: 0 !important; border: 0 !important; opacity: 0 !important; pointer-events: none !important; }
.dp-field input.dp-text.dp-invalid { border-color: var(--danger) !important; }
.dp-error { display: block; margin-top: 0.3rem; font-size: 0.8rem; color: var(--danger); }
.dp-error[hidden] { display: none; }
.dp-pop {
    position: fixed; z-index: 410; width: 304px; max-width: calc(100vw - 16px); padding: 0.6rem; box-sizing: border-box;
    background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.dp-pop[hidden] { display: none; }
.dp-head { display: grid; grid-template-columns: 32px 32px minmax(0, 1fr) 32px 32px; align-items: center; gap: 0.15rem; margin-bottom: 0.4rem; }
.dp-nav { width: 32px; height: 32px; display: inline-flex; align-items: center; justify-content: center; padding: 0; border: none; border-radius: 8px; background: transparent; color: var(--text); cursor: pointer; }
.dp-nav:hover { background: var(--bg-hover); }
.dp-title { text-align: center; font-weight: 600; text-transform: capitalize; font-size: 0.95rem; }
.dp-weekdays, .dp-row { display: grid; grid-template-columns: repeat(7, 1fr); }
.dp-weekdays span { text-align: center; font-size: 0.74rem; font-weight: 600; color: var(--text-muted); padding: 0.2rem 0; }
.dp-day { position: relative; height: 36px; padding: 0; border: none; border-radius: 8px; background: transparent; color: var(--text); font: inherit; font-size: 0.9rem; cursor: pointer; }
.dp-day:hover:not(:disabled) { background: var(--bg-hover); }
.dp-day.is-outside { opacity: 0.45; }
.dp-day.is-weekend { color: var(--text-muted); }
.dp-day.is-today { box-shadow: inset 0 0 0 1px var(--accent); }
.dp-day.is-selected { background: var(--accent); color: var(--accent-contrast); opacity: 1; }
.dp-day.is-holiday::after { content: ''; position: absolute; left: 50%; bottom: 4px; width: 4px; height: 4px; margin-left: -2px; border-radius: 50%; background: var(--warning); }
.dp-day:disabled { opacity: 0.25; cursor: not-allowed; }
.dp-day:focus-visible, .dp-nav:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.dp-foot { display: flex; align-items: center; gap: 0.4rem; margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid var(--border); }
.dp-foot .btn-small { min-height: 34px; padding: 0 0.7rem; font-size: 0.85rem; }
.dp-legend { margin-left: auto; display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.75rem; color: var(--text-muted); }
.dp-legend-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--warning); display: inline-block; }
@media (pointer: coarse) { .dp-day { height: 42px; } .dp-nav { width: 38px; height: 38px; } .dp-head { grid-template-columns: 38px 38px minmax(0, 1fr) 38px 38px; } }

/* ---------- Fenêtre de tâche et personnes concernées dans un formulaire (v6.42.0) ---------- */
.ui-form .admin-subsection-title { margin: 1.4rem 0 0.6rem; font-size: 1rem; font-weight: 700; }
.ui-form .kb-progress-head { display: flex; justify-content: space-between; align-items: baseline; gap: 0.5rem; }
.ui-form .kb-progress-readout { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); }
/* Curseur d'avancement : piste arrondie, partie atteinte en couleur d'accent (variable --pct posée par le script), poignée ronde — même rendu sur Safari, Chrome et Firefox. */
.ui-form input[type="range"] { -webkit-appearance: none; appearance: none; width: 100%; margin: 0; height: var(--ctl-h); background: transparent; cursor: pointer; --pct: 0%; }
.ui-form input[type="range"]::-webkit-slider-runnable-track { height: 8px; border-radius: 999px; background: linear-gradient(to right, var(--accent) var(--pct), var(--border) var(--pct)); }
.ui-form input[type="range"]::-moz-range-track { height: 8px; border-radius: 999px; background: var(--border); }
.ui-form input[type="range"]::-moz-range-progress { height: 8px; border-radius: 999px; background: var(--accent); }
.ui-form input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 22px; height: 22px; margin-top: -7px; border-radius: 50%; background: var(--accent); border: 3px solid var(--bg-elevated); box-shadow: 0 0 0 1px var(--accent); }
.ui-form input[type="range"]::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: var(--accent); border: 3px solid var(--bg-elevated); box-shadow: 0 0 0 1px var(--accent); }
.ui-form input[type="range"]:focus-visible { outline: none; }
.ui-form input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 1px var(--accent), 0 0 0 4px rgba(120, 140, 255, 0.35); }
.ui-form .kb-weather-select-row { display: flex; gap: 0.6rem; align-items: center; }   /* flex et non grille : un aperçu masqué ne réserve ni colonne ni écart, la liste garde toute la largeur */
.ui-form .kb-weather-select-row select { flex: 1 1 auto; min-width: 0; }
.ui-form .kb-weather-preview { flex: none; }
.ui-form .kb-weather-preview { display: inline-flex; align-items: center; justify-content: center; width: var(--ctl-h); height: var(--ctl-h); box-sizing: border-box; border: 1px solid var(--border); border-radius: var(--ctl-r); background: var(--bg); }
.ui-form .kb-weather-preview:empty { display: none; }
.ui-form .participants-field { margin-top: 1.6rem; }   /* le bloc des personnes est une SECTION : il respire au-dessus */
.ui-form .participants-title, .ui-form .participants-add-title { color: var(--text); font-size: 1rem; }
.ui-form .participants-editor { gap: 0.75rem; }
.ui-form .participants-filters { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 13rem) auto; gap: 0.5rem; align-items: center; }
.ui-form .role-filter-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0.5rem; align-items: center; }
.ui-form .participants-add { gap: 0.6rem; padding-top: 0.9rem; }
.ui-form .participants-add-title { font-size: 0.95rem; }
.ui-form .participants-add-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 14rem) auto; gap: 0.5rem; align-items: center; }
.ui-form .participants-cell-actions .btn-small { min-height: 34px; padding: 0 0.6rem; }
@media (max-width: 640px) {
    .ui-form .participants-filters, .ui-form .participants-add-row, .ui-form .role-filter-bar { grid-template-columns: minmax(0, 1fr); }
}

/* Diagnostic d'affichage de l'Agenda (v6.42.2) : actif seulement avec ?diag=1. Colore la bande de la barre d'état en rouge et affiche les mesures de l'appareil, pour voir ce
   que le navigateur annonce au lieu de le supposer. */
.cal-diag.cal-page::before { background: rgba(255, 0, 0, 0.85) !important; }
#cal-diag-box {
    position: fixed; left: 8px; right: 8px; bottom: calc(96px + env(safe-area-inset-bottom, 0px)); z-index: 60; margin: 0; padding: 8px 10px; border-radius: 8px;
    background: rgba(0, 0, 0, 0.88); color: #8f8; font: 11px/1.4 ui-monospace, Menlo, monospace; white-space: pre-wrap; pointer-events: none;
}

/* ---------- Sélecteur de date : heure, et rendu hors formulaire (v6.43.0) ---------- */
.dp-line { display: grid; grid-template-columns: minmax(0, 1fr); gap: 0.5rem; align-items: start; }
.dp-dt .dp-line { grid-template-columns: minmax(0, 1fr) 6.75rem; }
.dp-time[hidden] { display: none; }
/* Mêmes dimensions et même aspect que les autres champs, y compris HORS d'un formulaire « ui-form » (filtres, barres) : sélecteur peu spécifique, que les règles du socle remplacent. */
.dp-field input.dp-text, .dp-field input.dp-time {
    box-sizing: border-box; width: 100%; min-height: var(--ctl-h, 40px); margin: 0; padding: 0 0.75rem; border: 1px solid var(--border); border-radius: var(--ctl-r, 8px);
    background: var(--bg); color: var(--text); font: inherit; font-size: var(--ctl-font, 0.95rem); line-height: 1.3;
}
.dp-field input.dp-text { padding-right: calc(var(--ctl-h, 40px) + 4px) !important; }   /* la place du bouton calendrier, même sous les règles très spécifiques du socle */
.dp-field input.dp-time { text-align: center; padding: 0 0.4rem; font-variant-numeric: tabular-nums; }
.dp-field input.dp-text:disabled, .dp-field input.dp-time:disabled { opacity: 0.6; cursor: not-allowed; }
.dp-field input.dp-time.dp-invalid { border-color: var(--danger) !important; }
/* Lignes de période (vacances scolaires) : le sélecteur de date occupe une largeur fixe dans la rangée, comme le champ natif qu'il remplace. */
.admin-help-contact-row > .dp-field { flex: 0 0 200px; }

/* ---------- Fenêtre d'événement du calendrier au socle commun (v6.43.0) : les rangées en ligne de la section « Répéter » gardent leurs largeurs (les règles de champ du socle, très spécifiques, imposeraient 100 %) ---------- */
.ui-form .cal-recurrence-row, .ui-form .cal-recurrence-end-row { gap: 0.5rem; }
.ui-form .cal-recurrence-row input.cal-recurrence-interval { width: 5rem !important; }
.ui-form .cal-recurrence-row select { width: auto !important; min-width: 9rem; }
.ui-form .cal-recurrence-end-row input[type="number"] { width: 6rem !important; }
.ui-form .cal-recurrence-end-row .dp-field { flex: 0 0 13rem; }
.ui-form .cal-recurrence-weekday { min-height: 36px; }
.ui-form .admin-checkbox-field { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 var(--ui-gap); min-height: var(--ctl-h); }

/* ---------- Barre de filtres du Kanban au style commun (v6.43.0) : sa disposition en ligne est conservée (pas de « ui-form », qui étirerait chaque champ à 100 %) ; seuls les champs prennent
   les mêmes hauteur, coins, taille de police et flèche de liste que partout ailleurs. ---------- */
.kb-filters-bar select, .kb-filters-bar input:not([type="checkbox"]):not([type="radio"]) {
    box-sizing: border-box; min-height: var(--ctl-h, 40px); border-radius: var(--ctl-r, 8px); font-size: var(--ctl-font, 0.95rem);
}
.kb-filters-bar select {
    -webkit-appearance: none; appearance: none; padding-right: 2.2rem; cursor: pointer; text-overflow: ellipsis;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 1.1rem) 50%, calc(100% - 0.75rem) 50%; background-size: 0.35rem 0.35rem; background-repeat: no-repeat;
}
.kb-filters-bar .dp-field { min-width: 150px; }
.kb-filters-bar .btn-small { min-height: var(--ctl-h, 40px); border-radius: var(--ctl-r, 8px); }

/* ---------- Style commun des champs, appliqué à TOUS les motifs de formulaire de l'application (v6.44.0) ----------
   Mesuré avant : de 19 à 40 px de haut et de 0 à 8 px de rayon selon l'écran — les champs nombre, e-mail, téléphone, recherche et liste hors d'un « .admin-field » gardaient leur rendu
   natif de navigateur. Un seul jeu de variables (--ctl-h, --ctl-r, --ctl-font : 40 px, 8 px, 0,95 rem ; 44 px et 16 px sur appareil tactile) pour : champs de formulaire (.admin-field),
   filtres (.inbox-filter-field, .inbox-field), réglages de démonstration, barres d'outils (coffres, annuaire, images, messagerie, vues enregistrées, note d'ouverture), barre latérale
   (vault, recherche, mode d'affichage), réglages (test d'e-mail, avis de démonstration, tri des vaults), filtres d'en-tête de tableau, pages publiques. Chaque motif garde sa largeur d'origine, sauf les champs empilés d'un formulaire (.admin-field),
   qui prennent toute la largeur. */
.admin-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.admin-mail-test-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.cal-presets-controls > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.config-body > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.demo-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.demo-toggle-box > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.directory-toolbar-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.display-mode-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.inbox-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.inbox-filter-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.inbox-search-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.my-images-toolbar > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.opening-note-picker > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.search-box > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.vault-switcher > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.vaults-sort-wrap > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.vaults-toolbar > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]),
.password-field-wrap > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]) {
    box-sizing: border-box; min-height: var(--ctl-h); margin: 0; padding: 0 0.75rem; border: 1px solid var(--border); border-radius: var(--ctl-r);
    background-color: var(--bg); color: var(--text); font: inherit; font-size: var(--ctl-font); line-height: 1.3;
}
.admin-field > select,
.admin-mail-test-row > select,
.cal-presets-controls > select,
.config-body > select,
.demo-field > select,
.demo-toggle-box > select,
.directory-toolbar-row > select,
.display-mode-row > select,
.inbox-field > select,
.inbox-filter-field > select,
.inbox-search-row > select,
.my-images-toolbar > select,
.opening-note-picker > select,
.search-box > select,
.vault-switcher > select,
.vaults-sort-wrap > select,
.vaults-toolbar > select {
    box-sizing: border-box; min-height: var(--ctl-h); margin: 0; padding: 0 2.4rem 0 0.75rem; border: 1px solid var(--border); border-radius: var(--ctl-r);
    background-color: var(--bg); color: var(--text); font: inherit; font-size: var(--ctl-font); line-height: 1.3; cursor: pointer; text-overflow: ellipsis;
    -webkit-appearance: none; appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 1.15rem) 50%, calc(100% - 0.8rem) 50%; background-size: 0.35rem 0.35rem; background-repeat: no-repeat;
}
.admin-field > textarea,
.admin-mail-test-row > textarea,
.cal-presets-controls > textarea,
.config-body > textarea,
.demo-field > textarea,
.demo-toggle-box > textarea,
.directory-toolbar-row > textarea,
.display-mode-row > textarea,
.inbox-field > textarea,
.inbox-filter-field > textarea,
.inbox-search-row > textarea,
.my-images-toolbar > textarea,
.opening-note-picker > textarea,
.search-box > textarea,
.vault-switcher > textarea,
.vaults-sort-wrap > textarea,
.vaults-toolbar > textarea {
    box-sizing: border-box; min-height: 5.5rem; margin: 0; padding: 0.6rem 0.75rem; border: 1px solid var(--border); border-radius: var(--ctl-r);
    background-color: var(--bg); color: var(--text); font: inherit; font-size: var(--ctl-font); line-height: 1.4; resize: vertical;
}
.admin-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]), .admin-field > select, .admin-field > textarea { width: 100%; }
.password-field-wrap > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]) { flex: 1; padding-right: 2.6rem; }
input[type="search"] { -webkit-appearance: none; appearance: none; }

/* Champ NON modifiable (désactivé ou en lecture seule) : fond et texte distincts d'un champ modifiable (v6.44.0). La règle globale ci-dessus, plus spécifique que l'ancienne règle de
   .admin-field, avait supprimé cette distinction — repéré par le test d'ergonomie. */
.admin-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.admin-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.admin-field > select:disabled,
.admin-field > textarea:disabled,
.admin-field > textarea[readonly],
.admin-mail-test-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.admin-mail-test-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.admin-mail-test-row > select:disabled,
.admin-mail-test-row > textarea:disabled,
.admin-mail-test-row > textarea[readonly],
.cal-presets-controls > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.cal-presets-controls > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.cal-presets-controls > select:disabled,
.cal-presets-controls > textarea:disabled,
.cal-presets-controls > textarea[readonly],
.config-body > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.config-body > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.config-body > select:disabled,
.config-body > textarea:disabled,
.config-body > textarea[readonly],
.demo-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.demo-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.demo-field > select:disabled,
.demo-field > textarea:disabled,
.demo-field > textarea[readonly],
.demo-toggle-box > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.demo-toggle-box > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.demo-toggle-box > select:disabled,
.demo-toggle-box > textarea:disabled,
.demo-toggle-box > textarea[readonly],
.directory-toolbar-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.directory-toolbar-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.directory-toolbar-row > select:disabled,
.directory-toolbar-row > textarea:disabled,
.directory-toolbar-row > textarea[readonly],
.display-mode-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.display-mode-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.display-mode-row > select:disabled,
.display-mode-row > textarea:disabled,
.display-mode-row > textarea[readonly],
.inbox-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.inbox-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.inbox-field > select:disabled,
.inbox-field > textarea:disabled,
.inbox-field > textarea[readonly],
.inbox-filter-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.inbox-filter-field > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.inbox-filter-field > select:disabled,
.inbox-filter-field > textarea:disabled,
.inbox-filter-field > textarea[readonly],
.inbox-search-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.inbox-search-row > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.inbox-search-row > select:disabled,
.inbox-search-row > textarea:disabled,
.inbox-search-row > textarea[readonly],
.my-images-toolbar > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.my-images-toolbar > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.my-images-toolbar > select:disabled,
.my-images-toolbar > textarea:disabled,
.my-images-toolbar > textarea[readonly],
.opening-note-picker > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.opening-note-picker > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.opening-note-picker > select:disabled,
.opening-note-picker > textarea:disabled,
.opening-note-picker > textarea[readonly],
.search-box > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.search-box > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.search-box > select:disabled,
.search-box > textarea:disabled,
.search-box > textarea[readonly],
.vault-switcher > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.vault-switcher > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.vault-switcher > select:disabled,
.vault-switcher > textarea:disabled,
.vault-switcher > textarea[readonly],
.vaults-sort-wrap > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.vaults-sort-wrap > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.vaults-sort-wrap > select:disabled,
.vaults-sort-wrap > textarea:disabled,
.vaults-sort-wrap > textarea[readonly],
.vaults-toolbar > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled,
.vaults-toolbar > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"])[readonly],
.vaults-toolbar > select:disabled,
.vaults-toolbar > textarea:disabled,
.vaults-toolbar > textarea[readonly],
.password-field-wrap > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]):disabled {
    background-color: var(--bg-hover); color: var(--text-muted); cursor: not-allowed;
}

/* Filtres d'en-tête de tableau : variante COMPACTE assumée (un tableau dense ne supporte pas une rangée de champs de 40 px), mais mêmes coins, police et couleurs. */
table th > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]), table th > select, table td > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]), table td > select, select.admin-inline-select {
    box-sizing: border-box; min-height: 32px; padding: 0 0.5rem; border: 1px solid var(--border); border-radius: 6px; background-color: var(--bg); color: var(--text); font: inherit; font-size: 0.85rem;
}
/* Au doigt, la variante compacte monte à 40 px et 16 px de police (sinon Safari agrandit la page au focus). */
@media (hover: none), (pointer: coarse) {
    table th > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]), table th > select, table td > input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]):not([type="file"]):not([type="hidden"]):not([type="button"]):not([type="submit"]), table td > select, select.admin-inline-select { min-height: 40px; font-size: 16px; }
}

/* Cases à cocher et boutons radio : couleur d'accent de l'application (sinon un grand carré blanc natif, surtout visible en thème sombre sur téléphone), taille commune et alignement
   avec leur libellé (v6.44.0). */
input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }
.admin-checkbox-field { display: flex; align-items: center; gap: 0.5rem; }
.admin-checkbox-field > input[type="checkbox"], .admin-checkbox-field > input[type="radio"] { width: 1.15rem; height: 1.15rem; flex: none; margin: 0; }
@media (hover: none), (pointer: coarse) {
    .admin-checkbox-field > input[type="checkbox"], .admin-checkbox-field > input[type="radio"] { width: 1.4rem; height: 1.4rem; }
}

/* Style de formulaire commun : espacement des boutons posés directement dans la fenêtre, filet de séparation, et champ de couleur standard (v6.44.0). Constat : dans les réglages d'un
   agenda, sept boutons étaient collés les uns aux autres et le sélecteur de couleur était une petite boîte blanche native. */
.ui-form > .btn-small { margin: 0 0.5rem 0.75rem 0; }
.ui-form > hr { border: 0; border-top: 1px solid var(--border); margin: 1rem 0; }
.ui-form input[type="color"] {
    -webkit-appearance: none; appearance: none; box-sizing: border-box; flex: none; align-self: flex-start; width: 44px; height: var(--ctl-h); padding: 3px;
    border: 1px solid var(--border); border-radius: var(--ctl-r); background: var(--bg); cursor: pointer;
}
.ui-form input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
.ui-form input[type="color"]::-webkit-color-swatch { border: 0; border-radius: calc(var(--ctl-r) - 3px); }
.ui-form input[type="color"]::-moz-color-swatch { border: 0; border-radius: calc(var(--ctl-r) - 3px); }

/* Cases à cocher des fenêtres, formulaires et panneaux d'administration : rendu commun (v6.44.0). Constat : de grands carrés blancs natifs, très voyants en thème sombre (liste « Groupes »
   d'un nouvel utilisateur, cases de consentement). Bord et fond de l'application, coche à la couleur d'accent, état intermédiaire ; taille 1,15 rem (1,4 rem au doigt). */
.modal-body input[type="checkbox"], .admin-panel input[type="checkbox"], .ui-form input[type="checkbox"] {
    -webkit-appearance: none; appearance: none; box-sizing: border-box; flex: none; display: inline-grid; place-content: center; vertical-align: middle; margin: 0;
    width: 1.15rem; height: 1.15rem; border: 1.5px solid var(--text-muted); border-radius: 5px; background: var(--bg); cursor: pointer;
}
.modal-body input[type="checkbox"]:checked, .admin-panel input[type="checkbox"]:checked, .ui-form input[type="checkbox"]:checked,
.modal-body input[type="checkbox"]:indeterminate, .admin-panel input[type="checkbox"]:indeterminate, .ui-form input[type="checkbox"]:indeterminate { background: var(--accent); border-color: var(--accent); }
.modal-body input[type="checkbox"]:checked::after, .admin-panel input[type="checkbox"]:checked::after, .ui-form input[type="checkbox"]:checked::after {
    content: ''; width: 0.3rem; height: 0.58rem; border: solid var(--accent-contrast, #fff); border-width: 0 2px 2px 0; transform: translateY(-1px) rotate(45deg);
}
.modal-body input[type="checkbox"]:indeterminate::after, .admin-panel input[type="checkbox"]:indeterminate::after, .ui-form input[type="checkbox"]:indeterminate::after {
    content: ''; width: 0.6rem; height: 2px; background: var(--accent-contrast, #fff);
}
.modal-body input[type="checkbox"]:disabled, .admin-panel input[type="checkbox"]:disabled, .ui-form input[type="checkbox"]:disabled { opacity: 0.55; cursor: not-allowed; }
.modal-body input[type="checkbox"]:focus-visible, .admin-panel input[type="checkbox"]:focus-visible, .ui-form input[type="checkbox"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (hover: none), (pointer: coarse) {
    .modal-body input[type="checkbox"], .admin-panel input[type="checkbox"], .ui-form input[type="checkbox"] { width: 1.4rem; height: 1.4rem; }
}

/* ---------- Canvas : style des liens et sélection multiple (v6.46.0) ---------- */
.canvas-edge-style { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0.5rem; }
.canvas-edge-palette, .canvas-edge-seg { display: inline-flex; align-items: center; gap: 0.25rem; }
.canvas-edge-seg { padding: 2px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); }
.canvas-edge-swatch { width: 22px; height: 22px; padding: 0; border: 2px solid transparent; border-radius: 50%; cursor: pointer; box-shadow: 0 0 0 1px var(--border); }
.canvas-edge-swatch[aria-pressed="true"] { border-color: var(--text); }
.canvas-edge-swatch-default { background: linear-gradient(135deg, var(--accent) 50%, var(--bg) 50%); }
.canvas-edge-color-input { width: 26px; height: 26px; padding: 0; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); cursor: pointer; }
.canvas-edge-seg-btn { display: inline-flex; align-items: center; justify-content: center; min-width: 40px; height: 28px; padding: 0 4px; border: 1px solid transparent; border-radius: 6px; background: none; color: var(--text); cursor: pointer; }
.canvas-edge-seg-btn:hover { background: var(--bg-hover); }
.canvas-edge-seg-btn[aria-pressed="true"] { background: var(--accent); color: var(--accent-contrast); }
.canvas-edge-swatch:disabled, .canvas-edge-seg-btn:disabled, .canvas-edge-color-input:disabled { opacity: 0.5; cursor: not-allowed; }
@media (pointer: coarse) {
    .canvas-edge-swatch { width: 32px; height: 32px; }
    .canvas-edge-color-input { width: 36px; height: 36px; }
    .canvas-edge-seg-btn { min-width: 48px; height: 40px; }
}
/* Bouton « Plusieurs liens » : seulement au doigt (à la souris : Maj/Ctrl + clic et rectangle). */
.canvas-edge-multi-btn { display: none; }
@media (pointer: coarse) { .canvas-edge-multi-btn { display: inline-flex; } }
.canvas-edge-multi-btn[aria-pressed="true"] { background: var(--accent); color: var(--accent-contrast); }
.canvas-rubber { position: absolute; z-index: 7; pointer-events: none; border: 1px dashed var(--accent); background: rgba(100, 140, 255, 0.12); }
.canvas-rubbering, .canvas-rubbering * { user-select: none; -webkit-user-select: none; }
.canvas-edge-bridge-btn { gap: 4px; padding: 0 8px; font-size: 0.8rem; }

/* ---------- Couleur d'un tableau Kanban (v6.48.0) ---------- */
.kb-board-card { border-left: 6px solid var(--board-color, var(--border)); }
.kb-board-color-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.45rem; }
.kb-color-swatch { width: 30px; height: 30px; padding: 0; border: 2px solid transparent; border-radius: 50%; cursor: pointer; box-shadow: 0 0 0 1px var(--border); }
.kb-color-swatch[aria-pressed="true"] { border-color: var(--text); }
.kb-color-auto[aria-pressed="true"] { background: var(--accent); color: var(--accent-contrast); }
@media (pointer: coarse) { .kb-color-swatch { width: 40px; height: 40px; } }

/* ---------- Navigation en épi 3D des tâches Kanban (v6.49.0) ---------- */
.kb-epi[hidden], .kb-epi-float[hidden] { display: none; }
.kb-epi { display: flex; flex-direction: column; gap: 0.6rem; padding-bottom: 1rem; }
.kb-epi-header { display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap; }
.kb-epi-header h2 { margin: 0; font-size: 1.15rem; }
.kb-epi-count { margin-left: auto; color: var(--text-muted); font-size: 0.9rem; }
/* La scène est découpée à son bord (overflow: hidden) : sans marge, l'ombre des cartes y était coupée net, laissant une limite visible. La marge contient TOUTE l'ombre (la carte sortie projette la plus grande : 8px 10px 26px, soit 34 px à droite et 36 px en bas). */
.kb-epi-stage { position: relative; display: flex; justify-content: center; min-height: 120px; overflow: hidden; padding: 56px 44px 44px; }
/* La perspective s'applique aux ENFANTS directs : c'est donc la pile qui la porte (pas la scène). Pas de preserve-3d : l'ordre d'empilement des cartes est réglé par z-index. */
.kb-epi-pile { position: relative; perspective: 1600px; perspective-origin: 30% 25%; }
.epi-card {
    position: absolute; left: 0; width: var(--epi-w, 220px); height: var(--epi-h, 320px); transform-origin: left center; border-radius: 16px 16px 22px 22px;
    background: linear-gradient(160deg, #ececec, #dcdcdc); box-shadow: 4px 6px 14px rgba(0, 0, 0, 0.35); overflow: hidden; color: #1b1d22;
    transition: transform 0.38s cubic-bezier(0.22, 0.8, 0.3, 1), filter 0.2s, opacity 0.25s;
}
.epi-card.out { box-shadow: 8px 10px 26px rgba(0, 0, 0, 0.5); }
.epi-card.current { cursor: pointer; }
/* Cartes qui entrent dans la fenêtre ou la quittent : fondu. */
.epi-card.entering, .epi-card.leaving { opacity: 0; pointer-events: none; }
.epi-card-head {
    position: relative; display: flex; align-items: center; justify-content: flex-start; height: 22%; padding: 0 6%; background: var(--epi-color, #29b6f6);
    color: var(--epi-ink, #1b1d22); font-weight: 600; font-size: max(11px, calc(var(--epi-w, 220px) * 0.078));
}   /* texte de l'en-tête : blanc ou noir selon la couleur du tableau, 4,5:1 au moins (RGAA 3.2) — voir shared-contrast.js */
.epi-card.mine .epi-card-head { padding-right: 26%; }
.epi-card-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; max-width: 100%; }
.epi-moi { position: absolute; top: 12%; right: 5%; padding: 2px 9px; border-radius: 999px; background: #fff; color: var(--epi-pill-ink, #1b1d22); text-shadow: none; font-size: calc(var(--epi-w, 220px) * 0.06); font-weight: 800; letter-spacing: 0.03em; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25); }
.epi-card-body { display: flex; flex-direction: column; gap: calc(var(--epi-w, 220px) * 0.035); padding: 6% 6% 0; }
/* Le détail d'une carte (date, Réalisateur, avancement, tag, pied) n'est lisible que lorsqu'elle est SORTIE. */
.epi-date, .epi-roles, .epi-progress, .epi-card-foot { opacity: 0; transition: opacity 0.25s; }
.epi-card.current .epi-date, .epi-card.current .epi-roles, .epi-card.current .epi-progress, .epi-card.current .epi-tag, .epi-card.current .epi-card-foot { opacity: 1; }
/* Le texte courant de la carte est #1b1d22 sur un fond gris de #ececec à #dcdcdc : plus de 12:1. Le rouge est assombri (#a8201a) : le rouge habituel n'y fait que 3,5:1, sous les 4,5:1 du RGAA. */
.epi-date { display: flex; align-items: flex-start; gap: calc(var(--epi-w, 220px) * 0.03); font-weight: 700; font-size: max(11px, calc(var(--epi-w, 220px) * 0.07)); }
.epi-date-main { display: flex; flex-direction: column; min-width: 0; }
.epi-date-text { white-space: nowrap; }
.epi-date-text abbr { text-decoration: none; cursor: inherit; }
.epi-days { display: block; font-weight: 500; white-space: normal; overflow-wrap: anywhere; line-height: 1.25; }
.epi-days.late { color: #a8201a; font-weight: 700; }
.epi-roles { display: flex; flex-direction: column; gap: calc(var(--epi-w, 220px) * 0.02); }
.epi-role-row { display: flex; align-items: center; gap: calc(var(--epi-w, 220px) * 0.03); min-width: 0; font-size: max(11px, calc(var(--epi-w, 220px) * 0.07)); }
.epi-role-badge { flex: none; display: inline-grid; place-items: center; width: calc(var(--epi-w, 220px) * 0.09); height: calc(var(--epi-w, 220px) * 0.09); border-radius: 4px; background: var(--epi-color, #29b6f6); color: var(--epi-ink, #1b1d22); font-size: max(9px, calc(var(--epi-w, 220px) * 0.058)); font-weight: 800; text-shadow: none; }
.epi-person { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: help; border-bottom: 1px dotted rgba(0, 0, 0, 0.45); }
.epi-person:focus-visible, .epi-kanban-link:focus-visible { outline: 2px solid var(--epi-color, #29b6f6); outline-offset: 2px; }
.epi-none { color: #a8201a; font-weight: 700; }
/* Barre d'avancement : piste de la couleur de l'en-tête, partie avancée blanche qui porte la valeur. */
.epi-progress { position: relative; height: calc(var(--epi-w, 220px) * 0.095); padding: 2px; border-radius: 999px; background: var(--epi-color, #29b6f6); }
.epi-progress-fill { display: block; height: 100%; border-radius: 999px; background: #fff; }
.epi-progress-label { position: absolute; top: 50%; transform: translate(-50%, -50%); font-size: max(10px, calc(var(--epi-w, 220px) * 0.058)); font-weight: 600; color: #1b1d22; white-space: nowrap; text-shadow: none; }
.epi-progress-label.low { transform: translateY(-50%); color: var(--epi-ink, #1b1d22); }
/* Pied : un filet de la couleur de l'en-tête, puis le nom du kanban. */
.epi-card-foot { position: absolute; left: 0; right: 0; bottom: 0; height: 13%; display: flex; align-items: center; justify-content: center; border-top: 3px solid var(--epi-color, #29b6f6); background: rgba(0, 0, 0, 0.04); padding: 0 6%; }
.epi-kanban-link { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0; border: 0; background: none; color: #1b1d22; font: inherit; font-size: max(11px, calc(var(--epi-w, 220px) * 0.07)); cursor: pointer; }
.epi-kanban-link:hover { text-decoration: underline; }
.epi-date-arrow { width: 0; height: 0; border-left: 0.9em solid var(--epi-color, #29b6f6); border-top: 0.65em solid transparent; border-bottom: 0.65em solid transparent; flex: none; margin-top: 0.08em; }
.epi-tag { align-self: flex-start; padding: 2px 8px; border-radius: 6px; background: rgba(0, 0, 0, 0.1); font-size: calc(var(--epi-w, 220px) * 0.055); font-weight: 700; opacity: 0; transition: opacity 0.25s; }
/* Grisée, mais OPAQUE : une carte translucide au premier plan laissait voir le titre de la carte derrière elle. */
.epi-card.finished { filter: grayscale(1) brightness(0.9); }
/* Flèche de navigation en perspective : un curseur ovale la parcourt, dans les deux sens. */
.kb-epi-empty { text-align: center; padding: 2rem 1rem; }
@media (prefers-reduced-motion: reduce) { .epi-card, .epi-date, .epi-roles, .epi-progress, .epi-card-foot, .epi-tag, .kb-epi-thumb { transition: none; } }
/* Fenêtre flottante d'une tâche : au premier plan, déplaçable par son en-tête, refermable. */
.kb-epi-float {
    position: fixed; z-index: 60; width: min(360px, calc(100vw - 16px)); max-height: min(80vh, 560px); display: flex; flex-direction: column;
    background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); border-top: 6px solid var(--epi-color, #29b6f6); border-radius: 12px; box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5);
}
.kb-epi-float-head { display: flex; align-items: center; gap: 0.5rem; padding: 0.55rem 0.7rem; cursor: move; touch-action: none; border-bottom: 1px solid var(--border); }
.kb-epi-float-title { margin: 0; flex: 1; font-size: 1rem; overflow-wrap: anywhere; }
.kb-epi-float-close { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; border: 0; border-radius: 8px; background: none; color: var(--text); cursor: pointer; }
.kb-epi-float-close svg { width: 18px; height: 18px; }
.kb-epi-float-close:hover { background: var(--bg-hover); }
.kb-epi-float-body { padding: 0.6rem 0.8rem 0.8rem; overflow: auto; display: flex; flex-direction: column; gap: 0.5rem; }
.kb-epi-float-row { display: flex; flex-direction: column; gap: 2px; }
.kb-epi-float-label { font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
.kb-epi-float-value { font-size: 0.92rem; overflow-wrap: anywhere; }
.kb-epi-float-desc { white-space: pre-wrap; }
.kb-epi-float-people, .kb-epi-float-notes { margin: 0; padding-left: 1.1rem; }
.kb-epi-float-progress { display: block; height: 8px; border-radius: 4px; background: var(--bg-hover); overflow: hidden; margin-bottom: 3px; }
.kb-epi-float-progress span { display: block; height: 100%; background: var(--epi-color, #29b6f6); }
.kb-epi-board-link { padding: 0; border: 0; background: none; color: var(--accent); font: inherit; font-weight: 700; text-decoration: underline; cursor: pointer; text-align: left; }
@media (max-width: 700px) { .kb-epi-float { left: 8px !important; right: 8px !important; top: auto !important; bottom: 8px !important; width: auto; } .kb-epi-float-head { cursor: default; } }
/* Étiquette sous le curseur (« dans 65 j ») et bulle d'annuaire au survol d'un nom (v6.50.0). */
.kb-epi-person-tip { position: fixed; z-index: 70; max-width: min(320px, calc(100vw - 16px)); padding: 0.55rem 0.7rem; display: flex; flex-direction: column; gap: 0.25rem; background: var(--bg-elevated); color: var(--text); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 10px 28px rgba(0, 0, 0, 0.5); font-size: 0.88rem; pointer-events: none; }
.kb-epi-person-tip[hidden] { display: none; }
.kb-epi-tip-name { font-weight: 700; font-size: 0.95rem; }
.kb-epi-tip-row { display: flex; flex-direction: column; }
.kb-epi-tip-label { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-muted); }
/* Téléphone : marges plus étroites, donc ombres plus courtes (elles tiennent dans la marge : 13 px pour une carte de la pile, 16 px pour la carte sortie). */
@media (max-width: 700px) {
    .kb-epi-stage { padding: 56px 22px 44px 8px; }   /* étroite à gauche (l'ombre y est courte), plus large à droite (ombre de la carte sortie) */
    .epi-card { box-shadow: 3px 4px 10px rgba(0, 0, 0, 0.35); }
    .epi-card.out { box-shadow: 4px 6px 12px rgba(0, 0, 0, 0.5); }
}

/* ---------- Barre de navigation horizontale, fenêtre de 8 cartes, flèches, filtre (v6.51.0) ---------- */
/* Gris de la barre = gris des cartes grisées : le fond des cartes va de #ececec à #dcdcdc (moyenne #e4e4e4), assombri de 10 % par `filter: brightness(0.9)` : #cdcdcd. */
.kb-epi { --epi-grey: #cdcdcd; }
.kb-epi-rail-wrap { position: relative; height: 140px; margin-top: -40px; touch-action: none; user-select: none; }
.kb-epi-rail-wrap[hidden] { display: none; }
.kb-epi-bar { position: absolute; left: 0; right: 0; top: 56px; height: 40px; background: var(--epi-grey); clip-path: polygon(0 50%, 26px 0, calc(100% - 26px) 0, 100% 50%, calc(100% - 26px) 100%, 26px 100%); cursor: pointer; }
/* L'aiguille : une étiquette arrondie au-dessus, un trait rouge qui traverse la barre, deux triangles rouges dessous (on la glisse à gauche ou à droite). Zone de saisie large pour le doigt. */
.kb-epi-thumb { position: absolute; top: 0; width: 70px; height: 124px; margin-left: -35px; display: flex; flex-direction: column; align-items: center; cursor: grab; touch-action: none; }
.kb-epi-thumb:active { cursor: grabbing; }
.kb-epi-thumb:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 10px; }
.kb-epi-pill { position: relative; z-index: 1; padding: 3px 14px; border: 2px solid #1b1d22; border-radius: 999px; background: #fff; color: #1b1d22; font-size: 0.95rem; line-height: 1.3; white-space: nowrap; }
.kb-epi-pill.late { color: #a8201a; }
.kb-epi-needle { position: absolute; top: 30px; bottom: 0; left: 50%; width: 4px; margin-left: -2px; background: #d32f2f; }
.kb-epi-tri { position: absolute; bottom: 2px; width: 0; height: 0; border-top: 11px solid transparent; border-bottom: 11px solid transparent; }
.kb-epi-tri-left { left: 4px; border-right: 16px solid #d32f2f; }
.kb-epi-tri-right { right: 4px; border-left: 16px solid #d32f2f; }
.kb-epi-rail-label { position: absolute; bottom: 0; font-size: 0.85rem; color: var(--text-muted); }
.kb-epi-rail-now { left: 2px; }
.kb-epi-rail-future { right: 2px; }
/* Flèches rouges : des cartes existent avant / après la fenêtre ; leur nombre est écrit en rouge sur une pastille blanche (4,5:1 au moins, quel que soit le thème). */
.kb-epi-more { position: absolute; z-index: 200; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 4px; border: 0; background: none; cursor: pointer; }
.kb-epi-more[hidden] { display: none; }
.kb-epi-more svg { width: 38px; height: 26px; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.45)); }
.kb-epi-more-after { color: #ef5350; }
.kb-epi-more-after svg { transform: rotate(-35deg); }
.kb-epi-more-before { color: #b3261e; flex-direction: column-reverse; }
.kb-epi-more-before svg { transform: rotate(180deg); }
.kb-epi-more-count { min-width: 1.9em; padding: 1px 8px; border-radius: 999px; background: #fff; color: #a8201a; font-weight: 800; font-size: 0.85rem; line-height: 1.4; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35); }
.kb-epi-more:focus-visible { outline: 3px solid var(--accent); border-radius: 10px; }
/* Liste déroulante de filtrage : en haut à gauche du groupe de cartes (sa position horizontale suit la pile). */
.kb-epi-filter-wrap { position: absolute; top: 8px; left: 8px; z-index: 6; }
.kb-epi-filter-wrap[hidden] { display: none; }
.kb-epi-filter { width: 100%; }   /* aspect : style commun des champs (.ui-form select) */
@media (max-width: 700px) {
    .kb-epi-rail-wrap { height: 134px; margin-top: -34px; }
    .kb-epi-pill { font-size: 0.88rem; padding: 2px 11px; }
}

/* ---------- Profil : liste des filtres de la navigation en épi (v6.52.0) ---------- */
.epi-pref-list { list-style: none; margin: 0 0 0.6rem; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.epi-pref-row { display: flex; align-items: center; gap: 0.4rem; padding: 0.2rem 0.5rem; border: 1px solid var(--border); border-radius: 8px; background: var(--bg); }
.epi-pref-row.is-sep { border-style: dashed; color: var(--text-muted); }
.epi-pref-label { flex: 1; display: flex; align-items: center; gap: 0.4rem; min-width: 0; cursor: pointer; }
.epi-pref-row.is-sep .epi-pref-label { cursor: default; }
.epi-pref-btn { width: 36px; min-height: 36px; padding: 0; display: inline-flex; align-items: center; justify-content: center; flex: none; }
@media (pointer: coarse) { .epi-pref-btn { width: 44px; min-height: 44px; } }
.epi-pref-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }

/* Poignée de déplacement des lignes de la liste des filtres (glisser-déposer ; au clavier : flèches haut et bas) et ligne en cours de déplacement (v6.53.0). */
.epi-pref-handle { flex: none; width: 28px; min-height: 36px; padding: 0; border: 0; border-radius: 6px; background: none; color: var(--text); cursor: grab; touch-action: none; display: inline-flex; align-items: center; justify-content: center; }
.epi-pref-handle:hover { background: var(--bg-hover); }
.epi-pref-handle:focus-visible { outline: 2px solid var(--accent); }
.epi-pref-handle:active { cursor: grabbing; }
@media (pointer: coarse) { .epi-pref-handle { width: 44px; min-height: 44px; } }
.epi-pref-row.is-dragging { position: relative; z-index: 2; border-color: var(--accent); background: var(--bg-hover); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45); }

