@import url('variables.css');

/* ===== RESET ===== */
*, *::before, *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    font-size: 14px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Same background as body so Safari / Chrome mobile don't flash a white
       strip at the top or bottom when the address bar shows/hides. */
    background: var(--color-bg);
    height: 100%;
    /* color-scheme aligne le rendu natif des contrôles (date picker,
       scrollbar, checkbox, select dropdown) sur le thème AQIN. Sans ça,
       le calendar picker du navigateur reste blanc même en mode sombre. */
    color-scheme: light dark;
    /* Couleur de la sélection dans les date pickers natifs, checkboxes,
       radios, range, progress — identique au primary du design system. */
    accent-color: var(--color-primary, #3b82f6);
    /* Empêche le double-tap-to-zoom natif mobile (Safari/Chrome) sans
       désactiver le pincement-zoom (accessibilité) -- "manipulation" =
       pan + pinch-zoom autorisés, double-tap-zoom retiré. Les éléments
       qui déclarent déjà leur propre touch-action (canvas Ardoise, lignes
       swipe Aurore, carrousels drag) restent prioritaires : la cascade CSS
       classique s'applique, cette règle n'est qu'une base par défaut. */
    touch-action: manipulation;
    /* iOS Safari/PWA : un appui long ouvre son PROPRE menu callout (Copier/
       Partager/Regarder) en concurrence avec les menus contextuels custom
       de l'app (long-press -> event 'contextmenu' -> ContextMenu.show()) --
       lequel des deux gagne est aléatoire, contrairement au clic droit PC
       où e.preventDefault() sur 'contextmenu' supprime déjà totalement le
       menu natif du navigateur. -webkit-touch-callout hérite, donc une
       seule règle ici couvre toute l'app ; réactivé explicitement plus bas
       sur les vraies surfaces de saisie/édition, où le copier/coller natif
       iOS reste voulu (signalé 2026-08-12).*/
    -webkit-touch-callout: none;
    /* Flash bleu translucide qu'iOS/WebKit peint par défaut sur l'élément
       tenu au doigt -- propriété DIFFÉRENTE de -webkit-touch-callout
       ci-dessus (celle-là gère le menu natif Copier/Partager, celle-ci la
       couleur de retour visuel au toucher). Jamais désactivée jusqu'ici ;
       particulièrement visible sur un appui long (500ms, cf
       _wireLongPressSelection dans app.js) qui lui laisse largement le
       temps de s'afficher avant que le menu contextuel personnalisé
       n'apparaisse par-dessus (signalé 2026-08-16 : "la page colore tout
       en bleu"). */
    -webkit-tap-highlight-color: transparent;
}
/* Surfaces de saisie/édition réelles : on laisse iOS gérer sélection/
   copier-coller nativement (Scribe, commentaires, composeurs Aurore/Flow,
   champs de formulaire...) -- [contenteditable="true"] exclut bien les
   blocs contenteditable="false" (ex. images Scribe, cf
   reference_contenteditable_atomic_block_split), qui doivent rester
   couverts par le "none" ci-dessus comme le reste du chrome de l'app. */
input, textarea, [contenteditable="true"] {
    -webkit-touch-callout: default;
}
/* data-theme est posé sur <html> par js/app.js. On force color-scheme
   correspondant pour que les contrôles natifs (calendar picker, scrollbar)
   suivent. */
html[data-theme="dark"]  { color-scheme: dark; }
html[data-theme="light"] { color-scheme: light; }

/* Date picker indicator — l'icône à droite du champ <input type="date">.
   Par défaut elle est noire/grise et invisible sur fond sombre. On la
   passe au filter pour qu'elle s'aligne sur la couleur du texte AQIN. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
    cursor: pointer;
    opacity: 0.7;
    transition: opacity 0.15s, filter 0.15s;
    /* En thème sombre, on inverse l'icône pour qu'elle ressorte */
    filter: invert(0);
}
html[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator,
html[data-theme="dark"] input[type="datetime-local"]::-webkit-calendar-picker-indicator,
html[data-theme="dark"] input[type="month"]::-webkit-calendar-picker-indicator,
html[data-theme="dark"] input[type="time"]::-webkit-calendar-picker-indicator {
    filter: invert(1) hue-rotate(180deg);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover,
input[type="month"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover {
    opacity: 1;
}

/* Inputs date — alignement visuel avec le reste des form-input */
input[type="date"], input[type="datetime-local"], input[type="month"], input[type="time"] {
    color-scheme: inherit;
    accent-color: var(--color-primary);
    font-family: inherit;
}

body {
    font-family: var(--font-family);
    color: var(--color-text);
    background: var(--color-bg);
    line-height: 1.5;
    /* Comportement scroll calé sur la home (qui n'a jamais eu le bug de freeze
       au top/bottom sur iOS Safari). L'ancien `overflow:hidden + height:100vh
       + overscroll-behavior:none` venait du layout legacy avec sidebar (où
       body ne scrollait pas) — plus utilisé. Avec body scrollable + pas
       d'overscroll-behavior:none, le rubber-band iOS débloque naturellement
       le scroll quand on atteint les limites. Plus besoin de rafraîchir la
       page mobile. */
    overflow-x: hidden;
    overflow-y: auto;
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
    touch-action: manipulation;
}

a {
    color: var(--color-primary);
    text-decoration: none;
}

/* Pas de soulignement au hover — l'effet visuel d'interactivité passe
   par d'autres canaux (couleur, transform, ombre selon contexte).
   Évite les soulignements parasites sur les liens "card wrapping"
   (.nebula-album-card-link, etc.) qui héritent ce style. */
a:hover {
    text-decoration: none;
}

button {
    font-family: inherit;
    cursor: pointer;
    border: none;
    background: none;
    font-size: inherit;
}

input, select, textarea {
    font-family: inherit;
    font-size: inherit;
}

/* ===== LAYOUT ===== */
.app {
    display: flex;
    height: 100vh;
}

/* === Notifications slide-in panel (from right) === */
/* Notification pulse animation on new notif */
@keyframes notif-pulse-anim {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.18); }
    60%  { transform: scale(0.95); }
    100% { transform: scale(1); }
}
.notif-pulse { animation: notif-pulse-anim 0.6s ease; }

/* === Messages slide-in panel (global messaging) === */
.messages-slide-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.5);
    backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
    z-index: 998; opacity: 0; pointer-events: none;
    transition: opacity 0.25s ease;
}
.messages-slide-overlay.visible { opacity: 1; pointer-events: auto; }
.messages-slide-panel {
    position: fixed;
    top: 20px; right: 20px; bottom: 20px;
    width: 420px;
    max-width: calc(100vw - 40px);
    background: var(--color-surface);
    border-radius: 20px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.25);
    z-index: 999;
    display: flex; flex-direction: column;
    overflow: hidden;
    transform: translateX(calc(100% + 40px));
    transition: transform 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}
.messages-slide-panel.visible { transform: translateX(0); }
.messages-slide-header {
    display: flex; align-items: center; gap: 8px;
    padding: 16px 20px 12px; flex-shrink: 0;
    border-bottom: 1px solid var(--color-border);
}
.messages-slide-header h3 { flex: 1; font-size: 16px; font-weight: 700; margin: 0; color: var(--color-text); }
.messages-slide-body { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.messages-ws-list { flex: 1; overflow-y: auto; padding: 8px; }
.messages-ws-item {
    width: 100%; display: flex; align-items: center; gap: 12px;
    padding: 10px 12px; border-radius: 12px; border: none; background: transparent;
    color: var(--color-text); text-align: left; cursor: pointer; transition: background 0.15s;
}
.messages-ws-item:hover { background: var(--color-hover, var(--color-bg)); }
.messages-ws-avatar {
    width: 40px; height: 40px; border-radius: 12px;
    display: flex; align-items: center; justify-content: center;
    color: #fff; font-size: 14px; font-weight: 700; flex-shrink: 0;
}
.messages-ws-info { flex: 1; min-width: 0; }
.messages-ws-name { font-size: 14px; font-weight: 600; color: var(--color-text); }
.messages-ws-sub { font-size: 12px; color: var(--color-text-tertiary); }
.messages-empty { text-align: center; color: var(--color-text-tertiary); font-size: 13px; padding: 40px 20px; }
.messages-chat { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.messages-chat-list {
    flex: 1; overflow-y: auto; padding: 14px 16px;
    display: flex; flex-direction: column; gap: 8px;
}
.messages-msg { display: flex; flex-direction: column; max-width: 80%; }
.messages-msg.mine { align-self: flex-end; align-items: flex-end; }
.messages-msg-bubble {
    padding: 8px 12px; border-radius: 14px; font-size: 13px; line-height: 1.4;
    background: var(--color-bg); color: var(--color-text); word-break: break-word;
    white-space: pre-wrap;
}
.messages-msg.mine .messages-msg-bubble { background: var(--color-primary); color: #fff; }
.messages-msg-meta { font-size: 10px; color: var(--color-text-tertiary); margin-top: 2px; padding: 0 4px; }
.messages-chat-composer {
    display: flex; gap: 6px; padding: 10px; border-top: 1px solid var(--color-border);
    flex-shrink: 0;
}
.messages-chat-composer input {
    flex: 1; padding: 8px 12px; border: 1px solid var(--color-border);
    border-radius: 18px; background: var(--color-surface); color: var(--color-text); font-size: 13px;
}
.messages-chat-composer input:focus { outline: none; border-color: var(--color-primary); }
.messages-chat-composer button { border-radius: 50%; width: 36px; height: 36px; padding: 0; flex-shrink: 0; }
@media (max-width: 600px) {
    .messages-slide-panel { top: 12px; right: 12px; bottom: 12px; width: calc(100vw - 24px); transform: translateX(calc(100% + 24px)); }
}

/* === Notifications slide-in panel (redesigned: tabs + avatar cards) === */
.notif-slide-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.5);
    backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
    z-index: 998; opacity: 0; pointer-events: none;
    transition: opacity 0.25s ease;
}
.notif-slide-overlay.visible { opacity: 1; pointer-events: auto; }
/* Largeur et marge du volet : variables PARTAGÉES avec la règle qui pousse le
   contenu pour le volet Aurore (body.aurore-panel-push, plus bas), pour
   qu'elles ne puissent pas diverger. Mêmes valeurs qu'avant : aucun changement
   d'aspect, ni pour Aurore ni pour les autres volets de cette classe. */
:root {
    --notif-slide-w: 440px;
    --notif-slide-gap: 20px;
}
.notif-slide-panel {
    position: fixed;
    top: var(--notif-slide-gap); right: var(--notif-slide-gap); bottom: var(--notif-slide-gap);
    width: var(--notif-slide-w);
    max-width: calc(100vw - 2 * var(--notif-slide-gap));
    background: var(--color-surface);
    border-radius: 20px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.25);
    z-index: 999;
    display: flex; flex-direction: column;
    overflow: hidden;
    transform: translateX(calc(100% + 2 * var(--notif-slide-gap)));
    transition: transform 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}
.notif-slide-panel.visible { transform: translateX(0); }

.notif-slide-header {
    display: flex; align-items: center; justify-content: flex-end;
    gap: 12px;
    padding: 22px 22px 14px;
    flex-shrink: 0;
}
.notif-slide-header h3 {
    font-size: 20px; font-weight: 800; margin: 0;
    color: var(--color-text); letter-spacing: -0.01em;
}
.notif-slide-header-actions { display: flex; align-items: center; gap: 6px; position: relative; }
/* Panneau Aurore (chat-panel.php) : contrairement au panneau Notifications
   qui masque son <h3> (title:display:none) et se contente donc de pousser
   ses actions à droite via justify-content:flex-end, Aurore affiche un
   vrai groupe logo+titre à gauche. Avec flex-end hérité, ce groupe se
   retrouvait collé aux boutons de droite au lieu de rester à gauche. */
#aurore-main-header { justify-content: space-between; }
/* Panneau Notifications : même souci que Aurore ci-dessus, mais son <h3>
   est display:none (pas de titre visible) — donc pas de 2e groupe à
   gauche par défaut. On a sorti le bouton fermer de .notif-slide-header-
   actions (cf chat-panel.php) pour qu'il reste seul à droite,
   pendant que "Tout marquer comme lu" + le menu kebab restent groupés
   à gauche au lieu d'être collés contre le bouton fermer. */
#notif-slide-panel > .notif-slide-header { justify-content: space-between; }

.notif-readall-link {
    display: inline-flex; align-items: center; gap: 6px;
    background: transparent; border: none; cursor: pointer;
    color: var(--color-primary);
    font-size: 13px; font-weight: 600;
    padding: 6px 10px; border-radius: 8px;
    transition: background 0.15s;
}
.notif-readall-link:hover { background: rgba(59,130,246,0.08); }

.notif-kebab,
.notif-close-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 30px; height: 30px;
    background: transparent; border: none; cursor: pointer;
    color: var(--color-text-secondary, #64748b);
    border-radius: 8px;
    transition: background 0.15s, color 0.15s;
}
.notif-kebab:hover, .notif-close-btn:hover { background: var(--color-hover); color: var(--color-text); }

.notif-kebab-menu {
    /* position:fixed, positionnee en JS a l'ouverture (cf kebabBtn click,
       chat-panel.php) -- deux essais d'ancrage CSS pur (right:38px, right:0,
       left:0, tous le 2026-09-29, capture mobile a l'appui a chaque fois)
       ont echoue pour la meme raison : .notif-slide-header-actions
       (ancetre position:relative) change de largeur selon l'ecran
       (".notif-readall-link span { display:none }" le reduit a une icone
       sur mobile), donc AUCUN decalage relatif fixe ne peut a la fois
       fonctionner a toutes les largeurs -- exactement le meme constat que
       .notif-dm-msg-menu (filePanel.js) le jour meme. getBoundingClientRect()
       + clamp viewport, comme ce menu-la, au lieu de deviner un decalage. */
    position: fixed;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    padding: 4px; min-width: 180px;
    z-index: 1;
}
.notif-kebab-menu button {
    display: flex; align-items: center; gap: 10px; width: 100%;
    background: transparent; border: none; cursor: pointer;
    padding: 9px 12px; border-radius: 8px;
    font-size: 13px; color: var(--color-text); text-align: left;
    transition: background 0.15s;
}
.notif-kebab-menu button:hover { background: var(--color-hover); color: #ef4444; }
.notif-kebab-menu button svg { color: #ef4444; }

/* Actions à traiter (intégré depuis l'ancien bloc home.php) */
.notif-actions-todo {
    margin: 0 16px 12px;
    padding: 12px;
    border-radius: 14px;
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.08), rgba(245, 158, 11, 0.02));
    border: 1px solid rgba(245, 158, 11, 0.18);
    flex-shrink: 0;
}
.notif-actions-todo[hidden] { display: none; }
.notif-actions-todo-head {
    display: flex; align-items: center; gap: 8px;
    margin-bottom: 8px;
    font-size: 12px; font-weight: 700;
    color: #b45309;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
[data-theme="dark"] .notif-actions-todo-head { color: #f59e0b; }
.notif-actions-todo-icon { font-size: 14px; }
.notif-actions-todo-label { flex: 1; }
.notif-actions-todo-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 22px; height: 22px; padding: 0 7px;
    border-radius: 11px;
    background: #f59e0b;
    color: #fff;
    font-size: 11px; font-weight: 800;
    text-transform: none;
    letter-spacing: 0;
}
.notif-actions-todo-list { display: flex; flex-direction: column; gap: 4px; }
.notif-todo-item {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px;
    border-radius: 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    text-decoration: none;
    color: var(--color-text);
    transition: background 0.15s, border-color 0.15s, transform 0.15s;
    cursor: pointer;
}
.notif-todo-item:hover {
    background: var(--color-hover);
    border-color: var(--todo-color, var(--color-border));
    transform: translateX(2px);
}
.notif-todo-item-icon {
    width: 32px; height: 32px;
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    background: color-mix(in srgb, var(--todo-color, #64748b) 15%, transparent);
    color: var(--todo-color, #64748b);
    font-size: 14px; font-weight: 700;
    flex-shrink: 0;
}
.notif-todo-item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.notif-todo-item-label {
    font-size: 13px; font-weight: 600;
    color: var(--color-text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.notif-todo-item-sub {
    font-size: 11px;
    color: var(--color-text-tertiary, #94a3b8);
}
.notif-todo-item-arrow {
    color: var(--color-text-tertiary, #94a3b8);
    flex-shrink: 0;
    transition: transform 0.15s, color 0.15s;
}
.notif-todo-item:hover .notif-todo-item-arrow {
    color: var(--todo-color, var(--color-text));
    transform: translateX(2px);
}

/* Tabs */
.notif-tabs {
    display: flex; gap: 6px;
    padding: 0 22px 18px;
    flex-shrink: 0;
    overflow-x: auto;
    scrollbar-width: none;
}
.notif-tabs::-webkit-scrollbar { display: none; }
.notif-tab {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 7px 12px;
    background: transparent; border: none; cursor: pointer;
    border-radius: 10px;
    font-size: 13px; font-weight: 600;
    color: var(--color-text-secondary, #64748b);
    transition: background 0.15s, color 0.15s;
    white-space: nowrap;
}
.notif-tab:hover { background: var(--color-hover); color: var(--color-text); }
.notif-tab.active {
    background: rgba(59,130,246,0.1);
    color: var(--color-primary);
}
.notif-tab-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 20px; height: 20px; padding: 0 6px;
    border-radius: 6px;
    background: var(--color-bg);
    color: var(--color-text-secondary, #64748b);
    font-size: 11px; font-weight: 700;
    transition: background 0.15s, color 0.15s;
}
.notif-tab.active .notif-tab-count {
    background: rgba(59,130,246,0.18);
    color: var(--color-primary);
}
.notif-tab-count.zero { opacity: 0.5; }

.notif-section {
    flex: 1; min-height: 0;
    display: flex; flex-direction: column;
    overflow: hidden;
}
.notif-slide-content { flex: 1; overflow-y: auto; padding: 8px 12px 18px; }

/* Item card */
.notif-item {
    display: flex; gap: 14px;
    padding: 14px 12px;
    border-radius: 14px;
    margin-bottom: 2px;
    cursor: pointer;
    transition: background 0.15s;
    position: relative;
    /* Sans ça, un clic legerement a cote du petit rond de statut (20px,
       ecran Taches d'Aurore) atterrit sur le titre juste a cote et demarre
       une SELECTION DE TEXTE native au lieu de cocher -- le curseur clignotant
       qui en resulte "mange" ce premier clic, obligeant a recliquer (retour
       utilisateur 2026-08-21, capture a l'appui). Ces lignes sont des
       controles d'appli (case a cocher, ouverture de detail), jamais du
       texte a selectionner. */
    user-select: none;
    -webkit-user-select: none;
}
.notif-item:hover { background: var(--color-hover); }

/* Indice tactile du menu contextuel (Épingler/Bloquer/Retirer...) -- masqué
   par défaut (display:none inline sur le bouton, cf _renderConversationRow/
   _renderContactCardRow dans filePanel.js), réaffiché UNIQUEMENT sur
   pointeur grossier/sans survol (tactile) : le clic droit desktop reste le
   seul déclencheur là où il fonctionne déjà (demande utilisateur 2026-08-25,
   "les 3 petits points ... clic droit fonctionne déjà"). Audit UX du même
   jour : un appui long sans aucun indice visuel n'est pas découvrable sur
   mobile, d'où cette réintroduction ciblée au tactile seul. */
@media (hover: none) and (pointer: coarse) {
    .fp-touch-menu-hint { display: flex !important; }
}

/* Bouton « Inviter » d'une ligne de la page Contacts (2026-09-28 : ajouter
   un contact n'invite plus personne, l'invitation est ce geste séparé).
   Posé en frère du bouton de ligne (jamais dedans : un <button> dans un
   <button> est invalide) -- même principe que .fp-touch-menu-hint ci-dessus,
   et décalé à gauche de celui-ci au tactile où les deux coexistent. Le
   padding réservé sur la ligne empêche le nom de passer dessous. */
.fp-contact-invite-btn {
    position: absolute; top: 50%; right: 12px; transform: translateY(-50%);
    padding: 6px 14px; border: none; border-radius: 999px; cursor: pointer;
    background: var(--color-primary); color: #fff;
    font-family: inherit; font-size: 12px; font-weight: 700; line-height: 1.2;
    white-space: nowrap; z-index: 1;
    transition: opacity .15s;
}
.fp-contact-invite-btn:disabled { opacity: .5; cursor: default; }
.fp-contact-row-has-invite { padding-right: 96px !important; }
@media (hover: none) and (pointer: coarse) {
    .fp-contact-invite-btn { right: 42px; }
    .fp-contact-row-has-invite { padding-right: 126px !important; }
}

/* Avatar with type badge */
.notif-avatar-wrap {
    position: relative;
    flex-shrink: 0;
    width: 44px; height: 44px;
}
.notif-avatar-img,
.notif-avatar-init {
    width: 44px; height: 44px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    color: #fff; font-size: 14px; font-weight: 700;
    object-fit: cover;
    overflow: hidden;
}
.notif-avatar-init { letter-spacing: 0.02em; }
.notif-avatar-badge {
    position: absolute;
    bottom: -2px; right: -2px;
    width: 18px; height: 18px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    border: 2px solid var(--color-surface);
    box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}

.notif-body { flex: 1; min-width: 0; }
.notif-row1 {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 8px;
}
.notif-title {
    font-size: 14px; line-height: 1.4; color: var(--color-text);
    word-break: break-word;
}
.notif-actor {
    font-weight: 700;
}
.notif-action-text { font-weight: 400; color: var(--color-text-secondary, #475569); }

.notif-dot-wrap {
    flex-shrink: 0;
    width: 10px; height: 10px;
    margin-top: 6px;
}
.notif-dot {
    display: block;
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(59,130,246,0.15);
}

.notif-row2 {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px;
    margin-top: 3px;
    font-size: 12px;
    color: var(--color-text-tertiary, #94a3b8);
}
.notif-time-abs { font-weight: 500; }
.notif-time-rel { font-weight: 400; }

.notif-sub-card {
    margin-top: 10px;
    padding: 10px 12px;
    background: var(--color-bg);
    border-radius: 10px;
    font-size: 13px; line-height: 1.45;
    color: var(--color-text);
    display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: break-word;
}

/* Message d'un déposant (file_request_deposit) : plusieurs lignes, retours à la ligne conservés, et AFFICHÉ EN ENTIER.
   Le serveur le borne (500 caractères, 8 lignes) : pas de plafond de lignes ici. Avec « line-clamp: 8 », la ligne « Dans « titre » »
   comptait déjà pour une et un paragraphe de 500 caractères se replie sur ~15 lignes visuelles : la fin du message n'était lisible
   nulle part (relecture indépendante). */
.notif-sub-card.notif-sub-card--quote {
    white-space: pre-line;
    display: block;
    overflow: visible;
    -webkit-line-clamp: unset;
}

.notif-actions { display: flex; gap: 8px; margin-top: 10px; }
.notif-btn {
    padding: 7px 16px;
    border-radius: 8px;
    font-size: 13px; font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    transition: all 0.15s;
}
.notif-btn.primary { background: var(--color-primary); color: #fff; }
.notif-btn.primary:hover { background: #2563eb; transform: translateY(-1px); }
.notif-btn.ghost {
    background: var(--color-surface);
    color: var(--color-text);
    border-color: var(--color-border);
}
.notif-btn.ghost:hover { background: var(--color-hover); }
.notif-btn:disabled { opacity: 0.6; cursor: wait; transform: none; }

.notif-empty {
    text-align: center; padding: 60px 20px;
    color: var(--color-text-tertiary, #94a3b8); font-size: 13px;
}
/* :not() -- ne s'applique jamais a la nouvelle illustration EmptyState
   (uiKit.js, variante 'bell'), qui fixe deja sa propre opacite via
   .empty-state-illustration (app.css). Meme garde que le pattern "legacy
   single-icon" deja etabli plus bas (cf .empty-state > svg:not(...)). */
.notif-empty svg:not(.empty-state-illustration) { opacity: 0.25; margin-bottom: 14px; }

/* Notification badge */
.global-notif-badge {
    position: absolute;
    top: -3px; right: -3px;
    min-width: 16px; height: 16px; padding: 0 5px;
    border-radius: 10px;
    background: #ef4444;
    color: white;
    font-size: 10px;
    font-weight: 800;
    display: flex; align-items: center; justify-content: center;
    border: 2px solid var(--color-bg);
    box-shadow: 0 2px 6px rgba(239,68,68,0.4);
}

/* Sur mobile, le panneau Notifications passe en PLEIN ÉCRAN edge-to-edge
   (au lieu d'une carte flottante 440px) — gain de surface utile pour les
   listes de notifs + cohérence avec les autres modales mobile (cf
   `body.modal-open .modal { inset: 0 }` plus haut dans app.css). */
@media (max-width: 768px) {
    .notif-slide-panel {
        top: 0 !important;
        right: 0 !important;
        bottom: 0 !important;
        left: 0 !important;
        width: 100vw !important;
        max-width: 100vw !important;
        border-radius: 0 !important;
        border: none !important;
        box-shadow: none !important;
        transform: translateX(100%);
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .notif-slide-panel.visible { transform: translateX(0); }
    .notif-slide-header { padding: 16px 16px 10px; }
    .notif-slide-header h3 { font-size: 18px; }
    .notif-tabs { padding: 0 16px 12px; }
    .notif-readall-link span { display: none; }
}

/* === Info slide-in panel (from right) ===
   Classes préfixées fislide- (et non info-slide-*) pour ne jamais entrer en
   collision avec .info-slide-overlay/.info-slide-panel/.info-slide-header de
   templates/partials/info-slide-modal.php (modale generique "voir une page en
   overlay", incluse par templates/layouts/main.php sur TOUTE page) : même
   classe + <style> plus tardif dans le <body> => son position:relative
   écrasait le position:fixed ci-dessous en cascade, faisant du tiroir
   invisible un bloc en flux normal (90vh) -- d'où l'espace vide et le
   double scroll au chargement de /files. Les ids avaient déjà été renommés
   (cf commit 97b6732) mais pas les classes, insuffisant à lui seul. */
.fislide-overlay {
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    z-index: 998;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
}
.fislide-overlay.visible {
    opacity: 1;
    pointer-events: auto;
}
/* Info slide panel — home card style (floating, rounded) */
/* Largeur et marge du volet : variables PARTAGÉES avec la règle qui pousse le
   contenu juste en dessous, pour qu'elles ne puissent pas diverger. */
:root {
    --fislide-w: 400px;
    --fislide-gap: 20px;
}
.fislide-panel {
    position: fixed;
    top: var(--fislide-gap); right: var(--fislide-gap); bottom: var(--fislide-gap);
    width: var(--fislide-w);
    max-width: calc(100vw - 2 * var(--fislide-gap));
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 20px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
    z-index: 999;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transform: translateX(calc(100% + 2 * var(--fislide-gap)));
    transition: transform 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}
.fislide-panel.visible {
    transform: translateX(0);
}
/* Le volet Informations POUSSE le contenu vers la gauche au lieu de le
   recouvrir : sinon les fichiers de la partie droite de la grille restaient
   cachés derrière lui (demande utilisateur 2026-10-03, capture à l'appui).
   Même règle que celle retirée le 2026-08-14 (7b2b87d5, « flotter par-dessus »)
   -- l'utilisateur revient dessus. Le panneau, lui, reste position:fixed : ni
   voile ni gel du scroll (cf App.showFileInfo), seule la zone de contenu se
   rétrécit, la grille se réorganise toute seule (mise en page 100 % CSS,
   mesuré : 3 colonnes -> 2, plus aucune carte sous le volet).
   Réservé aux écrans > 900px : en dessous, le contenu restant serait trop
   étroit pour être utile ; et à <= 600px le volet est de toute façon plein
   écran (cf @media plus bas). La transition suit celle du volet (0.32s).
   C'est un CHOIX de l'utilisateur (demande 2026-10-03, « un bouton pour
   laisser le choix ») : body.info-panel-float, posé par App.initInfoPanelMode
   et mémorisé par appareil, annule la poussée -- le volet SURVOLE alors les
   fichiers, comme avant. Le bouton est .fislide-mode-btn, dans l'en-tête. */
.main-body {
    transition: padding-right 0.32s cubic-bezier(0.32, 0.72, 0, 1);
}
@media (min-width: 901px) {
    body.info-panel-open:not(.info-panel-float) .main-body {
        padding-right: calc(var(--fislide-w) + 2 * var(--fislide-gap));
    }
}
/* Volet AURORE : même mécanisme, au choix de l'utilisateur (demande
   2026-10-03, « le même bouton pour Aurore si on souhaite aussi le garder
   toujours visible »), mais NON poussé par défaut -- il reste flottant comme
   avant tant qu'on n'a pas cliqué le bouton .fp-ai-mode-btn, dans l'en-tête de
   l'accueil Aurore, à côté de la cloche (chat-panel.php).
   - body.aurore-panel-open  : le volet est ouvert (suivi par chat-panel.php) ;
   - body.aurore-panel-push  : choix de l'utilisateur, mémorisé par appareil ;
   - body.aurore-pushable    : INSCRIPTION par page ($_bodyExtraClass, cf
     templates/layouts/main.php). Seules les pages dont le contenu vit dans
     .main-body et s'y laisse rétrécir (Nuage, Flow) la posent ; ailleurs la
     poussée ne ferait rien (zones en position absolue/fixe, plein écran) et
     le bouton resterait un bouton mort : il y est masqué aussi.
   Même seuil que le volet Informations (> 900px ; en dessous le volet recouvre
   toujours, et passe en plein écran sous 769px). Spécificité (0,4,1) > celle du
   volet Informations (0,3,1) : si les deux classes se croisaient un instant
   (Aurore prend la place d'Informations), c'est Aurore qui décide. */
@media (min-width: 901px) {
    body.aurore-pushable.aurore-panel-open.aurore-panel-push .main-body {
        padding-right: calc(var(--notif-slide-w) + 2 * var(--notif-slide-gap));
    }
}
.fislide-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 18px 20px 10px;
    flex-shrink: 0;
}
.fislide-header h3 {
    font-size: 16px;
    font-weight: 700;
    margin: 0;
    color: var(--color-text);
}
/* Bouton « pousse / survole » (App.initInfoPanelMode). Même convention que la
   bascule grille/liste (.view-toggle-single) : UNE seule icône, celle du mode
   VERS lequel le clic bascule ; data-current = le mode actuel.
   Masqué sous 901px : le volet n'y pousse jamais, un choix n'aurait aucun
   effet -- même requête que la règle de poussée plus haut, elles ne peuvent
   pas diverger. Sélecteur à id : l'apparence de pastille ronde vient du groupe
   .modal-close / #fislide-close plus bas, qui impose display:flex et se
   trouve APRÈS cette règle dans le fichier. margin-left:auto colle le bouton
   au ✕ (le titre reste à gauche). */
#fislide-panel .fislide-mode-btn {
    display: none;
    margin: 0 8px 0 auto;
}
@media (min-width: 901px) {
    #fislide-panel .fislide-mode-btn { display: flex; }
}
.fislide-mode-btn .fm-icon { display: none; }
.fislide-mode-btn:not([data-current="float"]) .fm-icon-float { display: block; }
.fislide-mode-btn[data-current="float"] .fm-icon-push { display: block; }
.fislide-content {
    flex: 1;
    overflow-y: auto;
    padding: 0;
    display: flex;
    flex-direction: column;
}

/* ===== FilePanel — tabs + comments + versions (shared by /files and workspace) ===== */
.fp-tabs {
    display: flex;
    gap: 2px;
    padding: 10px 12px 0;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface);
    position: sticky; top: 0; z-index: 2;
}
.fp-tab {
    flex: 1;
    padding: 10px 8px;
    border: none; background: transparent;
    color: var(--color-text-tertiary);
    font-size: 12px; font-weight: 700;
    cursor: pointer;
    border-radius: 8px 8px 0 0;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color 0.15s, border-color 0.15s;
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
}
.fp-tab:hover { color: var(--color-text-secondary); }
.fp-tab.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }
.fp-tab-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px; padding: 0 5px;
    border-radius: 9px;
    background: var(--color-bg); color: var(--color-text-tertiary);
    font-size: 10px; font-weight: 700;
}
.fp-tab.active .fp-tab-count { background: var(--color-primary-light, rgba(0,122,255,0.15)); color: var(--color-primary); }

.fp-panel { padding: 16px 18px 24px; flex: 1; min-height: 0; }
.fp-loading, .fp-empty {
    text-align: center; padding: 32px 12px;
    color: var(--color-text-tertiary); font-size: 13px; line-height: 1.5;
}

/* Details */
.fp-details { display: flex; flex-direction: column; gap: 8px; }
.fp-row {
    display: flex; justify-content: space-between; gap: 12px;
    padding: 8px 0; border-bottom: 1px solid var(--color-border);
}
.fp-row:last-child { border-bottom: none; }
.fp-row-k { font-size: 11px; color: var(--color-text-tertiary); text-transform: uppercase; letter-spacing: 0.4px; font-weight: 700; flex-shrink: 0; }
.fp-row-v { font-size: 13px; color: var(--color-text); text-align: right; word-break: break-word; }

/* Comments */
.fp-comment-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
/* .fp-c-item réutilise .notif-item (même carte que le panneau Notifications,
   cf mémoire "harmonisation cartes Commentaires 2026-08-16") -- seul un
   correctif de curseur est nécessaire (ligne cliquable dans .notif-item,
   mais rien n'est cliquable au niveau de la ligne ici, juste ses enfants). */
.fp-c-item.notif-item { cursor: default; }
.fp-c-del {
    border: none; background: transparent;
    color: var(--color-text-tertiary); cursor: pointer;
    padding: 0 4px; font-size: 18px; line-height: 1; border-radius: 4px;
    margin-left: 4px;
}
.fp-c-del:hover { color: var(--color-danger); background: rgba(239,68,68,0.1); }
.fp-c-text { font-size: 14px; color: var(--color-text-secondary); margin-top: 4px; line-height: 1.4; word-break: break-word; }

.fp-comment-form { display: flex; gap: 6px; align-items: flex-end; margin-top: 8px; }
.fp-comment-input-wrap {
    flex: 1;
    position: relative;
    min-width: 0;
}
.fp-comment-input {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
    border-radius: 10px;
    font-size: 13px;
    font-family: inherit;
    resize: vertical;
    min-height: 40px; max-height: 160px;
}
.fp-comment-input:focus { outline: none; border-color: var(--color-primary); }
.fp-comment-form .btn { flex-shrink: 0; }

/* ===== @MENTION chips in rendered comments ===== */
.fp-mention {
    display: inline-block;
    padding: 1px 7px;
    border-radius: 6px;
    background: color-mix(in srgb, var(--color-primary) 16%, transparent);
    color: var(--color-primary);
    font-weight: 600;
    text-decoration: none;
    font-size: 12.5px;
    line-height: 1.4;
}

/* ===== @mention autocomplete popover ===== */
.fp-mention-pop {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    right: 0;
    max-height: 220px;
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.2);
    padding: 4px;
    z-index: 60;
    display: flex;
    flex-direction: column;
    gap: 1px;
}
.fp-mention-pop[hidden] { display: none !important; }
.fp-mention-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 8px;
    border: none;
    background: transparent;
    border-radius: 8px;
    cursor: pointer;
    text-align: left;
    color: var(--color-text);
    font-size: 13px;
    transition: background 0.1s;
}
.fp-mention-item.active,
.fp-mention-item:hover {
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
}
.fp-mention-av {
    width: 24px; height: 24px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: color-mix(in srgb, var(--color-primary) 18%, transparent);
    color: var(--color-primary);
    font-weight: 700;
    font-size: 11px;
}
.fp-mention-username { font-weight: 600; }

/* ============================================================
   Google-Docs-style threaded comments
   - Toolbar with status filters (Ouverts / Résolus / Mes / Tous)
   - Threads = root + replies indented under the same card
   - Resolved threads visually muted with footer + Rouvrir button
   - Inline edit + reply composers reuse .fp-comment-input
   ============================================================ */
.fp-c-toolbar {
    display: flex; align-items: center; gap: 8px;
    margin-bottom: 10px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--color-border);
}
.fp-c-filters {
    display: flex; gap: 4px; flex-wrap: wrap;
}
.fp-c-filter {
    border: 1px solid transparent;
    background: transparent;
    color: var(--color-text-secondary);
    font-size: 12px; font-weight: 600;
    padding: 4px 10px;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex; align-items: center; gap: 5px;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.fp-c-filter span {
    background: color-mix(in srgb, var(--color-text-tertiary) 18%, transparent);
    color: var(--color-text-secondary);
    border-radius: 999px;
    padding: 0 6px;
    font-size: 10.5px;
    font-weight: 700;
    min-width: 16px;
    text-align: center;
    line-height: 16px;
}
.fp-c-filter:hover {
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
    color: var(--color-text);
}
.fp-c-filter.active {
    background: color-mix(in srgb, var(--color-primary) 14%, transparent);
    color: var(--color-primary);
    border-color: color-mix(in srgb, var(--color-primary) 28%, transparent);
}
.fp-c-filter.active span {
    background: color-mix(in srgb, var(--color-primary) 22%, transparent);
    color: var(--color-primary);
}

.fp-thread-list {
    display: flex; flex-direction: column;
    gap: 12px;
    margin-bottom: 14px;
}
.fp-thread {
    border-radius: 14px;
    transition: opacity 0.18s;
}
.fp-thread-items {
    display: flex; flex-direction: column;
}
.fp-c-reply { margin-left: 40px; }
/* Per-comment inline action buttons (edit / delete) — replace the old × */
.fp-c-actions {
    display: inline-flex; align-items: center; gap: 2px;
    margin-left: 4px;
}
.fp-c-act {
    border: none; background: transparent;
    color: var(--color-text-tertiary);
    cursor: pointer;
    padding: 4px;
    border-radius: 6px;
    line-height: 0;
    display: inline-flex; align-items: center; justify-content: center;
}
.fp-c-act:hover {
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
}
.fp-c-act-del:hover {
    color: var(--color-danger);
    background: rgba(239, 68, 68, 0.1);
}
/* Inline edit composer (replaces .fp-c-text in place) */
.fp-c-edit-wrap {
    display: flex; flex-direction: column; gap: 6px;
    margin-top: 6px;
}
.fp-c-edit-input {
    width: 100%;
    box-sizing: border-box;
    padding: 8px 10px;
    border: 1px solid var(--color-primary);
    background: var(--color-bg);
    color: var(--color-text);
    border-radius: 10px;
    font-size: 13px;
    font-family: inherit;
    resize: vertical;
    min-height: 40px; max-height: 160px;
}
.fp-c-edit-input:focus { outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 18%, transparent); }
.fp-c-edit-buttons {
    display: flex; justify-content: flex-end; gap: 6px;
}

/* Thread action bar (Répondre / Marquer résolu) -- .notif-actions/.notif-btn
   fournissent déjà flex/gap/padding (mêmes boutons que le panneau
   Notifications) ; seul l'alignement sous le texte du commentaire racine
   est spécifique à ce contexte. */
.fp-thread-actions { padding-left: 70px; } /* 12 (padding .notif-item) + 44 (avatar) + 14 (gap) = aligné sous le texte */

/* Reply composer (one per thread) */
.fp-thread-reply {
    display: flex; flex-direction: column; gap: 6px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--color-border);
}
.fp-thread-reply[hidden] { display: none; }
.fp-reply-buttons {
    display: flex; justify-content: flex-end; gap: 6px;
}

/* Resolved state: muted text + green footer bar (carte déjà plate, cf .fp-thread) */
.fp-thread-resolved .fp-c-text,
.fp-thread-resolved .notif-actor {
    opacity: 0.7;
}
.fp-thread-resolved-bar {
    display: flex; align-items: center; gap: 6px;
    margin-top: 8px;
    padding: 6px 10px;
    background: color-mix(in srgb, #10b981 12%, transparent);
    color: #047857;
    border-radius: 8px;
    font-size: 11.5px; font-weight: 600;
}
.fp-thread-resolved-bar svg { flex-shrink: 0; }
.fp-thread-reopen {
    margin-left: auto;
    border: none;
    background: rgba(255, 255, 255, 0.6);
    color: #047857;
    font-size: 11.5px; font-weight: 700;
    padding: 3px 10px;
    border-radius: 6px;
    cursor: pointer;
}
.fp-thread-reopen:hover {
    background: #fff;
}

/* Mobile tweaks for the thread layout */
@media (max-width: 600px) {
    .fp-c-reply { margin-left: 24px; }
    .fp-c-filter { padding: 4px 8px; font-size: 11.5px; }
}

/* Versions */
.fp-v-list { display: flex; flex-direction: column; gap: 10px; }
.fp-v-item { display: flex; gap: 10px; padding: 10px; border: 1px solid var(--color-border); border-radius: 12px; background: var(--color-bg); }
.fp-v-item.current { background: var(--color-primary-light, rgba(0,122,255,0.08)); border-color: var(--color-primary); }
.fp-v-num {
    font-size: 11px; font-weight: 800;
    color: var(--color-text-tertiary);
    background: var(--color-surface);
    border-radius: 6px;
    padding: 3px 6px;
    align-self: flex-start;
    flex-shrink: 0;
}
.fp-v-item.current .fp-v-num { color: var(--color-primary); }
.fp-v-body { flex: 1; min-width: 0; }
.fp-v-head {
    display: flex; align-items: center; gap: 8px;
    font-size: 12px;
}
.fp-v-head strong { color: var(--color-text); font-size: 12px; font-weight: 700; }
.fp-v-date { color: var(--color-text-tertiary); font-size: 11px; margin-left: auto; }
.fp-v-meta { font-size: 11px; color: var(--color-text-tertiary); margin-top: 2px; }
.fp-v-actions { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.fp-v-actions .btn { padding: 5px 10px !important; font-size: 11px !important; }
/* Preview = card cover style */
.fislide-content .file-info-preview {
    width: 100%;
    aspect-ratio: 1.3;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    margin-bottom: 14px;
}
.fislide-content .file-info-preview img,
.fislide-content .file-info-preview video {
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.fislide-content .file-info-preview svg {
    width: 72px;
    height: 72px;
}
/* Name block */
.fislide-content .file-info-name {
    font-size: 16px;
    font-weight: 700;
    color: var(--color-text);
    word-break: break-word;
    padding: 0 4px;
    margin: 0 0 14px;
    line-height: 1.3;
}
/* Info rows — grouped in a card */
.fislide-content .file-info-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    font-size: 13px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    margin-bottom: 0;
}
.fislide-content .file-info-row + .file-info-row { margin-top: 4px; }
.fislide-content .file-info-label {
    color: var(--color-text-tertiary);
    font-weight: 500;
}
@media (max-width: 600px) {
    /* Full-screen panel on mobile — no margins, no rounded corners */
    .fislide-panel {
        top: 0; right: 0; bottom: 0; left: 0;
        width: 100vw;
        max-width: 100vw;
        height: 100vh;
        height: 100dvh; /* dynamic viewport for mobile browser chrome */
        border-radius: 0;
        border: none;
        box-shadow: none;
        transform: translateX(100%);
        /* Safe areas for notch / home indicator */
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }
    .fislide-panel.visible {
        transform: translateX(0);
    }
    .fislide-header {
        padding: 14px 16px 8px;
    }
    /* Wider chat bubbles on small screens */
    #fp-dm-messages [data-dm-row] > div { max-width: 86% !important; }
    /* Bigger touch targets in the composer */
    #fp-dm-input { font-size: 16px !important; } /* prevents iOS zoom-on-focus */
    /* Commentaires (onglet Aurore) : composeur + réponse + édition inline
       réutilisent tous .fp-comment-input (13-14px) -- même correctif */
    #fp-comment-input,
    .fp-comment-input { font-size: 16px !important; }
}

/* === No-sidebar layout (matches home-page visually) === */
body.no-sidebar-layout {
    overflow-x: hidden !important;  /* no horizontal scroll, ever */
    overflow-y: auto !important;    /* normal vertical scroll */
    height: auto !important;
    min-height: 100vh;
    /* IMPORTANT iOS : on REMET le rubber-band naturel (vs body défaut qui a
       overscroll-behavior:none). Sans ça, sur Safari mobile le scroll se
       FIGE quand on atteint le haut/bas du document — il faut rafraîchir la
       page pour le débloquer. Le rubber-band est ce qui "absorbe" l'élan
       restant et débloque le scroll. */
    overscroll-behavior-y: auto !important;
}
html:has(body.no-sidebar-layout) {
    height: auto;
    overflow: auto;
    overscroll-behavior-y: auto;
}
/* Embed mode (iframe loaded from home for legal/famille/solidaire pages).
   Même comportement scroll que no-sidebar, sans la chrome flottante. */
body.embed-mode {
    overflow-x: hidden !important;
    overflow-y: auto !important;
    height: auto !important;
    min-height: 100vh;
    background: var(--color-bg);
    overscroll-behavior-y: auto !important;
}
html:has(body.embed-mode) { height: auto; overflow: auto; overscroll-behavior-y: auto; }
.app-no-sidebar {
    display: block;
    width: 100%;
    /* IMPORTANT : .app { height: 100vh } doit être annulé ici.
       Sans ça, iOS Safari calcule la scroll-height du body à seulement
       100vh (hauteur de .app), même si .main-body déborde davantage.
       Le contenu en-dessous devient alors inaccessible au scroll du body
       → piège de scroll (scroll trap). On laisse la hauteur croître avec
       le contenu (height: auto), et c'est body.no-sidebar-layout qui
       fournit le scroll vertical via overflow-y:auto. */
    height: auto;
    min-height: 100vh;
    background: var(--color-bg);
}
.app-no-sidebar .main {
    width: 100%;
    height: auto;
    min-height: 100vh;
    margin: 0;
    padding: 0;
    background: transparent;
    display: block;
    overflow: visible;
}
.app-no-sidebar .main-body {
    display: block;
    /* Body-level scroll (comme la page Home) : .main-body ne scrolle PAS, c'est
       body.no-sidebar-layout qui le fait. Évite les bords de coupure visibles
       en haut/bas qui apparaissaient quand le container scrollait lui-même.
       Le contenu coule maintenant naturellement dans le flux de page. */
    overflow: visible;
    height: auto;
    min-height: 100vh;
    box-sizing: border-box;
    background: transparent;
    padding: 72px 0 0;
}
/* .content a overflow-y:auto (règle générale) qui peut créer un piège de
   scroll sur iOS Safari : même sans hauteur contrainte, l'élément est
   traité comme un container scroll potentiel et bloque le body scroll
   quand on atteint ses bornes. On force overflow-y:visible pour garantir
   que le body reste le seul container de scroll vertical sur toutes les
   pages (layout no-sidebar = toutes les pages actuelles). */
.app-no-sidebar .content {
    overflow-y: visible;
}
.no-sidebar-layout .sidebar,
.no-sidebar-layout .sidebar-overlay,
.no-sidebar-layout .file-info-panel {
    display: none !important;
}
/* =============================================================
   ADMIN PAGES — shared layout (users / settings / activity)
   ============================================================= */
/* ── Harmonisation Admin <-> Nuage (2026-08-20) ───────────────────────────
   La barre d'admin vivait DANS le flux : un en-tete de 64px reservait du vide
   pour une pastille opaque au rayon 999px. Nuage fait l'inverse depuis
   longtemps -- .header (relative, sans hauteur) se replie parce que sa
   pastille .header-actions est `fixed`, et celle-ci flotte en verre depoli
   a top:14 sur 44px de haut, rayon 14.
   On aligne l'admin sur Nuage, qui est la reference. */
.admin-page-header {
    position: relative;
    padding: 0 !important;
    background: transparent !important;
    border-bottom: none !important;
    box-shadow: none !important;
    min-height: 0;
    box-sizing: border-box;
    display: flex;
    align-items: center;
}
/* Le bouton menu quitte le flux avec l'en-tete : il flotte, aligne sur la
   pastille et taille comme elle (44x44, rayon 14, cf .no-sidebar-layout). */
.admin-page-header .btn-sidebar-toggle {
    position: fixed !important;
    left: 20px !important;
    top: 14px !important;
    transform: none !important;
    width: 44px !important;
    height: 44px !important;
    border-radius: 14px !important;
    z-index: 41;
}
.admin-page-header-center {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
}
/* users.php inclut header-actions.php : on ne garde QUE le centrage. Les
   surcharges visuelles (fond opaque, rayon 30px) qui se trouvaient ici
   annulaient le verre depoli de .header-actions -- la pastille d'admin ne
   ressemblait donc pas a celle de Nuage alors qu'elle en reutilisait le
   markup. Harmonisation 2026-08-20. */
.admin-page-header-center .header-actions {
    display: flex !important;
    justify-content: center;
}
.admin-page-content {
    /* 72px de degagement : la pastille flotte a top:14 sur 44px de haut,
       meme calcul que le reste de l'app. */
    padding: 72px 24px 60px !important;
    overflow-y: auto;
    max-width: 1200px;
    margin: 0 auto;
    width: 100%;
    box-sizing: border-box;
}
.admin-hero {
    text-align: center;
    margin-bottom: 28px;
    display: flex; flex-direction: column; align-items: center;
    gap: 10px;
}
.admin-hero-title {
    font-size: 30px;
    font-weight: 800;
    letter-spacing: -0.4px;
    margin: 0;
    background: linear-gradient(135deg, var(--color-text), var(--color-text-secondary));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.admin-hero-subtitle {
    margin: 0;
    font-size: 14px;
    color: var(--color-text-tertiary);
    font-weight: 500;
}
.admin-tabs {
    display: inline-flex;
    gap: 4px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    padding: 4px;
    box-shadow: var(--shadow-sm);
    margin-top: 8px;
}
/* When the tabs pill lives in the page header (replacing header-actions),
   give it a slightly heavier presence to match the standard pill height. */
/* Meme traitement que .header-actions (Nuage) : flottante, verre depoli,
   rayon 14. Les valeurs sont volontairement identiques a celles de
   .header-actions -- toute divergence se verrait immediatement a l'oeil en
   passant d'un ecran a l'autre. */
.admin-tabs-header {
    height: 44px;
    box-sizing: border-box;
    margin-top: 0;
    padding: 4px 6px;
}

/* === Onglets d'admin : icone seule (inactif) -> icone + libelle (actif) ===
   Meme regle que .ws-quick-action-btn et que .lib-btn du header Nuage : dans
   une pastille de navigation de PAGE, seul l'onglet courant porte son
   libelle. Les autres restent en icone, ce qui garde la pastille courte et
   fait de l'element actif le seul texte a lire.
   Les libelles ont ete enveloppes dans un <span> pour cette regle : ils
   etaient de simples noeuds texte, que le CSS ne peut pas cibler. */
/* Rayon aligne sur .ctx-tab (le commutateur d'espaces de Nuage, la reference
   montree par l'utilisateur) : conteneur a 14, bouton interieur a 10. Les
   onglets d'admin heritaient du 999px de .admin-tabs -- completement ronds
   dans une pastille aux angles doux, l'ecart sautait aux yeux. */
.admin-tabs-header .admin-tab {
    border-radius: 10px;
    /* Meme animation que .ctx-tab (la reference) : color et padding sur .25s.
       C'est le PADDING qui porte l'effet -- l'onglet s'elargit doucement quand
       son libelle apparait, au lieu de sauter d'un cran.
       On ajoute background et gap, que .ctx-tab n'a pas besoin d'animer mais
       qui changent ici (remplissage bleu de l'actif, ecart icone/libelle).
       Remplace le `transition: all 0.15s` de .admin-tab : `all` anime aussi
       ce qu'on ne veut pas -- dont border-radius et box-shadow -- et 0.15s
       jurait a cote des 0.25s du reste de l'app. */
    transition: color .25s ease, padding .25s ease,
                background .25s ease, gap .25s ease;
}
.admin-tabs-header .admin-tab:not(.active) > span {
    display: none !important;
}
.admin-tabs-header .admin-tab:not(.active) {
    gap: 0 !important;
    padding-left: 10px !important;
    padding-right: 10px !important;
}
.admin-tabs-header .admin-tab.active {
    gap: 6px !important;
    padding-left: 12px !important;
    padding-right: 12px !important;
}
.admin-tabs-header .admin-tab {
    padding: 8px 16px;
    font-size: 13px;
}
.admin-tab {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 14px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-secondary);
    text-decoration: none;
    transition: all 0.15s;
}
.admin-tab:hover { color: var(--color-text); background: var(--color-bg); text-decoration: none; }
.admin-tab.active { background: var(--color-primary); color: #fff; }
.admin-tab.active:hover { background: var(--color-primary); color: #fff; }

/* Section head actions (search + create button on the right) */
.admin-section-actions {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.admin-stats-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 14px;
    margin-bottom: 24px;
}
.admin-stat-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 18px;
    padding: 18px 20px;
    box-shadow: var(--shadow-sm);
    transition: transform 0.15s, box-shadow 0.15s;
}
.admin-stat-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.admin-stat-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.admin-stat-icon {
    width: 36px; height: 36px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--stat-color) 18%, transparent);
    color: var(--stat-color);
    display: flex; align-items: center; justify-content: center;
}
.admin-stat-icon svg { width: 18px; height: 18px; }
.admin-stat-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-tertiary);
}
.admin-stat-value {
    font-size: 26px;
    font-weight: 800;
    color: var(--color-text);
    line-height: 1.1;
    letter-spacing: -0.3px;
}
.admin-stat-sub {
    font-size: 12px;
    color: var(--color-text-tertiary);
    margin-top: 4px;
    font-weight: 500;
}
.admin-section-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 20px;
    padding: 22px 24px;
    box-shadow: var(--shadow-sm);
}
.admin-section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.admin-section-title {
    margin: 0;
    font-size: 15px;
    font-weight: 700;
    color: var(--color-text);
}
/* Même recette que .form-select juste en dessous (radius/padding/bordure) --
   le champ recherche avait sa propre forme "pilule" (radius:999px), en
   décalage visuel avec les select "Tous les rôles"/"Tous les statuts"
   juste à côté. Demande utilisateur 2026-09-12, capture d'écran. */
.admin-search {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 11px 14px;
    border-radius: 12px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    min-width: 240px;
}
.admin-search svg { color: var(--color-text-tertiary); flex-shrink: 0; }
.admin-search input {
    border: none; background: transparent; color: var(--color-text);
    font-size: 14px; outline: none; flex: 1;
}
.admin-search input::placeholder { color: var(--color-text-tertiary); }
@media (max-width: 900px) {
    .admin-stats-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
    .admin-page-header { padding: 10px 14px !important; }
    .admin-page-header .btn-sidebar-toggle { left: 10px !important; }
    .admin-page-content { padding: 20px 14px 40px !important; }
    .admin-hero-title { font-size: 22px; }
    .admin-tab { font-size: 11px; padding: 6px 10px; }
    .admin-stats-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
    .admin-section-head { flex-direction: column; align-items: stretch; }
    .admin-search { min-width: 0; width: 100%; }
}

/* Unified app-launcher look — applies on every page that uses the
   no-sidebar-layout (profile, workspaces, workspace-view, messages,
   calendar, dashboard, shared, trash, plans, admin/*).
   Same visual weight as the centered header-actions pill, so they
   sit on the exact same horizontal line. */
.no-sidebar-layout .btn-sidebar-toggle {
    display: flex !important;
    width: 44px !important;
    height: 44px !important;
    padding: 0 !important;
    align-items: center !important;
    justify-content: center !important;
    border-radius: 14px !important;
    background: var(--color-surface) !important;
    border: 1px solid var(--color-border) !important;
    box-shadow: var(--shadow-sm);
    color: var(--color-text-secondary);
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.no-sidebar-layout .btn-sidebar-toggle:hover {
    background: var(--color-surface) !important;
    border-color: var(--color-primary) !important;
    color: var(--color-primary);
}
.no-sidebar-layout .btn-sidebar-toggle svg,
.no-sidebar-layout .btn-sidebar-toggle img {
    width: 20px !important;
    height: 20px !important;
    display: block;
}
.no-sidebar-layout .header {
    /* Reserve space for the FIXED launcher (top-left 20+44+12) and
       the FIXED global corner (theme + notif + avatar on the right). */
    padding-left: 76px;
    padding-right: 180px;
}

/* === App launcher popover === */
.app-launcher {
    position: fixed;
    z-index: 1000;
    width: 320px;
    max-width: calc(100vw - 24px);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 16px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
    padding: 12px;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    opacity: 0;
    transform: translateY(-6px) scale(0.96);
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s ease;
}
.app-launcher.visible {
    opacity: 1;
    transform: translateY(0) scale(1);
    pointer-events: auto;
}
.app-launcher-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 12px 6px;
    border-radius: 12px;
    color: var(--color-text);
    text-decoration: none;
    transition: background 0.15s;
}
.app-launcher-item:hover {
    background: var(--color-hover, var(--color-bg));
    text-decoration: none;
}
.app-launcher-icon {
    width: 44px;
    height: 44px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.app-launcher-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text);
    text-align: center;
}

/* Global logo — top center, visible on all pages */
/* Floating brand in the header was tested and dropped — the header already
   carries the app-launcher (top-left) and the user corner (top-right), so
   adding a wordmark made the top row feel cluttered. The HTML stub is kept
   in layouts/main.php for future use; we simply hide it everywhere. */
.global-logo { display: none !important; }

/* Global user corner (all pages) — fixed so it stays visible when scrolling,
   aligned with the sticky header's 44px-tall content row (top 14px → bottom 58px). */
.global-user-corner {
    position: fixed;
    top: 14px;
    right: 16px;
    display: flex;
    align-items: center;
    gap: 6px;
    z-index: 50;
}
/* Theme toggle + notification bell — same rounded-square shape as the
   app launcher (left) and avatar (right), so the whole top row reads
   as a coherent row of tiles.
   !important is needed because the HTML also carries `.btn-ghost` which
   forces a transparent background (declared later in this file) and
   would otherwise override our surface fill. */
.global-corner-btn {
    width: 44px !important;
    height: 44px !important;
    border-radius: 14px !important;
    /* Glassmorphisme : fond translucide + blur → cohérent avec la pill centrale.
       Permet au contenu de scroller en-dessous avec un effet de verre. */
    background: color-mix(in srgb, var(--color-surface) 75%, transparent) !important;
    -webkit-backdrop-filter: saturate(180%) blur(18px);
            backdrop-filter: saturate(180%) blur(18px);
    border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent) !important;
    box-shadow: var(--shadow-sm);
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0 !important;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    text-decoration: none;
}
.global-corner-btn:hover {
    background: var(--color-surface) !important;
    color: var(--color-text);
    border-color: var(--color-primary) !important;
    text-decoration: none;
}
/* Notification badge positioned on top of the corner button */
.global-user-corner .global-notif-badge {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 10px;
    background: var(--color-danger, #ef4444);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--color-bg);
    box-sizing: content-box;
    pointer-events: none;
}
/* Avatar button — matches the app-launcher "soft surface" look so the
   top-right corner of every page stays visually balanced with the
   top-left launcher. 44×44 rounded square, surface background, subtle
   border + shadow. Image/initial inside uses a slightly smaller
   radius (12) so it nests cleanly inside the 14px outer radius. */
.global-user-avatar {
    width: 44px;
    height: 44px;
    border-radius: 14px;
    /* Glassmorphisme — cohérent avec la pill + corner btns. */
    background: color-mix(in srgb, var(--color-surface) 75%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
            backdrop-filter: saturate(180%) blur(18px);
    border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
    box-shadow: var(--shadow-sm);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 15px;
    cursor: pointer;
    overflow: hidden;
    text-decoration: none;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
    /* Clip any stray text/img that exceeds the rounded square */
    box-sizing: border-box;
    line-height: 1;
    text-overflow: clip;
    white-space: nowrap;
}
.global-user-avatar img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}
.global-user-avatar:hover {
    border-color: var(--color-primary);
    text-decoration: none;
    color: var(--color-primary);
}
/* Avatar image (when set) fills the button with a matching inner radius */
.global-user-avatar img {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover;
    border-radius: 12px !important;
    display: block;
}

@media (max-width: 768px) {
    .global-user-corner {
        top: 8px;
        right: 8px;
        gap: 4px;
    }
    .global-corner-btn,
    .global-user-avatar {
        width: 40px;
        height: 40px;
        border-radius: 12px;
    }
    .global-user-avatar img { border-radius: 10px !important; }
    .no-sidebar-layout .header {
        padding-right: 180px;
    }
}
@media (max-width: 480px) {
    .global-user-corner {
        gap: 3px;
    }
    .global-corner-btn,
    .global-user-avatar {
        width: 36px;
        height: 36px;
        border-radius: 10px;
    }
    .global-user-avatar img { border-radius: 8px !important; }
    .no-sidebar-layout .header {
        padding-right: 140px;
    }
}

/* ===== SIDEBAR ===== */
.sidebar {
    width: var(--sidebar-width);
    min-width: var(--sidebar-width);
    background: var(--color-bg);
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    overflow: hidden;
    border: none !important;
    border-right: none !important;
    transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                min-width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.2s ease;
}

.sidebar.collapsed {
    width: 0;
    min-width: 0;
    opacity: 0;
    pointer-events: none;
}

/* Prevent sidebar flash on page load when collapsed */
html.sidebar-start-collapsed .sidebar {
    width: 0;
    min-width: 0;
    opacity: 0;
    pointer-events: none;
    transition: none;
}

.btn-sidebar-toggle {
    width: 36px;
    height: 36px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    color: var(--color-text-secondary);
    background: transparent;
    border: 1px solid transparent;
    transition: all 0.2s ease;
    position: relative;
    cursor: pointer;
}

.btn-sidebar-toggle:hover {
    color: var(--color-text);
    background: var(--color-hover);
    border-color: var(--color-border);
}

.btn-sidebar-toggle:active {
    transform: scale(0.92);
}

.btn-sidebar-toggle .sidebar-icon-bar {
    display: block;
    width: 16px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
    transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
    position: absolute;
}

.btn-sidebar-toggle .bar-1 { transform: translateY(-5px); width: 16px; }
.btn-sidebar-toggle .bar-2 { width: 12px; }
.btn-sidebar-toggle .bar-3 { transform: translateY(5px); width: 16px; }

.btn-sidebar-toggle:hover .bar-2 { width: 16px; }

/* Animate to X when sidebar is open (mobile) */
.btn-sidebar-toggle.is-open .bar-1 { transform: rotate(45deg); width: 16px; }
.btn-sidebar-toggle.is-open .bar-2 { opacity: 0; width: 0; }
.btn-sidebar-toggle.is-open .bar-3 { transform: rotate(-45deg); width: 16px; }

#info-toggle-btn.active {
    color: var(--color-primary);
    background: var(--color-primary-light);
    border-radius: var(--radius-sm);
}

.sidebar-logo {
    padding: 20px 20px 16px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 16px;
    font-weight: 600;
    color: var(--color-text);
}

.sidebar-logo svg {
    width: 28px;
    height: 28px;
    color: var(--color-primary);
}

.sidebar-nav {
    flex: 1;
    padding: 12px 8px;
    overflow-y: auto;
}

.sidebar-nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: 13px;
    font-weight: 500;
    transition: background var(--transition-fast);
    cursor: pointer;
    width: 100%;
    text-align: left;
}

.sidebar-nav-item:hover {
    background: var(--color-surface-hover);
    text-decoration: none;
}

.sidebar-nav-item.active {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.sidebar-nav-item svg {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}

.sidebar-section-title {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding: 16px 12px 6px;
}

/* Storage bar */
.sidebar-storage {
    padding: 20px;
    margin: 0 12px 8px;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    text-align: center;
}

.storage-plan-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--color-text);
    margin-bottom: 4px;
}

.storage-upgrade-hint {
    font-size: 11px;
    font-weight: 600;
    color: var(--color-primary);
    margin-top: 8px;
    opacity: 0.8;
    transition: opacity 0.2s;
}

.sidebar-storage:hover .storage-upgrade-hint {
    opacity: 1;
}

.storage-plan-quota {
    font-size: 32px;
    font-weight: 700;
    color: var(--color-text);
    line-height: 1.2;
    margin-bottom: 12px;
}

/* Indicateur de quota compact dans la header-actions de Nuage */
.storage-mini-btn {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 5px 10px;
    border-radius: 99px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    text-decoration: none;
    color: var(--color-text-secondary);
    font-size: 11px;
    font-weight: 500;
    white-space: nowrap;
    transition: background .15s, border-color .15s;
}
.storage-mini-btn:hover {
    background: var(--color-bg);
    border-color: var(--color-primary);
    color: var(--color-text);
}
.storage-mini-bar {
    width: 48px;
    height: 4px;
    background: var(--color-border);
    border-radius: 99px;
    overflow: hidden;
    flex-shrink: 0;
}
.storage-mini-fill {
    height: 100%;
    background: var(--color-primary);
    border-radius: 99px;
    transition: width .3s ease;
}
.storage-mini-fill.warning { background: var(--color-warning, #f59e0b); }
.storage-mini-fill.danger  { background: var(--color-danger,  #ef4444); }
@media (max-width: 480px) { .storage-mini-btn { display: none; } }

.storage-bar {
    height: 4px;
    background: var(--color-border);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.storage-bar-fill {
    height: 100%;
    background: var(--color-primary);
    border-radius: var(--radius-full);
    transition: width var(--transition-slow);
}

.storage-bar-fill.warning {
    background: var(--color-warning);
}

.storage-bar-fill.danger {
    background: var(--color-danger);
}

.storage-text {
    font-size: 11px;
    color: var(--color-text-tertiary);
    margin-top: 8px;
}

/* User menu */
.sidebar-user {
    padding: 12px 20px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.sidebar-user-avatar {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-full);
    background: var(--color-primary);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    font-weight: 600;
    flex-shrink: 0;
}

.sidebar-user-info {
    flex: 1;
    min-width: 0;
}

.sidebar-user-name {
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sidebar-user-role {
    font-size: 11px;
    color: var(--color-text-tertiary);
}

/* ===== MAIN CONTENT ===== */
.main {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
}

.main-body {
    flex: 1;
    display: flex;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    /* Padding-top = clearance de la chrome flottante (pill + corner btns) :
       pill top:14 + height:44 = bottom à 58px, on ajoute ~14px de breathing
       room pour que les titres de page (h1) ne soient pas collés contre la pill.
       Total : 72px.
       Note : la chrome est glassmorphique → quand on scroll, le contenu
       passe derrière avec un effet blur (cf .header-actions, .global-corner-btn). */
    padding: 72px 0 0;
    box-sizing: border-box;
    /* scroll-padding-top : quand on scroll vers une ancre / un élément focus,
       le scroll s'arrête en-dessous de la pill (pas caché derrière). */
    scroll-padding-top: 64px;
}

.main-body > .content {
    flex: 1;
    min-width: 0;
}

/* Header — sticky at top so breadcrumb + pill + corner stay visible on scroll.
   Height fixed at 72px (14 top + 44 content + 14 bottom) so all three rows of
   items (launcher left / breadcrumb / pill / corner) share one baseline. */
/* Header is now a 0-height positioning shell — its visible children
   (sidebar toggle, breadcrumb) are floated as fixed tiles, the actions
   pill is its own fixed element. We removed `will-change: transform`
   and any transition because the header itself never moves anymore;
   keeping `will-change` would establish a containing block and trap
   our position:fixed children inside the (offscreen) parent. */
.header {
    position: relative;
    box-sizing: border-box;
    z-index: 35;
}
/* Search bar — hidden by default, toggled by the search icon in the pill.
   When .mobile-active is added, the bar slides down below the header as a
   centered overlay. Works on both desktop and mobile (same UX for both). */
.header > .search-bar { display: none; }
.header > .search-bar.mobile-active {
    display: flex;
    align-items: center;
    position: fixed;
    top: calc(14px + var(--verify-banner-h, 0px));
    left: 50%;
    transform: translateX(-50%);
    width: min(420px, calc(100vw - 32px));
    max-width: 420px;
    height: 44px;
    box-sizing: border-box;
    z-index: 50;
    padding: 0 8px 0 14px;
    background: color-mix(in srgb, var(--color-surface) 75%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
            backdrop-filter: saturate(180%) blur(18px);
    border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
    border-radius: 14px;
    box-shadow: var(--shadow-sm);
    animation: searchSlideDown 0.18s ease-out;
}
.header > .search-bar.mobile-active input {
    border: none;
    background: transparent;
    padding: 6px 10px;
    font-size: 14px;
}
.header > .search-bar.mobile-active input:focus {
    box-shadow: none;
    max-width: none;
}
/* Le pill d'actions se cache pendant que la recherche est active : la barre
   de recherche prend visuellement sa place plutot que d'apparaitre en dessous. */
.header:has(.search-bar.mobile-active) .header-actions {
    visibility: hidden;
    pointer-events: none;
}
.search-bar-close {
    display: none;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s;
    flex-shrink: 0;
    padding: 0;
}
.header > .search-bar.mobile-active .search-bar-close {
    display: flex;
}
.search-bar-close:hover {
    color: var(--color-text);
    transform: scale(1.05);
}
@keyframes searchSlideDown {
    from { opacity: 0; transform: translate(-50%, -10px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}
.header > div[style*="flex:1"] { display: none !important; }
.header > .btn-sidebar-toggle {
    flex-shrink: 0;
    display: flex !important;
}
.header > .breadcrumb {
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    font-weight: 700;
    font-size: 15px;
    margin-right: auto;
    /* Match the 44px tile height of the left launcher + right corner buttons
       so the title is visually centered with them. */
    display: flex;
    align-items: center;
    height: 44px;
}
.header > .breadcrumb .breadcrumb-item {
    color: var(--color-text);
    font-weight: 700;
    font-size: 15px;
}

/* Actions pill — centered inside top header, matched to corner-btn height (44px)
   so it aligns with the app launcher (left) and theme/bell/avatar (right). */
.header-actions {
    position: fixed;
    left: 50%;
    top: 14px;
    transform: translateX(-50%);
    height: 44px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    /* Glassmorphisme : fond translucide + backdrop-filter blur → le contenu
       peut scroller en-dessous avec un effet de verre dépoli. Permet de
       retirer le gros padding-top (71px → 12px) sur .main-body. */
    background: color-mix(in srgb, var(--color-surface) 75%, transparent);
    -webkit-backdrop-filter: saturate(180%) blur(18px);
            backdrop-filter: saturate(180%) blur(18px);
    border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
    box-shadow: var(--shadow-sm);
    border-radius: 14px;
    padding: 4px 6px;
    z-index: 40;
}
/* Mobile/tablet — flip the pill to the bottom for thumb-friendly access.
   Threshold matches the app's own TABLET breakpoint (1024px, cf. plus bas
   "===== TABLET (1024px) ====="): en dessous, la pill .header-actions
   (~460-500px de large avec tous ses boutons) ne tient plus centrée entre
   le hamburger et le breadcrumb #breadcrumb (signalement utilisateur
   2026-08-14 "header action passe derriere la nav gauche sur tablette") --
   #breadcrumb a un z-index plus eleve (55 vs 40) et passe donc devant,
   masquant les premieres icones du pill des ~1000px de large. */
@media (max-width: 1024px) {
    .header-actions {
        top: auto !important;
        bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
        max-width: calc(100vw - 24px);
        overflow-x: auto;
        scrollbar-width: none;
    }
    .header-actions::-webkit-scrollbar { display: none; }
    /* La barre de recherche est censee prendre la place du pill pendant
       qu'elle est active (cf ".header:has(.search-bar.mobile-active)
       .header-actions" plus haut) -- mais elle restait ancree en haut
       (top:14px) alors que le pill vient de descendre en bas ici. Sur
       mobile/tablette elle se retrouvait donc recouverte par le
       breadcrumb/launcher/avatar restes en haut, au lieu de visuellement
       remplacer le pill comme sur PC. Signale le 2026-09-09. */
    .header > .search-bar.mobile-active {
        top: auto;
        bottom: calc(12px + env(safe-area-inset-bottom, 0px));
        max-width: calc(100vw - 24px);
    }
}
.header-actions .btn-icon,
.header-actions .sort-dropdown,
.header-actions .view-toggle {
    position: relative;
    z-index: 1;
}
.header-actions .btn-icon {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    color: var(--color-text-secondary);
    background: transparent;
    border: none;
}
.header-actions .btn-icon:hover {
    background: var(--color-hover);
    color: var(--color-text);
}
/* Badge cyan permanent (meme couleur que l'icone de la modale Sauvegarde
   Photos) pour que ce bouton se distingue des icones neutres du pill,
   au lieu de se fondre avec recherche/tri/corbeille. */
#neb-backup-btn {
    position: relative;
    background: color-mix(in srgb, #06b6d4 16%, transparent);
    color: #06b6d4;
}
#neb-backup-btn:hover {
    background: color-mix(in srgb, #06b6d4 26%, transparent);
    color: #06b6d4;
}
/* Pastille de récence (NebulaBackup.refreshStatusBadge()) -- posée par JS
   au premier appel, jamais dans le markup PHP. fresh = sauvegardé
   aujourd'hui, ok = cette semaine, stale = plus ancien, none = jamais. */
#neb-backup-btn .nbk-status-dot {
    position: absolute;
    top: 1px;
    right: 1px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: 1.5px solid var(--color-bg-elevated, #16181d);
    background: #64748b;
}
#neb-backup-btn .nbk-status-dot.nbk-status-fresh { background: #10b981; }
#neb-backup-btn .nbk-status-dot.nbk-status-ok    { background: #06b6d4; }
#neb-backup-btn .nbk-status-dot.nbk-status-stale { background: #f59e0b; }
#neb-backup-btn .nbk-status-dot.nbk-status-none  { background: #64748b; }
.header-actions .view-toggle {
    display: flex;
    gap: 2px;
    border-radius: 9px;
    background: var(--color-bg);
    padding: 0;
    border: none;
}
.header-actions .view-toggle button {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    border: none;
    background: transparent;
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
.header-actions .view-toggle button.active {
    background: var(--color-hover);
    color: var(--color-text);
}
.header-actions .view-toggle button:hover:not(.active) {
    background: var(--color-hover);
    color: var(--color-text);
}
/* Divider pseudo-element before Dossier button */
.header-actions .header-divider {
    width: 1px;
    height: 22px;
    background: var(--color-border);
    margin: 0 4px;
    align-self: center;
}
.header-actions .btn {
    border-radius: 10px;
    padding: 7px 14px;
    font-size: 13px;
    font-weight: 600;
}
.header-actions .btn-sm {
    border-radius: 10px;
}
.header-actions .btn-secondary {
    background: transparent;
    border: none;
    color: var(--color-text);
}
.header-actions .btn-secondary:hover {
    background: var(--color-hover);
}
.header-actions .btn-primary {
    background: var(--color-primary);
    color: white;
    border: none;
}
.header-actions .btn-primary:hover {
    background: #0066d6;
}

/* Responsive header */
@media (max-width: 900px) {
    .header {
        gap: 8px;
        padding: 10px 12px;
    }
    .header-actions {
        padding: 4px;
        gap: 1px;
    }
    .header-actions .btn-icon {
        width: 30px;
        height: 30px;
    }
    .header-actions .btn span {
        display: none;
    }
    .header-actions .btn svg {
        margin: 0 !important;
    }
    .header-actions .btn {
        padding: 6px 8px;
    }
}
@media (max-width: 600px) {
    .header-actions .view-toggle,
    .header-actions #theme-toggle {
        display: none !important;
    }
    /* Info button (Flow hub / file info) stays visible on mobile */
    .header-actions #info-toggle-btn {
        display: inline-flex !important;
    }
}

.breadcrumb {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 1;
    min-width: 0;
    max-width: calc(50vw - 280px); /* stay clear of centered pill */
    overflow: hidden;
}
.breadcrumb .breadcrumb-item {
    max-width: 180px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: inline-block;
}
@media (max-width: 900px) {
    .breadcrumb { max-width: calc(100vw - 460px); }
    .breadcrumb .breadcrumb-item { max-width: 120px; }
}
@media (max-width: 600px) {
    .breadcrumb .breadcrumb-item:not(.current) { display: none; }
    .breadcrumb .breadcrumb-separator { display: none; }
}

.breadcrumb-item svg {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
}

.breadcrumb-item {
    font-size: 13px;
    color: var(--color-text-secondary);
    cursor: pointer;
    padding: 4px 6px;
    border-radius: var(--radius-xs);
    transition: background var(--transition-fast);
    white-space: nowrap;
}

.breadcrumb-item:hover {
    background: var(--color-bg);
    color: var(--color-text);
    text-decoration: none;
}

.breadcrumb-item.current {
    color: var(--color-text);
    font-weight: 600;
    cursor: default;
}

.breadcrumb-item.current:hover {
    background: none;
}

.breadcrumb-separator {
    color: var(--color-text-tertiary);
    font-size: 12px;
}

/* Search */
.search-bar {
    flex: 1;
    max-width: 420px;
    min-width: 0;
    margin: 0 auto;
    z-index: 1;
}

.search-bar input {
    width: 100%;
    padding: 9px 16px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    font-size: 13px;
    color: var(--color-text);
    transition: all var(--transition-fast);
    outline: none;
}

.search-bar input:focus {
    border-color: var(--color-primary);
    background: var(--color-surface);
    box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.12);
    max-width: 480px;
}

.search-bar input::placeholder {
    color: var(--color-text-tertiary);
}

.search-bar > svg {
    display: none;
}

/* Recherche de contact dans le panneau Aurore ("Nouveau message") — meme
   recette visuelle que .search-bar input (bordure + anneau focus) pour
   harmoniser avec la recherche Nuage/Scribe/Ardoise/Galaxie. */
.fp-search-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 9px 14px;
    transition: all var(--transition-fast);
}
.fp-search-bar:focus-within {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px rgba(0, 122, 255, 0.12);
}
.fp-search-bar svg {
    flex-shrink: 0;
    color: var(--color-text-tertiary);
}
.fp-search-bar input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    font-size: 13px;
    color: var(--color-text);
    font-family: inherit;
}

/* ===== BUTTONS ===== */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 16px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    font-weight: 500;
    transition: all var(--transition-fast);
    cursor: pointer;
    border: none;
    white-space: nowrap;
}

.btn svg {
    width: 16px;
    height: 16px;
}

.btn-primary {
    background: var(--color-primary);
    color: white;
}

.btn-primary:hover {
    background: var(--color-primary-hover);
}

.btn-secondary {
    background: var(--color-bg);
    color: var(--color-text);
    border: 1px solid var(--color-border);
}

.btn-secondary:hover {
    background: var(--color-border-light);
}

.btn-danger {
    background: var(--color-danger);
    color: white;
}

/* Bouton "succès" (vert) — utilisé pour les actions positives qui ne sont
   pas l'action principale du formulaire (ex. Résoudre un ticket dans le
   modale incident, Valider une demande dans la collab, etc.). Distinct du
   primary (bleu) pour signaler "c'est positif/terminer", pas "soumettre". */
.btn-success {
    background: var(--color-success);
    color: white;
    border: none;
}
.btn-success:hover {
    background: color-mix(in srgb, var(--color-success) 85%, #000);
}

.btn-danger:hover {
    background: var(--color-danger-hover);
}

/* Variante "outline" du danger -- utilisee pour une action destructive
   secondaire (ex. Revoquer un lien) dans un footer de modale ou le
   primary est ailleurs (Fermer/Continuer) ; sans ca .btn-danger-outline
   n'existait pas du tout et le bouton retombait sans bordure ni couleur,
   quasi invisible / illisible comme un lien texte. */
.btn-danger-outline {
    background: transparent;
    color: var(--color-danger);
    border: 1px solid var(--color-danger);
}
.btn-danger-outline:hover {
    background: color-mix(in srgb, var(--color-danger) 12%, transparent);
}

.btn-ghost {
    background: transparent;
    color: var(--color-text-secondary);
}

.btn-ghost:hover {
    background: var(--color-bg);
    color: var(--color-text);
}

.btn-icon {
    padding: 8px;
    border-radius: var(--radius-sm);
}

.btn-sm {
    padding: 5px 10px;
    font-size: 12px;
}

.btn-sm svg {
    width: 14px;
    height: 14px;
}

/* ===== FILE BROWSER ===== */
.content {
    flex: 1;
    overflow-y: auto;
    padding: 24px;
}

/* View toggle */
/* Legacy 2-bouton view-toggle (encore utilisé sur d'autres pages comme
   shared.php / workspace-view.php avec leurs propres IDs). On garde les
   styles pour ne pas casser. */
.view-toggle {
    display: flex;
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    padding: 2px;
}

.view-toggle-btn {
    padding: 6px 8px;
    border-radius: 6px;
    color: var(--color-text-secondary);
    transition: all var(--transition-fast);
}

.view-toggle-btn.active {
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--shadow-xs);
}

.view-toggle-btn svg {
    width: 16px;
    height: 16px;
}

/* Single-button view toggle (header Mes Fichiers) — affiche l'icône
   de la vue OPPOSÉE = ce que devient la vue après clic.
   Inline-flex + centrage = le bouton garde la même hauteur que ses voisins
   même si jamais les deux SVG se retrouvaient visibles en même temps
   (ex: avant que JS ne pose data-current). */
.view-toggle-single {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.view-toggle-single .vt-icon { display: none; }
/* Vue grille par défaut → on montre l'icône liste (cible du clic).
   Le sélecteur :not couvre aussi l'état initial (attr absent). */
.view-toggle-single:not([data-current="list"]) .vt-icon-list { display: block; }
.view-toggle-single[data-current="list"] .vt-icon-grid { display: block; }

/* Grid view — HOME-STYLE CARDS */
.file-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 20px;
}
/* Albums Nébuleuse (section ALBUMS de la vue Nuage) -- QUATRE par rangée
   plutôt que la densité générique. En auto-fill minmax(220px, 1fr), une
   grille de 1420 px produisait SIX colonnes de 220 px : des pochettes
   d'album trop petites pour qu'on distingue leur montage de photos.
   Quatre colonnes donnent 340 px, soit exactement le gabarit de carte
   retenu ailleurs dans le produit (cf .home-ws-card). Demande du
   2026-08-20.

   Sélection par :has() faute de classe dédiée : la section ALBUMS et la
   PHOTOTHÈQUE partagent `file-grid nebula-section-grid`, seule la présence
   de .nebula-album-card les distingue. La photothèque garde sa densité.

   On cible `.file-grid` et NON `.nebula-section-grid` : les albums vivent
   dans TROIS conteneurs différents et la règle doit valoir pour les trois.
   Le repli « Voir tout » (`.nebula-section-extra file-grid`, app.js) ne
   porte pas la classe de section -- les albums révélés repassaient donc à
   six colonnes de 220 px sous ceux affichés à 340 px. Signalé le
   2026-08-20. */
.file-grid:has(.nebula-album-card) {
    grid-template-columns: repeat(4, 1fr);
}
@media (max-width: 1100px) {
    .file-grid:has(.nebula-album-card) { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 820px) {
    .file-grid:has(.nebula-album-card) { grid-template-columns: repeat(2, 1fr); }
}
/* Telephone : DEUX pochettes par rangee (retour utilisateur 2026-08-29,
   inverse le choix "une par rangee" du 2026-08-20 -- une pochette d'album
   a 164px etait alors jugee illisible, ce n'est plus le sens souhaite).

   Le `!important` est INDISPENSABLE ici, ce n'est pas de la paresse : le bloc
   @media (max-width: 480px) force TOUTES les grilles de fichiers a
   `repeat(2, 1fr) !important` (ligne ~8501), ce qui bat n'importe quelle
   specificite. Une premiere version sans !important, calee sur 520px, etait
   donc inerte sous 480 et n'agissait que dans une bande de 40 pixels -- ou
   elle produisait une INVERSION : 1 colonne a 500px, 2 colonnes a 470px.
   Seuil a 640px, le meme que le `isMobile` d'app.js, pour qu'il n'y ait
   qu'une frontiere mobile a retenir.

   Souvenir reste a une carte par rangee : ce n'est pas une pochette
   generique mais une seule photo pleine largeur (format .82, cf plus haut),
   la demande ne visait que les vrais albums. */
@media (max-width: 640px) {
    .file-grid:has(.nebula-album-card) { grid-template-columns: repeat(2, 1fr) !important; }
    .file-grid:has(.nebula-memory-card) { grid-template-columns: 1fr !important; }
}

/* Grille photo d'un album Nébuleuse -- vignettes plus grandes que la grille
   générique (dossiers/documents, où 220px suffit) : une photo se parcourt
   mieux avec plus de surface, jugé trop petit à 220px (demande utilisateur
   2026-08-14). */
.file-grid.nebula-tile-grid {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.file-card {
    position: relative;
    background: var(--color-surface);
    border: 1px solid transparent;
    border-radius: 20px;
    padding: 14px;
    cursor: pointer;
    transition: transform 0.3s cubic-bezier(0.4,0,0.2,1), box-shadow 0.3s, border-color 0.2s;
    text-align: center;
    overflow: hidden;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
    will-change: transform;
    /* Sans ça, un double-clic pour ouvrir (dblclick -> handleFileOpen)
       sélectionne aussi le texte du nom de fichier comme n'importe quel
       double-clic navigateur -- ce qui fait apparaître le menu de
       sélection natif (barre de traduction/copie Edge, etc.) par-dessus
       l'UI (signalé 2026-08-07). */
    user-select: none;
    -webkit-user-select: none;
}

.file-card:hover {
    transform: translateY(-6px) scale(1.015);
    box-shadow:
        0 18px 40px color-mix(in srgb, var(--color-primary) 18%, transparent),
        0 4px 10px rgba(0, 0, 0, 0.08);
    border-color: color-mix(in srgb, var(--color-primary) 35%, var(--color-border));
}
.file-card:hover .file-card-thumb,
.file-card:hover .file-card-icon,
.file-card:hover .folder-card-icon {
    transform: scale(1.04);
    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.file-card:active {
    transform: translateY(-2px) scale(1);
    transition-duration: 0.08s;
}

.file-card.selected {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px var(--color-primary);
}

/* Cover zone (light background, icon/thumbnail inside) */
.file-card-icon {
    width: 100%;
    aspect-ratio: 1.3;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f7;
    border-radius: 14px;
    overflow: hidden;
}
[data-theme="dark"] .file-card-icon {
    background: #1e1e20;
}

.file-card-icon svg {
    width: 56px;
    height: 56px;
    display: block;
}

/* Folder card */
.folder-card-icon {
    width: 100%;
    aspect-ratio: 1.3;
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #f5f5f7;
    border-radius: 14px;
    --folder-color: #3B82F6;
    transition: background 0.2s;
}
[data-theme="dark"] .folder-card-icon {
    background: #1e1e20;
}

.folder-card-icon svg {
    width: 72px;
    height: 60px;
    filter: drop-shadow(0 2px 4px rgba(59, 130, 246, 0.25));
    transition: transform 0.2s;
}

.file-card:hover .folder-card-icon svg {
    transform: scale(1.08);
}
.file-card:hover .folder-card-icon {
    background: rgba(59,130,246,0.08);
}

/* Image thumbnail */
.file-card-thumb {
    width: 100%;
    aspect-ratio: 1.3;
    margin: 0;
    overflow: hidden;
    background: #f5f5f7;
    border-radius: 14px;
}

[data-theme="dark"] .file-card-thumb {
    background: #1e1e20;
}

/* Document thumbnail — fond coloré selon type + badge extension */
.file-doc-thumb {
    background: color-mix(in srgb, var(--doc-color) 10%, var(--color-surface));
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    overflow: visible;
}
[data-theme="dark"] .file-doc-thumb {
    background: color-mix(in srgb, var(--doc-color) 14%, #1e1e20);
}
.file-doc-icon svg {
    width: 52px;
    height: 52px;
    display: block;
}
.file-doc-ext {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--doc-color);
    background: color-mix(in srgb, var(--doc-color) 16%, transparent);
    padding: 3px 9px;
    border-radius: 6px;
    line-height: 1.4;
}

/* Enfant direct uniquement (pas descendant) -- une regle non scopee ici
   attrapait aussi l'avatar contributeur (.npt-avatar img, imbrique plus
   profond dans .npt-bottom/.npt-caption) et le faisait deborder en
   position:absolute sur toute la vignette au survol (bug signale 2026-08-16,
   visible uniquement dans les albums Nebuleuse -- la seule vignette avec un
   <img> imbrique en plus de la miniature principale). */
.file-card-thumb > img {
    /* -webkit-user-drag:none (audit thumbnail.jpg 2026-09-20) : complement CSS
       au draggable="false" desormais pose sur ces <img> -- meme convention
       que .scribe-img-frame img plus bas dans ce fichier. */
    -webkit-user-drag: none;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.file-card-thumb > svg {
    display: none;
}

.file-card-name {
    font-size: 13px;
    font-weight: 700;
    word-break: break-word;
    line-height: 1.3;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    color: var(--color-text);
    padding: 0 4px;
}

.file-card-meta {
    font-size: 11px;
    color: var(--color-text-tertiary);
    padding: 0 4px 2px;
}

/* List view */
/* ===== LIST VIEW — denser, richer, sticky header, image thumbnails ===== */
.file-list {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 16px;
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}

.file-list-header {
    display: grid;
    grid-template-columns: 36px 1fr 110px 140px 48px;
    gap: 14px;
    padding: 12px 16px;
    font-size: 11px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.6px;
    border-bottom: 1px solid var(--color-border);
    background: var(--color-surface);
    position: sticky;
    top: 0;
    z-index: 2;
}
.file-list-header > span {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    cursor: default;
    user-select: none;
}
.file-list-header > span[data-sort] { cursor: pointer; transition: color 0.15s; }
.file-list-header > span[data-sort]:hover { color: var(--color-text); }
.file-list-header > span.active { color: var(--color-primary); }
.file-list-header .flh-size, .file-list-header .flh-date { justify-content: flex-end; text-align: right; }
.file-list-header .sort-arrow {
    width: 10px; height: 10px;
    opacity: 0.6;
    transition: transform 0.2s;
}
.file-list-header > span.active .sort-arrow { opacity: 1; }
.file-list-header > span.desc .sort-arrow { transform: rotate(180deg); }

.file-list-row {
    display: grid;
    grid-template-columns: 36px 1fr 110px 140px 48px;
    gap: 14px;
    padding: 8px 16px;
    align-items: center;
    cursor: pointer;
    transition: background 0.15s;
    border-bottom: 1px solid var(--color-border-light);
    min-height: 52px;
    /* Même raison que .file-card : évite que le double-clic d'ouverture
       sélectionne le texte du nom/de la date/etc. (menu de sélection
       navigateur qui s'affiche par-dessus, signalé 2026-08-07). */
    user-select: none;
    -webkit-user-select: none;
}
.file-list-row:last-child { border-bottom: none; }
.file-list-row:hover { background: color-mix(in srgb, var(--color-primary) 4%, var(--color-surface)); }
.file-list-row.selected {
    background: color-mix(in srgb, var(--color-primary) 10%, var(--color-surface));
    box-shadow: inset 2px 0 0 var(--color-primary);
}

/* Checkbox column — visible on hover / when selected */
.flr-select {
    display: flex; align-items: center; justify-content: center;
}
.flr-check {
    width: 18px; height: 18px;
    border-radius: 5px;
    border: 2px solid var(--color-border);
    background: transparent;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    color: transparent;
    transition: all 0.15s;
    opacity: 0;
}
.file-list-row:hover .flr-check { opacity: 1; }
.file-list-row.selected .flr-check {
    opacity: 1;
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}
.flr-check svg { width: 12px; height: 12px; }

/* Name column — thumbnail or icon + filename + favorite star */
.file-list-name {
    display: flex; align-items: center;
    gap: 12px;
    min-width: 0;
}
.flr-thumb {
    width: 36px; height: 36px;
    border-radius: 8px;
    object-fit: cover;
    background: var(--color-bg);
    flex-shrink: 0;
    display: block;
}
.flr-icon {
    width: 36px; height: 36px;
    border-radius: 8px;
    background: var(--color-bg);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.flr-icon svg { width: 20px; height: 20px; }
.flr-text {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.flr-star { color: #fbbf24; flex-shrink: 0; display: inline-flex; }
.flr-star svg { width: 12px; height: 12px; }

.file-list-size,
.file-list-date {
    font-size: 12px;
    color: var(--color-text-secondary);
    font-variant-numeric: tabular-nums;
    text-align: right;
}
.file-list-row.type-folder .file-list-size,
.file-list-row.type-folder .file-list-date {
    color: var(--color-text-tertiary);
}

.file-list-actions {
    display: flex;
    justify-content: flex-end;
}
.file-list-actions .btn-icon {
    opacity: 0;
    transition: opacity 0.15s;
    width: 28px; height: 28px;
}
.file-list-row:hover .file-list-actions .btn-icon,
.file-list-row.selected .file-list-actions .btn-icon { opacity: 1; }

/* Drag feedback */
.file-list-row.dragging { opacity: 0.45; }
.file-list-row.drag-over-folder {
    background: color-mix(in srgb, var(--color-primary) 16%, var(--color-surface));
    box-shadow: inset 0 0 0 2px var(--color-primary);
}
.file-list-row.drag-over-folder.drag-over-copy {
    background: color-mix(in srgb, var(--color-success) 16%, var(--color-surface));
    box-shadow: inset 0 0 0 2px var(--color-success);
}
/* Meme feedback pour les lignes de la vue liste de Flow (Fichiers d'un
   espace) — classe differente (.ws-list-row) de celle de Nuage. */
.ws-list-row.dragging { opacity: 0.45; }
.ws-list-row.drag-over-folder {
    background: color-mix(in srgb, var(--color-primary) 16%, var(--color-surface));
    box-shadow: inset 0 0 0 2px var(--color-primary);
}

@media (max-width: 640px) {
    .file-list-header,
    .file-list-row {
        grid-template-columns: 1fr 80px 40px;  /* name | size | actions — hide date */
        padding: 8px 12px;
    }
    .file-list-header .flh-select,
    .file-list-row .flr-select { display: none; }
    .file-list-header .flh-date,
    .file-list-row .file-list-date { display: none; }
    .file-list-actions .btn-icon { opacity: 1; }  /* always visible on touch */
    .flr-thumb, .flr-icon { width: 32px; height: 32px; }
}

/* ===== EMPTY STATE ===== */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 64px 24px;
    color: var(--color-text-tertiary);
    text-align: center;
}

.empty-state-illustration {
    width: 140px;
    height: 140px;
    margin-bottom: 22px;
    opacity: 0.95;
    user-select: none;
}

/* Legacy single-icon empty states (backward compat) */
.empty-state > svg:not(.empty-state-illustration) {
    width: 64px;
    height: 64px;
    margin-bottom: 16px;
    opacity: 0.4;
}

.empty-state-title {
    font-size: 18px;
    font-weight: 700;
    color: var(--color-text);
    margin-bottom: 8px;
    letter-spacing: -0.2px;
}

.empty-state-text {
    font-size: 14px;
    color: var(--color-text-secondary);
    line-height: 1.55;
    max-width: 380px;
    margin: 0 auto 22px;
}

.empty-state-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 20px;
    border-radius: 12px;
    background: var(--color-primary);
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    text-decoration: none;
    border: none;
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s;
    box-shadow: 0 4px 14px color-mix(in srgb, var(--color-primary) 30%, transparent);
}
.empty-state-cta:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--color-primary) 40%, transparent);
    text-decoration: none;
    color: #fff;
}
.empty-state-cta.secondary {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    box-shadow: none;
}
.empty-state-cta.secondary:hover {
    background: var(--color-bg);
    color: var(--color-text);
}

.empty-state-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: center;
}

/* ===== SKELETON SCREENS ===== */
@keyframes skel-shimmer {
    0%   { background-position: -400px 0; }
    100% { background-position: 400px 0; }
}

.skel {
    background: linear-gradient(
        90deg,
        var(--color-bg) 0%,
        color-mix(in srgb, var(--color-text) 6%, var(--color-bg)) 50%,
        var(--color-bg) 100%
    );
    background-size: 800px 100%;
    border-radius: 8px;
    animation: skel-shimmer 1.4s linear infinite;
    display: block;
}

/* Skeleton variants */
.skel-circle  { border-radius: 50%; }
.skel-line    { height: 12px; }
.skel-line-sm { height: 9px; }
.skel-line-lg { height: 16px; }

/* File card grid skeleton */
.skel-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 14px;
    padding: 0 4px;
}
.skel-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 20px;
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.skel-card-thumb {
    width: 100%;
    aspect-ratio: 1.3;
    border-radius: 14px;
}
.skel-card-line {
    height: 12px;
    width: 70%;
    margin: 0 auto;
}
.skel-card-line.short { width: 40%; height: 9px; }

/* List view skeleton */
.skel-list {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 16px;
    overflow: hidden;
}
.skel-list-row {
    display: grid;
    grid-template-columns: 36px 1fr 110px 140px 48px;
    gap: 14px;
    padding: 12px 16px;
    align-items: center;
    border-bottom: 1px solid var(--color-border-light);
    min-height: 52px;
}
.skel-list-row:last-child { border-bottom: none; }
.skel-list-row .skel { height: 14px; }
.skel-list-row .skel-circle { width: 28px; height: 28px; }

/* Cockpit widget skeleton (for dsi-widget loading) */
.skel-widget-feed {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.skel-feed-row {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding: 8px 0;
}
.skel-feed-row .skel-circle { width: 28px; height: 28px; flex-shrink: 0; }
.skel-feed-lines { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.skel-feed-lines .skel { height: 10px; }
.skel-feed-lines .skel:first-child { width: 60%; }
.skel-feed-lines .skel:last-child  { width: 90%; }

/* ===== DRAG & DROP OVERLAY ===== */
.drop-zone {
    position: relative;
}

.drop-zone.drag-over::after {
    content: 'Glissez vos fichiers ici';
    position: absolute;
    inset: 0;
    background: rgba(0, 122, 255, 0.08);
    border: 2px dashed var(--color-primary);
    border-radius: var(--radius-md);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    font-weight: 500;
    color: var(--color-primary);
    z-index: 10;
    pointer-events: none;
}

/* ===== UPLOAD PROGRESS ===== */
.upload-panel {
    position: fixed;
    bottom: 20px;
    right: 20px;
    width: 360px;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
    z-index: var(--z-modal);
    display: none;
}

.upload-panel.visible {
    display: block;
}

.upload-panel-header {
    padding: 12px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--color-border-light);
    font-size: 13px;
    font-weight: 600;
}

.upload-panel-list {
    max-height: 240px;
    overflow-y: auto;
}

.upload-item {
    padding: 10px 16px;
    display: flex;
    align-items: center;
    gap: 10px;
    border-bottom: 1px solid var(--color-border-light);
}

.upload-item:last-child {
    border-bottom: none;
}

.upload-item-name {
    flex: 1;
    font-size: 12px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.upload-item-progress {
    width: 60px;
    height: 3px;
    background: var(--color-border);
    border-radius: var(--radius-full);
    overflow: hidden;
}

.upload-item-progress-bar {
    height: 100%;
    background: var(--color-primary);
    border-radius: var(--radius-full);
    transition: width 0.1s linear;
}

.upload-item-status {
    font-size: 11px;
    color: var(--color-text-tertiary);
    width: 40px;
    text-align: right;
}

.upload-item-status.success {
    color: var(--color-success);
}

.upload-item-status.error {
    color: var(--color-danger);
}

/* ===== MODAL ===== */
/* =========================================================================
   Modal — bottom-sheet on phone (<=640px), fullscreen on tablet (640-900px),
   centered on desktop. Le bottom-sheet est l'idiome mobile natif (iOS, Android).
   Cf audit P1 H3.
   ========================================================================= */
/* PHONE — bottom-sheet pattern */
@media (max-width: 640px) {
    /* iOS Safari : input[type=date/time] ont un rendu natif dont la largeur
       intrinsèque minimale peut dépasser le conteneur, même avec width:100%.
       -webkit-appearance:none force le rendu CSS pur (le picker natif apparaît
       quand même au tap). height+padding restaurent la taille normale. */
    input[type="date"].form-input,
    input[type="time"].form-input,
    input[type="datetime-local"].form-input {
        -webkit-appearance: none;
        appearance: none;
        padding: 12px 14px !important;
        line-height: 1.4 !important;
    }

    .modal-backdrop {
        padding: 0 !important;
        align-items: flex-end !important;
        justify-content: stretch !important;
    }
    .modal {
        overflow-x: hidden !important;
        margin: 0 !important;
        width: 100vw !important;
        max-width: none !important;
        height: auto !important;
        max-height: 92vh !important;
        max-height: 92dvh !important;
        min-height: 0 !important;
        border-radius: 20px 20px 0 0 !important;
        display: flex !important;
        flex-direction: column !important;
        transform: translateY(100%) !important;
        transition: transform 0.32s cubic-bezier(0.32, 0.72, 0, 1), opacity 0.2s ease !important;
    }
    .modal-backdrop.visible .modal {
        transform: translateY(0) !important;
    }
    /* Drag handle visuel sur le header (pattern iOS bottom-sheet) */
    .modal-header {
        padding: 18px 16px 12px !important;
        flex-shrink: 0 !important;
        position: sticky !important; top: 0 !important;
        background: var(--color-surface) !important;
        z-index: 2;
    }
    .modal-header::before {
        content: '';
        position: absolute;
        top: 6px; left: 50%;
        transform: translateX(-50%);
        width: 36px; height: 4px;
        background: var(--color-text-tertiary);
        opacity: 0.4;
        border-radius: 2px;
    }
    .modal-title { font-size: 16px !important; }
    .modal-close { width: 36px !important; height: 36px !important; }
    .modal-body {
        padding: 16px !important;
        flex: 1 !important;
        overflow-y: auto !important;
        overflow-x: hidden !important;
        -webkit-overflow-scrolling: touch;
    }
    .modal-footer {
        padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px)) !important;
        flex-shrink: 0 !important;
        position: sticky !important; bottom: 0 !important;
        background: var(--color-surface) !important;
        z-index: 2;
    }
    .modal-footer .btn { /* flex: 1; */ }
    .modal-footer .btn.btn-expand-on-hover,
    .modal-footer .btn.btn-icon-only {
        flex: 0 0 auto !important;
    }
    .sj-container {
        height: auto !important;
        max-height: none !important;
        flex: 1 !important;
        min-height: 0 !important;
    }
}
/* TABLET — fullscreen on (641-900px) */
@media (min-width: 641px) and (max-width: 900px) {
    .modal-backdrop {
        padding: 0 !important;
        align-items: stretch !important;
        justify-content: stretch !important;
    }
    .modal {
        margin: 0 !important;
        width: 100vw !important;
        max-width: none !important;
        height: 100vh !important;
        height: 100dvh !important;
        max-height: 100vh !important;
        max-height: 100dvh !important;
        min-height: 100vh !important;
        min-height: 100dvh !important;
        border-radius: 0 !important;
        display: flex !important;
        flex-direction: column !important;
        transform: none !important;
    }
    .modal-backdrop.visible .modal { transform: none !important; }
    .modal-header {
        padding: 14px 16px !important;
        flex-shrink: unset !important;
        position: absolute !important; top: env(safe-area-inset-top, 0px) !important; left: 0 !important; right: 0 !important;
        background: transparent !important;
        backdrop-filter: none !important;
        z-index: 10;
        pointer-events: none !important;
    }
    .modal-header > * { pointer-events: auto !important; }
    .modal-title { font-size: 16px !important; }
    .modal-close { width: 36px !important; height: 36px !important; }
    .modal-body {
        /* padding-top distinct des autres côtés : dégage le header flottant
           (position:absolute juste au-dessus, cf règle .modal-header) --
           auparavant écrasé par une 2e règle .modal-body{padding:16px}
           déclarée après, qui remettait le top à 16px et faisait chevaucher
           le contenu sous le header (repéré 2026-08-07 sur la modale
           Coffre-fort, mais touchait toutes les modales à cette largeur). */
        padding: 16px !important;
        padding-top: 54px !important;
        flex: 1 !important;
        overflow-y: auto !important;
        overflow-x: hidden !important;
        -webkit-overflow-scrolling: touch;
    }
    .modal-footer {
        padding: 12px 16px !important;
        flex-shrink: 0 !important;
        position: sticky !important; bottom: 0 !important;
        /* Cf modal-header — theme-aware. */
        background: var(--color-surface) !important;
        z-index: 2;
    }
    .modal-footer .btn {
        /* flex: 1; */
    }
    /* Exception : le bouton compact icon-only (corbeille du modale incident)
       ne doit PAS s'étendre — il garde sa largeur 36px. Sinon il prend toute
       la ligne en mobile à cause du flex:1 hérité, alors qu'on veut un
       petit carré rouge à gauche. */
    .modal-footer .btn.btn-expand-on-hover,
    .modal-footer .btn.btn-icon-only {
        flex: 0 0 auto !important;
    }
}

/* Lock page scroll while a modal is open.
   position:fixed on body is the only reliable way on iOS Safari;
   the saved scrollY is restored in Modal.close().
   Inner scroll containers (.content, .main-body, sidebars...) also get
   locked so nothing scrolls behind the modal.
   height:100dvh !important reprend exactement la technique de
   body.ws-scroll-lock (workspace-view.php) : la ou body.no-sidebar-layout
   n'a PAS de hauteur explicite (height:auto par defaut, elle grandit avec
   le contenu), .modal (height:100% !important sur mobile, cf plus bas)
   se retrouve a calculer un pourcentage d'une chaine d'ancetres dont la
   hauteur finale n'est jamais explicitement figee -- confirme en direct
   comme la cause de la bande de fond non peinte en bas des modales
   generiques (Aurore, "Nouvelle annonce"...) sur les pages HORS
   workspace en PWA standalone iOS, ABSENTE sur les pages workspace qui,
   elles, ont deja ce meme height:100dvh via ws-scroll-lock. */
html.modal-open {
    overflow: hidden !important;
    overscroll-behavior: contain;
    height: 100dvh !important;
}
body.modal-open {
    overflow: hidden !important;
    overscroll-behavior: contain;
    /* min-height, pas height : body a AUSSI top:-scrollY (posé par JS,
       Modal.lockScroll()) et bottom:0 (juste en dessous) pour figer le
       scroll visuellement. Une hauteur FIXE ici (100dvh, comme sur html)
       gagne sur l'étirement naturel top+bottom -- si la page était
       scrollée de N pixels au moment d'ouvrir la modale, le bas de la
       boîte de body s'arrêtait alors N pixels avant le bas de l'écran,
       laissant un bandeau vide (fond de html, "bande noire") sous
       N'IMPORTE QUELLE modale dès qu'on n'est plus tout en haut de la
       page -- desktop y compris, cette règle n'étant pas limitée au
       mobile (signalé par l'utilisateur 2026-09-08). min-height laisse
       top+bottom étirer la boîte jusqu'au bas réel du viewport quel que
       soit le scroll, tout en gardant le même plancher qu'avant pour une
       page non scrollée. */
    min-height: 100dvh !important;
    position: fixed;
    left: 0; right: 0;
    bottom: 0;
    width: 100%;
}
body.modal-open .content,
body.modal-open .main,
body.modal-open .main-body,
body.modal-open .msg-sidebar-scroll,
body.modal-open .msg-chat-list,
body.modal-open .ws-msg-messages,
body.modal-open .ws-cal-event-list,
body.modal-open .ws-tasks-list,
body.modal-open .ws-budget-list,
body.modal-open .scribe-a4-scroll {
    overflow: hidden !important;
    touch-action: none;
}

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    padding: 24px;
    z-index: var(--z-modal-backdrop);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    visibility: hidden;
    /* FIX CRITIQUE : pendant la transition de fermeture, visibility reste
       'visible' (~200ms) alors qu'opacity est déjà à 0 → le backdrop
       invisible absorbait tous les clics. pointer-events:none garantit
       qu'il ne capte jamais les clics quand il n'est pas actif. */
    pointer-events: none;
    transition: opacity var(--transition-normal), visibility var(--transition-normal);
    will-change: opacity;
    transform: translateZ(0);
}

.modal-backdrop.visible {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}

.modal {
    background: var(--color-surface);
    border-radius: 20px;
    box-shadow: 0 25px 60px rgba(0, 0, 0, 0.35);
    width: 100%;
    max-width: 560px;
    max-height: 90vh;
    overflow-y: auto;
    position: relative;
    /* overflow-y:auto rend overflow-x implicitement "auto" aussi,
       ce qui permet aux inputs date/time iOS de déborder horizontalement.
       overflow-x:hidden empêche ce comportement. */
    overflow-x: hidden;
    transform: scale(0.92) translateY(16px);
    opacity: 0;
    transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1), opacity 0.25s ease;
    will-change: transform, opacity;
}

.modal-backdrop.visible .modal {
    transform: scale(1) translateY(0);
    opacity: 1;
}

/* Pulse rapide quand l'utilisateur clique en dehors de la modale (qui ne
   se ferme plus au backdrop) — un clin d'œil pour dire "utilise la croix". */
@keyframes modalBumpKf {
    0%   { transform: scale(1) translateY(0); }
    35%  { transform: scale(1.015) translateY(-2px); }
    100% { transform: scale(1) translateY(0); }
}
.modal-backdrop.visible .modal.modal-bump {
    animation: modalBumpKf .25s ease;
}

.modal-header {
    padding: 16px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    position: absolute; top: 0; left: 0; right: 0; z-index: 10;
    background: transparent;
    pointer-events: none;
}
.modal-header > * { pointer-events: auto; }
/* Memo : header flottant transparent, même style que journal */
.modal:has(.smf-toolbar-row) .modal-header {
    background: transparent !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    pointer-events: none !important;
    justify-content: flex-end !important;
}
.modal:has(.smf-toolbar-row) .modal-header > * {
    pointer-events: auto !important;
}

.modal-body { padding: 56px 20px 16px; }
/* Exception : fiche élève école (header masqué via JS) */
.modal-body:has(.pov-sheet) { padding-top: 8px; }

.modal-title {
    font-size: 18px;
    font-weight: 800;
    letter-spacing: -0.2px;
    color: var(--color-text);
    /* Header flottant (absolute) + body padde a 56px = 1 seule ligne prevue.
       Un titre long ne doit JAMAIS wrapper sous peine de recouvrir le corps :
       ellipse + texte complet dans l'attribut title (pose par modal.js). */
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.modal-close,
#fislide-close,
.fislide-mode-btn,
.nbk-close,
#frp-close,
.qrscan-close {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s;
    flex-shrink: 0;
    padding: 0;
    font-size: 16px;
    line-height: 1;
}

.modal-close:hover,
#fislide-close:hover,
.fislide-mode-btn:hover,
.nbk-close:hover,
#frp-close:hover,
.qrscan-close:hover {
    color: var(--color-text);
    transform: scale(1.05);
}

/* Bouton ← retour : visible uniquement sur les modales empilées (push()).
   Permet de revenir à la modale parente sans perdre le contexte. */
.modal-back {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s;
    flex-shrink: 0;
    padding: 0;
    margin-right: 4px;
}
.modal-back:hover {
    color: var(--color-primary);
    border-color: var(--color-primary);
    transform: scale(1.05) translateX(-1px);
}
/* Sur les modales empilées, on aligne le titre à gauche du bouton ← */
.modal-header:has(.modal-back) .modal-title { margin-right: auto; }

/* Bouton ❓ aide universel — apparaît à droite avant le ✕ */
.modal-help {
    width: 30px; height: 30px;
    border-radius: 50%;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: all 0.2s;
    flex-shrink: 0; padding: 0;
    margin-right: 4px;
}
.modal-help:hover {
    color: #3b82f6;
    border-color: #3b82f6;
    transform: scale(1.05);
}

/* Journal : même hauteur que mémo, contenu part du haut */
.modal:has(.sj-container) {
    height: 90vh !important;
    max-height: 90vh !important;
    display: flex !important;
    flex-direction: column !important;
}
/* Header journal — aucun fond, juste les boutons flottants */
.modal:has(.sj-container) .modal-header {
    background: transparent !important;
    backdrop-filter: none !important;
    -webkit-backdrop-filter: none !important;
    pointer-events: none !important;
}
.modal:has(.sj-container) .modal-header > * {
    pointer-events: auto !important;
}
/* Bouton mode switch dans le header journal — même style que .sj-mode-switch */
.modal:has(.sj-container) .modal-header .sj-mode-switch {
    order: -1;
}
.modal-body:has(.sj-container) {
    padding-top: 0 !important;
    flex: 1 !important;
    overflow: hidden !important;
    display: flex !important;
    flex-direction: column !important;
    padding-bottom: 0 !important;
}
.modal-body:has(.sj-container) .sj-container {
    flex: 1 !important;
    height: auto !important;
    max-height: none !important;
}

.modal-footer {
    padding: 16px 24px 20px;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
/* Pattern à 2 groupes pour les modales avec beaucoup d'actions :
     [🗑]            ←spacer→     [Transférer · Quick · Fermer · Modifier]
   Le spacer central force destructif à gauche / actions à droite ;
   le groupe right peut wrap proprement sans casser l'alignement gauche. */
.modal-footer-spacer { flex: 1 1 auto; min-width: 0; }
.modal-footer-actions {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 8px;
    flex: 1;
}
/* Le bouton primary (Modifier) est poussé à droite via margin-left: auto.
   Les actions secondaires (transfert, quick-actions) restent à gauche. */
.modal-footer-actions > .btn-primary {
    margin-left: auto;
}
/* Sauf s'il grandit au survol (btn-expand-on-hover) : un margin-left:auto
   se recalcule à chaque frame pendant la transition de largeur, donc le
   bouton "fuit" sous le curseur (vibration, clics ratés). On le laisse
   dans le flux normal — sa position reste stable pendant le hover. */
.modal-footer-actions > .btn-primary.btn-expand-on-hover {
    margin-left: 0;
}
/* Bouton destructif compact icon-only (corbeille) — gain de place dans
   un footer chargé. Le `.btn-icon-only` reset le padding pour donner un
   carré 36×36 propre, et garde la couleur danger. */
.btn.btn-icon-only {
    padding: 0;
    width: 36px;
    height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.btn.btn-icon-only svg { display: block; }

/* Pattern "expand on hover" — bouton qui démarre en carré icon-only
   et s'étend AU SURVOL pour révéler son label inline. Animation douce
   sur la largeur ; le label est en `max-width: 0; overflow: hidden`
   au repos. Cf retour user "c'est mieux l'animation visible au passage
   de la souris" (vs tooltip flottant). */
.btn.btn-expand-on-hover {
    padding: 0 0 0 0;
    height: 36px;
    min-width: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: flex-start;
    flex-shrink: 0;
    overflow: hidden;
    transition: padding 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.btn.btn-expand-on-hover svg {
    flex-shrink: 0;
    width: 16px; height: 16px;
    margin: 0 10px;
}
.btn.btn-expand-on-hover .btn-expand-label {
    display: inline-block;
    max-width: 0;
    margin-left: 0;
    margin-right: 0;
    overflow: hidden;
    white-space: nowrap;
    opacity: 0;
    transform: translateX(-4px);
    transition: max-width 0.22s cubic-bezier(0.32, 0.72, 0, 1),
                opacity 0.18s ease 0.04s,
                transform 0.22s cubic-bezier(0.32, 0.72, 0, 1),
                margin 0.22s cubic-bezier(0.32, 0.72, 0, 1);
}
.btn.btn-expand-on-hover:hover,
.btn.btn-expand-on-hover:focus-visible {
    padding-right: 4px;
}
.btn.btn-expand-on-hover:hover .btn-expand-label,
.btn.btn-expand-on-hover:focus-visible .btn-expand-label {
    max-width: 220px;
    opacity: 1;
    transform: translateX(0);
    margin-right: 8px;
}
/* Tactile (pas de hover) → on garde icon-only en permanence. */
@media (hover: none) {
    .btn.btn-expand-on-hover .btn-expand-label { display: none; }
}
@media (max-width: 480px) {
    /* Sur mobile, on stacke proprement : destructif compact à gauche,
       actions full-width en-dessous. */
    .modal-footer-spacer { display: none; }
    .modal-footer-actions { width: 100%; justify-content: stretch; }
}

/* ===== FORMS ===== */
.form-group {
    margin-bottom: 16px;
}

.form-label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-secondary);
    margin-bottom: 6px;
    padding: 0 2px;
}

.form-input {
    width: 100%;
    padding: 12px 14px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    font-size: 14px;
    color: var(--color-text);
    transition: border-color 0.15s, box-shadow 0.15s;
    outline: none;
    font-family: inherit;
    /* iOS Safari : date/time inputs ont une largeur intrinsèque minimale
       qui peut dépasser le conteneur. max-width + appearance:none les force
       à respecter width:100% dans tous les contextes. */
    max-width: 100%;
    min-width: 0;
    box-sizing: border-box;
}

.form-input:focus {
    border-color: var(--color-primary);
    /* Couleur brute -> color-mix(var(--color-primary)) (28/08) : la valeur
       codee en dur (bleu) ne suivait jamais la couleur de marque scopee
       (ex. violet Flow) -- le focus restait bleu alors que le reste de
       l'interface (boutons, onglets actifs) suit deja l'accent local.
       color-mix() reste visuellement identique partout ailleurs (le bleu
       #007aff par defaut n'a pas change), seul Flow en beneficie. */
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 15%, transparent);
}

/* Un <select> desactive (ex: Niveau/Parent principal pour un parent
   partage, cf profile.php _childRowHtml()) n'avait jusqu'ici AUCUNE
   difference visuelle avec un select modifiable -- seul le curseur du
   navigateur le trahissait. Sans ca, "lecture seule" ne se voit pas. */
.form-input:disabled {
    opacity: .55;
    cursor: not-allowed;
}

.form-select {
    width: 100%;
    padding: 12px 14px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    font-size: 14px;
    color: var(--color-text);
    outline: none;
    cursor: pointer;
}

/* ===== SHARE MODAL (harmonisé Nébuleuse / Nuage / Scribe, 2026-08-17) =====
   Vocabulaire visuel partagé par les 3 modales de partage de l'app --
   remplace le style="" inline massif de chacune. Réutilise .form-group/
   .form-label/.form-input/.btn* ci-dessus partout où c'est possible ;
   classes ci-dessous seulement pour ce qu'aucune des 3 n'avait déjà. */
.share-modal-tabs {
    display: flex;
    gap: 3px;
    padding: 3px;
    border-radius: 10px;
    background: var(--color-bg);
    margin-bottom: 16px;
}
.share-modal-tab {
    flex: 1;
    border: none;
    background: transparent;
    color: var(--color-text-tertiary);
    font-size: 12px;
    font-weight: 600;
    font-family: inherit;
    padding: 7px 0;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.share-modal-tab.active {
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--shadow-sm);
}

.share-modal-section-label {
    font-size: 10px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.07em;
    margin-bottom: 8px;
}

.share-modal-members {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-height: 28px;
    margin-bottom: 14px;
}
.share-modal-member {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 8px 4px;
    border-radius: 8px;
}
/* Avatar initiale -- converge Nébuleuse (violet) et Nuage/Scribe (bleu)
   sur var(--color-primary), au lieu de 2 teintes codées en dur différentes. */
.share-modal-member-avatar {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: var(--color-primary-light);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    font-weight: 700;
    flex-shrink: 0;
}
.share-modal-member-name {
    font-size: 13.5px;
    color: var(--color-text);
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.share-modal-member-chip {
    font-size: 10.5px;
    font-weight: 700;
    padding: 3px 8px;
    border-radius: 999px;
    flex-shrink: 0;
}
.share-modal-member-chip-pending {
    color: var(--color-warning);
    background: var(--color-warning-light);
}
.share-modal-member-chip-accepted {
    color: var(--color-success);
    background: var(--color-success-light);
}
/* :hover CSS -- remplace le hack mouseover/mouseout JS de Nébuleuse. */
.share-modal-member-revoke {
    background: none;
    border: none;
    color: var(--color-text-tertiary);
    cursor: pointer;
    font-size: 14px;
    line-height: 1;
    padding: 4px 8px;
    border-radius: 8px;
    flex-shrink: 0;
    transition: color 0.15s;
}
.share-modal-member-revoke:hover {
    color: var(--color-danger);
}
/* Droit d'un destinataire de NOTE (Lecture / Edition) : liste deroulante discrete, a la taille de son contenu. */
.share-modal-role {
    width: auto;
    flex: none;
    padding: 5px 26px 5px 11px;
    font-size: 12.5px;
    border-radius: 10px;
}

.share-modal-empty {
    font-size: 12.5px;
    color: var(--color-text-tertiary);
    padding: 4px 2px;
}

.share-modal-invite {
    display: flex;
    gap: 8px;
}
.share-modal-invite-input {
    flex: 1;
    min-width: 0;
}
.share-modal-hint {
    font-size: 11px;
    color: var(--color-text-tertiary);
    margin-top: 8px;
    line-height: 1.4;
}

/* Sous-vue "Lien public" -- formulaire de génération ou lien actif. */
.share-modal-link-intro {
    font-size: 12.5px;
    color: var(--color-text-secondary);
    margin-bottom: 12px;
    line-height: 1.4;
}
.share-modal-link-url-row {
    display: flex;
    gap: 8px;
}
.share-modal-link-url-row .form-input {
    font-size: 12px;
    font-family: var(--font-mono);
    cursor: pointer;
}
.share-modal-link-status {
    font-size: 11px;
    color: var(--color-text-tertiary);
    margin-top: 6px;
    display: flex;
    align-items: center;
    gap: 4px;
}
.share-modal-link-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 14px;
}

/* Nuage : sélecteur de permission (Lecture seule / Modification) -- 0 règle
   CSS jusqu'ici, entièrement piloté en style inline par _selectSharePerm(). */
.share-perm-card {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1.5px solid var(--color-border);
    border-radius: 10px;
    cursor: pointer;
    background: transparent;
    font-size: 13px;
    color: var(--color-text);
    transition: border-color 0.15s, background 0.15s;
}
.share-perm-card.active {
    border-color: var(--color-primary);
    background: var(--color-primary-light);
}

/* ===== CONTEXT MENU ===== */
@keyframes ctx-appear {
    from { opacity: 0; transform: translateY(-5px) scale(0.97); }
    to   { opacity: 1; transform: translateY(0)   scale(1);     }
}

.context-menu {
    position: fixed;
    background: var(--color-surface);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg), 0 2px 8px rgba(0,0,0,.12);
    padding: 5px;
    min-width: 220px;
    z-index: var(--z-context-menu);
    display: none;
    max-height: calc(100vh - 20px);
    overflow-y: auto;
    overscroll-behavior: contain;
}

.context-menu.visible {
    display: block;
    animation: ctx-appear 0.13s cubic-bezier(0.2, 0, 0.2, 1);
}

/* ── Toolbar (icon-only quick actions, Windows-style) ── */
.ctx-toolbar {
    display: flex;
    align-items: center;
    padding: 3px 2px 1px;
    gap: 1px;
}

.ctx-toolbar-btn {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    height: 32px;
    min-width: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.ctx-toolbar-btn:hover  { background: var(--color-bg); }
.ctx-toolbar-btn.danger { color: var(--color-danger); }
.ctx-toolbar-btn.active { color: var(--color-primary); }

.ctx-toolbar-btn svg    { width: 16px; height: 16px; flex-shrink: 0; }

.ctx-toolbar-sep {
    width: 1px;
    height: 16px;
    background: var(--color-border);
    flex-shrink: 0;
    margin: 0 2px;
}

/* ── Title (menu générique sans fichier de référence, ex. fond vide) ── */
.context-menu-title {
    padding: 6px 10px 5px;
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--color-text-tertiary);
}

/* ── Items ── */
.context-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    color: var(--color-text);
    width: 100%;
    text-align: left;
    border: none;
    background: none;
    cursor: pointer;
    transition: background var(--transition-fast);
}

.context-menu-item:hover  { background: color-mix(in srgb, var(--color-primary) 8%, var(--color-bg)); }
.context-menu-item.primary { font-weight: 600; }
.context-menu-item.danger  { color: var(--color-danger); }

.context-menu-item svg    { width: 16px; height: 16px; flex-shrink: 0; }

.ctx-label    { flex: 1; }
.ctx-shortcut {
    font-size: 11px;
    opacity: 0.38;
    padding-left: 16px;
    white-space: nowrap;
    flex-shrink: 0;
}

.context-menu-separator {
    height: 1px;
    background: var(--color-border-light);
    margin: 4px 6px;
}

/* ===== PREVIEW OVERLAY ===== */
/* Preview overlay — home-index style */
/* Mini-barre flottante audio en arrière-plan : apparaît quand l'utilisateur
   réduit le previewer audio pour naviguer dans l'app pendant l'écoute.
   Équivalent du Picture-in-Picture mais pour l'audio (que les navigateurs ne
   supportent pas en PiP natif). */
.audio-mini-bar {
    position: fixed;
    bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%);
    z-index: 9999;
    display: flex;
    align-items: center;
    gap: 12px;
    background: rgba(20, 20, 22, 0.92);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    color: #f8fafc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    padding: 8px 12px 8px 8px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
    max-width: calc(100vw - 24px);
    animation: audio-mini-in 0.25s ease;
}
@keyframes audio-mini-in {
    from { transform: translate(-50%, 16px); opacity: 0; }
    to   { transform: translate(-50%, 0);    opacity: 1; }
}
.audio-mini-bar .amb-btn {
    width: 34px; height: 34px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.08);
    color: #f8fafc;
    cursor: pointer;
    display: inline-flex;
    align-items: center; justify-content: center;
    flex-shrink: 0;
    transition: background .12s;
}
.audio-mini-bar .amb-btn:hover { background: rgba(255, 255, 255, 0.18); }
.audio-mini-bar .amb-info {
    display: flex; flex-direction: column;
    min-width: 120px; max-width: 220px;
    line-height: 1.2;
}
.audio-mini-bar .amb-name {
    font-size: 13px; font-weight: 600;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.audio-mini-bar .amb-time {
    font-size: 11px; color: #94a3b8;
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}

/* Pastille flottante pendant un PiP video actif -- meme recette visuelle
   que .audio-mini-bar, mais pas de transport (play/pause/seek) : la
   fenetre PiP native de l'OS a deja les siens, seul un retour vers
   l'apercu riche manquait (audit 2026-09-04). */
.video-pip-bar {
    position: fixed;
    bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    left: 50%;
    transform: translateX(-50%);
    z-index: 9999;
    display: flex;
    align-items: center;
    gap: 10px;
    background: rgba(20, 20, 22, 0.92);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    color: #f8fafc;
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    padding: 8px 8px 8px 16px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
    max-width: calc(100vw - 24px);
    animation: audio-mini-in 0.25s ease;
}
.video-pip-bar .vpb-icon { flex-shrink: 0; color: #94a3b8; }
.video-pip-bar .vpb-name {
    font-size: 13px; font-weight: 600;
    max-width: 160px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.video-pip-bar .vpb-return {
    flex-shrink: 0;
    padding: 8px 14px;
    font-size: 12.5px; font-weight: 700;
    border: none; border-radius: 999px; cursor: pointer;
    background: var(--color-primary); color: #fff;
    white-space: nowrap;
}
.video-pip-bar .vpb-return:hover { background: #0066d6; }
.video-pip-bar .vpb-close {
    width: 30px; height: 30px; flex-shrink: 0;
    border-radius: 50%; border: none; cursor: pointer;
    background: rgba(255, 255, 255, 0.08); color: #f8fafc;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background .12s;
}
.video-pip-bar .vpb-close:hover { background: rgba(255, 255, 255, 0.18); }
@media (max-width: 480px) {
    .video-pip-bar .vpb-name { max-width: 90px; }
}

.preview-overlay {
    position: fixed;
    inset: 0;
    /* Toujours sombre — lightbox, indépendant du thème clair/sombre */
    background: rgba(10, 10, 10, 0.96);
    /* Empêche le "swipe back" du navigateur (Chrome Android, Safari iOS, desktop
       trackpad) quand la preview est ouverte. */
    overscroll-behavior: none;
    /* Sprint B fix — utilise --z-modal-backdrop (2500) au lieu de --z-modal
       (2600) pour qu'un Modal système ouvert depuis l'aperçu PDF (ex:
       "Réorganiser les pages") passe devant. Sinon collision de z-index :
       les 2 sont à 2600, mais .preview-overlay créant un stacking context
       via backdrop-filter, le modal restait piégé dessous. */
    z-index: var(--z-modal-backdrop);
    display: none;
    /* Sécurité : même si display:none échoue (bug navigateur ou état transitoire),
       pointer-events:none garantit que l'overlay ne bloque jamais les clics. */
    pointer-events: none;
    flex-direction: column;
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    padding: 0px;
}

.preview-overlay.visible {
    display: flex;
    pointer-events: auto;
    animation: previewFadeIn 0.25s ease;
}
/* Mode plein écran natif (F11 / bouton fullscreen) — l'overlay doit
   prendre toute la surface de l'écran, sans la marge `padding: 20px`
   du mode windowed. Couvre aussi -webkit/-moz prefixed pour vieux
   browsers Safari/Firefox. */
.preview-overlay:fullscreen,
.preview-overlay:-webkit-full-screen,
.preview-overlay:-moz-full-screen {
    width: 100vw;
    height: 100vh;
    max-width: none;
    max-height: none;
    padding: 0;
    background: rgba(0, 0, 0, 0.95);
}
@keyframes previewFadeIn {
    from { opacity: 0; transform: scale(1.015); }
    to   { opacity: 1; transform: scale(1); }
}
@keyframes previewFadeOut {
    /* Symetrique de previewFadeIn (zoom + fondu) : la fermeture ne faisait
       que du fondu pur, contrairement a l'ouverture qui "pop" legerement --
       retour utilisateur 2026-08-29, "fais pareil pour la fermeture". */
    from { opacity: 1; transform: scale(1); }
    to   { opacity: 0; transform: scale(0.97); }
}
.preview-overlay.closing {
    animation: previewFadeOut 0.18s ease forwards;
    pointer-events: none;
}

.preview-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 20px 20px 10px 18px;
    max-height: 140px;
    transition: opacity .25s ease, max-height .25s ease, padding .25s ease;
    /* Jamais compense la zone de securite iOS (encoche/Dynamic Island) --
       le header flottait sous la barre de statut au lieu d'etre pousse en
       dessous. max() garde le padding desktop d'origine quand il n'y a
       pas de zone de securite (env() vaut 0). */
    padding-top: max(20px, env(safe-area-inset-top, 0px));
    color: white;
    gap: 12px;
    flex-shrink: 0;
}

.preview-filename {
    font-size: 14px;
    font-weight: 700;
    color: white;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.preview-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}

/* Meme recette que .pdfprev-tb-btn (barre du lecteur PDF), cf .prev-tool-btn
   plus haut -- coins arrondis, transparent au repos, pas de bordure ni de
   zoom au survol. Taille 40px conservee (cible tactile deja etablie ici). */
.preview-actions button {
    color: #f8fafc;
    width: 40px;
    height: 40px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    background: transparent;
    border: none;
    transition: background .12s;
}

.preview-actions button:hover {
    background: rgba(255,255,255,.12);
}

.preview-actions button svg {
    width: 18px;
    height: 18px;
}

/* Content as a floating card (home-card style) */
.preview-content {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    overflow: auto;
    min-height: 0;
}

.preview-content img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: 20px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
}

.preview-content video {
    max-width: 100%;
    max-height: 100%;
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    background: #000;
}

/* L'élément <audio> est caché — le player custom .prev-audio-player gère l'UI */
.prev-audio-player audio { display: none; }

/* ── Lecteur audio custom (preview overlay) ──────────────────────────── */
.prev-audio-player {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 28px;
    background: rgba(255,255,255,.07);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border: 1px solid rgba(255,255,255,.13);
    border-radius: 28px;
    padding: 44px 52px 40px;
    width: 100%;
    max-width: 460px;
    color: #fff;
}
.prev-audio-art {
    width: 120px;
    height: 120px;
    border-radius: 50%;
    background: rgba(255,255,255,.09);
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255,255,255,.5);
    flex-shrink: 0;
    overflow: hidden;
    transition: border-radius .25s ease;
}
.prev-audio-art.has-cover {
    border-radius: 14px;
    width: 160px;
    height: 160px;
}
.prev-audio-cover {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.prev-audio-meta { text-align: center; width: 100%; }
.prev-audio-title {
    font-size: 15px;
    font-weight: 600;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 356px;
}
.prev-audio-ext {
    font-size: 11px;
    color: rgba(255,255,255,.38);
    text-transform: uppercase;
    letter-spacing: .07em;
    margin-top: 4px;
}
.prev-audio-controls { width: 100%; display: flex; flex-direction: column; gap: 16px; }
.prev-audio-time-bar { display: flex; align-items: center; gap: 10px; width: 100%; }
.prev-audio-current, .prev-audio-total {
    font-size: 11.5px;
    color: rgba(255,255,255,.45);
    font-variant-numeric: tabular-nums;
    min-width: 32px;
}
.prev-audio-total { text-align: right; }
.prev-audio-seek {
    flex: 1;
    -webkit-appearance: none;
    appearance: none;
    height: 4px;
    border-radius: 2px;
    background: rgba(255,255,255,.22);
    cursor: pointer;
    outline: none;
}
.prev-audio-seek::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 14px; height: 14px;
    border-radius: 50%;
    background: #fff;
    cursor: pointer;
    box-shadow: 0 1px 4px rgba(0,0,0,.5);
}
.prev-audio-seek::-moz-range-thumb {
    width: 14px; height: 14px;
    border-radius: 50%;
    background: #fff;
    border: none;
    cursor: pointer;
}
.prev-audio-btns {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
}
.prev-audio-btn {
    background: none;
    border: none;
    color: rgba(255,255,255,.65);
    cursor: pointer;
    padding: 8px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background .14s, color .14s;
}
.prev-audio-btn:hover { background: rgba(255,255,255,.1); color: #fff; }
.prev-audio-play {
    width: 54px !important;
    height: 54px !important;
    background: rgba(255,255,255,.14) !important;
    color: #fff !important;
}
.prev-audio-play:hover { background: rgba(255,255,255,.24) !important; }
.prev-audio-play.playing { background: var(--color-primary, #3b82f6) !important; }

/* PDF / HTML iframe — home-card style */
.preview-content iframe {
    width: 100%;
    height: 100%;
    max-width: 1100px;
    border: none;
    background: white;
    border-radius: 20px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
}

/* ===== Pack Previewer — Lots A + B + C ===== */

/* Header refondu : 3 zones (titre + counter / toolbar / actions) */
.preview-header-left {
    display: flex; align-items: center; gap: 14px;
    flex: 1; min-width: 0;
}
.preview-counter {
    font-size: 11px; font-weight: 700;
    color: rgba(255,255,255,.7);
    background: rgba(255,255,255,.08);
    padding: 4px 10px; border-radius: 999px;
    border: 1px solid rgba(255,255,255,.08);
    flex-shrink: 0;
}
.preview-toolbar {
    display: flex; gap: 4px; flex-wrap: wrap;
    background: rgba(255,255,255,.06);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 999px;
    padding: 4px;
}
/* Meme recette que .pdfprev-tb-btn (barre du lecteur PDF) -- coins arrondis
   6px au lieu de cercles plein, couleur idle pleine au lieu d'un blanc a 70%
   d'opacite, transition limitee au fond -- harmonisation demandee le 09-13,
   le lecteur PDF servant de reference. */
.prev-tool-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px;
    padding: 0;
    border-radius: 6px;
    background: transparent;
    border: none;
    color: #f8fafc;
    cursor: pointer;
    transition: background .12s;
}
.prev-tool-btn:hover {
    background: rgba(255,255,255,.12);
}
.prev-tool-btn.active {
    color: #fff;
    background: rgba(59,130,246,.4);
}
/* Notation 1-5 etoiles (lecteur photo) -- cluster compact dans le meme
   pill que le reste de la toolbar, meme couleur active que le favori. */
.prev-rating {
    display: inline-flex;
    align-items: center;
    gap: 1px;
    padding: 0 2px;
}
.prev-rating-star {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 34px;
    padding: 0;
    border-radius: 6px;
    background: transparent;
    border: none;
    color: rgba(255,255,255,.5);
    cursor: pointer;
    transition: all .15s;
}
.prev-rating-star:hover {
    color: rgba(255,255,255,.85);
}
.prev-rating-star.active {
    color: #fbbf24;
}
/* Séparateur vertical dans la toolbar preview */
.prev-tool-sep {
    display: inline-block;
    width: 1px;
    height: 22px;
    background: rgba(255,255,255,.12);
    align-self: center;
    margin: 0 2px;
    flex-shrink: 0;
}

/* Badge zoom temporaire (centré en bas de l'image) */
.preview-zoom-badge {
    position: absolute;
    bottom: 100px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(0,0,0,.72);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    padding: 5px 14px;
    border-radius: 999px;
    border: 1px solid rgba(255,255,255,.1);
    backdrop-filter: blur(8px);
    pointer-events: none;
    opacity: 0;
    transition: opacity .2s ease;
    z-index: 20;
    letter-spacing: .03em;
}
.preview-zoom-badge.visible { opacity: 1; }

/* Boutons de nav (chevrons gauche/droite) */
.preview-nav-btn {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 56px; height: 56px;
    border-radius: 50%;
    background: rgba(0,0,0,.5);
    border: 1px solid rgba(255,255,255,.1);
    color: #fff;
    cursor: pointer;
    transition: all .15s;
    display: flex; align-items: center; justify-content: center;
    z-index: 10;
}
.preview-nav-btn:hover   { background: rgba(0,0,0,.75); transform: translateY(-50%) scale(1.05); }
.preview-nav-btn:disabled { opacity: .2; cursor: not-allowed; transform: translateY(-50%); }
.preview-nav-btn.prev { left: 24px; }
.preview-nav-btn.next { right: 24px; }

/* Stage image avec zoom + rotation */
.preview-image-stage {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
    position: relative;
    padding-bottom: 10px;
    transition: padding-bottom .25s ease;
}
.preview-image-stage img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: 5px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    transform-origin: center center;
    transition: transform .25s ease, opacity .22s ease, border-radius .25s ease, box-shadow .25s ease;
    will-change: transform, opacity;
    user-select: none;
}
.preview-image-stage:has(img[style*="scale"]):not(:has(img[style*="scale(1)"])) { cursor: grab; }
.preview-image-stage canvas {
    position: absolute;
    pointer-events: auto;
    cursor: crosshair;
    border-radius: 20px;
}

/* EXIF popover */
.preview-exif-pop {
    position: absolute;
    top: 75px; right: 20px;
    width: 280px; max-height: 70vh;
    overflow-y: auto;
    background: rgba(20,20,20,.95);
    border: 1px solid rgba(255,255,255,.1);
    border-radius: 12px;
    box-shadow: 0 12px 40px rgba(0,0,0,.6);
    color: #eee;
    z-index: 20;
    backdrop-filter: blur(20px);
}
.preview-exif-head {
    padding: 12px 14px;
    font-size: 11px; font-weight: 700;
    text-transform: uppercase; letter-spacing: .5px;
    color: rgba(255,255,255,.7);
    border-bottom: 1px solid rgba(255,255,255,.08);
}
.preview-exif-tbl {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}
.preview-exif-tbl td {
    padding: 7px 14px;
    border-bottom: 1px solid rgba(255,255,255,.05);
}
.preview-exif-tbl td:first-child {
    color: rgba(255,255,255,.55);
    width: 100px;
}
.preview-exif-tbl td:last-child { color: #eee; }

/* Bloc share (réutilise le style ws-an-share-block) */
.ws-an-share-block { /* déjà défini dans le pack annonces */ }

.preview-text-pre {
    background: rgba(255,255,255,.04);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 14px;
    color: #e7e7e7;
    padding: 22px;
    margin: 0;
    max-height: 80vh;
    overflow: auto;
    font-family: ui-monospace, SFMono-Regular, monospace;
    font-size: 13px;
    line-height: 1.55;
    white-space: pre-wrap;
    word-wrap: break-word;
    max-width: 1000px;
    width: 100%;
}

@media (max-width: 768px) {
    .preview-nav-btn { width: 44px; height: 44px; }
    .preview-nav-btn.prev { left: 8px; }
    .preview-nav-btn.next { right: 8px; }

    /* La toolbar (zoom/rotation/outils/exif/diaporama/notation/favori/partage)
       ne tient plus dans le header sous 768px -- bascule en feuille ancrée en
       bas, ouverte via le bouton "..." de .preview-actions (prev-more-btn).
       Reste ouverte jusqu'a fermeture explicite (cf _toggleToolbarSheet). */
    .preview-toolbar {
        display: none;
        position: fixed;
        left: 0; right: 0; bottom: 0;
        margin: 0;
        background: rgba(20,20,20,.97);
        backdrop-filter: blur(20px);
        border: 1px solid rgba(255,255,255,.12);
        border-bottom: none;
        border-radius: 20px 20px 0 0;
        padding: 14px 16px max(14px, env(safe-area-inset-bottom, 0px));
        gap: 10px;
        flex-wrap: wrap;
        justify-content: center;
        z-index: 60;
        box-shadow: 0 -12px 40px rgba(0,0,0,.55);
        max-height: 62vh;
        overflow-y: auto;
    }
    .preview-toolbar.sheet-open { display: flex; }
    .preview-toolbar .prev-tool-btn { width: 40px; height: 40px; }
    .preview-toolbar .prev-rating-star { width: 26px; height: 40px; }

    .preview-toolbar-backdrop {
        position: fixed;
        inset: 0;
        background: rgba(0,0,0,.45);
        z-index: 55;
    }
}
@media (min-width: 769px) {
    /* .preview-actions button (regle generique) porte display:flex avec une
       specificite (0,1,1) qui bat .prev-more-btn seule (0,1,0) -- ce
       "display:none" n'avait donc jamais eu d'effet ici, sur AUCUNE largeur
       d'ecran, le bouton restait affiche partout. Sur desktop il ne fait
       rien de visible une fois clique : sa seule fonction (_toggleToolbarSheet)
       n'a d'effet que sur la variante ".sheet-open" reservee au mobile
       (retour utilisateur 09-13). Meme prefixe que .active juste en dessous,
       qui bat deja .preview-actions button pour la meme raison. */
    .preview-actions .prev-more-btn { display: none; }
}
.preview-actions .prev-more-btn.active {
    color: #fff;
    background: rgba(59,130,246,.4);
}

/* ─── Preview — Filmstrip de vignettes (iOS-style, desktop + mobile) ─────── */

/* Quand le filmstrip est visible, on remonte les boutons nav pour qu'ils
   restent centrés sur la zone image et non sur l'overlay entier. */
.preview-overlay.has-thumbstrip .preview-nav-btn {
    top: calc(50% - 42px);   /* 42px = moitié de la hauteur du filmstrip (84px) */
}

.preview-thumbstrip {
    width: 100%;
    flex-shrink: 0;
    height: 84px;
    background: linear-gradient(to top, rgba(0,0,0,0.82) 55%, transparent);
    overflow: hidden;
    position: relative; /* pour l'indicateur absolu */
    transition: opacity .25s ease, height .25s ease;
}

/* Indicateur fixe centré — les miniatures défilent dessous */
.preview-thumb-indicator {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 60px;
    height: 60px;
    border: 2px solid var(--color-primary, #3b82f6);
    border-radius: 10px;
    box-shadow: 0 0 0 3px rgba(59,130,246,.25);
    pointer-events: none;
    z-index: 2;
}

.preview-thumbstrip-inner {
    display: flex;
    align-items: center;
    justify-content: flex-start; /* centrage via padding, pas flex */
    gap: 5px;
    height: 100%;
    /* Padding latéral = 50% - demi-vignette : permet à la 1re et dernière
       miniature d'être centrées sous l'indicateur lors du scroll. */
    padding: 10px calc(50% - 27px);
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    cursor: grab;
    user-select: none;
}
.preview-thumbstrip-inner.dragging {
    cursor: grabbing;
}

.preview-thumbstrip-inner::-webkit-scrollbar {
    display: none;
}

.preview-thumb-item {
    flex-shrink: 0;
    position: relative;  /* needed for .preview-thumb-vid-badge absolute overlay */
    width: 54px;
    height: 54px;
    border-radius: 7px;
    overflow: hidden;
    cursor: pointer;
    opacity: 0.5;
    transition: opacity .15s, outline-color .15s, transform .15s;
    outline: 2px solid transparent;
    outline-offset: 1px;
    background: rgba(255,255,255,0.07);
}

.preview-thumb-item:hover {
    opacity: 0.82;
    transform: scale(1.06);
}

.preview-thumb-item.active {
    opacity: 1;
    transform: scale(1.1);
    /* L'indicateur fixe (.preview-thumb-indicator) remplace l'outline */
}

.preview-thumb-item img,
.preview-thumb-item video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
    border-radius: inherit;
}

/* Badge ▶ sur les vignettes vidéo */
.preview-thumb-vid-badge {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    line-height: 1;
    color: rgba(255,255,255,0.92);
    text-shadow: 0 1px 6px rgba(0,0,0,0.7);
    pointer-events: none;
    background: rgba(0,0,0,0.18);
}

.preview-thumb-generic {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    line-height: 1;
}

/* Vignette audio — note de musique + badge extension */
.preview-thumb-audio {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    background: rgba(244, 63, 94, .13);
    color: #f43f5e;
}
.preview-thumb-audio-ext {
    font-size: 8.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: #f43f5e;
    line-height: 1;
}

@media (max-width: 768px) {
    .preview-thumbstrip { height: 76px; }
    .preview-thumb-item { width: 48px; height: 48px; }
    .preview-overlay.has-thumbstrip .preview-nav-btn { top: calc(50% - 38px); }
    .preview-thumbstrip-inner { padding: 10px calc(50% - 24px); }
    .preview-thumb-indicator { width: 54px; height: 54px; }
}

/* ===== AQIN Fort — Toggle switch (réutilisé dans /vault/security ET file-info) ===== */
.vsec-switch {
    position: relative; width: 42px; height: 24px;
    background: var(--color-border);
    border-radius: 999px;
    cursor: pointer;
    transition: background .15s;
    flex-shrink: 0;
    display: inline-block;
}
.vsec-switch::after {
    content: '';
    position: absolute; top: 2px; left: 2px;
    width: 20px; height: 20px;
    border-radius: 50%;
    background: #fff;
    transition: transform .15s;
}
.vsec-switch.on { background: #F59E0B; }
.vsec-switch.on::after { transform: translateX(18px); }

.btn-xs {
    padding: 4px 10px;
    font-size: 11px;
    border-radius: 6px;
}

/* ── Cinéma (fullscreen natif) — header + thumbstrip repliés en fondu,
   pas juste display:none (retour utilisateur 2026-08-29, "une animation
   fluide") : display n'est pas animable, donc opacity + la dimension qui
   les occupe (max-height / height) glissent ensemble vers 0. overflow:
   hidden seulement ICI (pas dans la regle de base du header) pour ne
   jamais rogner un menu/popover ouvert depuis la toolbar en usage normal. */
.preview-overlay.cinema-mode .preview-header {
    opacity: 0;
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    overflow: hidden;
    pointer-events: none;
}
.preview-overlay.cinema-mode .preview-thumbstrip {
    opacity: 0;
    height: 0;
    pointer-events: none;
}

/* Image sans décorations — bords arrondis, ombre et padding supprimés */
.preview-overlay.cinema-mode .preview-image-stage { padding-bottom: 0; }
.preview-overlay.cinema-mode .preview-image-stage img {
    border-radius: 0;
    box-shadow: none;
}

/* Boutons nav : invisibles au repos, visibles au survol de l'overlay */
.preview-overlay.cinema-mode .preview-nav-btn {
    top: 50% !important;
    opacity: 0;
    transition: opacity 0.2s ease;
}
.preview-overlay.cinema-mode:hover .preview-nav-btn { opacity: 1; }

/* ── Fondu auto pendant la lecture vidéo (Preview._armIdleHide, preview.js) ──
   En-tête + flèches + bande de vignettes seulement -- jamais la barre
   <video controls> native, déjà gérée par le navigateur. .preview-header et
   .preview-thumbstrip ont déjà leur transition opacity déclarée plus haut ;
   .preview-nav-btn transitionne via son "transition: all .15s" existant. */
.preview-overlay.controls-idle .preview-header,
.preview-overlay.controls-idle .preview-nav-btn,
.preview-overlay.controls-idle .preview-thumbstrip {
    opacity: 0;
    pointer-events: none;
}

/* ── Mode lecture — plein écran style Scribe ───────────────────────────── */
.preview-overlay.reading-mode .preview-header,
.preview-overlay.reading-mode .preview-nav-btn,
.preview-overlay.reading-mode .preview-thumbstrip { display: none !important; }
.preview-overlay.reading-mode #preview-content {
    overflow-y: auto;
    align-items: center;
    justify-content: flex-start;
    padding: 48px 24px;
}
.preview-overlay.reading-mode .preview-pre-wrap,
.preview-overlay.reading-mode pre.preview-pre {
    background: #fff; color: #1a1a1a; border: none; border-radius: 4px;
    max-width: 820px; max-height: none;
    padding: 48px 56px; box-shadow: 0 0 60px rgba(0,0,0,.5);
    font-size: 14px; line-height: 1.7;
}

.preview-exit-reading {
    display: none;
    position: fixed; top: 16px; right: 20px;
    z-index: calc(var(--z-modal-backdrop) + 1);
    align-items: center; gap: 7px;
    background: rgba(0,0,0,.72); color: #fff;
    border: none; border-radius: 10px;
    padding: 8px 14px; font-size: 13px; font-weight: 600;
    cursor: pointer;
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
    transition: background .15s;
}
.preview-exit-reading:hover { background: rgba(0,0,0,.88); }
.preview-overlay.reading-mode .preview-exit-reading { display: flex; }


/* CSV table */
.preview-csv-wrap {
    background: rgba(255,255,255,.04);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 14px;
    max-width: 95vw;
    width: 100%;
    max-height: 85vh;
    display: flex; flex-direction: column;
    overflow: hidden;
}
.preview-csv-tbl {
    flex: 1;
    overflow: auto;
    display: block;
    border-collapse: collapse;
    font-size: 13px;
    color: #eee;
}
.preview-csv-tbl thead {
    position: sticky; top: 0;
    background: rgba(20,20,20,.95);
    backdrop-filter: blur(8px);
    z-index: 5;
}
.preview-csv-tbl th, .preview-csv-tbl td {
    padding: 8px 14px;
    border-bottom: 1px solid rgba(255,255,255,.08);
    border-right: 1px solid rgba(255,255,255,.05);
    text-align: left;
    white-space: nowrap;
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
}
.preview-csv-tbl th { font-weight: 700; color: #fff; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; }
.preview-csv-tbl tr:hover td { background: rgba(59,130,246,.08); }
.preview-csv-foot {
    padding: 10px 16px;
    font-size: 11px;
    color: rgba(255,255,255,.5);
    border-top: 1px solid rgba(255,255,255,.08);
    background: rgba(0,0,0,.2);
}

/* JSON */
.preview-json { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* SVG */
.preview-svg svg { max-width: 100%; height: auto; display: block; margin: 0 auto; }

/* Fallback joli pour fichiers non lisibles */
.preview-unsupported {
    background: rgba(255,255,255,.04);
    border: 1px solid rgba(255,255,255,.08);
    border-radius: 20px;
    padding: 50px 40px;
    text-align: center;
    color: #eee;
    max-width: 460px;
    width: 100%;
    box-shadow: 0 12px 40px rgba(0,0,0,.4);
}
.preview-unsupported-icon {
    font-size: 80px;
    line-height: 1;
    margin-bottom: 16px;
}
.preview-unsupported-name {
    font-size: 17px;
    font-weight: 700;
    color: #fff;
    margin-bottom: 8px;
    word-break: break-all;
}
.preview-unsupported-meta {
    display: inline-flex;
    gap: 10px;
    align-items: center;
    font-size: 12px;
    color: rgba(255,255,255,.6);
    margin-bottom: 18px;
}
.preview-unsupported-pill {
    display: inline-block;
    padding: 3px 10px;
    border-radius: 999px;
    background: rgba(59,130,246,.18);
    color: #60a5fa;
    font-weight: 700;
    letter-spacing: .5px;
    font-size: 11px;
}
.preview-unsupported-text {
    font-size: 13px;
    color: rgba(255,255,255,.65);
    line-height: 1.6;
    margin: 0 0 20px;
}
.preview-unsupported-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 11px 22px;
    border-radius: 999px;
    background: #3b82f6;
    color: #fff;
    text-decoration: none;
    font-weight: 700;
    font-size: 13px;
    transition: all .15s;
}
.preview-unsupported-btn:hover {
    background: #2563eb;
    transform: translateY(-1px);
}

/* "Signer" CTA in PDF preview header */
.preview-sign-btn {
    display: inline-flex !important;
    align-items: center; gap: 6px;
    padding: 7px 14px !important;
    width: auto !important;
    height: auto !important;
    background: #3b82f6 !important;
    color: #fff !important;
    border: none !important;
    border-radius: 8px !important;
    font-size: 13px !important;
    font-weight: 600 !important;
    cursor: pointer;
    margin-right: 4px;
}
.preview-sign-btn:hover { background: #2563eb !important; }

/* ================ Custom PDF Preview Viewer (PdfPreview module) ================ */
.pdfprev-overlay {
    position: fixed; inset: 0;
    z-index: var(--z-modal-backdrop);
    display: flex; flex-direction: column;
    color: #f8fafc;
    font-family: var(--font-family, -apple-system, BlinkMacSystemFont, sans-serif);
    /* aucun geste sur le viewer (toolbar comprise) ne fait défiler la page derrière */
    overscroll-behavior: none;
}
.pdfprev-toolbar {
    display: flex; align-items: center; gap: 8px;
    padding: 8px 12px;
    background: #1e1e1e;
    border-bottom: 1px solid #2d2d2d;
    flex-shrink: 0;
    height: 60px;
    box-sizing: border-box;
    /* min-width:0 indispensable pour que les enfants flex shrink correctement.
       overflow-x:auto en filet de sécurité quand le viewport est trop étroit
       même pour la version icon-only (ex iPhone SE 320px) — l'utilisateur peut
       scroller horizontalement plutôt que perdre les boutons hors-écran. */
    min-width: 0;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;            /* Firefox */
    -ms-overflow-style: none;         /* IE/Edge */
}
.pdfprev-toolbar::-webkit-scrollbar { display: none; } /* Chrome/Safari */
/* Boutons et groupes : ne shrink JAMAIS (icônes deviennent illisibles si
   compressées). Seul le filename peut rétrécir. */
.pdfprev-toolbar > .pdfprev-tb-btn,
.pdfprev-toolbar > .pdfprev-tb-group,
.pdfprev-toolbar > .pdfprev-sign-btn,
.pdfprev-toolbar > .pdfprev-tb-download {
    flex-shrink: 0;
}
.pdfprev-filename {
    font-size: 13px;
    font-weight: 500;
    color: #f8fafc;
    max-width: 300px;
    min-width: 0;
    flex-shrink: 1;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdfprev-spacer { flex: 1; }
.pdfprev-spacer-sm { width: 8px; }
.pdfprev-tb-group {
    display: inline-flex; align-items: center; gap: 4px;
    background: rgba(255,255,255,0.05);
    border-radius: 8px;
    padding: 2px;
}
.pdfprev-tb-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    background: transparent;
    color: #f8fafc;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    text-decoration: none;
    transition: background .12s;
}
.pdfprev-tb-btn:hover { background: rgba(255,255,255,0.12); }
.pdfprev-tb-btn:disabled { opacity: 0.4; cursor: default; }

.pdfprev-page-info {
    display: inline-flex; align-items: center;
    color: #cbd5e1;
    font-size: 13px;
    padding: 0 6px;
    gap: 4px;
}
.pdfprev-page-info input {
    width: 36px;
    background: rgba(255,255,255,0.08);
    color: #fff;
    border: none;
    border-radius: 4px;
    padding: 4px 6px;
    font-size: 13px;
    text-align: center;
    font-family: inherit;
    -moz-appearance: textfield;
}
.pdfprev-page-info input::-webkit-outer-spin-button,
.pdfprev-page-info input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.pdfprev-zoom-label {
    color: #cbd5e1;
    font-size: 13px;
    min-width: 44px;
    text-align: center;
}

.pdfprev-sign-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 14px;
    background: #3b82f6;
    color: #fff;
    border: none;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
}
.pdfprev-sign-btn:hover { background: #2563eb; }
/* Etat "actif" pour un bouton bascule (ex: Detecter les champs, sign-document.php) --
   .pdfprev-sign-btn est deja pleinement colore au repos, un fond plus fonce +
   un lisere interieur suffisent a signaler l'etat sans dupliquer le style. */
.pdfprev-sign-btn.spdf-active { background: #1d4ed8; box-shadow: inset 0 0 0 2px rgba(255,255,255,.35); }
.pdfprev-sign-btn.spdf-active:hover { background: #1e40af; }

.pdfprev-body { flex: 1; display: flex; min-height: 0; }
.pdfprev-sidebar {
    width: 160px;
    flex-shrink: 0;
    background: #1e1e1e;
    border-right: 1px solid #2d2d2d;
    overflow-y: auto;
    transition: width .2s;
    overscroll-behavior: contain; /* le scroll des vignettes reste dans le volet */
}

.pdfprev-sidebar.collapsed { width: 0; border-right: none; overflow: hidden; }
.pdfprev-thumbs {
    display: flex; flex-direction: column;
    gap: 8px;
    padding: 12px 8px;
}
.pdfprev-thumb {
    cursor: pointer;
    text-align: center;
    padding: 4px;
    border-radius: 6px;
    transition: background .12s;
}
.pdfprev-thumb:hover { background: rgba(255,255,255,0.05); }
.pdfprev-thumb-canvas-wrap {
    background: #fff;
    box-shadow: 0 2px 6px rgba(0,0,0,0.3);
    margin: 0 auto;
    width: fit-content;
}
.pdfprev-thumb.active .pdfprev-thumb-canvas-wrap {
    outline: 2px solid #3b82f6;
}
.pdfprev-thumb-canvas-wrap canvas { display: block; }
.pdfprev-thumb-label {
    font-size: 11px;
    color: #94a3b8;
    margin-top: 4px;
}

/* ── Gestion des pages PDF (suppression / réordonnancement) ──────────────
   Tout est scopé sous .pdfprev- : ces styles servent la visionneuse overlay
   ET la page scribe-pdf.php, qui déplace le même .pdfprev-sidebar dans sa
   propre colonne. Une seule implémentation, deux hôtes. */

/* Pas de fond ni de bordure : le bouton doit flotter sur le panneau, pas
   reposer sur un bandeau plus sombre qui se lisait comme un second niveau
   d'interface (le projet proscrit par ailleurs les bordures visibles).
   `position: sticky` part avec le fond : une barre collante ET transparente
   laisserait les vignettes defiler DERRIERE le bouton. */
.pdfprev-pagebar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 8px; flex-wrap: wrap;
    padding: 10px 8px;
    background: transparent;
}
.pdfprev-pagebar[hidden] { display: none; }
.pdfprev-pagebar-info {
    font-size: 11px; color: #94a3b8; flex: 1 1 100%;
}
.pdfprev-pagebar-actions { display: flex; gap: 6px; width: 100%; }
.pdfprev-pagebar-btn {
    flex: 1;
    padding: 7px 10px;
    font-size: 12px; font-weight: 600; font-family: inherit;
    color: var(--color-text, #e5e7eb);
    background: rgba(255,255,255,0.06);
    border: none; border-radius: 8px;
    cursor: pointer;
    transition: background .15s, opacity .15s;
}
.pdfprev-pagebar-btn:hover { background: rgba(255,255,255,0.12); }
.pdfprev-pagebar-btn.primary { background: var(--color-primary, #3b82f6); color: #fff; }
.pdfprev-pagebar-btn.primary:hover { background: #2f6fd0; }
.pdfprev-pagebar-btn:disabled { opacity: .55; cursor: default; }

/* La croix de suppression n'existe qu'en mode gestion. */
.pdfprev-thumb-del {
    position: absolute; top: 2px; right: 2px;
    width: 20px; height: 20px;
    display: none; align-items: center; justify-content: center;
    padding: 0;
    color: #fff; background: rgba(190, 40, 40, .92);
    border: none; border-radius: 50%;
    cursor: pointer;
}
.pdfprev-thumb-del:hover { background: #d33; }

.pdfprev-thumbs.pdfprev-mgmt .pdfprev-thumb { position: relative; cursor: grab; }
.pdfprev-thumbs.pdfprev-mgmt .pdfprev-thumb:active { cursor: grabbing; }
.pdfprev-thumbs.pdfprev-mgmt .pdfprev-thumb .pdfprev-thumb-del { display: flex; }
.pdfprev-thumbs.pdfprev-mgmt .pdfprev-thumb.dragging { opacity: .4; }
/* Repère de dépôt : la vignette survolée s'écarte visuellement. */
.pdfprev-thumbs.pdfprev-mgmt .pdfprev-thumb.dragging ~ .pdfprev-thumb { transition: transform .12s; }
.pdfprev-thumb.active .pdfprev-thumb-label { color: #93c5fd; }

.pdfprev-main {
    flex: 1;
    overflow: auto;
}
/* Conteneur interne des pages — cible du transform pendant le pincement */
.pdfprev-pages-inner {
    display: flex; flex-direction: column; align-items: center;
    gap: 14px;
    width: 100%;            /* centrage horizontal effectif */
    min-width: fit-content; /* scroll horizontal atteignable quand zoomé */
    transform-origin: 50% 0;
}
.pdfprev-page {
    background: #fff;
    box-shadow: 0 4px 16px rgba(0,0,0,0.5);
    position: relative;
    flex-shrink: 0;
}
.pdfprev-page canvas { display: block; }
/* Placeholder shimmer while waiting for lazy render */
.pdfprev-page-pending {
    background:
        linear-gradient(90deg, transparent 0%, rgba(0,0,0,0.04) 50%, transparent 100%) #fafafa;
    background-size: 200% 100%;
    animation: pdfprev-shimmer 1.4s linear infinite;
}
@keyframes pdfprev-shimmer {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
.pdfprev-error {
    color: #fca5a5;
    background: rgba(239,68,68,0.1);
    padding: 24px;
    border-radius: 12px;
    text-align: center;
    margin: 40px auto;
    max-width: 600px;
    font-size: 14px;
}
/* Page individuelle qui a échoué — fallback discret pour ne pas bloquer la lecture des autres pages */
.pdfprev-page-error {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: #fca5a5;
    background: rgba(239,68,68,0.06);
    border: 1px dashed rgba(239,68,68,0.25);
    border-radius: 8px;
    font-size: 13px;
}

/* Breakpoint intermédiaire : avant que ça déborde (toolbar avec hamburger +
   filename + page-nav + zoom + rotate + Modifier + Signer + download + close
   = ~1000px de contenu si on garde les labels). On masque les libellés des
   gros boutons et on réduit le filename pour gagner ~180px d'un coup. */
@media (max-width: 1100px) {
    .pdfprev-filename { max-width: 200px; }
    .pdfprev-sign-btn span { display: none; }
    .pdfprev-sign-btn { padding: 7px 10px; }
}
@media (max-width: 900px) {
    .pdfprev-toolbar { gap: 6px; padding: 8px 10px; }
    .pdfprev-filename { max-width: 160px; }
    .pdfprev-spacer-sm { width: 4px; }
    .pdfprev-body { position: relative; }
    /* Volet vignettes en SURCOUCHE du document (il ne compresse plus les
       pages et ne décale plus leur largeur calculée) — l'ancien
       `width:0 !important` à 720px le rendait inouvrable. */
    .pdfprev-sidebar {
        position: absolute; left: 0; top: 0; bottom: 0; z-index: 6;
        width: 148px;
        box-shadow: 6px 0 22px rgba(0,0,0,.45);
    }
    .pdfprev-sidebar.collapsed { width: 0; box-shadow: none; }
}
@media (max-width: 720px) {
    .pdfprev-filename { max-width: 120px; font-size: 12px; }
    /* Cibles tactiles : 34px mini */
    .pdfprev-tb-btn { width: 34px; height: 34px; }
    .pdfprev-sign-btn { padding: 8px 10px; }
    .pdfprev-main { padding: 10px 8px; padding-bottom: 120px; /* Espace pour barre edit */ }
    /* Barre edit sur mobile : évite recouvrir le contenu */
    .pdfedit-toolbar-inline { position: fixed; bottom: 0; left: 0; right: 0; z-index: 100; width: 100%; }
}
@media (max-width: 480px) {
    .pdfprev-toolbar { padding: 6px 6px; gap: 3px; }
    .pdfprev-filename { display: none; }
    .pdfprev-tb-group { padding: 1px; }
    .pdfprev-page-info input { width: 30px; }
    .pdfprev-spacer-sm { width: 0; }
    /* Le zoom par boutons est remplacé par pincer / double-tap sur tactile :
       on libère le groupe entier (≈110px) et on GARDE Pivoter (utile pour
       les scans) que l'ancienne règle sacrifiait. */
    .pdfprev-tb-zoom { display: none; }
    .pdfprev-page-info { padding: 0 2px; gap: 2px; font-size: 12px; }

    /* Cache le panneau d'édition par défaut sur mobile (Modifier, Signer, Outils) */
    #pdfprev-edit-panel {
        display: none !important;
        flex: 0 0 0 !important;
        width: 0 !important;
        min-width: 0 !important;
        overflow: hidden !important;
        border: none !important;
        padding: 0 !important;
        margin: 0 !important;
    }
    /* Affiche que s'il y a une classe spéciale (pour user actions futures) */
    #pdfprev-edit-panel.show {
        display: flex !important;
        flex: 1 1 auto !important;
        width: auto !important;
    }
}

/* ═══════════════════════════════════════════════════════════════════════
   PDF Preview — Sign Mode (state machine view↔sign sans close+open)
   La carte « Signer » dans la toolbar bascule en mode sign : pages cliquables,
   panneau signatures sous la toolbar, boutons Annuler/Enregistrer révélés.
   ═══════════════════════════════════════════════════════════════════════ */

/* Boutons de mode sign : cachés par défaut, révélés via .pdfprev-mode-sign */
.pdfprev-tb-sign-cancel,
.pdfprev-tb-sign-save { display: none !important; }
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-sign-cancel,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-sign-save { display: inline-flex !important; }

/* En mode sign : on cache les actions inutiles pour clarifier l'UI */
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-zoom,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-rotate,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-edit,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-sign,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-tools,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-print,
.pdfprev-overlay.pdfprev-mode-sign .pdfprev-tb-download { display: none !important; }
/* En mode edit : idem pour Outils */
.pdfprev-overlay.pdfprev-mode-edit .pdfprev-tb-tools { display: none !important; }
/* Bouton Outils — variante neutre (distinct du bleu Sign/Edit) */
.pdfprev-tb-tools {
    background: rgba(99,102,241,.2) !important;
    border: 1px solid rgba(99,102,241,.4) !important;
    color: #c7d2fe !important;
}
.pdfprev-tb-tools:hover, .pdfprev-tb-tools.active {
    background: rgba(99,102,241,.38) !important;
    color: #fff !important;
}

/* Cancel = ghost rouge, Save = primary vert pour démarquer visuellement */
.pdfprev-tb-sign-cancel {
    background: rgba(239,68,68,0.12);
    color: #ef4444;
    border: 1px solid rgba(239,68,68,0.25);
}
.pdfprev-tb-sign-cancel:hover { background: rgba(239,68,68,0.2); }
.pdfprev-tb-sign-save {
    background: #10b981;
    color: #fff;
    border: 1px solid #059669;
}
.pdfprev-tb-sign-save:hover { background: #059669; }

/* Panneau signatures (entre toolbar et body en mode sign) */
.pdfprev-sign-panel {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 16px;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    flex-wrap: wrap;
}
.pdfprev-sign-panel[hidden] { display: none; }
.pdfprev-sign-panel-label {
    font-size: 11px; font-weight: 700;
    color: var(--color-text-tertiary);
    text-transform: uppercase; letter-spacing: 0.06em;
}
.pdfprev-sign-list {
    display: flex; gap: 8px; flex: 1; flex-wrap: wrap; align-items: center;
    min-height: 44px;
}
.pdfprev-sign-list-loading,
.pdfprev-sign-empty {
    font-size: 12px; color: var(--color-text-tertiary); font-style: italic;
}
.pdfprev-sign-thumb {
    position: relative;
    width: 80px; height: 36px;
    border: 2px solid var(--color-border);
    border-radius: 8px;
    background: #fff;
    cursor: pointer;
    transition: border-color .15s, transform .15s;
    overflow: hidden;
    flex-shrink: 0;
}
.pdfprev-sign-thumb:hover { border-color: var(--color-primary); transform: translateY(-1px); }
.pdfprev-sign-thumb.active {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px rgba(0,122,255,0.25);
}
.pdfprev-sign-thumb img {
    width: 100%; height: 100%;
    object-fit: contain;
    padding: 4px;
}
.pdfprev-sign-thumb-del {
    position: absolute; top: 2px; right: 2px;
    width: 18px; height: 18px;
    border-radius: 50%;
    background: rgba(239,68,68,0.9); color: #fff;
    border: none; cursor: pointer;
    font-size: 12px; font-weight: 700; line-height: 1;
    opacity: 0; transition: opacity .15s;
}
.pdfprev-sign-thumb:hover .pdfprev-sign-thumb-del { opacity: 1; }
.pdfprev-sign-draw {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    border-radius: 8px;
    background: var(--color-primary); color: #fff;
    border: none; cursor: pointer;
    font-size: 12px; font-weight: 600;
    transition: background .15s;
}
.pdfprev-sign-draw:hover { background: #0066d6; }
.pdfprev-sign-hint {
    font-size: 11px; color: var(--color-text-tertiary); font-style: italic;
    flex-basis: 100%;
}

/* Overlay click sur chaque page : invisible mais cliquable, curseur crosshair
   en mode placement actif (signature sélectionnée). */
.pdfprev-sign-overlay {
    position: absolute;
    inset: 0;
    pointer-events: auto;
    z-index: 2;
}
body.pdfsign-placement-mode .pdfprev-sign-overlay { cursor: crosshair; }

/* La page en mode sign doit être en `position: relative` pour que l'overlay
   absolute s'aligne dessus. Vérifié — .pdfprev-page n'a pas de position définie
   ailleurs, donc on l'ajoute ici. */
.pdfprev-page { position: relative; }

@media (max-width: 720px) {
    .pdfprev-sign-panel { padding: 8px 12px; gap: 8px; }
    .pdfprev-sign-thumb { width: 64px; height: 30px; }
    .pdfprev-sign-hint { display: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   PDF Preview — Edit Mode (state machine view↔edit, plugin pdfEditor.js)
   La carte « Modifier » dans la toolbar bascule en mode edit : toolbar
   d'outils s'injecte sous la toolbar principale, overlays SVG sur les pages.
   ═══════════════════════════════════════════════════════════════════════ */

/* En mode edit : on cache uniquement Modifier + Signer (déjà dans ce mode) */
.pdfprev-overlay.pdfprev-mode-edit .pdfprev-tb-edit,
.pdfprev-overlay.pdfprev-mode-edit .pdfprev-tb-sign { display: none !important; }

/* Toolbar inline injectée par PdfEditor.attach() — visible uniquement en mode edit */
.pdfedit-toolbar-inline {
    display: flex;
    align-items: center;
    gap: 10px;
    position: relative;
}
.pdfedit-toolbar-inline .pdfedit-tools {
    display: flex; gap: 2px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 2px;
}
.pdfedit-toolbar-inline .pdfedit-tool {
    width: 32px; height: 32px;
    display: inline-flex; align-items: center; justify-content: center;
    background: transparent;
    border: none;
    border-radius: 6px;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background .15s, color .15s;
}
.pdfedit-toolbar-inline .pdfedit-tool:hover {
    background: var(--color-hover);
    color: var(--color-text);
}
.pdfedit-toolbar-inline .pdfedit-tool.active {
    background: var(--color-primary);
    color: #fff;
}
.pdfedit-toolbar-inline .pdfedit-colors {
    display: flex; gap: 4px;
    padding: 7px 8px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 8px;
}
.pdfedit-toolbar-inline .pdfedit-color {
    width: 22px; height: 22px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
    transition: transform .15s, border-color .15s;
}
.pdfedit-toolbar-inline .pdfedit-color:hover { transform: scale(1.1); }
.pdfedit-toolbar-inline .pdfedit-color.active {
    border-color: var(--color-text);
    transform: scale(1.15);
}
.pdfedit-toolbar-inline .pdfedit-tb-spacer { flex: 1; }
.pdfedit-toolbar-inline .pdfedit-tb-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    border-radius: 8px;
    background: transparent;
    border: 1px solid var(--color-border);
    color: var(--color-text);
    font-size: 12px; font-weight: 600;
    cursor: pointer;
    transition: background .15s;
}
.pdfedit-toolbar-inline .pdfedit-tb-btn:hover { background: var(--color-hover); }
.pdfedit-toolbar-inline .pdfedit-tb-btn.active {
    background: var(--color-primary);
    color: #fff;
    border-color: var(--color-primary);
}
.pdfedit-toolbar-inline .pdfedit-tb-cancel {
    background: rgba(239,68,68,0.12);
    color: #ef4444;
    border-color: rgba(239,68,68,0.25);
}
.pdfedit-toolbar-inline .pdfedit-tb-cancel:hover { background: rgba(239,68,68,0.2); }
.pdfedit-toolbar-inline .pdfedit-save-btn {
    background: #10b981;
    color: #fff;
    border-color: #059669;
}
.pdfedit-toolbar-inline .pdfedit-save-btn:hover { background: #059669; }
.pdfedit-toolbar-inline .pdfedit-hint {
    flex-basis: 100%;
    font-size: 11px;
    color: var(--color-text-tertiary);
    font-style: italic;
    padding-top: 4px;
}

/* Overlay SVG par page — dimensionne automatiquement, capture les pointeurs */
.pdfedit-overlay-svg {
    position: absolute;
    inset: 0;
    pointer-events: auto;
    z-index: 2;
}
/* Pages preview : doivent être position:relative pour ancrer overlay (déjà fait par sign mode) */

@media (max-width: 720px) {
    .pdfedit-toolbar-inline { padding: 6px 8px; gap: 6px; }
    .pdfedit-toolbar-inline .pdfedit-tool { width: 28px; height: 28px; }
    .pdfedit-toolbar-inline .pdfedit-tb-btn span { display: none; }
    .pdfedit-toolbar-inline .pdfedit-hint { display: none; }
}

/* PDF preview chromeless layout — the iframe with the native browser PDF
   viewer takes the whole overlay, our actions float in the top-right corner */
.preview-content-fullscreen {
    position: absolute !important;
    inset: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
    max-width: none !important;
    max-height: none !important;
    background: #1e1e1e;
}
.preview-content-fullscreen iframe,
.preview-content-fullscreen .pdf-viewer {
    width: 100% !important;
    height: 100% !important;
    max-width: none !important;
    border-radius: 0 !important;
    box-shadow: none !important;
}
.preview-floating-actions {
    position: fixed;
    top: 6px;
    right: 6px;
    z-index: 10010;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 4px;
    background: rgba(30, 30, 30, 0.85);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-radius: 10px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}
.preview-float-btn {
    width: 38px;
    height: 38px;
    background: transparent;
    color: #fff;
    border: none;
    border-radius: 9px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background .12s;
}
.preview-float-btn:hover { background: rgba(255, 255, 255, 0.12); }
.preview-float-btn svg { width: 18px; height: 18px; }
.preview-floating-actions .preview-sign-btn {
    margin-right: 0 !important;
    padding: 8px 14px !important;
    font-size: 13px !important;
}

@media (max-width: 540px) {
    .preview-floating-actions { top: 4px; right: 4px; gap: 2px; }
    .preview-float-btn { width: 34px; height: 34px; }
    .preview-floating-actions .preview-sign-btn span { display: none; }
    .preview-floating-actions .preview-sign-btn {
        padding: 8px 10px !important;
    }
}

/* ================ PDF Editor (annotations) ================ */
.pdfedit-overlay {
    position: fixed; inset: 0;
    background: #1e1e1e;
    z-index: 10000;
    display: flex; flex-direction: column;
    color: #f8fafc;
}
.pdfedit-toolbar {
    display: flex; align-items: center; gap: 8px;
    padding: 10px 16px;
    background: #1e1e1e;
    border-bottom: 1px solid #2d2d2d;
    flex-shrink: 0;
    flex-wrap: wrap;
}
.pdfedit-filename {
    font-size: 13px; font-weight: 600;
    max-width: 300px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pdfedit-spacer { flex: 1; }
.pdfedit-tb-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    width: 66px; height: 36px;
    background: transparent;
    border: 1px solid transparent;
    color: #f8fafc;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.pdfedit-tb-btn:hover { background: #2d2d2d; }
.pdfedit-tb-btn.pdfedit-tb-secondary,
.pdfedit-tb-btn.pdfedit-save-btn {
    width: auto; padding: 0 14px;
    font-size: 13px; font-weight: 600;
    gap: 6px;
}
.pdfedit-save-btn {
    background: var(--color-primary, #007aff);
    color: #fff;
    border-color: var(--color-primary, #007aff);
}
.pdfedit-save-btn:hover { filter: brightness(1.1); }
.pdfedit-tools {
    display: inline-flex; gap: 2px;
    background: #2d2d2d;
    padding: 3px;
    border-radius: 10px;
}
.pdfedit-tool {
    width: 32px; height: 32px;
    border: none; background: transparent;
    color: #c0c0c0;
    border-radius: 7px;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 0.12s, color 0.12s;
}
.pdfedit-tool:hover { background: #3a3a3a; color: #fff; }
.pdfedit-tool.active {
    background: var(--color-primary, #007aff); color: #fff;
}
.pdfedit-colors {
    display: inline-flex; gap: 4px;
    padding-left: 8px;
    border-left: 1px solid #2d2d2d;
}
.pdfedit-color {
    width: 26px; height: 26px;
    border-radius: 50%;
    border: 2px solid #2d2d2d;
    cursor: pointer;
    transition: transform 0.12s, border-color 0.12s;
}
.pdfedit-color:hover { transform: scale(1.1); }
.pdfedit-color.active { border-color: #fff; transform: scale(1.15); }
.pdfedit-main {
    flex: 1;
    overflow: auto;
    padding: 24px;
    display: flex; flex-direction: column; align-items: center; gap: 16px;
}
.pdfedit-page {
    position: relative;
    background: #fff;
    box-shadow: 0 8px 30px rgba(0,0,0,0.5);
}
.pdfedit-page canvas { display: block; }
.pdfedit-overlay-svg {
    position: absolute; inset: 0;
    pointer-events: auto;
}
.pdfedit-overlay-svg .pdfedit-rect-anno,
.pdfedit-overlay-svg .pdfedit-path-anno,
.pdfedit-overlay-svg .pdfedit-text-anno,
.pdfedit-overlay-svg .pdfedit-checkbox-anno {
    cursor: pointer;
}
/* Petite case à cocher : on rend explicite la zone interactive et un léger
   hover pour l'état décoché (le tick + cadre déjà visibles suffisent au
   feedback visuel à l'état coché). */
.pdfedit-overlay-svg .pdfedit-checkbox-anno rect {
    transition: fill-opacity .12s;
}
.pdfedit-overlay-svg .pdfedit-checkbox-anno:hover rect {
    fill-opacity: 1;
}
/* Input inline pour ajout de texte directement sur la page (alternative
   moderne au prompt() : Adobe Acrobat-style). */
.pdfedit-inline-text {
    position: absolute;
    z-index: 5;
    background: rgba(255, 255, 255, 0.96);
    border: 2px dashed var(--color-primary, #007aff);
    border-radius: 4px;
    padding: 1px 6px;
    font-family: Helvetica, Arial, sans-serif;
    font-weight: 500;
    line-height: 1.2;
    outline: none;
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
    min-width: 80px;
}
.pdfedit-inline-text:focus { background: #fff; }

/* Form field overlay (AcroForm fill mode) */
.pdfedit-form-input {
    position: absolute;
    z-index: 4;
    background: rgba(255, 255, 0, 0.18);
    border: 1.5px solid rgba(0, 122, 255, 0.7);
    border-radius: 3px;
    padding: 1px 4px;
    box-sizing: border-box;
    color: #000;
    font-family: Helvetica, Arial, sans-serif;
    font-weight: 500;
    outline: none;
    cursor: text;
}
.pdfedit-form-input[type="checkbox"] {
    cursor: pointer;
    padding: 0;
    accent-color: var(--color-primary);
}
.pdfedit-form-input:focus {
    background: rgba(255, 255, 0, 0.35);
    border-color: var(--color-primary);
    box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.25);
}
.pdfedit-tb-btn.active {
    background: var(--color-primary, #007aff) !important;
    color: #fff !important;
    border-color: var(--color-primary, #007aff) !important;
}
.pdfedit-hint {
    position: fixed;
    bottom: 20px; left: 50%; transform: translateX(-50%);
    background: rgba(0, 122, 255, 0.95);
    color: #fff;
    padding: 8px 16px;
    border-radius: 999px;
    font-size: 12px; font-weight: 600;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    z-index: 1;
    pointer-events: none;
}

/* Modal "Pages" — grille de miniatures avec drag/drop */
.pdfedit-pgs {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 12px;
    max-height: 60vh;
    overflow-y: auto;
}
.pdfedit-pg {
    position: relative;
    background: var(--color-bg);
    border: 2px solid var(--color-border);
    border-radius: 10px;
    padding: 8px;
    cursor: grab;
    transition: transform 0.15s, border-color 0.15s;
}
.pdfedit-pg.dragging { opacity: 0.4; cursor: grabbing; }
.pdfedit-pg.drag-over { border-color: var(--color-primary); transform: scale(1.05); }
.pdfedit-pg-thumb {
    width: 100%;
    aspect-ratio: 0.7;
    background: #fff;
    border-radius: 4px;
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    transition: transform 0.2s;
}
.pdfedit-pg-thumb img { width: 100%; height: 100%; object-fit: contain; }
.pdfedit-pg-num {
    text-align: center;
    font-size: 12px; font-weight: 700;
    color: var(--color-text-secondary);
    margin-top: 6px;
}
.pdfedit-pg-actions {
    position: absolute; top: 4px; right: 4px;
    display: flex; gap: 2px;
    opacity: 0;
    transition: opacity 0.15s;
}
.pdfedit-pg:hover .pdfedit-pg-actions { opacity: 1; }
.pdfedit-pg-btn {
    width: 24px; height: 24px;
    border-radius: 6px;
    border: none;
    background: rgba(0, 0, 0, 0.7);
    color: #fff;
    font-weight: 700;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
}
.pdfedit-pg-btn:hover { background: rgba(0, 0, 0, 0.9); }
.pdfedit-pg-btn.pdfedit-pg-del { color: #ff453a; }

/* Workspace tag-bar (chips Favoris/Images/Vidéos/...) — placée au-dessus du
   file-browser et de la toolbar. Reuses .sidebar-cat / .sidebar-tag-fav ; la
   différence ici c'est juste le padding plus serré (la pill flottante au-
   dessus prend déjà beaucoup d'air). */
.ws-tag-bar { padding: 8px 16px 4px; }
.ws-tag-bar[hidden] { display: none; }
.ws-cat-clear {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 4px 10px;
    background: transparent;
    border: 1px dashed var(--color-border);
    color: var(--color-text-tertiary);
    border-radius: 14px;
    font-size: 11px; font-weight: 600;
    cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
}
.ws-cat-clear:hover {
    background: var(--color-hover);
    color: var(--color-text);
    border-color: var(--color-border-strong, var(--color-border));
    border-style: solid;
}

@media (max-width: 768px) {
    .pdfedit-toolbar { gap: 4px; padding: 8px 10px; }
    .pdfedit-filename { display: none; }
    .pdfedit-tb-btn.pdfedit-tb-secondary span,
    .pdfedit-save-btn span { display: none; }
    .pdfedit-tb-btn.pdfedit-tb-secondary,
    .pdfedit-save-btn { width: 36px; padding: 0; }
    .pdfedit-main { padding: 12px 8px; }
}

/* ================ PDF Signature Editor ================ */
.pdfsign-overlay {
    position: fixed; inset: 0;
    background: #1e1e1e;
    z-index: 10000;
    display: flex; flex-direction: column;
    color: #f8fafc;
}
.pdfsign-topbar {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 16px;
    background: #1e1e1e;
    border-bottom: 1px solid #2d2d2d;
    flex-shrink: 0;
}
.pdfsign-title { font-size: 14px; font-weight: 600; }
.pdfsign-spacer { flex: 1; }
.pdfsign-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    border-radius: 8px;
    border: none;
    cursor: pointer;
    font-size: 13px; font-weight: 600;
    font-family: inherit;
}
.pdfsign-btn-ghost { background: rgba(255,255,255,0.1); color: #f8fafc; }
.pdfsign-btn-ghost:hover { background: rgba(255,255,255,0.18); }
.pdfsign-btn-primary { background: #3b82f6; color: #fff; }
.pdfsign-btn-primary:hover:not(:disabled) { background: #2563eb; }
.pdfsign-btn-primary:disabled { opacity: 0.6; cursor: wait; }
.pdfsign-spin {
    display: inline-block; width: 12px; height: 12px;
    border: 2px solid rgba(255,255,255,0.4);
    border-top-color: #fff;
    border-radius: 50%;
    animation: pdfsign-spin 0.8s linear infinite;
}
@keyframes pdfsign-spin { to { transform: rotate(360deg); } }

.pdfsign-body { flex: 1; display: flex; min-height: 0; }
.pdfsign-sidebar {
    width: 240px;
    flex-shrink: 0;
    background: #1e1e1e;
    border-right: 1px solid #2d2d2d;
    padding: 16px 14px;
    display: flex; flex-direction: column;
    overflow-y: auto;
}
.pdfsign-sidebar-head {
    font-size: 11px; font-weight: 700;
    color: #94a3b8;
    text-transform: uppercase; letter-spacing: 0.5px;
    margin-bottom: 10px;
}
.pdfsign-sigs { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.pdfsign-sig-empty {
    font-size: 12px; color: #94a3b8;
    background: rgba(255,255,255,0.05);
    padding: 12px;
    border-radius: 8px;
    text-align: center;
}
.pdfsign-sig-item {
    position: relative;
    background: #fff;
    border: 2px solid transparent;
    border-radius: 8px;
    padding: 10px;
    cursor: pointer;
    min-height: 60px;
    display: flex; align-items: center; justify-content: center;
    transition: border-color .12s;
}
.pdfsign-sig-item:hover { border-color: #64748b; }
.pdfsign-sig-item.active { border-color: #3b82f6; box-shadow: 0 0 0 3px rgba(59,130,246,0.2); }
.pdfsign-sig-item img { max-width: 100%; max-height: 50px; object-fit: contain; pointer-events: none; }
.pdfsign-sig-del {
    position: absolute; top: 4px; right: 4px;
    width: 20px; height: 20px;
    border: none;
    background: rgba(239,68,68,0.85);
    color: #fff;
    border-radius: 50%;
    font-size: 14px; line-height: 1;
    cursor: pointer;
    display: none;
}
.pdfsign-sig-item:hover .pdfsign-sig-del { display: block; }
.pdfsign-draw-btn {
    display: flex; align-items: center; justify-content: center; gap: 6px;
    padding: 10px;
    background: rgba(59,130,246,0.18);
    color: #93c5fd;
    border: 1px dashed #3b82f6;
    border-radius: 8px;
    cursor: pointer;
    font-size: 12px; font-weight: 600;
    font-family: inherit;
}
.pdfsign-draw-btn:hover { background: rgba(59,130,246,0.28); }
.pdfsign-hint {
    margin: 14px 0 0;
    font-size: 11px; color: #94a3b8;
    line-height: 1.5;
}

.pdfsign-pages {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
    display: flex; flex-direction: column; align-items: center;
    gap: 16px;
    background: #1e1e1e;
}
.pdfsign-page {
    position: relative;
    background: #fff;
    box-shadow: 0 4px 16px rgba(0,0,0,0.5);
}
.pdfsign-page canvas { display: block; }
.pdfsign-page-overlay {
    position: absolute; inset: 0;
    cursor: default;
}
body.pdfsign-placement-mode .pdfsign-page-overlay { cursor: copy; }
.pdfsign-placed {
    position: absolute;
    border: 2px dashed transparent;
    cursor: move;
    user-select: none;
}
.pdfsign-placed:hover { border-color: #3b82f6; }
.pdfsign-placed img { width: 100%; height: 100%; object-fit: contain; pointer-events: none; }
.pdfsign-placed-del {
    position: absolute; top: -10px; right: -10px;
    width: 22px; height: 22px;
    background: #ef4444; color: #fff;
    border: 2px solid #fff;
    border-radius: 50%;
    font-size: 14px; line-height: 1;
    cursor: pointer;
    display: none;
}
.pdfsign-placed:hover .pdfsign-placed-del { display: block; }
.pdfsign-placed-resize {
    position: absolute; bottom: -6px; right: -6px;
    width: 14px; height: 14px;
    background: #3b82f6;
    border: 2px solid #fff;
    border-radius: 3px;
    cursor: nwse-resize;
    display: none;
}
.pdfsign-placed:hover .pdfsign-placed-resize { display: block; }
@media (hover: none) {
    .pdfsign-placed-del, .pdfsign-placed-resize { display: block !important; }
    .pdftext-drag-handle { display: flex !important; }
}

/* Annotations texte (remplissage de formulaire) — meme conteneur/hover que
   .pdfsign-placed (position/border/resize/suppression), specialise pour du
   texte modifiable en permanence plutot qu'une image figee. */
body.pdftext-placement-mode .pdfprev-page { cursor: crosshair; }
/* sign-document.php (signataire externe) place directement sur .pdfprev-page,
   sans le conteneur .pdfprev-sign-overlay/.pdfsign-page-overlay de
   scribe-pdf.php -- indicateur de curseur manquant pour ce mode la, aligne
   sur la regle equivalente de pdftext-placement-mode juste au-dessus. */
body.pdfsign-placement-mode .pdfprev-page { cursor: crosshair; }
.pdftext-annotation { cursor: default; user-select: auto; }
.pdftext-content {
    width: 100%; height: 100%;
    outline: none;
    overflow: hidden;
    cursor: text;
    user-select: text;
    white-space: pre-wrap;
    word-break: break-word;
    color: #111;
    font-family: Arial, Helvetica, sans-serif;
    line-height: 1.2;
}
.pdftext-drag-handle {
    position: absolute; top: -10px; left: -10px;
    width: 20px; height: 20px;
    background: #3b82f6; color: #fff;
    border: 2px solid #fff;
    border-radius: 50%;
    display: none;
    align-items: center; justify-content: center;
    cursor: move;
    font-size: 10px;
}
.pdfsign-placed.pdftext-annotation:hover .pdftext-drag-handle { display: flex; }

/* Champs de formulaire detectes (AcroForm) — cliquables, non lies au drag
   des annotations placees (calque distinct, purement indicatif tant que
   non rempli). */
.pdftext-detected-field {
    position: absolute;
    border: 1.5px dashed #10b981;
    background: rgba(16,185,129,0.08);
    cursor: pointer;
    box-sizing: border-box;
}
.pdftext-detected-field:hover { background: rgba(16,185,129,0.22); border-color: #059669; }
.pdftext-detected-field[data-field-type="Btn"] { border-radius: 50%; }
/* Case a cocher deja cochee dans le PDF d'origine (fieldValue != Off) —
   distinct visuellement des champs vides a remplir. */
.pdftext-detected-field-checked {
    border-color: #f59e0b;
    background: rgba(245,158,11,0.14);
    display: flex; align-items: center; justify-content: center;
    color: #d97706; font-weight: 700; font-size: 11px;
}
.pdftext-detected-field-checked:hover { background: rgba(245,158,11,0.24); border-color: #d97706; }

/* Petite barre flottante : taille de texte d'une annotation en cours
   d'edition — meme style que #spdf-zoom-pill (pilule sombre, -/+). */
.pdftext-size-toolbar {
    position: absolute;
    display: flex; align-items: center; gap: 6px;
    background: rgba(20,20,25,0.92);
    border-radius: 20px;
    padding: 4px 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.35);
    z-index: 20;
    white-space: nowrap;
}
.pdftext-size-toolbar button {
    width: 22px; height: 22px;
    border: none; border-radius: 50%;
    background: rgba(255,255,255,0.1);
    color: #fff;
    font-size: 13px; line-height: 1;
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
}
.pdftext-size-toolbar button:hover { background: rgba(255,255,255,0.2); }
.pdftext-size-toolbar button.active { background: #3b82f6; }
.pdftext-size-toolbar .pdftext-size-label {
    color: #fff; font-size: 12px; min-width: 26px; text-align: center;
}
.pdftext-size-toolbar .pdftext-fmt-sep {
    width: 1px; min-width: 1px; max-width: 1px; height: 18px; background: rgba(255,255,255,0.18); flex-shrink: 0;
}
.pdftext-size-toolbar select {
    background: rgba(255,255,255,0.1);
    color: #fff;
    border: none; border-radius: 12px;
    height: 22px; font-size: 11px;
    padding: 0 4px;
    max-width: 84px;
    cursor: pointer;
}
.pdftext-size-toolbar select:hover { background: rgba(255,255,255,0.2); }
.pdftext-size-toolbar select option { color: #111; background: #fff; }

/* Draw signature modal */
.pdfsign-draw-modal {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.7);
    z-index: 10001;
    display: flex; align-items: center; justify-content: center;
    padding: 16px;
}
.pdfsign-draw-card {
    background: #fff;
    border-radius: 16px;
    padding: 24px;
    max-width: 640px;
    width: 100%;
    color: #1e293b;
}
.pdfsign-draw-card h3 { margin: 0 0 4px; font-size: 18px; }
.pdfsign-draw-hint { margin: 0 0 16px; font-size: 13px; color: #64748b; }
.pdfsign-draw-card canvas {
    width: 100%;
    height: 200px;
    background: #f8fafc;
    border: 2px dashed #cbd5e1;
    border-radius: 8px;
    cursor: crosshair;
    touch-action: none;
}
.pdfsign-draw-actions {
    display: flex; align-items: center; gap: 8px;
    margin-top: 16px;
}
/* Ghost buttons inside the white draw-card need dark styling */
.pdfsign-draw-card .pdfsign-btn-ghost {
    background: #f1f5f9;
    color: #475569;
    border: 1px solid #e2e8f0;
}
.pdfsign-draw-card .pdfsign-btn-ghost:hover {
    background: #e2e8f0;
    color: #1e293b;
}
/* Close (✕) button in the card header */
.pdfsign-draw-header {
    display: flex; align-items: flex-start; justify-content: space-between;
    margin-bottom: 4px;
}
.pdfsign-draw-close {
    width: 32px; height: 32px;
    border-radius: 8px;
    background: transparent; border: none;
    color: #94a3b8; font-size: 18px; line-height: 1;
    cursor: pointer; display: flex; align-items: center; justify-content: center;
    flex-shrink: 0; margin: -4px -4px 0 0;
    transition: background 0.12s, color 0.12s;
}
.pdfsign-draw-close:hover { background: #f1f5f9; color: #1e293b; }

@media (max-width: 768px) {
    .pdfsign-sidebar { width: 180px; padding: 12px 10px; }
    .pdfsign-pages { padding: 12px; }
}
@media (max-width: 540px) {
    .pdfsign-body { flex-direction: column; }
    .pdfsign-sidebar {
        width: 100%; max-height: 30%;
        border-right: none; border-bottom: 1px solid #2d2d2d;
    }
    .pdfsign-sigs { flex-direction: row; overflow-x: auto; }
    .pdfsign-sig-item { min-width: 100px; flex-shrink: 0; }
    .pdfsign-hint { display: none; }
}

/* ============================================================
   Signature Pad — standalone dark-card modal
   ============================================================ */
.sigpad-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.82);
    display: flex; align-items: center; justify-content: center;
    z-index: 9999;
    padding: 20px;
    backdrop-filter: blur(4px);
}
.sigpad-card {
    width: 100%; max-width: 560px;
    background: #1c1c1e;
    border-radius: 20px;
    border: 1px solid rgba(255,255,255,0.08);
    box-shadow: 0 32px 80px rgba(0,0,0,0.6), 0 2px 8px rgba(0,0,0,0.4);
    overflow: hidden;
    display: flex; flex-direction: column;
}
.sigpad-canvas-wrap {
    position: relative;
    height: 260px;
    background: #fff;
    border-bottom: 1px solid rgba(0,0,0,0.08);
    cursor: crosshair;
}
.sigpad-baseline {
    position: absolute;
    left: 5%; right: 5%;
    top: 70%;
    height: 1px;
    background: rgba(0,0,0,0.1);
    pointer-events: none;
}
.sigpad-canvas-wrap canvas {
    display: block;
    width: 100%; height: 100%;
    touch-action: none;
}
.sigpad-placeholder {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    font-size: 15px; color: rgba(0,0,0,0.22);
    font-weight: 500; letter-spacing: 0.02em;
    pointer-events: none;
    transition: opacity 0.2s;
}
.sigpad-footer {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px;
}
.sigpad-footer-left {
    display: flex; align-items: center; gap: 8px;
    flex: 1; min-width: 0;
}
.sigpad-logo {
    width: 28px; height: 28px;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    color: rgba(255,255,255,0.5);
}
.sigpad-doc-title {
    font-size: 13px; color: rgba(255,255,255,0.45);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sigpad-actions {
    display: flex; gap: 8px; flex-shrink: 0;
}
.sigpad-btn {
    height: 34px; padding: 0 16px;
    border-radius: 99px; border: none; cursor: pointer;
    font-size: 13px; font-weight: 500; font-family: inherit;
    transition: opacity 0.15s, background 0.15s;
}
.sigpad-btn-write {
    background: rgba(255,255,255,0.12);
    color: rgba(255,255,255,0.75);
}
.sigpad-btn-write:hover { background: rgba(255,255,255,0.18); }
.sigpad-btn-continue {
    background: #fff;
    color: #111;
}
.sigpad-btn-continue:hover { background: rgba(255,255,255,0.88); }

/* Galerie signatures sauvegardées */
.sigpad-gallery {
    padding: 12px 14px 0;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.sigpad-gallery-label {
    font-size: 10px; font-weight: 700; letter-spacing: 0.07em; text-transform: uppercase;
    color: rgba(255,255,255,0.3); margin-bottom: 8px;
}
.sigpad-gallery-list {
    display: flex; flex-wrap: wrap; gap: 8px;
    padding-bottom: 12px;
}
.sigpad-gallery-item {
    position: relative;
    width: 110px; height: 56px;
    background: #f4f4f3;
    border-radius: 10px;
    border: 1.5px solid rgba(0,0,0,0.1);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
    transition: border-color 0.15s;
}
.sigpad-gallery-item:hover { border-color: rgba(0,0,0,0.25); }
.sigpad-gallery-item.active {
    border-color: var(--color-primary, #3b82f6);
    box-shadow: 0 0 0 2px rgba(59,130,246,0.25);
}
.sigpad-gallery-item img {
    max-width: 90%; max-height: 80%;
    object-fit: contain;
    opacity: 0.9;
}
.sigpad-gallery-del {
    position: absolute; top: 3px; right: 3px;
    width: 18px; height: 18px;
    background: rgba(0,0,0,0.55); border: none;
    border-radius: 50%; cursor: pointer;
    display: none; align-items: center; justify-content: center;
    color: rgba(255,255,255,0.7);
}
.sigpad-gallery-item:hover .sigpad-gallery-del { display: flex; }
.sigpad-gallery-del:hover { background: rgba(239,68,68,0.8); color: #fff; }
/* ── Onglets ── */
.sigpad-tab-bar {
    display: flex; gap: 6px;
    padding: 10px 14px;
    border-bottom: 1px solid rgba(255,255,255,0.06);
}
.sigpad-tab {
    flex: 1; height: 32px;
    border-radius: 8px; border: none; cursor: pointer;
    font-size: 12px; font-weight: 500; font-family: inherit;
    background: transparent; color: rgba(255,255,255,0.4);
    display: flex; align-items: center; justify-content: center; gap: 5px;
    transition: background 0.15s, color 0.15s;
}
.sigpad-tab:hover { background: rgba(255,255,255,0.07); color: rgba(255,255,255,0.7); }
.sigpad-tab.active { background: rgba(255,255,255,0.12); color: rgba(255,255,255,0.92); }

/* ── Onglet Texte ── */
.sigpad-text-wrap {
    height: 260px; padding: 12px 14px;
    box-sizing: border-box;
    display: flex; flex-direction: column; gap: 6px;
}
.sigpad-text-input {
    width: 100%; height: 38px; flex-shrink: 0;
    background: rgba(255,255,255,0.07);
    border: 1.5px solid rgba(255,255,255,0.1);
    border-radius: 10px; color: #fff;
    font-size: 15px; padding: 0 12px;
    font-family: inherit; outline: none; box-sizing: border-box;
}
.sigpad-text-input:focus { border-color: rgba(255,255,255,0.25); }
.sigpad-text-input::placeholder { color: rgba(255,255,255,0.25); }
.sigpad-text-extras {
    display: flex; flex-direction: column; gap: 5px; flex-shrink: 0;
}
.sigpad-text-extra {
    width: 100%; height: 29px;
    background: rgba(255,255,255,0.05);
    border: 1px solid rgba(255,255,255,0.08);
    border-radius: 8px; color: rgba(255,255,255,0.82);
    font-size: 12px; padding: 0 10px;
    font-family: inherit; outline: none; box-sizing: border-box;
    transition: border-color 0.15s;
}
.sigpad-text-extra:focus { border-color: rgba(255,255,255,0.22); background: rgba(255,255,255,0.07); }
.sigpad-text-extra::placeholder { color: rgba(255,255,255,0.2); }
.sigpad-text-row { display: flex; gap: 5px; }
.sigpad-text-row .sigpad-text-extra { flex: 1; min-width: 0; }
.sigpad-font-list {
    flex: 1; display: flex; gap: 8px; min-height: 0;
}
.sigpad-font-opt {
    flex: 1; min-width: 0;
    background: #f4f4f3;
    border-radius: 10px;
    border: 1.5px solid rgba(0,0,0,0.1);
    cursor: pointer; overflow: hidden;
    display: flex; flex-direction: column; align-items: stretch;
    transition: border-color 0.15s;
}
.sigpad-font-opt:hover { border-color: rgba(0,0,0,0.25); }
.sigpad-font-opt.active {
    border-color: var(--color-primary, #3b82f6);
    box-shadow: 0 0 0 2px rgba(59,130,246,0.25);
}
.sigpad-font-opt canvas {
    display: block; width: 100%;
    flex: 1; min-height: 0;
}
.sigpad-font-opt-name {
    font-size: 10px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
    color: rgba(0,0,0,0.35); text-align: center; padding: 3px 0 5px;
    flex-shrink: 0;
}

/* ── Onglet Importer ── */
.sigpad-import-area {
    height: 260px; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: background 0.15s;
}
.sigpad-import-area.drag-over {
    background: rgba(59,130,246,0.1);
    outline: 2px dashed rgba(59,130,246,0.45);
    outline-offset: -6px;
}
.sigpad-import-ph {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    color: rgba(255,255,255,0.3); pointer-events: none;
}
.sigpad-import-ph span { font-size: 13px; }
.sigpad-import-ph small { font-size: 11px; color: rgba(255,255,255,0.18); }
.sigpad-import-preview-wrap {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    padding: 14px; box-sizing: border-box;
}
.sigpad-import-preview-wrap img {
    max-width: 100%; max-height: 100%; object-fit: contain;
    border-radius: 6px;
}

/* Canvas dé-accentué quand une sig est sélectionnée */
.sigpad-canvas-wrap.sigpad-canvas-dimmed { opacity: 0.4; }

@media (max-width: 480px) {
    .sigpad-canvas-wrap { height: 180px; }
    .sigpad-text-wrap { height: 220px; }
    .sigpad-import-area { height: 180px; }
    .sigpad-doc-title { display: none; }
    .sigpad-gallery-item { width: 90px; height: 48px; }
    .sigpad-tab { font-size: 11px; gap: 3px; }
}

/* PDF.js multi-page viewer — pages stacked vertically, each fit-to-width */
.pdf-viewer {
    width: 100%;
    height: 100%;
    max-width: 1100px;
    overflow-y: auto;
    overflow-x: hidden;
    box-sizing: border-box;
    background: #2a2a2a;
    border-radius: 20px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    -webkit-overflow-scrolling: touch;
}
.pdf-viewer canvas { box-shadow: 0 2px 8px rgba(0,0,0,0.3); }

.preview-content pre {
    background: var(--color-surface);
    color: #d4d4d4;
    padding: 24px;
    border-radius: var(--radius-md);
    font-family: var(--font-mono);
    font-size: 13px;
    max-width: 900px;
    width: 100%;
    max-height: 100%;
    overflow: auto;
    white-space: pre-wrap;
    word-wrap: break-word;
}

.video-thumb {

    background: linear-gradient(135deg, #1e1e20 0%, #2a2a2e 100%);
}
[data-theme="light"] .video-thumb {
    background: linear-gradient(135deg, #e5e7eb 0%, #d1d5db 100%);
}

.video-play-icon {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 52px;
    height: 52px;
    background: rgba(0, 0, 0, 0.55);
    border-radius: 50%;
    backdrop-filter: blur(4px);
    height: 48px;
    background: rgba(0,0,0,0.6);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0.8;
    transition: all var(--transition-fast);
}

.file-card:hover .video-play-icon {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1.1);
}

.video-play-icon svg {
    margin-left: 3px;
}

/* ===== TOAST NOTIFICATIONS ===== */
.toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    z-index: var(--z-toast);
    max-width: calc(100vw - 40px);
    pointer-events: none;
}

.toast {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18), 0 2px 6px rgba(0, 0, 0, 0.08);
    padding: 12px 14px 12px 12px;
    font-size: 13px;
    line-height: 1.4;
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 280px;
    max-width: 420px;
    color: var(--color-text);
    animation: toastIn 0.32s cubic-bezier(0.32, 0.72, 0, 1) forwards;
    pointer-events: auto;
    will-change: transform, opacity;
}

/* Color-coded leading icon tile so each type is recognizable in dark + light */
.toast-icon {
    width: 30px;
    height: 30px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.toast-icon svg { width: 16px; height: 16px; }

.toast-msg {
    flex: 1;
    min-width: 0;
    overflow-wrap: anywhere;
}

.toast-close {
    background: transparent;
    border: none;
    color: var(--color-text-tertiary);
    width: 24px; height: 24px;
    border-radius: 6px;
    padding: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background 0.15s, color 0.15s;
}
.toast-close:hover {
    background: color-mix(in srgb, var(--color-text) 8%, transparent);
    color: var(--color-text);
}
.toast-close svg { width: 14px; height: 14px; }
.toast-action {
    background: color-mix(in srgb, currentColor 12%, transparent);
    border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
    color: inherit;
    border-radius: 6px;
    padding: 3px 10px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    flex-shrink: 0;
    white-space: nowrap;
    transition: background 0.15s;
}
.toast-action:hover { background: color-mix(in srgb, currentColor 22%, transparent); }

/* Per-type colored icon tiles */
.toast-success .toast-icon {
    background: color-mix(in srgb, var(--color-success) 16%, transparent);
    color: var(--color-success);
}
.toast-error .toast-icon {
    background: color-mix(in srgb, var(--color-danger) 16%, transparent);
    color: var(--color-danger);
}
.toast-warning .toast-icon {
    background: color-mix(in srgb, var(--color-warning) 18%, transparent);
    color: var(--color-warning);
}
.toast-info .toast-icon {
    background: color-mix(in srgb, var(--color-primary) 16%, transparent);
    color: var(--color-primary);
}

/* Slim accent bar on the left edge, colored per type */
.toast::before {
    content: '';
    position: absolute;
    left: 0; top: 8px; bottom: 8px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--color-primary);
}
.toast { position: relative; }
.toast-success::before { background: var(--color-success); }
.toast-error::before   { background: var(--color-danger); }
.toast-warning::before { background: var(--color-warning); }
.toast-info::before    { background: var(--color-primary); }

.toast.removing {
    animation: toastOut 0.26s cubic-bezier(0.32, 0.72, 0, 1) forwards;
}

@keyframes toastIn {
    from { opacity: 0; transform: translateX(110%) scale(0.95); }
    60%  { opacity: 1; }
    to   { opacity: 1; transform: translateX(0) scale(1); }
}

@keyframes toastOut {
    from { opacity: 1; transform: translateX(0) scale(1); }
    to   { opacity: 0; transform: translateX(110%) scale(0.95); }
}

/* Mobile: full-width toasts at the bottom */
@media (max-width: 600px) {
    .toast-container {
        top: auto;
        bottom: 16px;
        right: 12px;
        left: 12px;
        max-width: none;
    }
    .toast {
        min-width: 0;
        max-width: none;
    }
    @keyframes toastIn {
        from { opacity: 0; transform: translateY(60px) scale(0.95); }
        to   { opacity: 1; transform: translateY(0) scale(1); }
    }
    @keyframes toastOut {
        from { opacity: 1; transform: translateY(0) scale(1); }
        to   { opacity: 0; transform: translateY(60px) scale(0.95); }
    }
}

/* ===== LOGIN PAGE ===== */
.login-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background: var(--color-bg);
    overflow: auto;
}

.login-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: 40px;
    width: 100%;
    max-width: 400px;
    margin: 20px;
}

.login-logo {
    text-align: center;
    margin-bottom: 32px;
}

.login-logo svg {
    width: 48px;
    height: 48px;
    color: var(--color-primary);
}

.login-logo h1 {
    font-size: 22px;
    font-weight: 600;
    margin-top: 12px;
}

.login-error {
    background: #fef2f2;
    border: 1px solid #fecaca;
    color: var(--color-danger);
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    margin-bottom: 16px;
}

.login-form .form-group {
    margin-bottom: 20px;
}

.login-form .btn {
    width: 100%;
    padding: 12px;
    font-size: 14px;
}

/* ===== SHARE PUBLIC PAGE ===== */
.share-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background: var(--color-bg);
    overflow: auto;
}

.share-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    width: 100%;
    margin: 20px;
    text-align: center;
}

.share-card-icon {
    width: 72px;
    height: 72px;
    margin: 0 auto 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-primary-light);
    border-radius: var(--radius-lg);
}

.share-card-icon svg {
    width: 36px;
    height: 36px;
    color: var(--color-primary);
}

.share-card-name {
    font-size: 18px;
    font-weight: 600;
    margin-bottom: 4px;
    word-break: break-word;
}

.share-card-meta {
    font-size: 13px;
    color: var(--color-text-secondary);
    margin-bottom: 8px;
}

.share-card-owner {
    font-size: 12px;
    color: var(--color-text-tertiary);
    margin-bottom: 24px;
}

/* QR code dans la modale de partage */
.share-qr-wrap summary::-webkit-details-marker { display: none; }
.share-qr-wrap[open] .share-qr-chevron { transform: rotate(180deg); }

/* ===== ADMIN ===== */
/* Note: .admin-tabs / .admin-tab pill styles live higher in the file
   (~ line 575). The old flat bar variant lived here and shadowed them.
   Removed — pill styles now apply cleanly. */

.admin-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
    margin-bottom: 24px;
}

.stat-card {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    padding: 20px;
    box-shadow: var(--shadow-xs);
}

.stat-card-label {
    font-size: 12px;
    color: var(--color-text-secondary);
    margin-bottom: 4px;
}

.stat-card-value {
    font-size: 28px;
    font-weight: 700;
}

/* Table */
.data-table {
    width: 100%;
    border-collapse: collapse;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.data-table th {
    text-align: left;
    padding: 12px 16px;
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    border-bottom: 1px solid var(--color-border);
}

.data-table td {
    padding: 12px 16px;
    font-size: 13px;
    border-bottom: 1px solid var(--color-border-light);
}

.data-table tr:last-child td {
    border-bottom: none;
}

.data-table tr:hover td {
    background: var(--color-bg);
}

/* Badge */
.badge {
    display: inline-block;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 600;
}

.badge-admin {
    background: #fef3c7;
    color: #92400e;
}

.badge-user {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.badge-active {
    background: #d1fae5;
    color: #065f46;
}

.badge-suspended {
    background: #fef2f2;
    color: #991b1b;
}

/* Chaque plan porte sa couleur de la page Tarifs -- un violet unique pour
   tous rendait la colonne illisible : c'est justement le plan qu'on vient y
   chercher. Les valeurs sont celles de --pc dans plans.php ; les changer
   d'un cote sans l'autre reintroduirait l'incoherence qu'on corrige ici. */
.badge-plan {
    --pc: #94a3b8;                                    /* free, et repli */
    background: color-mix(in srgb, var(--pc) 16%, transparent);
    color: var(--pc);
}
/* Compte de test : ambre, a cote du plan et non a sa place -- un compte de
   test a aussi un plan, et les deux informations se lisent ensemble. */
.badge-test {
    margin-left: 6px;
    background: color-mix(in srgb, #f59e0b 16%, transparent);
    color: #f59e0b;
}

.badge-plan[data-plan="etoile"]    { --pc: #f59e0b; }
.badge-plan[data-plan="pro"]       { --pc: #3b82f6; }
.badge-plan[data-plan="business"]  { --pc: #8b5cf6; }
.badge-plan[data-plan="solidaire"] { --pc: #10b981; }

/* Pagination */
.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 16px;
}

.pagination-btn {
    padding: 6px 12px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    color: var(--color-text-secondary);
    transition: all var(--transition-fast);
}

.pagination-btn:hover {
    background: var(--color-bg);
}

.pagination-btn.active {
    background: var(--color-primary);
    color: white;
}

.pagination-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ===== RESPONSIVE ===== */
@media (max-width: 768px) {
    .sidebar {
        position: fixed;
        left: -100%;
        top: 0;
        bottom: 0;
        z-index: 100;
        transition: left var(--transition-normal);
    }

    .sidebar.open {
        left: 0;
    }

    .sidebar-overlay {
        position: fixed;
        inset: 0;
        background: rgba(0,0,0,0.4);
        z-index: 99;
        display: none;
    }

    .sidebar-overlay.visible {
        display: block;
    }

    .header {
        padding: 0 16px;
    }

    .file-grid {
        grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
        gap: 8px;
    }

    .content {
        padding: 10px;
        /* Renforce le fix no-sidebar : sur mobile, .content ne doit
           jamais être un container scroll vertical — le body scrolle. */
        overflow-y: visible;
        
    }

    .upload-panel {
        width: calc(100% - 32px);
        left: 16px;
        right: 16px;
    }

    .modal {
        margin: 16px;
    }

    .btn-mobile-menu {
        display: flex;
    }
}

@media (min-width: 769px) {
    .btn-mobile-menu {
        display: none;
    }

    .sidebar-overlay {
        display: none !important;
    }
}

/* ===== FOLDER TREE (for move dialog) ===== */
.folder-tree {
    max-height: 300px;
    overflow-y: auto;
}

.folder-tree-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    font-size: 13px;
    transition: background var(--transition-fast);
}

.folder-tree-item:hover {
    background: var(--color-bg);
}

.folder-tree-item.selected {
    background: var(--color-primary-light);
    color: var(--color-primary);
}

.folder-tree-item svg {
    width: 18px;
    height: 18px;
    color: var(--color-warning);
}

/* ===== SCROLLBAR ===== */
::-webkit-scrollbar {
    width: 6px;
    height: 6px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: var(--radius-full);
}

::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-tertiary);
}

/* ===== LOADING ===== */
.loading-spinner {
    width: 24px;
    height: 24px;
    border: 2px solid var(--color-border);
    border-top-color: var(--color-primary);
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

.loading-center {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 60px;
}

/* ===== ANIMATIONS ===== */
.file-card {
    animation: fadeInUp 0.3s ease forwards;
    opacity: 0;
}

.file-list-row {
    animation: fadeInUp 0.2s ease forwards;
    opacity: 0;
}

@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

.file-grid .file-card:nth-child(1) { animation-delay: 0.02s; }
.file-grid .file-card:nth-child(2) { animation-delay: 0.04s; }
.file-grid .file-card:nth-child(3) { animation-delay: 0.06s; }
.file-grid .file-card:nth-child(4) { animation-delay: 0.08s; }
.file-grid .file-card:nth-child(5) { animation-delay: 0.10s; }
.file-grid .file-card:nth-child(6) { animation-delay: 0.12s; }
.file-grid .file-card:nth-child(7) { animation-delay: 0.14s; }
.file-grid .file-card:nth-child(8) { animation-delay: 0.16s; }
.file-grid .file-card:nth-child(n+9) { animation-delay: 0.18s; }

/* ===== BATCH ACTIONS BAR ===== */
/* ===== Header library shortcuts (Favoris / Partages / Corbeille) =====
   Icône seule au repos, icône + label coloré quand actif (page courante).
   Visibles uniquement dans la famille "Mes fichiers" via auto-détection PHP. */
.header-actions .lib-btn,
.ws-pill-write-group .lib-btn {
    display: inline-flex; align-items: center; gap: 6px;
    height: 34px; padding: 0 9px;
    border-radius: 9px;
    background: transparent; border: 1px solid transparent;
    color: var(--color-text-secondary, #64748b);
    text-decoration: none;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s, padding 0.2s;
    flex-shrink: 0;
}
.header-actions .lib-btn:hover,
.ws-pill-write-group .lib-btn:hover {
    background: var(--color-hover);
    color: var(--color-text);
}
.header-actions .lib-btn-label {
    display: none;
    font-size: 13px; font-weight: 600;
    white-space: nowrap;
}
.header-actions .lib-btn.active {
    padding: 0 12px;
}
.header-actions .lib-btn.active .lib-btn-label { display: inline; }

/* Couleurs identitaires par section quand actif (cohérent avec home stat cards) */
.header-actions .lib-btn-favoris.active {
    background: rgba(245, 158, 11, 0.14);
    color: #f59e0b;
    border-color: rgba(245, 158, 11, 0.32);
}
.header-actions .lib-btn-shared.active {
    background: rgba(168, 85, 247, 0.14);
    color: #a855f7;
    border-color: rgba(168, 85, 247, 0.32);
}
.header-actions .lib-btn-trash.active {
    background: rgba(239, 68, 68, 0.14);
    color: #ef4444;
    border-color: rgba(239, 68, 68, 0.32);
}

/* Import button : action principale → fond primaire plein pour garder l'emphase
   visuelle malgré le passage en icône. Hover assombrit légèrement. */
/* Bouton upload : discret, icône simple (comme les autres actions) */
.header-actions .lib-btn-import,
.ws-pill-write-group .lib-btn-import {
    background: transparent;
    color: var(--color-text-secondary);
    border-color: transparent;
}
/* État "note partagée" du bouton Partager (header Scribe) */
.header-actions #sfp-share-btn.share-active {
    color: var(--color-primary, #3b82f6);
    background: rgba(59, 130, 246, 0.12);
}
.header-actions .lib-btn-import:hover,
.ws-pill-write-group .lib-btn-import:hover {
    background: var(--color-hover);
    color: var(--color-text);
    border-color: var(--color-border);
}
/* Nouveau dossier : icône neutre, hover discret */
.header-actions .lib-btn-newfolder {
    color: var(--color-text-secondary, #64748b);
}
.header-actions .lib-btn-newfolder:hover {
    background: var(--color-hover);
    color: var(--color-text);
}

/* Mobile : sur petits écrans, garder l'icône seule même quand actif (gain de place) */
@media (max-width: 720px) {
    .header-actions .lib-btn.active { padding: 0 9px; }
    .header-actions .lib-btn.active .lib-btn-label { display: none; }
}

/* ===== BATCH BAR (refonte) =====
   Pill flottante glassmorphic en bas d'écran. Apparaît dès 1 sélection.
   Architecture : [☐ Tout] · "N sélectionné" | [Fav] [Move] [DL] [Del] | [×]
   Fond noir transparent + blur pour bien ressortir sur fond clair ET sombre. */
.batch-bar {
    position: fixed;
    bottom: 24px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(15, 23, 42, 0.92);
    color: #fff;
    border: 1px solid rgba(255,255,255,0.10);
    border-radius: 999px;
    padding: 8px 10px 8px 12px;
    display: flex;
    align-items: center;
    gap: 4px;
    box-shadow: 0 12px 36px rgba(0,0,0,0.32), 0 2px 8px rgba(0,0,0,0.18);
    backdrop-filter: blur(18px) saturate(1.4);
    -webkit-backdrop-filter: blur(18px) saturate(1.4);
    z-index: var(--z-modal);
    white-space: nowrap;
    animation: batch-bar-in 0.32s cubic-bezier(0.34, 1.56, 0.64, 1);
    max-width: calc(100vw - 24px);
}
[data-theme="light"] .batch-bar {
    background: rgba(15, 23, 42, 0.94);
}

@keyframes batch-bar-in {
    from { transform: translateX(-50%) translateY(40px) scale(0.94); opacity: 0; }
    to   { transform: translateX(-50%) translateY(0) scale(1);       opacity: 1; }
}

/* Bouton "Tout sélectionner" — case checkbox visuelle */
.batch-select-all {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px;
    background: transparent; border: none; cursor: pointer;
    border-radius: 50%;
    color: rgba(255,255,255,0.85);
    transition: background 0.15s, color 0.15s;
}
.batch-select-all:hover { background: rgba(255,255,255,0.10); color: #fff; }
.batch-select-all-box {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; height: 18px;
    border: 1.7px solid rgba(255,255,255,0.55);
    border-radius: 5px;
    background: transparent;
    transition: background 0.15s, border-color 0.15s;
    position: relative;
}
.batch-select-all-check,
.batch-select-all-dash {
    position: absolute; inset: 0;
    margin: auto;
    opacity: 0;
    color: #fff;
    transition: opacity 0.15s;
}
.batch-select-all.some-selected .batch-select-all-box {
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.batch-select-all.some-selected .batch-select-all-dash { opacity: 1; }
.batch-select-all.all-selected .batch-select-all-box {
    background: var(--color-primary);
    border-color: var(--color-primary);
}
.batch-select-all.all-selected .batch-select-all-check { opacity: 1; }

/* Même bouton, contexte toolbar claire (header-actions) au lieu du batch-bar
   sombre : les tokens ci-dessus (blanc en dur) ne conviennent pas ici. */
.header-actions .batch-select-all {
    width: 34px; height: 34px;
    padding: 0;
    border-radius: 50%;
    color: var(--color-text-secondary);
}
.header-actions .batch-select-all:hover { background: var(--color-bg); color: var(--color-text); }
.header-actions .batch-select-all.some-selected,
.header-actions .batch-select-all.all-selected { color: var(--color-primary); }

.batch-bar-count {
    font-size: 13px;
    font-weight: 600;
    padding: 0 6px;
    color: #fff;
    letter-spacing: -0.01em;
}

.batch-bar-sep {
    width: 1px; height: 22px;
    background: rgba(255,255,255,0.14);
    margin: 0 4px;
    flex-shrink: 0;
}

.batch-bar-actions {
    display: flex;
    align-items: center;
    gap: 2px;
}

.batch-bar-btn {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 7px 13px;
    background: transparent; border: none; cursor: pointer;
    border-radius: 999px;
    color: rgba(255,255,255,0.92);
    font-size: 13px; font-weight: 600;
    transition: background 0.15s, color 0.15s, transform 0.12s;
    white-space: nowrap;
}
.batch-bar-btn:hover {
    background: rgba(255,255,255,0.12);
    color: #fff;
}
.batch-bar-btn:active { transform: scale(0.96); }
.batch-bar-btn svg { flex-shrink: 0; }
.batch-bar-btn-label { display: inline; }

.batch-bar-btn-danger { color: #fca5a5; }
.batch-bar-btn-danger:hover {
    background: rgba(239, 68, 68, 0.20);
    color: #fff;
}

.batch-bar-close {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 32px;
    background: transparent; border: none; cursor: pointer;
    border-radius: 50%;
    color: rgba(255,255,255,0.65);
    transition: background 0.15s, color 0.15s;
}
.batch-bar-close:hover { background: rgba(255,255,255,0.10); color: #fff; }

/* Mobile : réduire à des icônes seules pour ne pas déborder */
@media (max-width: 600px) {
    .batch-bar { padding: 6px 8px; gap: 2px; }
    .batch-bar-count { font-size: 12px; padding: 0 4px; }
    .batch-bar-btn-label { display: none; }
    .batch-bar-btn { padding: 8px 10px; }
    .batch-bar-sep { margin: 0 2px; }
}

/* ===== FAVORITES ===== */
.favorite-btn {
    position: absolute;
    top: 6px;
    /* à GAUCHE du bouton ⋮ (6+28+4) — les deux étaient superposés à right:6px,
       l'étoile était recouverte et incliquable */
    right: 38px;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    background: rgba(0,0,0,0.3);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border: none;
    color: white;
    opacity: 0;
    transition: all var(--transition-fast);
    z-index: 2;
}

/* Per-card selection checkbox (top-left). Mirrors the workspace pattern. */
.file-card-checkbox {
    position: absolute;
    top: 6px; left: 6px;
    width: 22px; height: 22px;
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,0.8);
    background: rgba(0,0,0,0.35);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: transparent;
    opacity: 0;
    transition: opacity .15s, background .15s, border-color .15s, color .15s;
    z-index: 5;
}
.file-card-checkbox svg { width: 12px; height: 12px; }
.file-card:hover .file-card-checkbox { opacity: 1; }
.file-card.selected .file-card-checkbox {
    opacity: 1;
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}
/* Mobile : on cache les checkboxes par défaut (trop bruité visuellement
   sur petite surface). On les révèle uniquement quand le mode sélection
   est actif (au moins 1 fichier sélectionné via "Tout sélectionner" ou
   tap sur un checkbox déjà visible). La sélection individuelle reste
   possible via long-press → context menu. */
@media (hover: none) {
    .file-card-checkbox { opacity: 0; }
    body.selection-active .file-card-checkbox { opacity: 1; }
}

/* Rectangle de sélection au lasso — cliquer-glisser depuis le fond de la
   grille/liste (App._wireGridMarqueeSelect). Positionné en fixed et suivi
   en JS via clientX/Y, donc indépendant du scroll de la page.
   --color-primary-light n'est PAS utilisable ici : ce token vaut #e8f2ff
   (opaque) en thème clair mais #0a84ff1a (10% alpha) en thème sombre --
   correct pour ses autres usages (badges/puces à fond plein), mais un
   rectangle de sélection doit rester translucide dans les deux thèmes
   pour ne pas masquer les fichiers qu'il survole. color-mix() reproduit
   le meme poids visuel que la valeur sombre actuelle, dans les deux
   themes. */
.marquee-select-box {
    position: fixed;
    border: 1px solid var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    border-radius: 3px;
    pointer-events: none;
    z-index: 500;
}

.file-card:hover .favorite-btn {
    opacity: 1;
}

/* Plus de force "always visible" sur les fichiers favoris en vue grille :
   la liste devient beaucoup plus calme — y compris sur mobile. La couleur
   dorée reste, donc dès qu'on survole / tape une card, une étoile pleine
   jaune indique le statut favori. Pour voir l'ensemble des favoris d'un
   coup, il y a la page dédiée /favoris. */
.favorite-btn.active {
    color: #fbbf24;
    background: rgba(0,0,0,0.5);
}

.favorite-btn svg {
    width: 14px;
    height: 14px;
}

/* Coeur de selection Partage Flow -- membre AQIN qui
   consulte un dossier partage recu depuis SON PROPRE compte (Nuage), en
   bas a droite de la miniature pour ne pas collisionner avec favori/menu. */
.gallery-select-btn {
    position: absolute;
    bottom: 8px;
    right: 8px;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    background: rgba(0,0,0,0.4);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border: none;
    color: white;
    transition: all var(--transition-fast);
    z-index: 3;
}
.gallery-select-btn.active {
    color: #ef4444;
    background: rgba(0,0,0,0.55);
}
.gallery-select-btn svg {
    width: 15px;
    height: 15px;
}

/* Menu contextuel button (trois points) */
.card-menu-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    background: rgba(0,0,0,0.4);
    backdrop-filter: blur(4px);
    border: none;
    display: flex !important;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: rgba(255,255,255,0.8);
    transition: opacity 0.2s, background 0.2s;
    opacity: 0;
    padding: 0;
    z-index: 10;
    pointer-events: auto !important;
}

.file-card:hover .card-menu-btn {
    opacity: 1;
}

.card-menu-btn:hover,
.card-menu-btn:active {
    opacity: 1 !important;
    background: rgba(0,0,0,0.6) !important;
    color: #fff !important;
}

.card-menu-btn svg {
    width: 16px;
    height: 16px;
    pointer-events: none;
}

/* Le ⋮ suit EXACTEMENT le comportement de l'étoile favoris : révélé au
   survol de la carte (et par l'état :hover collant du premier tap sur
   tactile). Sur mobile, le menu contextuel reste aussi accessible par
   l'appui long (événement contextmenu natif). */

/* file-card needs relative for favorites */
.file-card {
    position: relative;
}

/* ===== THEME TOGGLE ===== */
.theme-toggle {
    width: 40px;
    height: 22px;
    background: var(--color-border);
    border-radius: var(--radius-full);
    cursor: pointer;
    position: relative;
    transition: background var(--transition-fast);
    border: none;
    padding: 0;
    flex-shrink: 0;
}

.theme-toggle::after {
    content: '';
    position: absolute;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: white;
    top: 2px;
    left: 2px;
    transition: transform var(--transition-fast);
    box-shadow: var(--shadow-sm);
}

[data-theme="dark"] .theme-toggle {
    background: var(--color-primary);
}

[data-theme="dark"] .theme-toggle::after {
    transform: translateX(18px);
}

/* ===== RECENT FILES SECTION ===== */
.section-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text-secondary);
    margin-bottom: 12px;
    display: flex;
    align-items: center;
    gap: 6px;
}

.section-title svg {
    width: 16px;
    height: 16px;
}

.recent-files-bar {
    display: flex;
    gap: 10px;
    overflow-x: auto;
    padding-bottom: 8px;
    margin-bottom: 20px;
}

.recent-file-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--color-surface);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border);
    cursor: pointer;
    white-space: nowrap;
    font-size: 12px;
    transition: all var(--transition-fast);
    flex-shrink: 0;
}

.recent-file-chip:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-sm);
}

.recent-file-chip svg {
    width: 16px;
    height: 16px;
}

/* ===== UPLOAD DROPDOWN ===== */
.upload-dropdown {
    position: relative;
}

.upload-dropdown-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 9px;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: 0px;
    min-width: 200px;
    z-index: var(--z-dropdown);
    display: none;
}

.upload-dropdown-menu.visible {
    display: block;
}

.upload-dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: 13px;
    width: 100%;
    cursor: pointer;
    transition: background var(--transition-fast);
}

.upload-dropdown-item:hover {
    background: var(--color-surface-hover);
}

.upload-dropdown-item svg {
    flex-shrink: 0;
}

/* Filet entre groupes (Créer / Importer / Numériser, 2026-09-28). Cette
   classe existait dans le HTML de plusieurs menus (Nuage, Flow, "Coller")
   sans AUCUNE règle : les séparateurs étaient invisibles. Même trait que
   .context-menu-separator (le menu clic droit "Importer" en est la version
   bureau). */
.upload-dropdown-sep {
    height: 1px;
    background: var(--color-border-light);
    margin: 4px 8px 0;
}

/* Intitulé de groupe : mêmes petites majuscules discrètes que les autres
   sur-titres de l'application (.sidebar-section-title, .context-menu-title). */
.upload-dropdown-group-label {
    padding: 8px 12px 4px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-text-tertiary);
    cursor: default;
    user-select: none;
    -webkit-user-select: none;
}

/* Scanner un document / Importer une photo à scanner / Scanner un QR code
   -- réservés Mobile/Tablette/PWA (retour utilisateur 2026-09-14, capture
   du menu Importer en plein desktop) : masqués au-delà de 1024px (même
   seuil que le reste du projet pour "mobile ou tablette", cf app.js/
   workspace-view.js), sauf en PWA installée (display-mode: standalone),
   où le clavier/souris ne garantit pas un vrai desktop (ex. PWA installée
   sur un grand écran tactile). contextMenu.js relit le display calculé de
   ces boutons pour rester synchronisé (cf son propre commentaire).
   .scan-menu-only : filet + intitulé « Numériser » du même groupe, qui
   doivent apparaître et disparaître avec eux (jamais un intitulé seul). */
@media (min-width: 1025px) {
    .scan-menu-item, .scan-menu-only { display: none; }
}
@media (min-width: 1025px) and (display-mode: standalone) {
    .scan-menu-item { display: flex; }
    .scan-menu-only { display: block; }
}

/* ===== SORT DROPDOWN ===== */
.sort-dropdown {
    position: relative;
}

.sort-dropdown-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 4px;
    background: var(--color-surface);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    padding: 6px;
    min-width: 180px;
    z-index: var(--z-dropdown);
    display: none;
}

.sort-dropdown-menu.visible {
    display: block;
}

.sort-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    color: var(--color-text);
    cursor: pointer;
    width: 100%;
    text-align: left;
    border: none;
    background: none;
    transition: background var(--transition-fast);
}

.sort-option:hover {
    background: var(--color-bg);
}

.sort-option.active {
    color: var(--color-primary);
    font-weight: 600;
}

.sort-arrow {
    font-size: 11px;
    color: var(--color-text-tertiary);
}


/* ===== FILE INFO PANEL ===== */
.file-info-panel {
    width: 320px;
    background: var(--color-bg);
    overflow-y: auto;
    padding: 20px;
    flex-shrink: 0;
    display: none;
    flex-direction: column;
    transition: width var(--transition-normal), opacity var(--transition-normal);
    will-change: width, opacity;
    transform: translateZ(0);
}

.file-info-panel.visible {
    display: flex;
}

.file-info-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 20px;
}

.file-info-preview {
    width: 100%;
    height: 200px;
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--color-bg);
    margin-bottom: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.file-info-preview img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.file-info-preview svg {
    width: 64px;
    height: 64px;
    color: var(--color-text-tertiary);
}

.file-info-name {
    font-size: 16px;
    font-weight: 600;
    word-break: break-word;
    margin-bottom: 16px;
}

.file-info-row {
    display: flex;
    justify-content: space-between;
    padding: 8px 0;
    font-size: 13px;
    border-bottom: 1px solid var(--color-border-light);
}

.file-info-label {
    color: var(--color-text-secondary);
}

/* ===== DRAG & DROP ===== */
.file-card.dragging {
    opacity: 0.4;
    transform: scale(0.95);
}

.file-card.drag-over-folder,
.sidebar-nav-item.drag-over-folder {
    outline: 2px dashed var(--color-primary);
    outline-offset: -2px;
    background: var(--color-primary-light);
    transform: scale(1.02);
    transition: all var(--transition-fast);
}

/* Ctrl/Cmd tenu pendant le survol = copier au lieu de déplacer -- même
   gabarit que .drag-over-folder ci-dessus, teinte verte (couleur "copie",
   cohérente avec --color-success ailleurs) au lieu du bleu primaire. */
.file-card.drag-over-folder.drag-over-copy,
.sidebar-nav-item.drag-over-folder.drag-over-copy {
    outline-color: var(--color-success);
    background: color-mix(in srgb, var(--color-success) 14%, var(--color-bg));
}

/* ===== PROFILE PAGE ===== */
.profile-container {
    max-width: 600px;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.profile-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: 24px;
    border: 1px solid var(--color-border);
}

.profile-hero {
    text-align: center;
    padding: 32px 24px;
}

.profile-avatar-large {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: var(--color-primary);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 32px;
    font-weight: 700;
    margin: 0 auto 16px;
}

.profile-hero-name {
    font-size: 22px;
    font-weight: 700;
    color: var(--color-text);
    margin-bottom: 4px;
}

.profile-hero-email {
    font-size: 14px;
    color: var(--color-text-secondary);
}

.profile-stats {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
}

.profile-stat-card {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    padding: 20px 16px;
    border: 1px solid var(--color-border);
    text-align: center;
}

.profile-stat-icon {
    width: 40px;
    height: 40px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto 12px;
}

.profile-stat-value {
    font-size: 22px;
    font-weight: 700;
    color: var(--color-text);
    margin-bottom: 4px;
}

.profile-stat-label {
    font-size: 12px;
    color: var(--color-text-tertiary);
}

.profile-card-title {
    font-size: 16px;
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: 16px;
}

.profile-storage-text {
    font-size: 13px;
    color: var(--color-text-secondary);
    margin-top: 8px;
}

/* ===== ADMIN IMPROVEMENTS ===== */
.admin-section-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border);
    overflow: hidden;
}

.admin-section-header {
    padding: 16px 20px;
    border-bottom: 1px solid var(--color-border);
}

.admin-section-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--color-text);
}

.stat-card {
    position: relative;
    overflow: hidden;
}

.stat-card-icon {
    width: 40px;
    height: 40px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 12px;
}

.table-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--color-primary);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 600;
    flex-shrink: 0;
}

.data-table-wrap {
    overflow-x: auto;
}

.activity-badge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 600;
    white-space: nowrap;
}

.pagination-dots {
    padding: 6px 4px;
    color: var(--color-text-tertiary);
    font-size: 12px;
}

/* ===== SETTINGS PAGE ===== */
.settings-container {
    max-width: 640px;
    display: flex;
    flex-direction: column;
    gap: 20px;
}

.settings-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: 24px;
    border: 1px solid var(--color-border);
}

.settings-card-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
}

.settings-card-icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

.settings-card-title {
    font-size: 15px;
    font-weight: 600;
    color: var(--color-text);
}

.settings-row {
    display: flex;
    gap: 16px;
}

.form-hint {
    display: block;
    font-size: 11px;
    color: var(--color-text-tertiary);
    margin-top: 4px;
}

/* ===== LOGIN ERROR FLEX ===== */
.login-error {
    display: flex;
    align-items: center;
}

/* ===== RESPONSIVE MOBILE ===== */
@media (max-width: 768px) {
    .header {
        padding: 10px 12px;
        gap: 8px;
        flex-wrap: wrap;
    }

    .header-actions {
        gap: 6px;
    }

    .header-actions .btn span,
    .header-actions .btn:not(.btn-icon) {
        font-size: 0;
        padding: 8px;
    }

    .header-actions .btn svg {
        margin: 0;
    }

    .breadcrumb {
        flex: 1;
        min-width: 0;
        overflow: hidden;
    }

    .file-grid {
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 14px !important;
    }

    /* Cartes mobiles : mêmes proportions que desktop.
       :not(.nebula-photo-tile) -- une tuile photo de Nébuleuse est une image
       PLEIN CADRE, sans chrome : `.file-card.nebula-photo-tile { padding: 0 }`
       le dit plus haut, mais ce `!important` le battait malgré une
       specificite inferieure. Sur mobile la photo se retrouvait donc encadree
       de 14px de gris, alors qu'elle est bord a bord sur ordinateur.
       Signale le 2026-08-20. */
    .file-card:not(.nebula-photo-tile) {
        padding: 14px !important;
    }

    /* file-card-name, file-card-meta, file-card-thumb, file-card-icon svg :
       on laisse les valeurs desktop s'appliquer (13px / 11px / aspect-ratio / 56px) */

    .file-list-row {
        font-size: 12px;
    }

    .file-list-size,
    .file-list-date {
        display: none;
    }

    .batch-bar {
        padding: 8px 12px;
        gap: 8px;
        font-size: 12px;
    }

    .batch-bar .btn {
        font-size: 0;
        padding: 8px;
    }

    .batch-bar .btn svg {
        margin: 0;
    }

    .preview-content video {
        max-width: 100%;
        max-height: 80%;
        border-radius: 12px;
    }

    .preview-header {
        padding: 12px 16px;
        padding-top: max(12px, env(safe-area-inset-top, 0px));
    }

    .profile-container {
        padding: 0 !important;
    }

    .profile-stats {
        grid-template-columns: 1fr;
    }

    .settings-row {
        flex-direction: column;
        gap: 0;
    }

    .admin-stats {
        grid-template-columns: repeat(2, 1fr);
    }

    .file-info-panel {
        position: fixed;
        right: 0;
        top: 0;
        bottom: 0;
        width: 100% !important;
        z-index: var(--z-modal);
    }

    .sort-dropdown-menu {
        right: -40px;
    }

    /* Login mobile */
    .login-card {
        padding: 32px 24px;
        margin: 16px;
    }

    /* Sidebar toggle hamburger */
    .btn-sidebar-toggle {
        display: flex;
    }

    /* Workspaces grid */
    .ws-grid {
        grid-template-columns: 1fr;
        gap: 12px;
    }
    .ws-card { padding: 16px; }
    .ws-card-icon { width: 38px; height: 38px; border-radius: 10px; font-size: 15px; }
    .ws-card-footer { flex-wrap: wrap; gap: 8px; }

    /* Shared page */
    .shared-tabs {
        max-width: 100%;
    }
    .shared-tab {
        padding: 8px 12px;
        font-size: 12px;
        gap: 6px;
    }
    .shared-tab svg { display: none; }
    .shared-ws-grid {
        grid-template-columns: 1fr;
        gap: 10px;
    }
    .shared-ws-card { padding: 14px; gap: 12px; }
    .shared-ws-icon { width: 40px; height: 40px; border-radius: 10px; font-size: 15px; }
    .shared-ws-name { font-size: 14px; }
    .shared-file-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 8px;
    }
    .shared-file-card { padding: 14px 12px 12px; }
    .shared-card-icon { width: 44px; height: 44px; border-radius: 10px; margin-bottom: 8px; }
    .shared-card-name { font-size: 12px; }
    .shared-file-row { padding: 10px 12px; gap: 10px; }
    .shared-file-name { font-size: 13px; }
    .shared-file-detail span:nth-child(n+3) { display: none; }
    .shared-file-badges { gap: 4px; }

    /* Admin */
    .admin-stats {
        grid-template-columns: repeat(2, 1fr);
        gap: 10px;
    }
    .stat-card { padding: 16px; }
    .stat-card-value { font-size: 24px; }

    /* Data table responsive */
    .data-table {
        display: block;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .data-table th,
    .data-table td {
        padding: 10px 12px;
        font-size: 12px;
        white-space: nowrap;
    }

    /* Profile */
    .profile-container {
        padding: 0 !important;
    }
    .profile-stats {
        grid-template-columns: 1fr;
    }
    .profile-card { padding: 20px; }

    /* mobile : see fullscreen block below (applied for widths <= 900px) */

    /* Toast */
    .toast {
        left: 12px !important;
        right: 12px !important;
        max-width: none !important;
    }

    /* Context menu */
    .context-menu {
        min-width: 180px;
    }

    /* Upload panel */
    .upload-panel {
        width: calc(100% - 24px);
        left: 12px;
        right: 12px;
        bottom: 12px;
    }

    /* Breadcrumb */
    .breadcrumb-item:not(.current) {
        display: none;
    }
    .breadcrumb-separator {
        display: none;
    }
    .breadcrumb-item.current {
        font-size: 14px;
    }

    /* Settings admin */
    .settings-card {
        padding: 16px;
    }
    .settings-row {
        flex-direction: column;
        gap: 8px;
    }
    .settings-row label {
        min-width: auto;
    }

    /* Pagination */
    .pagination {
        flex-wrap: wrap;
        gap: 4px;
    }
    .pagination-btn {
        padding: 6px 10px;
        font-size: 12px;
    }
}

@media (max-width: 480px) {
    .file-grid {
        grid-template-columns: repeat(2, 1fr) !important;
        gap: 14px !important;
        padding: 0px;
    }

    .view-toggle {
        display: none;
    }

    /* #sort-dropdown (id), pas .sort-dropdown (classe) : Scribe réutilise la
       même classe pour son propre tri (#sh-sort-dropdown, scribe-home.php --
       "même dropdown que Nuage", scribe-home.js) sans vouloir hériter de ce
       masquage pensé uniquement pour le sélecteur Nuage/fichiers -- un
       sélecteur de classe capturait aussi le sien par accident, rendant le
       bouton de tri Scribe totalement invisible (donc injoignable) sur les
       écrans ≤480px, signalé 2026-08-12. */
    .header-actions #sort-dropdown,
    .header-actions #theme-toggle {
        display: none;
    }

    /* Login */
    .login-card {
        padding: 28px 20px;
        margin: 12px;
        border-radius: 16px;
    }
    .login-logo h1 { font-size: 20px; }
    .login-logo p { font-size: 12px; }
    .login-bg-1 { width: 250px; height: 250px; }
    .login-bg-2 { width: 180px; height: 180px; }

    /* Profile */
    .profile-container { gap: 12px; }
    .profile-card { padding: 16px; }
    .profile-hero { padding: 20px 16px; }
    .profile-avatar-large { width: 60px; height: 60px; font-size: 24px; }
    .profile-hero-name { font-size: 18px; }
    .profile-hero-email { font-size: 12px; }
    .profile-stats { grid-template-columns: 1fr !important; }
    .profile-stat-value { font-size: 20px; }

    /* Admin */
    .admin-stats { grid-template-columns: 1fr !important; }
    .stat-card { padding: 14px; }
    .stat-card-value { font-size: 22px; }

    /* Shared */
    .shared-tabs { flex-direction: column; max-width: 100%; }
    .shared-tab { padding: 8px 12px; font-size: 12px; }
    .shared-ws-grid { grid-template-columns: 1fr !important; }
    .shared-file-grid { grid-template-columns: 1fr !important; }
    .shared-file-row { flex-wrap: wrap; gap: 8px; padding: 10px 12px; }
    .shared-file-badges { width: 100%; justify-content: flex-start; }
    .shared-file-actions { width: 100%; justify-content: flex-end; }

    /* Workspaces */
    .ws-grid { grid-template-columns: 1fr !important; }
    .ws-card { padding: 16px; }
    .ws-card-name { font-size: 14px; }
    .ws-card-desc { font-size: 11px; }
    .ws-card-actions { display: flex !important; }

    /* Sidebar */
    .sidebar-logo span { display: none; }
    .sidebar-user-info { display: none; }
}

/* ===== TABLET (1024px) ===== */
@media (max-width: 1024px) {
    .sidebar {
        width: 200px;
        min-width: 200px;
    }
    .admin-stats {
        grid-template-columns: repeat(2, 1fr);
    }
    .shared-file-grid {
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    }
}

/* ===== TOUCH-FRIENDLY ===== */
@media (hover: none) and (pointer: coarse) {
    .btn-icon { min-width: 40px; min-height: 40px; }
    .sidebar-nav-item { padding: 10px 14px; }
    .file-list-row { padding: 12px 14px; }
    .ws-card-actions { display: flex !important; }
    .shared-card-actions { display: flex !important; }
    .context-menu-item { padding: 10px 16px; }
}

/* ===== DARK MODE ADJUSTMENTS ===== */
[data-theme="dark"] .login-card,
[data-theme="dark"] .share-card {
    background: var(--color-surface);
}

[data-theme="dark"] .login-error {
    background: #3b1a1a;
    border-color: #7f1d1d;
}

[data-theme="dark"] .badge-admin {
    background: #78350f;
    color: #fef3c7;
}

[data-theme="dark"] .badge-active {
    background: #064e3b;
    color: #d1fae5;
}

[data-theme="dark"] .badge-suspended {
    background: #7f1d1d;
    color: #fef2f2;
}

/* En sombre, seule la teinte du fond change : le texte reste la couleur du
   plan, qui est deja lisible sur les deux fonds. */
[data-theme="dark"] .badge-plan {
    background: color-mix(in srgb, var(--pc) 22%, transparent);
}

[data-theme="dark"] .batch-bar {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
}

[data-theme="dark"] .stat-card-icon[style*="background:#dbeafe"] {
    background: #1e3a5f !important;
}

[data-theme="dark"] .settings-card-icon[style*="background:#d1fae5"] {
    background: #064e3b !important;
}

[data-theme="dark"] .profile-stat-icon[style*="background:#d1fae5"] {
    background: #064e3b !important;
}

[data-theme="dark"] .preview-content pre {
    background: #111;
}

/* ===== MOBILE SEARCH TOGGLE ===== */
.btn-mobile-search {
    display: flex !important;
    padding: 6px 8px;
    border-radius: 8px;
    background: transparent;
    border: none;
    color: var(--color-text-secondary);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
}
.btn-mobile-search.active {
    background: color-mix(in srgb, var(--color-primary) 14%, transparent);
    color: var(--color-primary);
}

.btn-mobile-search:hover {
    background: var(--color-hover);
    color: var(--color-text);
}

@media (max-width: 768px) {
    .btn-mobile-search {
        display: flex !important;
    }
    .header .search-bar {
        display: none;
    }
    .header .search-bar.mobile-active {
        display: flex;
    }
}

/* =============================================================
   FIXED HEADER CHROME — launcher + user corner stay anchored
   during scroll on every no-sidebar layout page. Uses !important
   to defeat the per-page `position: absolute` declarations.
   ============================================================= */
.no-sidebar-layout .btn-sidebar-toggle,
.ws-page-header .btn-sidebar-toggle,
.profile-page-header .btn-sidebar-toggle,
.admin-page-header .btn-sidebar-toggle,
.ws-page-header .btn-sidebar-toggle {
    position: fixed !important;
    top: 14px !important;
    left: 20px !important;
    transform: none !important;
    z-index: 55;
}
/* Le breadcrumb (Galaxie/Nuage/Fort) doit aussi être fixe pour que
   .header soit un shell 0-hauteur et éviter le double espacement en Chrome.
   :not(.ws-page-header) exclut les pages workspace qui ont leur propre gestion. */
.no-sidebar-layout .header:not(.ws-page-header) > .breadcrumb {
    position: fixed !important;
    top: 14px !important;
    left: 76px !important;
    height: 44px !important;
    z-index: 55;
    display: flex !important;
    align-items: center;
    transform: none !important;
}
.global-user-corner {
    position: fixed !important;
}

/* =============================================================
   MOBILE AUDIT — consolidated responsive fixes.
   Keeps all mobile tweaks in one block so fixes stay discoverable
   and overrides earlier per-page @media rules that were inconsistent.
   ============================================================= */

/* --- TABLET (≤ 900px) --- */
@media (max-width: 900px) {
    /* Shrink the launcher proportionally and reduce the reserved header
       padding-right since the global corner is narrower at this size. */
    .no-sidebar-layout .btn-sidebar-toggle {
        width: 40px !important;
        height: 40px !important;
        border-radius: 12px !important;
    }
    .no-sidebar-layout .btn-sidebar-toggle svg,
    .no-sidebar-layout .btn-sidebar-toggle img {
        width: 18px !important;
        height: 18px !important;
    }
    .no-sidebar-layout .header {
        padding-right: 140px;  /* was 180px — tighter */
    }
}

/* --- SMALL MOBILE (≤ 640px) --- */
@media (max-width: 640px) {
    /* 1. Header launcher + global corner — compact */
    .no-sidebar-layout .btn-sidebar-toggle {
        width: 36px !important;
        height: 36px !important;
        border-radius: 10px !important;
    }
    .no-sidebar-layout .btn-sidebar-toggle svg,
    .no-sidebar-layout .btn-sidebar-toggle img {
        width: 16px !important;
        height: 16px !important;
    }
    .global-user-corner { top: 10px; right: 10px; gap: 4px; }
    .global-corner-btn,
    .global-user-avatar { width: 36px; height: 36px; border-radius: 10px; }
    .global-user-avatar img { border-radius: 8px !important; }
    .no-sidebar-layout .header {
        padding-right: 120px;
        padding-left: 12px;
        min-height: 56px !important;
    }

    /* 2. Any header row with absolute launcher must leave room for both edges */
    .ws-page-header,
    .profile-page-header,
    .admin-page-header {
        min-height: 56px !important;
        padding: 8px 12px !important;
        box-sizing: border-box;
    }
    /* Launcher stays FIXED on mobile too — just shift origin */
    .no-sidebar-layout .btn-sidebar-toggle,
    .ws-page-header .btn-sidebar-toggle,
    .profile-page-header .btn-sidebar-toggle,
    .admin-page-header .btn-sidebar-toggle,
    .ws-page-header .btn-sidebar-toggle {
        top: 10px !important;
        left: 10px !important;
    }

    /* 3. Centered pills should wrap / shrink, never horizontally scroll the page */
    .ws-page-header-center,
    .profile-page-header-center,
    .admin-page-header-center {
        padding-left: 52px;   /* space for launcher */
        padding-right: 110px; /* space for corner */
        max-width: 100%;
        overflow: hidden;
    }
    .ws-page-header-center .header-actions,
    .profile-page-header-center .header-actions,
    .admin-page-header-center .header-actions,
    .admin-tabs-header {
        max-width: 100%;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        flex-wrap: nowrap;
        border-radius: 20px;
        padding: 3px 4px;
    }
    .ws-page-header-center .header-actions::-webkit-scrollbar,
    .profile-page-header-center .header-actions::-webkit-scrollbar,
    .admin-page-header-center .header-actions::-webkit-scrollbar,
    .admin-tabs-header::-webkit-scrollbar { display: none; }
    .admin-tabs-header .admin-tab { font-size: 12px; padding: 6px 10px; }
    .admin-tabs-header .admin-tab svg { width: 12px; height: 12px; }

    /* 4. Workspaces page title — smaller + more compact search pill */
    .ws-page-title { margin: 20px 0 18px !important; gap: 8px !important; }
    .ws-page-title h1 { font-size: 22px !important; line-height: 1.15; }
    .ws-page-subtitle { font-size: 12px !important; }
    .ws-page-search { min-width: 0 !important; width: 100%; max-width: 320px; }

    /* 5. Ws cards + grid padding on narrow screens */
    .ws-page-content { padding: 16px 14px 40px !important; }
    .ws-card { padding: 0px !important; min-height: 260px !important; border-radius: 18px !important; }
    .ws-card-cover { min-height: 140px !important; }
    .ws-card-name { font-size: 15px !important; }

    /* 6. Profile hero compact */
    .profile-page-content { padding: 20px 14px 40px !important; }
    .profile-hero-block { margin-bottom: 20px !important; gap: 6px !important; }
    .profile-avatar-wrapper, .profile-avatar-huge { width: 84px !important; height: 84px !important; }
    .profile-avatar-huge { font-size: 32px !important; }
    .profile-avatar-edit { width: 28px; height: 28px; }
    .profile-hero-name { font-size: 22px !important; }
    .profile-hero-email { font-size: 13px !important; }
    .profile-stats-grid { grid-template-columns: 1fr 1fr !important; gap: 10px !important; }
    .profile-stat-card { padding: 14px !important; }
    .profile-stat-value { font-size: 20px !important; }
    .profile-card { padding: 18px 16px !important; }
    .profile-card-title { font-size: 14px !important; }

    /* 7. Admin pages compact */
    .admin-page-content { padding: 18px 14px 40px !important; }
    .admin-hero { margin-bottom: 18px !important; gap: 6px !important; }
    .admin-hero-title { font-size: 22px !important; }
    .admin-hero-subtitle { font-size: 12px !important; }
    .admin-section-card { padding: 16px !important; border-radius: 16px !important; }
    .admin-section-head { flex-direction: column; align-items: stretch !important; gap: 10px !important; }
    .admin-search { min-width: 0 !important; width: 100%; }
    .admin-section-actions { flex-direction: column; align-items: stretch; gap: 8px; }
    .admin-section-actions .btn { width: 100%; justify-content: center; }

    /* Family cockpit adjustments */
    .fam-today-num { font-size: 30px !important; }
    .fam-budget-big { font-size: 22px !important; }
    .fam-meal-desc { font-size: 15px !important; }

    /* School cockpit adjustments */
    .school-pinned-title { font-size: 16px !important; }
    .school-photo-grid { grid-template-columns: repeat(3, 1fr) !important; gap: 4px !important; }

    /* 9. Publications / Incidents feeds — single column */
    .ws-pub-container { padding: 0 !important; }
    .ws-pub-header { flex-direction: column; align-items: flex-start !important; gap: 6px !important; margin-bottom: 8px !important; }
    .ws-pub-header h3 { margin: 0 !important; }
    /* Le bloc titre "Incidents N incidents" est redondant sur mobile :
       l'utilisateur voit déjà "Incidents" highlight dans la pill flottante en bas.
       On le cache pour gagner ~50px de hauteur. */
    #ws-incidents .ws-pub-header-left { display: none !important; }
    .ws-pub-header h3 { font-size: 17px !important; }
    .ws-pub-feed { grid-template-columns: 1fr !important; gap: 16px !important; }
    .ws-pub-article { padding: 22px 20px !important; border-radius: 18px !important; }
    .ws-pub-article-header { margin-bottom: 18px !important; }
    .ws-pub-title { font-size: 15px !important; margin: 0 0 10px !important; }
    .ws-inc-badges { gap: 8px !important; margin-bottom: 12px !important; }
    .ws-pub-content.truncated { line-height: 1.6 !important; }
    .ws-inc-assignment { margin-top: 14px !important; padding-top: 12px !important; }
    /* Déclarer = FAB flottant en bas à droite (style cohérent avec le bouton
       Applications). Sort du grid → libère une cellule. JS met display=''
       pour les non-viewers, donc on ne force pas display ici. */
    #ws-inc-add-btn {
        position: fixed;
        bottom: calc(78px + env(safe-area-inset-bottom, 0px));
        right: 14px;
        width: 52px;
        height: 52px;
        padding: 0;
        border-radius: 50%;
        justify-content: center;
        align-items: center;
        z-index: 40;
        box-shadow: 0 6px 20px rgba(0,122,255,0.4);
        font-size: 0; /* masque le label "Déclarer", on garde l'icône SVG */
    }
    #ws-inc-add-btn svg { width: 22px !important; height: 22px !important; }
    /* Header incidents : scroll horizontal sur mobile au lieu d'une grille
       2-colonnes qui empilait 4 rangées et bouffait ~210px de hauteur (cf
       retour user "ça occupe trop d'espace"). Tous les contrôles restent
       sur UNE ligne ; le user swipe pour atteindre les actions secondaires
       (macros, bulk, export, share, kb). Pattern mobile-natif courant. */
    .ws-inc-header-actions {
        width: 100%;
        display: flex !important;
        flex-wrap: nowrap !important;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        gap: 6px;
        padding-bottom: 4px;
        margin-bottom: 10px !important;
        align-items: center !important;
    }
    .ws-inc-header-actions::-webkit-scrollbar { display: none; }
    /* Tous les enfants gardent leur largeur naturelle, pas de shrink. */
    .ws-inc-header-actions > * { flex-shrink: 0; min-width: 0; }
    .ws-inc-mine-toggle { padding: 6px 10px; font-size: 11px; }
    .ws-inc-group-trigger { padding: 6px 10px; font-size: 11px; }
    .ws-inc-group-trigger-label { max-width: 90px; }
    .ws-inc-sort { padding: 6px 8px; font-size: 11px; max-width: 110px; }
    /* Boutons icône (search-toggle, stats, macros, bulk, export, share, kb)
       en carré compact 34×34 — au lieu de width:100% qui les étirait dans
       la grille. */
    .ws-inc-search-toggle {
        display: inline-flex !important;
        width: 34px !important;
        height: 34px !important;
        padding: 0 !important;
        border-radius: 8px !important;
        font-size: 14px;
    }
    .ws-inc-search-toggle svg { width: 14px; height: 14px; }
    /* Recherche : input s'ouvre inline en remplaçant l'icône search-toggle.
       On garde le toggle visible pour le re-fermer ; le wrap apparaît à
       droite et reste scrollable. */
    .ws-inc-search-wrap { display: none !important; }
    .ws-inc-search-wrap.open { display: inline-flex !important; }
    .ws-inc-search-input { width: 160px !important; }
    .ws-inc-search-input:focus { width: 180px !important; }

    /* 10. Workspace portal hero — avoid huge backgrounds */
    .ws-left-panel { min-height: 220px !important; }
    .ws-left-title { font-size: 22px !important; }
    /* 11. File browser inline toolbar wraps clean */
    .ws-files-toolbar { gap: 8px !important; }
    .ws-files-toolbar .btn { padding: 6px 10px !important; font-size: 12px !important; }
    .ws-files-toolbar-spacer { display: none; }

    /* 12. Modals — full-height on mobile (reinforces earlier rules) */
    body.modal-open .modal {
        inset: 0 !important;
        width: 100% !important;
        max-width: 100% !important;
        height: 100% !important;
        max-height: 100% !important;
        border-radius: 0 !important;
        margin: 0 !important;
        padding-top: env(safe-area-inset-top, 0px) !important;
        /* .modal (regle de base ci-dessus) a will-change:transform,opacity
           inconditionnel pour l'animation d'ouverture desktop. Combine a
           une hauteur ici forcee en pourcentage (donc calculee en pixel
           fractionnaire par le navigateur, ex. 843.984375px) sur mobile/PWA
           standalone, ca force un calque de composition GPU separe dont
           l'arrondi au pixel entier laisse un fin bord non peint en bas de
           la modale, revelant le fond noir semi-transparent du backdrop
           derriere au lieu du fond de la modale -- confirme en direct sur
           plusieurs modales generiques (Aurore, "Nouvelle annonce"), pas
           seulement sur le panneau memo qui neutralisait deja ce probleme
           pour lui-meme (aurore-memo.js). Neutralise ici uniquement pour le
           cas plein-ecran mobile concerne -- le desktop garde son animation
           GPU-accelere, la ou ce bug ne se produit pas. */
        will-change: auto !important;
    }
    /* Modal partage : contenu court (titre, quelques collaborateurs,
       champ email) -- pas besoin du plein ecran mobile. Petite fenetre
       centree (comme sur desktop) plutot qu'une bottom-sheet ou un plein
       ecran. Reutilisee aussi pour le flash de chargement Scribe (meme
       gabarit compact centre). */
    .modal-backdrop:has(.sh-share-modal-compact) {
        align-items: center !important;
        justify-content: center !important;
        padding: 24px !important;
    }
    body.modal-open .modal.sh-share-modal-compact {
        inset: auto !important;
        position: relative !important;
        width: min(92vw, 420px) !important;
        max-width: 420px !important;
        height: auto !important;
        max-height: 80vh !important;
        border-radius: 20px !important;
        margin: 0 !important;
        /* Fenetre centree, ne touche jamais l'encoche/status bar -- le
           padding-top:env(safe-area-inset-top) herite de la regle
           generique (prevu pour les modales plein ecran) n'a pas lieu
           d'etre ici. */
        padding-top: 0 !important;
    }
    /* Petite fenetre centree : pas de poignee de glissement (pattern
       bottom-sheet, n'a pas de sens ici) -- retire le pseudo-element et le
       padding-top supplementaire qui lui etait reserve. */
    .modal.sh-share-modal-compact .modal-header {
        padding: 16px 16px 12px !important;
        position: relative !important;
    }
    .modal.sh-share-modal-compact .modal-header::before { display: none !important; }

    /* 13. Batch bar — full-width sticky on mobile */
    .batch-bar {
        left: 8px !important;
        right: 8px !important;
        bottom: 8px !important;
        transform: none !important;
        width: auto !important;
        max-width: none !important;
        flex-wrap: wrap;
        gap: 6px !important;
        padding: 10px 12px !important;
    }

    /* 14. Any horizontal scroll emergency — force max-width */
    html, body { max-width: 100vw; overflow-x: hidden; }
}

/* --- VERY SMALL (≤ 420px) --- */
@media (max-width: 420px) {
    /* Hide the Pill's extra header action labels — icons only */
    .header-actions .btn span:not([class*="badge"]) { display: none; }
    .admin-tabs-header .admin-tab span { display: none; }
    .admin-tabs-header .admin-tab { padding: 6px 8px; }

    /* Reduce card grids on workspaces page to 1 col */
    .ws-grid { grid-template-columns: 1fr !important; }
}

/* --- WORKSPACE-VIEW header — fit launcher + centered pill + global corner
       on one single row without overlap at 356–640px.
       Strategy: flex header with explicit padding for fixed launcher/corner,
       pill flows naturally in center (NOT absolute), shrinks if needed,
       supports horizontal touch-scroll if too many quick actions exist. */

/* === Quick actions: icône seule (inactif) → icône + label (actif). Tous les boutons. === */
.ws-quick-action-btn {
    border-radius: 10px;
}
.ws-quick-action-btn:not(.active) > span,
.ws-pill-chat-modes .ws-chat-feature-btn:not(.active) > span {
    display: none !important;
}
.ws-quick-action-btn:not(.active),
.ws-pill-chat-modes .ws-chat-feature-btn:not(.active) {
    gap: 0 !important;
    padding-left: 10px !important;
    padding-right: 10px !important;
}
.ws-quick-action-btn.active,
.ws-pill-chat-modes .ws-chat-feature-btn.active {
    gap: 6px !important;
    padding-left: 12px !important;
    padding-right: 12px !important;
}

@media (max-width: 640px) {
    .ws-page-header {
        display: flex !important;
        align-items: center;
        justify-content: center;
        min-height: 56px !important;
        /* Reserve space for the FIXED launcher (left) and corner (right). */
        padding: 8px 110px 8px 56px !important;
        box-sizing: border-box;
        position: relative;
    }
    .ws-quick-actions {
        /* Drop the absolute centering — flow in the header's flex row */
        position: static !important;
        left: auto !important;
        top: auto !important;
        transform: none !important;
        flex-wrap: nowrap !important;
        gap: 4px !important;
        max-width: 100%;
        width: auto;
        overflow-x: auto;
        scrollbar-width: none;
        -webkit-overflow-scrolling: touch;
        padding: 3px 4px;
        background: var(--color-surface);
        border: 1px solid var(--color-border);
        border-radius: 22px;
        box-shadow: var(--shadow-sm);
    }
    .ws-quick-actions::-webkit-scrollbar { display: none; }
    /* Inactive buttons: pure icon (30x30 square). Active button keeps its
       label so the user always sees the current section name. */
    .ws-quick-action-btn,
    .ws-pill-chat-modes .ws-chat-feature-btn {
        height: 30px !important;
        padding: 0 !important;
        border-radius: 8px !important;
        flex-shrink: 0;
        overflow: hidden;
        justify-content: center;
        gap: 0 !important;
    }
    .ws-quick-action-btn:not(.active),
    .ws-pill-chat-modes .ws-chat-feature-btn:not(.active) {
        width: 30px !important;
    }
    .ws-quick-action-btn svg,
    .ws-pill-chat-modes .ws-chat-feature-btn svg {
        width: 14px !important; height: 14px !important;
    }
    .ws-quick-action-btn:not(.active) span,
    .ws-pill-chat-modes .ws-chat-feature-btn:not(.active) span {
        display: none !important;
    }
    /* Active button: icon + label, pill-shaped. */
    .ws-quick-action-btn.active,
    .ws-pill-chat-modes .ws-chat-feature-btn.active {
        width: auto !important;
        padding: 0 12px !important;
        border-radius: 16px !important;
        gap: 6px !important;
        white-space: nowrap;
    }
    .ws-quick-action-btn.active span,
    .ws-pill-chat-modes .ws-chat-feature-btn.active span {
        display: inline !important;
        font-size: 11px;
        font-weight: 600;
    }
    /* Tous les boutons : label visible uniquement quand actif — déjà géré ci-dessus. */

    /* Same treatment for the workspaces / profile / admin headers — they are
       already flex, but make sure padding reserves room for the fixed chrome. */
    .no-sidebar-layout .header {
        padding-right: 110px !important;
        padding-left: 56px !important;
    }
    /* Shrink the global corner visually so 3 buttons fit under 100px */
    .global-user-corner { gap: 4px !important; top: 12px !important; right: 10px !important; }
    .global-corner-btn,
    .global-user-avatar { width: 34px !important; height: 34px !important; border-radius: 9px !important; }
    .global-user-avatar img { border-radius: 7px !important; }
    .global-corner-btn svg { width: 14px !important; height: 14px !important; }
    /* Hide the theme toggle entirely on mobile — keep only notif + avatar */
    .global-user-corner #theme-toggle { display: none !important; }

}

/* ==============================================================
   TAGS / LABELS — orthogonal file taxonomy
   ============================================================== */

/* Base dot used everywhere tags appear */
.tag-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--tag-color, #6366F1);
    flex-shrink: 0;
}

/* Clickable dot inside a chip — cycle color */
.tag-dot-btn {
    border: none;
    cursor: pointer;
    padding: 0;
    transition: transform 0.15s, box-shadow 0.15s;
    position: relative;
}
.tag-dot-btn:hover {
    transform: scale(1.4);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--tag-color, #6366F1) 25%, transparent);
}

/* ========== Tag chip (FilePanel details, filter banner) ========== */
.tag-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px 4px 10px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--tag-color, #6366F1) 14%, var(--color-surface));
    border: 1px solid color-mix(in srgb, var(--tag-color, #6366F1) 30%, transparent);
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text);
    max-width: 100%;
    line-height: 1.4;
}
.tag-chip .tag-dot {
    background: var(--tag-color, #6366F1);
    width: 7px; height: 7px;
}
.tag-chip-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 200px;
}
.tag-chip-x {
    background: transparent;
    border: none;
    color: var(--color-text-secondary);
    font-size: 16px;
    line-height: 1;
    padding: 0 2px;
    cursor: pointer;
    border-radius: 50%;
    width: 16px; height: 16px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
}
.tag-chip-x:hover {
    background: color-mix(in srgb, var(--tag-color, #6366F1) 30%, transparent);
    color: var(--color-text);
}
.tag-chip-active {
    background: color-mix(in srgb, var(--tag-color, #6366F1) 22%, var(--color-surface));
}

/* Panneau de tags (FilePanel, #fp-tags-chips) : la croix ne doit apparaitre
   qu'au survol du tag concerne, sur un appareil a pointeur reel. Avant ce
   correctif rien ne masquait .tag-chip-x -- la regle .tag-chip-x:hover
   ci-dessus ne stylait que le survol DIRECT du bouton (fond colore au
   survol), sans jamais agir sur sa visibilite, d'ou l'impression de mode
   edition permanent (toutes les croix visibles en meme temps). Scope a
   #fp-tags-chips uniquement : .tag-chip-x sert aussi au bouton "Retirer le
   filtre" de la banniere de filtre (app.js, #tag-filter-clear-x,
   .tag-chip-active) qui doit lui rester visible en permanence -- seule
   action de cette banniere, rien a reveler. (Diagnostic + demande
   utilisateur, 2026-09-19.) */
@media (hover: hover) {
    #fp-tags-chips .tag-chip-x {
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.15s ease;
    }
    #fp-tags-chips .tag-chip:hover .tag-chip-x,
    #fp-tags-chips .tag-chip:focus-within .tag-chip-x {
        opacity: 1;
        pointer-events: auto;
    }
}

/* ========== Profile webhooks section ========== */
.profile-webhooks-card {
    background: var(--color-surface);
    border-radius: 20px;
    padding: 20px;
    box-shadow: var(--shadow-sm);
    margin-bottom: 16px;
}
.profile-webhooks-head {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
}
.profile-webhooks-icon {
    width: 36px; height: 36px;
    border-radius: 10px;
    background: var(--color-primary);
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.profile-webhooks-icon svg { width: 18px; height: 18px; }
.profile-webhooks-text { flex: 1; }
.profile-webhooks-title { font-weight: 600; font-size: 14px; color: var(--color-text); }
.profile-webhooks-sub { font-size: 12px; color: var(--color-text-tertiary); margin-top: 2px; }

.webhooks-list { display: flex; flex-direction: column; gap: 8px; }
.webhooks-empty {
    padding: 16px;
    text-align: center;
    color: var(--color-text-tertiary);
    font-size: 13px;
    font-style: italic;
}
.webhook-row {
    display: flex;
    gap: 12px;
    padding: 12px 14px;
    background: var(--color-bg);
    border-radius: 14px;
    border: 1px solid var(--color-border-light);
    align-items: flex-start;
}
.webhook-row-disabled { opacity: 0.55; }
.webhook-row-main { flex: 1; min-width: 0; }
.webhook-row-label { font-weight: 600; font-size: 13px; color: var(--color-text); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.webhook-row-url { font-size: 12px; color: var(--color-text-secondary); margin-top: 2px; word-break: break-all; }
.webhook-row-meta { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }
.webhook-evt-chip {
    background: var(--color-hover);
    color: var(--color-text-secondary);
    font-size: 10px;
    padding: 2px 8px;
    border-radius: 10px;
    font-family: var(--font-mono);
}
.webhook-row-last { font-size: 11px; color: var(--color-text-tertiary); margin-top: 6px; }
.webhook-row-actions { display: flex; gap: 2px; flex-shrink: 0; }
.webhook-badge-off, .webhook-badge-fail {
    font-size: 10px; padding: 2px 8px; border-radius: 10px; font-weight: 600;
}
.webhook-badge-off { background: var(--color-hover); color: var(--color-text-tertiary); }
.webhook-badge-fail { background: #fee2e2; color: #991b1b; }

.webhooks-doc {
    margin-top: 14px;
    padding: 10px 14px;
    background: var(--color-bg);
    border-radius: 12px;
    font-size: 12px;
    color: var(--color-text-secondary);
}
.webhooks-doc summary { cursor: pointer; font-weight: 600; user-select: none; }
.webhooks-doc-body { margin-top: 10px; line-height: 1.5; }
.webhooks-doc-body pre {
    background: var(--color-surface);
    padding: 10px;
    border-radius: 8px;
    overflow-x: auto;
    font-size: 11px;
}
.webhooks-doc-body code { font-family: var(--font-mono); font-size: 11px; background: var(--color-surface); padding: 1px 5px; border-radius: 4px; }

/* Webhook modal */
.webhook-modal {
    position: fixed; inset: 0; z-index: 1000;
    background: rgba(0,0,0,0.5);
    display: flex; align-items: center; justify-content: center;
    padding: 16px;
}
.webhook-modal[hidden] { display: none; }
.webhook-modal-card {
    background: var(--color-surface);
    border-radius: 20px;
    width: 100%; max-width: 520px;
    max-height: 90vh;
    display: flex; flex-direction: column;
    box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}
.webhook-modal-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 18px 20px;
    border-bottom: 1px solid var(--color-border-light);
}
.webhook-modal-head h3 { margin: 0; font-size: 16px; }
.webhook-modal-body { padding: 18px 20px; overflow-y: auto; }
.webhook-modal-footer {
    display: flex; gap: 8px; justify-content: flex-end;
    padding: 14px 20px;
    border-top: 1px solid var(--color-border-light);
}
.webhook-events {
    display: flex; flex-direction: column;
    gap: 6px;
    margin-top: 6px;
    padding: 10px;
    background: var(--color-bg);
    border-radius: 10px;
}
.webhook-evt-row {
    display: flex; align-items: center; gap: 8px;
    cursor: pointer;
    padding: 4px;
}
.webhook-evt-row code { font-family: var(--font-mono); font-size: 12px; }

/* ========== Profile toggle switch (used for digest opt-in) ========== */
.profile-toggle {
    position: relative;
    display: inline-block;
    width: 44px;
    height: 24px;
    flex-shrink: 0;
    cursor: pointer;
}
.profile-toggle input { opacity: 0; width: 0; height: 0; }
.profile-toggle-slider {
    position: absolute;
    inset: 0;
    background: var(--color-border);
    border-radius: 24px;
    transition: background .2s;
}
.profile-toggle-slider::before {
    content: '';
    position: absolute;
    height: 18px;
    width: 18px;
    left: 3px;
    top: 3px;
    background: #fff;
    border-radius: 50%;
    transition: transform .2s;
    box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
.profile-toggle input:checked + .profile-toggle-slider { background: var(--color-primary); }
.profile-toggle input:checked + .profile-toggle-slider::before { transform: translateX(20px); }

/* ========== Trash auto-purge notice ========== */
.trash-purge-notice {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px;
    margin: 0 0 16px;
    background: var(--color-warning-bg, #fef3c7);
    color: var(--color-warning-text, #92400e);
    border-radius: 12px;
    font-size: 13px;
    line-height: 1.4;
}
.trash-purge-notice svg { flex-shrink: 0; }
.trash-purge-notice[hidden] { display: none; }

/* ========== FilePanel Expiration section ========== */
.fp-exp-section {
    padding: 14px 0 12px;
    border-bottom: 1px solid var(--color-border-light);
    margin-bottom: 14px;
}
.fp-exp-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    flex-wrap: wrap;
}
.fp-exp-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.6px;
}
.fp-exp-current {
    font-size: 12px;
    color: var(--color-text);
    background: var(--color-warning-bg, #fef3c7);
    color: var(--color-warning-text, #92400e);
    padding: 3px 10px;
    border-radius: 12px;
    font-weight: 600;
}
.fp-exp-none { font-size: 12px; color: var(--color-text-tertiary); }
.fp-exp-clear {
    background: transparent;
    border: none;
    color: var(--color-text-tertiary);
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
    padding: 0 4px;
}
.fp-exp-clear:hover { color: var(--color-danger); }
.fp-exp-row {
    display: flex;
    gap: 8px;
    align-items: center;
}
.fp-exp-input {
    flex: 1;
    padding: 7px 10px;
    border: 1px solid var(--color-border);
    border-radius: 8px;
    background: var(--color-bg);
    color: var(--color-text);
    font-size: 13px;
    font-family: inherit;
}
.fp-exp-save {
    padding: 7px 14px;
    border: none;
    border-radius: 8px;
    background: var(--color-primary);
    color: #fff;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
}
.fp-exp-save:hover { background: #0066d6; }
.fp-exp-save:disabled { opacity: 0.6; cursor: wait; }
.fp-exp-hint {
    margin: 8px 0 0;
    font-size: 11px;
    color: var(--color-text-tertiary);
    line-height: 1.4;
}

/* ========== FilePanel Quick Actions ========== */
.fp-quick-actions {
    display: flex;
    gap: 8px;
    padding: 12px 0 14px;
    border-bottom: 1px solid var(--color-border-light);
    margin-bottom: 14px;
}
.fp-qa-btn {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
    padding: 10px 6px;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    color: var(--color-text-secondary);
    font-size: 11px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
}
.fp-qa-btn:hover {
    background: var(--color-surface);
    border-color: var(--color-primary);
    color: var(--color-primary);
    transform: translateY(-1px);
}
.fp-qa-btn svg { flex-shrink: 0; }

/* ========== FilePanel Tags section ========== */
.fp-tags-section {
    padding: 14px 0 10px;
    border-bottom: 1px solid var(--color-border-light);
    margin-bottom: 14px;
}
.fp-tags-head {
    display: flex;
    align-items: center;
    margin-bottom: 8px;
}
.fp-tags-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.6px;
}
.fp-tags-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
}

/* "+ Tag" button */
.tag-add-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 14px;
    background: transparent;
    border: 1px dashed var(--color-border);
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
}
.tag-add-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 6%, transparent);
}

/* ========== Tag picker popover ========== */
.tag-picker {
    margin-top: 10px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-md);
    padding: 8px;
    max-height: 280px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.tag-picker[hidden] { display: none !important; }
.tag-picker-input {
    width: 100%;
    padding: 8px 10px;
    border-radius: 8px;
    border: 1px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text);
    font-size: 13px;
    outline: none;
    transition: border 0.15s;
}
.tag-picker-input:focus {
    border-color: var(--color-primary);
}
.tag-picker-list {
    overflow-y: auto;
    max-height: 220px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.tag-picker-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 7px 10px;
    border-radius: 8px;
    background: transparent;
    border: none;
    color: var(--color-text);
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s;
    width: 100%;
}
.tag-picker-item:hover {
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
}
.tag-picker-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.tag-picker-create {
    color: var(--color-primary);
    font-weight: 600;
    border-top: 1px solid var(--color-border-light);
    margin-top: 4px;
    padding-top: 10px;
}
.tag-picker-create svg { color: var(--color-primary); }
.tag-picker-empty {
    padding: 12px 10px;
    font-size: 12px;
    color: var(--color-text-tertiary);
    text-align: center;
}

/* ========== Tag dots on cards / list rows ========== */
.file-card-tags {
    position: absolute;
    bottom: 6px;
    left: 10px;
    display: flex;
    gap: 3px;
    align-items: center;
    pointer-events: none;
    z-index: 2;
}
.file-card-tags .tag-dot {
    width: 9px; height: 9px;
    box-shadow: 0 0 0 2px var(--color-surface);
}
.file-tag-more {
    font-size: 10px;
    font-weight: 700;
    color: var(--color-text-secondary);
    padding: 0 4px;
    border-radius: 6px;
    background: var(--color-surface);
    line-height: 14px;
    margin-left: 2px;
}

/* In list rows — inline next to filename */
.file-list-row .file-tag-dots {
    display: inline-flex;
    gap: 3px;
    align-items: center;
    margin-left: 6px;
    flex-shrink: 0;
}
.file-list-row .file-tag-dots .tag-dot {
    width: 7px; height: 7px;
}
.file-list-row .file-tag-more {
    background: transparent;
    font-size: 10px;
}

/* ========== Protected (system) folders — small lock badge top-left ========== */
.file-card.protected,
.file-list-row.protected {
    position: relative;
}
.file-card.protected::before,
.file-list-row.protected::before {
    content: "";
    position: absolute;
    top: 8px;
    left: 8px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background:
        url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='none' stroke='white' stroke-width='1.8' stroke-linecap='round'><path d='M16 16 Q24 11 28 16 Q24 21 16 16'/><path d='M16 16 Q8 21 4 16 Q8 11 16 16'/><circle cx='16' cy='16' r='1.5' fill='white'/></svg>") center / 10px 10px no-repeat,
        linear-gradient(135deg, #8B5CF6 0%, #5B21B6 100%);
    backdrop-filter: blur(2px);
    pointer-events: none;
    z-index: 5;
}
.file-list-row.protected::before {
    top: 50%;
    left: 8px;
    transform: translateY(-50%);
}

/* ========== "Tout sélectionner" — icon button inside header-actions pill ======= */
.select-all-toggle {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.select-all-toggle[hidden] { display: none !important; }
.select-all-toggle .select-all-box {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: 2px solid var(--color-text-secondary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: transparent;
    transition: background .12s, border-color .12s, color .12s;
}
.select-all-toggle .select-all-box svg { width: 10px; height: 10px; }
.select-all-toggle:hover .select-all-box { border-color: var(--color-primary); }
.select-all-toggle.all-selected .select-all-box,
.select-all-toggle.some-selected .select-all-box {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: #fff;
}
.select-all-toggle.some-selected .select-all-box svg polyline { display: none; }
.select-all-toggle.some-selected .select-all-box::after {
    content: "";
    display: block;
    width: 9px;
    height: 2px;
    background: #fff;
    border-radius: 1px;
}
/* Small count badge bottom-right of the icon when something is selected */
.select-all-badge {
    position: absolute;
    bottom: -4px;
    right: -4px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 10px;
    background: var(--color-primary);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    box-shadow: 0 0 0 2px var(--color-bg);
}
.select-all-badge[hidden] { display: none !important; }

/* ========== Tag bar (top of /files page) ========== */
.tag-bar-wrap { position: relative; }
.tag-bar {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    padding: 20px 16px 8px;
    align-items: center;
}
.tag-bar:empty { display: none; }
/* "Plus / Moins" toggle revealed on mobile when the chips wrap to >1 row.
   App.renderSidebarTags toggles the .has-overflow class after measuring. */
.tag-bar-toggle { display: none; }
.tag-bar-toggle.has-overflow {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    border-radius: 999px;
    padding: 5px 10px;
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    margin: 0 12px 8px auto;
    transition: background .15s, color .15s;
}
.tag-bar-toggle.has-overflow:hover {
    background: var(--color-hover);
    color: var(--color-text);
}
.tag-bar-toggle svg { transition: transform .2s; }
.tag-bar-wrap.expanded .tag-bar-toggle svg { transform: rotate(180deg); }

/* ========== Categories chips — Finder-style "Kind" pills (live in .tag-bar) ========== */
.sidebar-cat {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 13px;
    border-radius: 16px;
    /* Neutre au repos -- la teinte de categorie ne s'affiche que sur l'icone
       et sur .active (cf plus bas) ; jusqu'a 11 chips simultanement satures
       diluaient le signal de la selection active (audit 2026-08-12). */
    background: var(--color-surface);
    border: 1.5px solid var(--color-border);
    color: var(--color-text);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    transition: background .12s, transform .08s, border-color .12s, box-shadow .12s;
}
.sidebar-cat:hover {
    background: color-mix(in srgb, var(--cat-color, #6366F1) 16%, transparent);
    border-color: color-mix(in srgb, var(--cat-color, #6366F1) 40%, var(--color-border));
    transform: translateY(-1px);
}
/* Halo autour de l'onglet actif : le fait "remonter" visuellement par
   rapport aux autres (translateY + anneau lumineux colore), pour rester
   identifiable meme sans distinguer finement la teinte de fond (malvoyants). */
.sidebar-cat.active {
    background: var(--cat-color, var(--color-primary));
    border-color: var(--cat-color, var(--color-primary));
    color: #fff;
    transform: translateY(-2px);
    box-shadow:
        0 0 0 3px color-mix(in srgb, var(--cat-color, var(--color-primary)) 40%, transparent),
        0 6px 16px color-mix(in srgb, var(--cat-color, var(--color-primary)) 55%, transparent);
}
.sidebar-cat-icon {
    display: inline-flex;
    color: var(--cat-color, var(--color-primary));
}
.sidebar-cat.active .sidebar-cat-icon { color: #fff; }
.sidebar-cat-name { line-height: 1; }
.sidebar-cat-count {
    background: var(--color-bg);
    color: var(--color-text-secondary);
    border-radius: 8px;
    padding: 1px 6px;
    font-size: 10px;
    font-weight: 600;
}
.sidebar-cat.active .sidebar-cat-count {
    background: rgba(255,255,255,0.25);
    color: #fff;
}

/* Empty-state suggestion chips — 5 default starter tags with one-click add. */
.sidebar-tags-suggest {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    width: 100%;
}
.sidebar-tags-suggest-hint {
    font-size: 11px;
    color: var(--color-text-tertiary);
    font-weight: 500;
}
.sidebar-tags-suggest-chips { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.tag-seed-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px 4px 12px;
    border-radius: 14px;
    background: transparent;
    border: 1px dashed color-mix(in srgb, var(--tag-color, #6366F1) 55%, var(--color-border));
    color: var(--color-text);
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    transition: background .12s, border-style .12s, transform .08s;
}
.tag-seed-chip:hover { background: color-mix(in srgb, var(--tag-color, #6366F1) 12%, transparent); border-style: solid; transform: translateY(-1px); }
.tag-seed-chip:disabled { opacity: 0.5; cursor: not-allowed; }
.tag-seed-chip .tag-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--tag-color, #6366F1); }
.tag-seed-plus { color: color-mix(in srgb, var(--tag-color, #6366F1) 80%, var(--color-text)); font-weight: 700; margin-left: 2px; }
.sidebar-tags-suggest-all {
    border: none;
    background: transparent;
    color: var(--color-primary);
    font-size: 11px;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
    padding: 2px 4px;
    border-radius: 4px;
    transition: background .12s;
}
.sidebar-tags-suggest-all:hover { background: color-mix(in srgb, var(--color-primary) 10%, transparent); text-decoration: none; }
.sidebar-tags-suggest-all:disabled { opacity: 0.5; cursor: not-allowed; text-decoration: none; }
.sidebar-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px 5px 12px;
    border-radius: 14px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text-secondary);
    font-size: 12px;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: all 0.15s;
}
.sidebar-tag:hover {
    border-color: var(--color-primary);
    color: var(--color-text);
}
.sidebar-tag.active {
    background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
    border-color: var(--color-primary);
    color: var(--color-primary);
}

/* User-tag wrapper: positions the (×) delete button on top-right of the chip,
   visible on hover (or always on touch devices). */
.sidebar-tag-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
}
.sidebar-tag-del {
    position: absolute;
    top: -6px;
    right: -6px;
    width: 18px;
    height: 18px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-secondary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0;
    transform: scale(0.85);
    transition: opacity .12s, transform .12s, background .12s, color .12s, border-color .12s;
    z-index: 2;
}
.sidebar-tag-wrap:hover .sidebar-tag-del,
.sidebar-tag-del:focus-visible {
    opacity: 1;
    transform: scale(1);
}
.sidebar-tag-del:hover {
    background: #ef4444;
    border-color: #ef4444;
    color: #fff;
}
/* Tactile (pas de survol fiable) : la croix reste masquee par defaut --
   ancien fallback "toujours visible" retire (encombrement signale par
   l'utilisateur, 2026-09-19). Revelee par un appui long sur le tag (classe
   posee par _wireSidebarTagLongPress() dans app.js), meme geste que les
   actions secondaires natives iOS/Android. */
@media (hover: none) {
    .sidebar-tag-wrap.tag-del-revealed .sidebar-tag-del {
        opacity: 1;
        transform: scale(1);
    }
}

/* Virtual "★ Favoris" chip — visually distinct from user-defined tags */
.sidebar-tag-fav {
    background: color-mix(in srgb, #fbbf24 10%, var(--color-surface));
    border-color: color-mix(in srgb, #fbbf24 35%, var(--color-border));
    color: #b45309;
}
.sidebar-tag-fav:hover {
    background: color-mix(in srgb, #fbbf24 18%, var(--color-surface));
    border-color: #fbbf24;
    color: #92400e;
}
.sidebar-tag-fav.active {
    background: color-mix(in srgb, #fbbf24 22%, var(--color-surface));
    border-color: #fbbf24;
    color: #92400e;
}
[data-theme="dark"] .sidebar-tag-fav        { color: #fbbf24; }
[data-theme="dark"] .sidebar-tag-fav:hover  { color: #fde68a; }
[data-theme="dark"] .sidebar-tag-fav.active { color: #fde68a; }
.sidebar-tag-fav .sidebar-tag-fav-icon {
    color: #fbbf24;
    font-size: 14px;
    line-height: 1;
    text-shadow: 0 0 6px color-mix(in srgb, #fbbf24 50%, transparent);
}
.sidebar-tag-fav.active .sidebar-tag-count,
.sidebar-tag-fav .sidebar-tag-count {
    background: color-mix(in srgb, #fbbf24 22%, transparent);
    color: #b45309;
}
[data-theme="dark"] .sidebar-tag-fav .sidebar-tag-count { color: #fbbf24; }

.sidebar-tag-name {
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sidebar-tag-count {
    font-size: 10px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    padding: 1px 6px;
    border-radius: 10px;
    background: var(--color-bg);
}
.sidebar-tag.active .sidebar-tag-count {
    background: color-mix(in srgb, var(--color-primary) 20%, transparent);
    color: var(--color-primary);
}
.sidebar-tags-empty {
    font-size: 11px;
    color: var(--color-text-tertiary);
    padding: 2px 0;
}

/* ========== Active tag filter banner — shares the row with the tag chips ========== */
.tag-filter-banner {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    padding: 0;
    /* Pulled up with a negative margin so the "Filtré par : [tag] Effacer"
       line sits on the same visual row as the tag chips (.tag-bar) just above. */
    margin: -34px 16px 8px;
    background: transparent;
    border: none;
    font-size: 12px;
    position: relative;
    z-index: 2;
    min-height: 26px;
    /* The banner overlaps the tag-bar row visually — let clicks fall through
       to the tags underneath, and re-enable pointer events only on the
       interactive children (chip + "Effacer" link). */
    pointer-events: none;
}
.tag-filter-banner > * { pointer-events: auto; }
.tag-filter-banner[hidden] { display: none; }
.tag-filter-label {
    font-size: 11px;
    color: var(--color-text-tertiary);
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}
.tag-filter-clear {
    margin-left: 2px;
    background: transparent;
    border: none;
    color: var(--color-text-tertiary);
    font-size: 11px;
    font-weight: 500;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 4px;
    transition: color 0.15s, background 0.15s;
    text-decoration: underline;
    text-underline-offset: 2px;
}
.tag-filter-clear:hover {
    color: var(--color-primary);
    background: transparent;
    text-decoration: none;
}

/* ========== Saved searches / smart folders (bar above tag-bar) ========== */
.saved-search-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 14px 16px 2px;
}
.saved-search-bar[hidden] { display: none; }
.saved-search-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--color-text-tertiary);
    margin-right: 4px;
}
.saved-search-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 6px 5px 10px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--ss-color, #6366F1) 8%, var(--color-surface));
    border: 1px solid color-mix(in srgb, var(--ss-color, #6366F1) 25%, var(--color-border));
    color: var(--color-text);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
    position: relative;
}
.saved-search-chip:hover {
    background: color-mix(in srgb, var(--ss-color, #6366F1) 14%, var(--color-surface));
    border-color: var(--ss-color, #6366F1);
}
.saved-search-chip.active {
    background: color-mix(in srgb, var(--ss-color, #6366F1) 18%, var(--color-surface));
    border-color: var(--ss-color, #6366F1);
    color: var(--ss-color, #6366F1);
}
.saved-search-icon {
    font-size: 13px;
    line-height: 1;
}
.saved-search-name {
    max-width: 180px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.saved-search-del {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    padding: 0;
    margin-left: 2px;
    background: transparent;
    border: none;
    border-radius: 50%;
    color: var(--color-text-tertiary);
    cursor: pointer;
    opacity: 0;
    transition: all 0.15s;
}
.saved-search-chip:hover .saved-search-del {
    opacity: 1;
}
.saved-search-del:hover {
    background: color-mix(in srgb, var(--color-danger, #EF4444) 15%, transparent);
    color: var(--color-danger, #EF4444);
}

/* "+ Enregistrer cette recherche" chip — dashed to signal creation affordance */
.saved-search-save-chip {
    border-style: dashed;
    background: transparent;
    color: var(--color-primary);
    border-color: color-mix(in srgb, var(--color-primary) 45%, transparent);
    padding: 5px 10px;
}
.saved-search-save-chip:hover {
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
    border-color: var(--color-primary);
    border-style: dashed;
}

/* Icon & color pickers inside the save modal */
.ss-icon-picker, .ss-color-picker {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.ss-icon-opt {
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    background: var(--color-surface);
    border: 2px solid var(--color-border);
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.15s;
}
.ss-icon-opt:hover { border-color: var(--color-primary); }
.ss-icon-opt.active {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 12%, var(--color-surface));
}
.ss-color-opt {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    transition: all 0.15s;
    padding: 0;
}
.ss-color-opt:hover { transform: scale(1.1); }
.ss-color-opt.active {
    border-color: var(--color-text);
    box-shadow: 0 0 0 2px var(--color-bg), 0 0 0 4px currentColor;
}

/* ========== Mobile adjustments ========== */
@media (max-width: 640px) {
    .tag-bar { padding: 14px 12px 6px; gap: 6px; }
    /* Collapsed by default — show only the first row of chips with a soft
       fade at the right so the user knows there's more behind the toggle. */
    .tag-bar-wrap:not(.expanded) .tag-bar {
        max-height: 44px;
        overflow: hidden;
    }
    .tag-bar-wrap.has-overflow:not(.expanded) .tag-bar {
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 80px), transparent calc(100% - 30px));
                mask-image: linear-gradient(to right, #000 calc(100% - 80px), transparent calc(100% - 30px));
    }
    .tag-bar-wrap.expanded .tag-bar { max-height: none; }
    /* Reserve room on the right of the chip row for the floating toggle so
       the Plus / Moins button sits inline with the chips instead of below. */
    .tag-bar-wrap.has-overflow .tag-bar { padding-right: 70px; }
    .tag-bar-wrap.has-overflow .tag-bar-toggle.has-overflow {
        position: absolute;
        top: 11px;
        right: 12px;
        margin: 0;
        z-index: 2;
    }
    /* On narrow mobile the tag chips wrap to 2-3 rows; the negative-margin
       overlap that works on desktop ends up colliding with the wrapped row
       (and visually leaks under the folder-path-bar). Stack the banner below
       the tag chips instead — clearer and no z-index gymnastics required. */
    .tag-filter-banner {
        margin: 4px 12px 8px;
        padding: 0;
        justify-content: flex-start;
        pointer-events: auto;
    }
    .sidebar-tag { font-size: 11px; padding: 4px 8px 4px 10px; }
    .sidebar-tag-name { max-width: 120px; }
    .file-card-tags { bottom: 4px; left: 6px; }
    .saved-search-bar { padding: 10px 12px 0; gap: 6px; }
    .saved-search-chip { font-size: 11px; padding: 4px 6px 4px 8px; }
    .saved-search-name { max-width: 120px; }
    .saved-search-del { opacity: 1; }
}

/* ==============================================================
   FULL-TEXT SEARCH RESULTS
   ============================================================== */
.search-results {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 16px;
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}
.search-result {
    display: grid;
    grid-template-columns: 48px 1fr 40px;
    gap: 14px;
    padding: 14px 16px;
    align-items: flex-start;
    cursor: pointer;
    border-bottom: 1px solid var(--color-border-light);
    transition: background 0.15s;
}
.search-result:last-child { border-bottom: none; }
.search-result:hover {
    background: color-mix(in srgb, var(--color-primary) 5%, var(--color-surface));
}

.sr-thumb-wrap {
    width: 48px; height: 48px;
    border-radius: 10px;
    background: var(--color-bg);
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.sr-thumb {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
.sr-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}
.sr-icon svg { width: 24px; height: 24px; }

.sr-body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.sr-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.sr-name {
    font-size: 14px;
    font-weight: 600;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.sr-badges {
    display: inline-flex;
    gap: 4px;
    flex-wrap: wrap;
}
.sr-badge {
    font-size: 10px;
    font-weight: 800;
    padding: 3px 9px;
    border-radius: 999px;
    text-transform: uppercase;
    border: 1px solid transparent;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    display: inline-flex;
    align-items: center;
    gap: 4px;
    line-height: 1;
    letter-spacing: 0.4px;
}
/* Bleu pour match du nom — couleur primary, glow subtil */
.sr-badge-name {
    background: color-mix(in srgb, var(--color-primary) 22%, transparent);
    color: var(--color-primary);
    border-color: color-mix(in srgb, var(--color-primary) 35%, transparent);
    text-shadow: 0 0 8px color-mix(in srgb, var(--color-primary) 30%, transparent);
}
.sr-badge-name::before {
    content: '';
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--color-primary);
    box-shadow: 0 0 6px color-mix(in srgb, var(--color-primary) 70%, transparent);
}

/* Vert plus saturé pour match du contenu */
.sr-badge-content {
    background: color-mix(in srgb, #10B981 24%, transparent);
    color: #059669;
    border-color: color-mix(in srgb, #10B981 40%, transparent);
    text-shadow: 0 0 8px color-mix(in srgb, #10B981 30%, transparent);
}
.sr-badge-content::before {
    content: '';
    width: 5px; height: 5px;
    border-radius: 50%;
    background: #10B981;
    box-shadow: 0 0 6px color-mix(in srgb, #10B981 70%, transparent);
}

/* Orange pour tag — couleur warning */
.sr-badge-tag {
    background: color-mix(in srgb, #F59E0B 26%, transparent);
    color: #B45309;
    border-color: color-mix(in srgb, #F59E0B 42%, transparent);
    text-shadow: 0 0 8px color-mix(in srgb, #F59E0B 30%, transparent);
}
.sr-badge-tag::before {
    content: '';
    width: 5px; height: 5px;
    border-radius: 50%;
    background: #F59E0B;
    box-shadow: 0 0 6px color-mix(in srgb, #F59E0B 70%, transparent);
}

/* Dark mode override — plus saturé sur fond foncé pour lisibilité */
[data-theme="dark"] .sr-badge-content { color: #34D399; }
[data-theme="dark"] .sr-badge-tag { color: #FBBF24; }

.sr-snippet {
    font-size: 13px;
    color: var(--color-text-secondary);
    line-height: 1.5;
    padding: 4px 10px;
    border-left: 3px solid color-mix(in srgb, var(--color-primary) 40%, transparent);
    background: var(--color-bg);
    border-radius: 0 8px 8px 0;
    margin-top: 2px;
}
.sr-snippet mark {
    background: color-mix(in srgb, #FBBF24 35%, transparent);
    color: var(--color-text);
    padding: 1px 3px;
    border-radius: 3px;
    font-weight: 600;
}

.sr-meta {
    font-size: 12px;
    color: var(--color-text-tertiary);
    display: flex;
    align-items: center;
    gap: 6px;
}
.sr-dot { opacity: 0.5; }

.sr-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
}
.sr-actions .btn-icon {
    opacity: 0;
    transition: opacity 0.15s;
}
.search-result:hover .sr-actions .btn-icon { opacity: 1; }

@media (max-width: 640px) {
    .search-result {
        grid-template-columns: 40px 1fr 32px;
        padding: 12px;
        gap: 10px;
    }
    .sr-thumb-wrap { width: 40px; height: 40px; }
    .sr-actions .btn-icon { opacity: 1; }
    .sr-name { font-size: 13px; }
}

/* ==============================================================
   BRAND LOGOS — theme-aware swap
   Use one element with both src variants; CSS hides the wrong one
   based on [data-theme] on <html>. Works for favicon + wordmark.
   ============================================================== */
.aqin-logo, .aqin-fav {
    display: inline-block;
    vertical-align: middle;
}
/* Default (no data-theme yet, e.g. light system default) → show light variants */
.aqin-logo[data-for="dark"], .aqin-fav[data-for="dark"] { display: none; }
.aqin-logo[data-for="light"], .aqin-fav[data-for="light"] { display: inline-block; }
/* When theme is dark, flip */
[data-theme="dark"] .aqin-logo[data-for="dark"],
[data-theme="dark"] .aqin-fav[data-for="dark"] { display: inline-block; }
[data-theme="dark"] .aqin-logo[data-for="light"],
[data-theme="dark"] .aqin-fav[data-for="light"] { display: none; }

/* ==============================================================
   ONBOARDING WIZARD (first-run overlay)
   ============================================================== */
.onb-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.75);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    opacity: 0;
    transition: opacity 0.25s ease;
}
.onb-overlay.visible { opacity: 1; }
.onb-overlay.onb-closing { opacity: 0; pointer-events: none; }   /* 250 ms dans le DOM : il ne doit avaler aucun clic */

.onb-card {
    width: 100%;
    max-width: 480px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 24px;
    padding: 36px 32px 0;                 /* le bas est porte par .onb-footer (collant) */
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.5);
    position: relative;
    text-align: center;
    animation: onbPop 0.35s cubic-bezier(0.32, 0.72, 0, 1);
}
@keyframes onbPop {
    from { transform: scale(0.92) translateY(16px); opacity: 0; }
    to   { transform: scale(1) translateY(0); opacity: 1; }
}

/* ================================================================
   Floating header refactor — kill the in-flow .header bar entirely.
   The hamburger + page title float top-left, the user corner stays
   top-right, and the actions pill stays centered with sticky-on-
   scroll-up behavior. All three groups share a frosted-glass style.
   ================================================================ */

/* Collapse the .header element to a 0-height positioning context.
   Its visible children (sidebar toggle, breadcrumb, search-bar) are
   re-positioned as floating fixed elements below; the included
   header-actions partial was already position:fixed. */
.header {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    padding: 0 !important;
    margin: 0 !important;
    height: 0 !important;
    min-height: 0 !important;
    overflow: visible;
    position: relative;
}
.header.profile-page-header,
.header.no-sidebar-layout-header { /* same treatment for floating-tile variants */
    background: transparent !important;
    box-shadow: none !important;
    padding: 0 !important;
    height: 0 !important;
    min-height: 0 !important;
}
/* .admin-page-header collapses to 0 like the other floating-tile headers,
   and the centered admin-tabs pill is pinned to the viewport via fixed
   positioning (top:14px, centered). This matches the look of other pages. */
.header.admin-page-header {
    background: transparent !important;
    box-shadow: none !important;
    padding: 0 !important;
    height: 0 !important;
    min-height: 0 !important;
    border-bottom: none !important;
    overflow: visible;
}
.admin-page-header .admin-page-header-center {
    position: fixed !important;
    top: 14px !important;
    left: 50% !important;
    right: auto !important;
    transform: translateX(-50%) !important;
    width: auto !important;
    max-width: calc(100vw - 240px) !important;
    z-index: 50 !important;
    padding: 0 !important;
}
/* Aligne sur le rendu REEL de .header-actions (Nuage) : 70% de surface,
   blur(14px), bordure a 70%, rayon 14.
   ATTENTION : il existe DEUX regles .header-actions dans ce fichier. La
   premiere (~ligne 2063) annonce 75% / saturate(180%) blur(18px) / bordure
   80% -- elle est PERIMEE, ecrasee par la seconde. S'y fier donne des
   valeurs proches mais fausses, et l'ecart se voit en passant d'un ecran a
   l'autre. Mesurer le rendu, pas lire la premiere regle trouvee.
   Seul le rayon divergeait vraiment ici : 22px au lieu de 14.
   NE PAS positionner dans cette regle : c'est .admin-page-header-center qui
   flotte (fixed, top 14), et son transform fait du conteneur un bloc de
   reference pour position:fixed -- repositionner la pastille en plus
   donnerait un double decalage (constate : rendu a top 28).
   Harmonisation 2026-08-20. */
.admin-page-header .admin-tabs.admin-tabs-header {
    margin-top: 0;
    padding: 4px 6px;
    background: color-mix(in srgb, var(--color-surface) 70%, transparent);
    -webkit-backdrop-filter: blur(14px);
            backdrop-filter: blur(14px);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
    box-shadow: var(--shadow-sm);
    border-radius: 14px;
}

/* Hamburger floats top-left as a frosted tile, mirror of the right corner. */
.header > .btn-sidebar-toggle {
    position: fixed !important;
    top: 14px !important;
    left: 16px !important;
    width: 44px !important;
    height: 44px !important;
    padding: 0 !important;
    border-radius: 14px !important;
    background: color-mix(in srgb, var(--color-surface) 70%, transparent) !important;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent) !important;
    box-shadow: var(--shadow-sm);
    color: var(--color-text-secondary) !important;
    display: flex !important;
    align-items: center;
    justify-content: center;
    z-index: 50;
    margin: 0 !important;
}
.header > .btn-sidebar-toggle:hover {
    color: var(--color-text) !important;
    border-color: var(--color-primary) !important;
}

/* Breadcrumb floats next to the hamburger as a frosted pill containing the
   page title (Mes fichiers / Corbeille / Profil…) and any folder path JS
   appends when navigating into subfolders. */
.header > .breadcrumb {
    position: fixed !important;
    top: 14px !important;
    left: 70px !important;
    height: 44px;
    padding: 0 18px;
    border-radius: 14px;
    background: color-mix(in srgb, var(--color-surface) 70%, transparent);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
    box-shadow: var(--shadow-sm);
    color: var(--color-text);
    display: inline-flex !important;
    align-items: center;
    z-index: 50;
    font-size: 14px;
    font-weight: 600;
    max-width: calc(100vw - 380px);
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.header > .breadcrumb .breadcrumb-item { color: var(--color-text); }
.header > .breadcrumb .breadcrumb-item.current { color: var(--color-text); font-weight: 600; }

/* Context switcher (segmented control) — replaces the breadcrumb on /files
   and /workspaces. Two tabs that toggle between personal files and the
   workspaces listing. Renders inside the existing breadcrumb pill.

   The active background is a single sliding pill (`::before`) positioned by
   JS (App._initContextSwitcher) via the --ctx-x / --ctx-w custom properties,
   so the highlight glides between tabs on click instead of jumping. */
.header > .breadcrumb.context-switcher {
    padding: 4px;
    gap: 2px;
    position: relative;
}
.header > .breadcrumb.context-switcher::before {
    content: '';
    position: absolute;
    top: 4px;
    bottom: 4px;
    left: 4px;
    width: var(--ctx-w, 0px);
    transform: translateX(var(--ctx-x, 0px));
    background: color-mix(in srgb, var(--color-text) 12%, transparent);
    border-radius: 10px;
    pointer-events: none;
    z-index: 0;
    opacity: 0;
    transition: opacity .2s;
}
/* Pill becomes visible (and starts animating between tabs) once JS has
   measured the active tab and set the initial position. */
.header > .breadcrumb.context-switcher.ctx-ready::before {
    opacity: 1;
    transition:
        transform .35s cubic-bezier(.4,1.3,.45,1),
        width     .35s cubic-bezier(.4,1.3,.45,1),
        opacity   .2s;
}
/* Galaxie réservé aux plans payants : masqué de la nav pour Free/Étoile
   (body.no-galaxie posé par le layout). Masque le pill ET son séparateur,
   y compris après reconstruction par _updateNavContext(). */
/* Le pill Galaxie disparait pour qui n'y a pas droit (body.no-galaxie, pose
   par le layout). Ces pills sont un commutateur entre les apps qu'on UTILISE :
   y laisser une destination qui renvoie sur un ecran d'upgrade en fait une
   fausse piste, a chaque page.

   L'entree du LANCEUR, elle, reste visible en toutes circonstances : c'est la
   que la fonctionnalite se decouvre et se vend. Deux surfaces, deux roles --
   ne pas reunifier les deux regles. */
body.no-galaxie .ctx-tab-galaxie,
body.no-galaxie .ctx-tab-galaxie + .ctx-tab-sep,
body.no-galaxie .ctx-tab-sep:first-child { display: none !important; }

.header > .breadcrumb .ctx-tab {
    display: inline-flex;
    align-items: center;
    padding: 0 14px;
    height: 36px;
    border-radius: 10px;
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text-tertiary);
    text-decoration: none;
    transition: color .25s ease, padding .25s ease;
    cursor: pointer;
    position: relative;
    z-index: 1;
}
.header > .breadcrumb .ctx-tab:hover { color: var(--color-text); }
.header > .breadcrumb .ctx-tab.active { color: var(--color-text); }
/* Séparateur › entre deux ctx-tabs (ex : Nuage › Scribe) */
/* Le separateur etait un glyphe typographique alors que tous les autres
   chevrons de l'interface (repli du volet, bascule d'espace) sont des traces
   SVG a extremites arrondies : deux familles de fleches cote a cote. Aucune
   propriete de police ne permet d'arrondir un glyphe, d'ou le masque SVG.

   Le caractere reste dans le HTML : il porte le sens pour les lecteurs
   d'ecran et les seize gabarits qui l'emploient n'ont pas a changer -- seule
   sa peinture change. Teinte en currentColor, il suit donc le theme comme
   avant. */
.header > .breadcrumb .ctx-tab-sep {
    display: block;
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    color: var(--color-text-muted);
    opacity: .55;
    font-size: 0;          /* masque le glyphe sans le retirer du DOM */
    line-height: 1;
    pointer-events: none;
    user-select: none;
    margin: 0 2px;
    background-color: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='9 18 15 12 9 6'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
}

/* === Auto-collapse des onglets inactifs ============================
   Au repos, les onglets non actifs masquent leur label (icône seule)
   pour réduire l'encombrement visuel du switcher. Au survol du switcher
   complet, tous les labels réapparaissent avec une animation max-width.
   La pill active ne bouge pas — c'est uniquement les inactifs qui
   s'étendent. Le JS repositionne ::before sur l'active après transition
   pour garder l'highlight aligné. */
.header > .breadcrumb .ctx-tab .ctx-tab-label {
    display: inline-block;
    overflow: hidden;
    white-space: nowrap;
    max-width: 100px;
    opacity: 1;
    transition: max-width .3s cubic-bezier(.4,1.3,.45,1),
                opacity   .2s ease,
                margin    .25s ease;
}
/* Labels inactifs TOUJOURS cachés — icône seule.
   Le label n'est visible que sur l'onglet actif, même au hover. */
.header > .breadcrumb.context-switcher .ctx-tab:not(.active) .ctx-tab-label {
    max-width: 0;
    opacity: 0;
    margin-left: -2px;  /* compense le gap visuel quand le label disparaît */
}
.header > .breadcrumb.context-switcher .ctx-tab:not(.active) {
    padding: 0 10px;     /* tab compact : icône seule */
}
.header > .breadcrumb.context-switcher .ctx-tab:not(.active) .ctx-tab-icon {
    margin-right: 0;
}

/* === Identité produit AQIN dans les pills nav ===
   Mini-icône inline alignée verticalement, espace 6px avant le label. */
.header > .breadcrumb .ctx-tab .ctx-tab-icon {
    width: 16px;
    height: 16px;
    margin-right: 6px;
    vertical-align: -3px;
    display: inline-block;
}

/* Pill Galaxie (Espaces) : violet permanent pour identité produit */
.header > .breadcrumb .ctx-tab.ctx-tab-galaxie {
    color: #8B5CF6;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-galaxie {
    color: #a78bfa;
}
.header > .breadcrumb .ctx-tab.ctx-tab-galaxie:hover {
    color: #6D28D9;
}
.header > .breadcrumb .ctx-tab.ctx-tab-galaxie.active {
    color: #6D28D9;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-galaxie.active {
    color: #c4b5fd;
}

/* Pill Nuage (Mes Fichiers) : bleu permanent pour identité produit */
.header > .breadcrumb .ctx-tab.ctx-tab-nuage {
    color: #3B82F6;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-nuage {
    color: #60a5fa;
}
.header > .breadcrumb .ctx-tab.ctx-tab-nuage:hover {
    color: #1D4ED8;
}
.header > .breadcrumb .ctx-tab.ctx-tab-nuage.active {
    color: #1D4ED8;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-nuage.active {
    color: #93c5fd;
}

/* Pill Fort (Coffre-fort) : ton ambre permanent — alias historique vault */
.header > .breadcrumb .ctx-tab.ctx-tab-vault {
    color: #B45309;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-vault {
    color: #fbbf24;
}
.header > .breadcrumb .ctx-tab.ctx-tab-vault:hover {
    color: #92400e;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-vault:hover {
    color: #fcd34d;
}
.header > .breadcrumb .ctx-tab.ctx-tab-vault.active {
    color: #92400e;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-vault.active {
    color: #fcd34d;
}

/* Pill Nébuleuse (Photothèque) : rose permanent */
.header > .breadcrumb .ctx-tab.ctx-tab-nebuleuse {
    color: #ec4899;
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-nebuleuse {
    color: #f472b6;
}
.header > .breadcrumb .ctx-tab.ctx-tab-nebuleuse:hover {
    color: #db2777;
    background: rgba(236, 72, 153, 0.08);
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-nebuleuse:hover {
    background: rgba(236, 72, 153, 0.1);
}
.header > .breadcrumb .ctx-tab.ctx-tab-nebuleuse.active {
    color: #be185d;
    background: rgba(236, 72, 153, 0.12);
}
[data-theme="dark"] .header > .breadcrumb .ctx-tab.ctx-tab-nebuleuse.active {
    color: #f9a8d4;
    background: rgba(236, 72, 153, 0.14);
}

/* Folder path / search context bar — sits above the file grid when the
   user is inside a subfolder, has searched, or is filtering by favorites.
   Hidden at root since the floating switcher already shows the context. */
.folder-path-bar {
    display: none !important;   /* masqué — le switcher Galaxie/Nuage/Fort suffit */
}
.folder-path-bar[hidden] { display: none; }
.folder-path-bar .breadcrumb-item {
    color: var(--color-text-secondary);
    text-decoration: none;
    padding: 2px 6px;
    border-radius: 6px;
    transition: background .12s, color .12s;
}
.folder-path-bar .breadcrumb-item:hover { background: var(--color-hover); color: var(--color-text); }
.folder-path-bar .breadcrumb-item.current { color: var(--color-text); font-weight: 600; }
.folder-path-bar .breadcrumb-separator { color: var(--color-text-tertiary); padding: 0 2px; }

/* === Workspaces listing page (/workspaces) === */
.ws-tabs-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}
.ws-tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.ws-tab {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 14px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    font-size: 13px;
    font-weight: 600;
    color: var(--color-text-tertiary);
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
    font-family: inherit;
}
.ws-tab:hover { color: var(--color-text-secondary); }
.ws-tab.active {
    color: var(--color-text);
    background: var(--color-surface);
    border-color: var(--color-border);
}
.ws-tab-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 20px; height: 20px;
    padding: 0 6px;
    background: var(--color-hover);
    color: var(--color-text-tertiary);
    border-radius: 10px;
    font-size: 11px; font-weight: 700;
}
.ws-tab.active .ws-tab-count {
    background: var(--color-primary);
    color: #fff;
}

/* Onglets Mes espaces / Partagés DANS la pill .header-actions (/workspaces) --
   meme pattern visuel que les onglets Flow dans leur pill (.ws-quick-action-btn,
   "Fil de l'espace"/"Agenda", workspace-view.css) : fond plein colore quand
   actif plutot que le simple contour de .ws-tab (reserve a l'usage restant de
   .ws-tab, la rangee Fichiers/Partages par moi DANS un Flow, cf
   workspace-view.php). Demande utilisateur 2026-09-10 ("plus coherent avec
   le UI de AQIN Cloud"). */
.ws-header-tabs { display: flex; align-items: center; gap: 2px; }
.ws-header-tab-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 12px;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--color-text-secondary);
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: color .15s;
}
.ws-header-tab-btn:hover { background: var(--color-hover); color: var(--color-text); }
.ws-header-tab-btn.active { background: var(--color-primary); color: #fff; }
.ws-header-tab-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px;
    padding: 0 5px;
    background: var(--color-hover);
    color: var(--color-text-tertiary);
    border-radius: 9px;
    font-size: 10.5px; font-weight: 700;
}
.ws-header-tab-btn.active .ws-header-tab-count { background: rgba(255,255,255,.25); color: #fff; }
@media (max-width: 640px) {
    .ws-header-tab-btn span:first-child { max-width: 90px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Chevron "Changer d'espace" fusionne dans l'onglet "Mes espaces" (au lieu
   d'une pill .ws-org-switch separee qui repetait le meme nom d'entreprise
   juste a cote, cf workspaces.php) -- 2 boutons distincts (accessibilite :
   jamais de bouton imbrique dans un bouton) mais colles sans coupure
   visuelle, suivant ensemble l'etat actif/inactif de l'onglet. Demande
   utilisateur 2026-09-10 ("il faut fusionner les deux"). */
/* align-items:stretch (pas center) -- le chevron doit epouser exactement
   la hauteur reelle de l'onglet (padding + contenu, jamais une valeur fixe
   devinee) pour qu'aucune marche ne soit visible entre les deux boutons,
   quelle que soit la taille de police/le zoom navigateur. Signale par
   l'utilisateur : "le bouton du switch n'est pas la meme hauteur" -- une
   height:30px codee en dur ne correspondait pas a la hauteur reelle
   (padding 7px + contenu) de .ws-header-tab-btn. */
.ws-header-tab-group { display: inline-flex; align-items: stretch; }
.ws-header-tab-group .ws-header-tab-btn { border-top-right-radius: 0; border-bottom-right-radius: 0; }
/* .ws-header-tab-group-single : compte avec un seul Flow, donc sans chevron
   (rien vers quoi basculer) -- le coin droit aplati ci-dessus n'a alors plus
   de bouton chevron pour le "completer" visuellement, laissant une arete
   carree cote droit de la pill. Restaure le rayon normal dans ce cas.
   Signale par l'utilisateur : "il manque le radius a droite du bouton"
   (classe deja posee cote PHP au moment de la fusion chevron/onglet,
   la regle CSS correspondante avait ete oubliee). */
.ws-header-tab-group-single .ws-header-tab-btn { border-top-right-radius: 10px; border-bottom-right-radius: 10px; }
.ws-header-tab-chevron-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px;
    padding: 0;
    border: none;
    border-top-left-radius: 0; border-bottom-left-radius: 0;
    border-top-right-radius: 10px; border-bottom-right-radius: 10px;
    background: transparent;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: color .15s, background .15s;
}
.ws-header-tab-chevron-btn:hover { background: var(--color-hover); color: var(--color-text); }
.ws-header-tab-chevron-btn.active { background: var(--color-primary); color: #fff; }
.ws-header-tab-chevron-btn[aria-expanded="true"] .ws-org-switch-chevron { transform: rotate(180deg); }
.ws-org-switch-chevron { transition: transform .2s ease; }

.ws-search-box {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 7px 12px;
    border: 1px solid var(--color-border);
    border-radius: 999px;
    background: var(--color-surface);
    flex: 1;
    max-width: 320px;
    transition: border-color .15s;
}
.ws-search-box:focus-within { border-color: var(--color-primary); }
.ws-search-box svg { color: var(--color-text-tertiary); flex-shrink: 0; }
.ws-search-box input {
    flex: 1;
    border: none;
    background: transparent;
    outline: none;
    font-size: 13px;
    color: var(--color-text);
    font-family: inherit;
}
.workspaces-grid {
    display: grid;
    /* Colonnes a LARGEUR FIXE, alignees sur les cartes de l'accueil
       (.home-ws-card) et sur les souvenirs de Nebuleuse : 340 px.
       Avant : minmax(260px, 1fr) en auto-fill -- la carte s'etirait a la
       largeur d'une piste variable, jusqu'a plus de 440 px sur grand ecran,
       soit un gabarit different de partout ailleurs dans le produit.
       Harmonisation du 2026-08-20.
       minmax(260px, 340px) essaye en premier pour combler l'espace vide sur
       grand ecran (cf plus bas) : rejete -- auto-fill calcule le nombre de
       pistes sur le MAX de la plage quand ce max est une longueur fixe (pas
       1fr), pas sur le min, donc minmax(260,340) se comporte a l'identique
       de 340px fixe (aucune piste ne se retrecissait jamais). Verifie en
       direct, 2026-09-10. Le nombre de colonnes est donc force par paliers
       explicites ci-dessous plutot que par une astuce minmax. */
    grid-template-columns: repeat(auto-fill, 340px);
    gap: 16px;
}
/* Paliers larges : force 4 puis 5 colonnes une fois qu'il y a la place --
   sans ca, la 4e/5e carte retombait seule sur une nouvelle ligne des qu'il
   manquait quelques px, laissant tout l'espace a droite de la ligne
   precedente inutilise.
   Premiere version (340px fixes) exigeait 1480px/1840px pour rentrer --
   bien au-dela d'un ecran de PC portable courant (1366/1440px), qui
   restait donc coince a 3 colonnes avec l'espace vide signale. Remplace
   par des pistes FLEXIBLES (repeat(N, 1fr)) : les cartes se retrecissent
   legerement pour occuper exactement la largeur disponible en 4 (ou 5)
   colonnes, quelle que soit la resolution exacte -- 1366px donne des
   cartes ~310px, 1440px ~330px, plus jamais d'espace mort a droite.
   Seuils choisis pour rester lisible (4 colonnes >=1150px, ~270px/carte
   au minimum ; 5 colonnes >=1700px, ~310px/carte au minimum) plutot que
   pile la largeur ou 4/5 cartes de 340px fixes rentreraient tout juste.
   Demande utilisateur 2026-09-10 ("toujours 4 rangees [colonnes] ou un
   espace vide a droite sur les ecrans PC portable"). */
@media (min-width: 1150px) {
    .workspaces-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 1700px) {
    .workspaces-grid { grid-template-columns: repeat(5, 1fr); }
}
/* Mobile tweaks for the /workspaces page: reinstate side padding (since
   .content padding is 0 on mobile), hide the search box (the tab strip is
   enough on phones — search is desktop-power-user). */
@media (max-width: 640px) {
    /* Sous cette largeur une piste de 340 px deborde avec le padding : on
       repasse en colonne pleine largeur. */
    .workspaces-grid { padding: 0 12px; grid-template-columns: 1fr; }
    .ws-tabs-row { padding: 0 12px; }
    .ws-search-box { display: none !important; }
}
.ws-card {
    display: flex; flex-direction: column;
    background: var(--color-surface);
    border: 1px solid transparent;
    border-radius: 20px;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    box-shadow: var(--shadow-sm);
    transition: transform .18s, box-shadow .18s, border-color .18s;
    cursor: pointer;
    position: relative;
}
.ws-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 12px 32px rgba(0,0,0,0.16);
    border-color: var(--color-primary);
    text-decoration: none;
}
/* Cancel the global a:hover { text-decoration: underline } so card text
   never gets underlined on hover. */
.ws-card,
.ws-card:hover,
.ws-card * { text-decoration: none !important; }

/* Panneau d'info (haut) puis zone illustree (bas) -- ordre volontairement
   inverse du "cover-first" precedent, pour reproduire la reference (carte
   info claire au-dessus, illustration/lueur en dessous). */
.ws-card-body { padding: 20px 20px 16px; display: flex; flex-direction: column; }
.ws-card-eyebrow {
    font-size: 12.5px; font-weight: 600; color: var(--color-text-tertiary);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    margin-bottom: 16px;
}
.ws-card-title { font-size: 24px; font-weight: 700; letter-spacing: -0.4px; color: var(--color-text); line-height: 1.15; }
[data-theme="dark"] .ws-card-title { color: #fff; }
.ws-card-status {
    font-size: 13.5px; color: var(--color-text-secondary); margin-top: 6px;
}
/* Repli sur 2 lignes avec troncature (pas 1 seule, ni illimite) + bouton
   "Voir plus" -- l'ancien white-space:nowrap coupait des descriptifs
   entiers a quelques mots (releve utilisateur sur la tagline About
   personnalisee d'un espace, souvent plus longue que "Avec X, Y"). Le
   bouton n'est affiche que si le texte deborde reellement, cf JS
   (scrollHeight > clientHeight apres rendu). */
.ws-card-status-text {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; white-space: normal;
}
.ws-card-status.expanded .ws-card-status-text {
    -webkit-line-clamp: unset; overflow: visible;
}
.ws-card-status-more {
    display: block; margin-top: 3px; padding: 0;
    background: none; border: none; cursor: pointer;
    font-family: inherit; font-size: 12px; font-weight: 700;
    color: var(--color-primary);
}
/* "display:block" ci-dessus a la meme specificite que le [hidden] par
   defaut du navigateur -- charge apres, il l'emportait et le bouton
   restait visible meme attribut hidden pose (releve utilisateur, DOM
   confirme hidden=true mais bouton visible a l'ecran). Meme piege deja
   corrige sur .info-slide-overlay -- repeter [hidden] avec la classe pour
   regagner en specificite. */
.ws-card-status-more[hidden] { display: none; }
.ws-card-status-more:hover { text-decoration: underline; }

.ws-card-cover {
    position: relative;
    min-height: 176px;
    background-size: cover;
    background-position: center;
    overflow: hidden;
}
.ws-card-cover.no-bg {
    background:
        radial-gradient(ellipse 140% 90% at 30% 15%, color-mix(in srgb, var(--ws-color, #6366F1) 42%, white) 0%, var(--ws-color, #6366F1) 45%, color-mix(in srgb, var(--ws-color, #6366F1) 65%, #000) 100%);
}
.ws-card-cover-caption {
    position: absolute; top: 14px; left: 0; right: 0;
    text-align: center; font-size: 11.5px; font-weight: 500;
    color: rgba(255,255,255,0.65);
}
.ws-card-cover-letters { position: absolute; right: 28px; top: 40px; text-align: right; }
.ws-card-cover-letter {
    display: block; color: #fff; font-weight: 700;
    font-size: calc(24px - (var(--i)) * 6px);
    opacity: calc(1 - (var(--i)) * 0.24);
    transform: rotate(calc(-8deg + (var(--i)) * 3deg));
    margin-top: calc((var(--i)) * 4px);
}

/* ---- Cartes plus hautes, et deux presentations au choix -------------
   "Fiche" (defaut) conserve l'ordre historique voulu plus haut : panneau
   de texte en haut, illustration en bas. "Immersif" fait passer l'image
   en fond de carte, le texte venant se poser dessus sur un degrade.
   Le basculement porte sur la grille, jamais sur les cartes elles-memes. */
/* min-height plutot qu'aspect-ratio : contrairement a une carte-souvenir
   (image pleine), celle-ci empile un nom, une description et un pied de
   carte. Un ratio impose rognerait une description longue ; une hauteur
   MINIMALE donne le meme gabarit sans jamais tronquer.
   463px -> 400px : les colonnes sont devenues flexibles (1fr, cf paliers
   4/5 colonnes plus haut) -- une carte bien plus large que les 340px
   d'origine gardait la meme hauteur fixe, la rendant disproportionnee
   ("ecrasee sur les cotes"). Reduit pour un ratio plus equilibre sur les
   grands ecrans large 4/5 colonnes. Demande utilisateur 2026-09-10. */
.workspaces-grid .ws-card { min-height: 400px; }
.workspaces-grid .ws-card-cover { flex: 1; }

/* Popover "Personnaliser", meme role que celui de l'accueil : le reglage
   d'apparence vit dedans plutot qu'en bascule nue dans la barre, parce que
   ce n'en est pas une -- c'est un parametre du proprietaire, applique a
   tous ceux qui voient ses espaces. */
/* Point d'entree deplace dans le menu ⋮ de la carte (modale Modal.open) --
   seul le contenu (options + miniatures + hint) reste, l'ancien popover
   ancre au bouton "Personnaliser" du header a disparu avec lui. */
.ws-personalize-opts { display: flex; gap: 8px; }
.ws-personalize-opt {
    flex: 1;
    display: flex; flex-direction: column; align-items: center; gap: 7px;
    padding: 10px 6px;
    border: 1px solid transparent;
    border-radius: 12px;
    background: var(--color-hover);
    color: var(--color-text-secondary);
    font-size: 12px; font-weight: 600; font-family: inherit;
    cursor: pointer;
    transition: color .15s, border-color .15s;
}
.ws-personalize-opt:hover { color: var(--color-text); }
.ws-personalize-opt.active {
    border-color: var(--color-primary);
    color: var(--color-text);
}
/* Apercu miniature : haut = illustration, bas = texte. En immersif le bloc
   de texte se pose sur l'illustration au lieu de lui succeder. */
.ws-personalize-thumb {
    width: 100%; height: 46px;
    border-radius: 8px;
    overflow: hidden;
    display: flex; flex-direction: column;
    background: var(--color-surface);
}
.ws-personalize-thumb i { display: block; background: var(--color-text-tertiary); opacity: .35; }
.ws-personalize-opt[data-ws-view="fiche"] .ws-personalize-thumb i:first-child { height: 16px; opacity: .18; }
.ws-personalize-opt[data-ws-view="fiche"] .ws-personalize-thumb i:last-child  { flex: 1; }
.ws-personalize-opt[data-ws-view="immersif"] .ws-personalize-thumb i:first-child { flex: 1; }
.ws-personalize-opt[data-ws-view="immersif"] .ws-personalize-thumb i:last-child  { height: 14px; opacity: .18; }
.ws-personalize-hint {
    margin: 12px 0 0;
    font-size: 11.5px; line-height: 1.45;
    color: var(--color-text-tertiary);
}

/* L'illustration passe en fond ; z-index 0 la laisse sous le menu et le
   badge non-lus, qui sont deja en z-index 2. */
.ws-card.ws-card-immersif .ws-card-cover {
    position: absolute;
    inset: 0;
    min-height: 0;
    z-index: 0;
}
/* .ws-card-body precede .ws-card-cover dans le DOM ; la couverture etant
   sortie du flux, le body reste seul enfant en flux et margin-top:auto
   suffit a le plaquer en bas. */
.ws-card.ws-card-immersif .ws-card-body {
    position: relative;
    z-index: 1;
    margin-top: auto;
    padding: 20px;
    background: linear-gradient(to top,
        rgba(0,0,0,0.80) 0%, rgba(0,0,0,0.55) 45%, rgba(0,0,0,0) 100%);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}
/* Sur une photo, le texte ne peut plus suivre le theme : il est toujours
   clair, sinon il devient illisible en theme clair sur image sombre. */
.ws-card.ws-card-immersif .ws-card-title,
[data-theme="dark"] .ws-card.ws-card-immersif .ws-card-title { color: #fff; }
.ws-card.ws-card-immersif .ws-card-eyebrow {
    color: rgba(255,255,255,0.72);
    margin-bottom: 10px;
}
.ws-card.ws-card-immersif .ws-card-status { color: rgba(255,255,255,0.88); }
/* La legende "Ouvrir l'espace" doublonnerait le titre desormais en surimpression. */
.ws-card.ws-card-immersif .ws-card-cover-caption { display: none; }

/* Badge "nouveautés" (messages non lus depuis la derniere visite) --
   coin haut-gauche pour ne jamais chevaucher .ws-card-menu (haut-droite). */
.ws-card-unread-badge {
    position: absolute;
    top: 10px; left: 10px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 6px;
    border-radius: 10px;
    background: #ef4444;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}

/* Badge organisation sur les cartes workspace */
.ws-card-org-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 10px;
    font-weight: 600;
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-primary) 22%, transparent);
    border-radius: 6px;
    padding: 2px 7px;
    margin-bottom: 10px;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Normalize <button> variants of .ws-card so the dashed "Créer un espace"
   tile inherits the same look as the <a> cards around it. */
button.ws-card { font: inherit; width: 100%; text-align: left; }
.ws-card-create {
    border: 2px dashed var(--color-border);
    background: transparent;
    align-items: center;
    justify-content: center;
    min-height: 220px;
}
.ws-card-create:hover { border-color: var(--color-primary); }
/* Tuile "dossier" d'organisation — regroupe les espaces liés à une même org
   sur /workspaces (au lieu d'une carte par espace). Accent violet cohérent
   avec le badge org existant (.ws-card-org-badge). */
.ws-card-org-folder { border-color: rgba(99,102,241,0.35); }
.ws-card-org-folder:hover { border-color: #6366F1; }
.ws-card-create-content { text-align: center; padding: 24px; }
.ws-card-create-plus {
    font-size: 38px;
    color: var(--color-primary);
    line-height: 1;
    margin-bottom: 8px;
}
.ws-card-create-title { font-size: 14px; font-weight: 700; color: var(--color-text); }
.ws-card-create-sub { font-size: 12px; color: var(--color-text-tertiary); margin-top: 2px; }

.ws-empty-tab {
    grid-column: 1 / -1;
    text-align: center;
    padding: 40px 20px;
    color: var(--color-text-tertiary);
    font-size: 14px;
}

/* Rangees de la modale "Salaries" (openStaffModal(), /workspaces) -- meme
   gabarit .ws-mem-row* que la modale "Membres" d'un Flow (showMembers(),
   public/css/workspace-view.css:4587-4598), copie ici car cette page ne
   charge pas workspace-view.css. Demande utilisateur 2026-09-11 ("cette
   modal invitation doit reprendre le même mécanisme que Flow") : la
   premiere version (liste inline .ws-staff-* + petit modal d'invitation
   separe) est remplacee par UN SEUL modal complet, cf plan
   glittery-tickling-dahl.md. */
.ws-mem-row { display:flex; align-items:center; gap:12px; padding:10px 12px; border-radius:10px; background:var(--color-bg); }
.ws-mem-row-info { flex:1; min-width:0; }
.ws-mem-row-name { font-size:14px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ws-mem-row-sub { font-size:11px; color:var(--color-text-tertiary); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.ws-mem-row-actions { display:flex; align-items:center; gap:8px; flex-shrink:0; }

/* Appartenance Flow d'un salarié (modale "Salariés", Galaxie) -- puce
   retirable par Flow + lien "+ Flow" pour en ajouter un. */
.ws-staff-flows-line { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-top:4px; min-height:18px; }
.ws-staff-flow-chip { display:inline-flex; align-items:center; gap:5px; font-size:10px; font-weight:600; padding:3px 6px 3px 9px; border-radius:8px; background:var(--color-bg); color:var(--color-text-secondary); }
.ws-staff-flow-chip button { background:none; border:none; padding:0; margin:0; cursor:pointer; color:var(--color-text-tertiary); font-size:13px; line-height:1; }
.ws-staff-flow-chip button:hover { color:var(--color-danger); }
.ws-staff-flow-add { background:none; border:none; padding:0; font-size:10px; font-weight:600; color:var(--color-primary); cursor:pointer; }

/* System quick-access cards (Mes fichiers, Corbeille) — same shape as a
   workspace card but with an icon-filled cover instead of a member photo. */
.ws-card-cover-system {
    background: linear-gradient(135deg, var(--ws-color, #6366F1), color-mix(in srgb, var(--ws-color, #6366F1) 60%, #000));
    color: rgba(255,255,255,0.95);
    display: flex; align-items: center; justify-content: center;
}
.ws-card-cover-system svg { opacity: 0.95; }

/* === Card AQIN Nuage dans /workspaces : cover bleu identité produit === */
.ws-card-cover-nuage {
    background: linear-gradient(135deg, #3B82F6 0%, #1D4ED8 100%);
    color: rgba(255,255,255,0.98);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}
.ws-card-cover-nuage svg {
    filter: drop-shadow(0 2px 6px rgba(0,0,0,0.15));
}
.ws-card.ws-card-nuage:hover {
    box-shadow: 0 6px 20px rgba(59, 130, 246, 0.25);
}

/* === Card AQIN Fort (coffre-fort) dans /workspaces : cover ambre + badge compteur === */
.ws-card-cover-vault {
    background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
    color: rgba(255, 255, 255, 0.98);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
}
.ws-card-cover-vault::after {
    /* Texture diagonale subtile pour différencier visuellement */
    content: '';
    position: absolute; inset: 0;
    background: repeating-linear-gradient(135deg,
        transparent 0,
        transparent 20px,
        rgba(255,255,255,0.04) 20px,
        rgba(255,255,255,0.04) 40px);
    pointer-events: none;
}
.ws-card-cover-vault svg {
    opacity: 0.95;
    filter: drop-shadow(0 2px 6px rgba(0,0,0,0.15));
    position: relative;
    z-index: 1;
}
/* Badge nombre de fichiers en haut-droite du cover ambre */
.ws-card-vault-badge {
    position: absolute;
    top: 12px;
    right: 12px;
    min-width: 28px;
    height: 28px;
    padding: 0 9px;
    border-radius: 14px;
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 2px 8px rgba(0,0,0,0.2);
    z-index: 2;
}
/* Pill état (verrouillé / déverrouillé) dans le footer de la card vault */
.ws-card-vault-state {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    border-radius: 999px;
    background: rgba(245, 158, 11, 0.12);
    color: #B45309;
    font-size: 11px;
    font-weight: 600;
    line-height: 1;
}
.ws-card-vault-state-unlocked {
    background: rgba(16, 185, 129, 0.12);
    color: #047857;
}
[data-theme="dark"] .ws-card-vault-state {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.18);
}
[data-theme="dark"] .ws-card-vault-state-unlocked {
    color: #6ee7b7;
    background: rgba(16, 185, 129, 0.18);
}
/* Hover : la card vault se distingue plus que les autres */
.ws-card.ws-card-vault:hover {
    box-shadow: 0 6px 20px rgba(245, 158, 11, 0.25);
}

/* Menu (⋯) en haut à droite des cartes possédées — propose Supprimer.
   Toujours visible (le hover-only était trop discret sur mobile). */
.ws-card-menu {
    position: absolute;
    top: 10px; right: 10px;
    z-index: 2;
}
.ws-card-menu-btn {
    width: 32px; height: 32px;
    border-radius: 10px;
    border: none;
    background: rgba(0, 0, 0, 0.45);
    color: #fff;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center;
    transition: background 0.15s, transform 0.15s;
}
.ws-card-menu-btn:hover,
.ws-card-menu-btn.open {
    background: rgba(0, 0, 0, 0.7);
    transform: scale(1.05);
}
.ws-card-menu-pop {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 200px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
    padding: 4px;
    display: flex; flex-direction: column; gap: 1px;
}
.ws-card-menu-pop[hidden] { display: none; }
.ws-card-menu-item {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 8px 10px;
    border: none; background: transparent;
    border-radius: 8px;
    cursor: pointer;
    color: var(--color-text);
    font-size: 13px; font-weight: 500;
    text-align: left;
    transition: background 0.12s;
}
.ws-card-menu-item:hover { background: var(--color-hover); }
.ws-card-menu-danger {
    color: var(--color-danger, #ef4444);
}
.ws-card-menu-danger:hover {
    background: rgba(239, 68, 68, 0.1);
    color: var(--color-danger, #ef4444);
}

/* All four corner tiles (hamburger left, theme + notif + avatar right) share
   the EXACT same look at every breakpoint — same size, radius, blur, border.
   The hamburger is the reference (44x44, 14px radius). The avatar's inner
   <img> stays slightly less rounded so the image fits flush inside. */
.global-corner-btn,
.global-user-avatar {
    width: 44px !important;
    height: 44px !important;
    border-radius: 14px !important;
    padding: 0 !important;
    background: color-mix(in srgb, var(--color-surface) 70%, transparent) !important;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent) !important;
    box-shadow: var(--shadow-sm);
    color: var(--color-text-secondary) !important;
    display: flex !important;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    text-decoration: none;
}
.global-corner-btn:hover,
.global-user-avatar:hover {
    background: color-mix(in srgb, var(--color-surface) 85%, transparent) !important;
    color: var(--color-text) !important;
    border-color: var(--color-primary) !important;
}
.global-corner-btn svg { width: 18px !important; height: 18px !important; }
.global-user-avatar img {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover;
    border-radius: 12px !important;
}
.global-user-corner { gap: 6px !important; top: 14px !important; right: 16px !important; }

/* Mobile: keep the SAME size and look as desktop — only the position tightens
   to the corner, like the hamburger does. Earlier mobile rules that shrunk
   these tiles to 36–38px are deliberately overridden here. */
@media (max-width: 640px) {
    .global-user-corner { top: 10px !important; right: 10px !important; gap: 4px !important; }
    .global-corner-btn,
    .global-user-avatar {
        width: 40px !important;
        height: 40px !important;
        border-radius: 12px !important;
    }
    .global-user-avatar img { border-radius: 10px !important; }
    .global-corner-btn svg { width: 16px !important; height: 16px !important; }
}

/* Home page (/) uses its own classes (.home-top-btn / .home-top-avatar) for
   the same theme + notif + avatar trio. Unify them with the global tiles
   so the entire app shares one visual language. */
.home-top-btn,
.home-top-avatar {
    width: 44px !important;
    height: 44px !important;
    border-radius: 14px !important;
    padding: 0 !important;
    background: color-mix(in srgb, var(--color-surface) 70%, transparent) !important;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent) !important;
    box-shadow: var(--shadow-sm);
    color: var(--color-text-secondary) !important;
    display: inline-flex !important;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    text-decoration: none;
    transition: background .15s, border-color .15s, color .15s, transform .15s;
}
.home-top-btn:hover,
.home-top-avatar:hover {
    background: color-mix(in srgb, var(--color-surface) 85%, transparent) !important;
    color: var(--color-text) !important;
    border-color: var(--color-primary) !important;
    transform: translateY(-1px);
}
.home-top-btn svg { width: 18px !important; height: 18px !important; }
.home-top-avatar img { width: 100% !important; height: 100% !important; object-fit: cover; border-radius: 12px !important; }
.home-top-right { gap: 6px !important; }
@media (max-width: 640px) {
    .home-top-btn,
    .home-top-avatar {
        width: 40px !important;
        height: 40px !important;
        border-radius: 12px !important;
    }
    .home-top-avatar img { border-radius: 10px !important; }
    .home-top-btn svg { width: 16px !important; height: 16px !important; }
    .home-top-right { gap: 4px !important; }
}

/* Header-actions: matching frosted look + transition for scroll-aware show/hide.
   We animate `top` rather than stacking a translateY on the existing
   translateX(-50%) — two transforms in the same property tend to fight when
   media queries override one of them, so this is the robust path. */
.header-actions {
    background: color-mix(in srgb, var(--color-surface) 70%, transparent) !important;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent) !important;
}
/* Auto-hide retiré : la classe .is-hidden était posée par App.initHeaderAutoHide
   au scroll mais le comportement était buggé (disparition intempestive dans
   les espaces). Plus de transition top/opacity ni de règle .is-hidden — la
   pill reste toujours visible désormais. */

/* Mobile: keep the breadcrumb visible right next to the hamburger so the
   user always knows what page / context they're on (Espaces / Mes fichiers
   switcher, "Corbeille", folder name, etc.). Compressed in size to share
   the row with the right-side corner tiles (notif, theme, avatar). */
@media (max-width: 640px) {
    .header > .btn-sidebar-toggle {
        top: 10px !important;
        left: 10px !important;
        width: 40px !important;
        height: 40px !important;
    }
    .header > .breadcrumb,
    .no-sidebar-layout .header:not(.ws-page-header) > .breadcrumb {
        top: 10px !important;
        left: 58px !important;
        height: 40px;
        padding: 0 12px;
        font-size: 13px;
        max-width: calc(100vw - 180px);
    }
    .header > .breadcrumb.context-switcher {
        padding: 3px;
    }
    .header > .breadcrumb.context-switcher::before {
        top: 3px;
        bottom: 3px;
    }
    .header > .breadcrumb .ctx-tab {
        padding: 0 10px;
        height: 34px;
        font-size: 12px;
    }
}

/* Workspace pages have their own title block (.ws-top-title) inside the
   .ws-page-header. The base CSS positions it absolute relative to that
   header (which is now 0px tall), so we re-anchor it as a floating frosted
   pill next to the hamburger, mirroring the breadcrumb on other pages. */
/* Le titre de l'espace n'est plus une pastille autonome : il est devenu
   l'onglet actif du context-switcher "Galaxie › <espace>", exactement comme
   "Scribe" l'est de "Nuage › Scribe". Le fond givre, la position flottante
   et le pill glissant viennent desormais du conteneur .breadcrumb, donc plus
   rien a redefinir ici -- mais les !important restent necessaires : les
   regles absolues d'origine vivent dans un <style> inline de
   workspace-view.php, donc apres cette feuille dans la cascade. */
.ws-top-title {
    position: static !important;
    transform: none !important;
    height: 36px;
    padding: 0 12px !important;
    border-radius: 10px !important;
    background: transparent !important;
    border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent) !important;
    box-shadow: var(--shadow-sm);
    /* Constrain so the pill never collides with the centered .header-actions
       (which on workspace pages extends ~280px each side from 50%) or the
       right user corner (~180px). 50vw - 360 leaves a clean ~30px gap. */
    min-width: 0;
    max-width: 100% !important;
    overflow: visible;  /* let the settings menu dropdown escape */
    z-index: 60;        /* above .header-actions (40) so the gear stays clickable */
}
/* Le titre de l'espace est un onglet du switcher : il doit adopter la
   typographie des autres onglets (13px/600), pas celle d'un titre de page.
   En 16px/700 il elargissait la pastille jusqu'a la faire deborder sous les
   noms longs. Selecteur par id : les regles d'origine vivent dans un <style>
   inline de workspace-view.php, donc apres cette feuille dans la cascade --
   seule une specificite superieure les emporte, l'ordre ne suffit pas. */
#ws-ctx .ws-top-title-main {
    font-size: 13px;
    font-weight: 600;
}
#ws-ctx .ws-top-title-sub { font-size: 11px; }

/* Plafond de largeur : sans lui, un nom d'espace long etirait la pastille
   jusqu'a percuter la pilule d'actions centree, qui deborde d'environ 280px
   de part et d'autre du milieu. La pastille demarrant a left:70, il lui
   reste 50vw - 370. Uniquement au-dessus de 1100px : en dessous la pilule
   centree n'est plus la, et une regle existante borne deja le titre a 240px
   -- la meme formule y donnerait une valeur negative. */
@media (min-width: 1101px) {
    #ws-ctx { max-width: calc(50vw - 370px); }
}

/* Bascule entre espaces + identite "entreprise proprietaire", DANS
   .header-actions (un seul bouton pour toutes les largeurs, plus de
   pastille fixe separee sur desktop) -- demande utilisateur 2026-09-10
   ("deplacer comme sur mobile le bouton selection") : un ancrage unique
   qui suit .header-actions dans ses deux positions (pill centree en haut
   >=1024px, pill scrollable en bas en dessous), plutot que deux elements
   distincts a synchroniser. Le bouton reutilise .ws-quick-action-btn (les
   autres boutons de la pill) pour un rendu visuel identique a ses voisins
   ("Fil de l'espace"/"Contact") -- seul le libelle (.ws-org-switch-label)
   se revele a partir de 1101px, l'icone seule suffit en dessous (pill
   compacte). Toujours affiche meme sans autre Flow (identite, pas QUE un
   switcher) ; le chevron + popover de bascule ne s'ajoutent que si
   $hasOtherWorkspaces (rien a lister sinon). */
.ws-org-switch-btn-static { cursor: default; }
.ws-org-switch-label { display: none; }
.ws-org-switch-chevron { flex-shrink: 0; opacity: .7; transition: transform .2s ease; }
.ws-org-switch .ws-quick-action-btn[aria-expanded="true"] { background: var(--color-hover); color: var(--color-text); }
.ws-org-switch .ws-quick-action-btn[aria-expanded="true"] .ws-org-switch-chevron { transform: rotate(180deg); }
@media (min-width: 1101px) {
    /* Specificite : .ws-quick-action-btn:not(.active) > span est a
       (0,2,1) avec !important (cf plus haut dans ce fichier, systeme
       d'onglets Fil de l'espace/Agenda) -- le bouton switcher n'est
       jamais .active (ce n'est pas un onglet de mode), donc cette regle
       masquait le libelle malgre display:inline-block ci-dessous.
       .ws-org-switch span.ws-org-switch-label egale sa specificite
       (0,2,1) et vient apres dans la cascade -> l'emporte. Trouve en
       direct, 2026-09-10 (libelle jamais revele malgre matchMedia=true). */
    .ws-org-switch span.ws-org-switch-label {
        display: inline-block !important;
        max-width: 160px;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    /* Meme systeme de specificite que ci-dessus : .ws-quick-action-btn:
       not(.active) force gap:0/padding compact en !important -- sans
       ecraser ces trois-la aussi, le libelle desormais visible collerait
       contre l'icone. */
    .ws-org-switch .ws-quick-action-btn {
        gap: 6px !important;
        padding-left: 12px !important;
        padding-right: 12px !important;
    }
}
/* Popover de bascule -- reparente vers <body> et positionne en JS
   (WS._initOneWorkspaceSwitcher, workspace-view.js) plutot qu'ancre en
   CSS : le bouton vit dans .header-actions, qui a overflow-x:auto sous
   1024px (cf plus bas) -- tout descendant absolute/fixed y restait piege
   dans le clip de la pastille (meme piege deja corrige sur le menu
   "Importer", cf initUploadDropdown()). Une position calculee au clic
   depuis getBoundingClientRect() fonctionne quelle que soit la largeur
   d'ecran, donc plus besoin d'ancrage CSS differencie. */
.ws-switch-pop {
    min-width: 210px;
    max-width: 320px;
    padding: 6px;
    border-radius: 14px;
    background: var(--color-surface);
    box-shadow: 0 16px 40px rgba(0,0,0,0.28);
    z-index: 1000;
}
.ws-switch-pop[hidden] { display: none; }
.ws-switch-item {
    display: block;
    padding: 9px 12px;
    border-radius: 9px;
    font-size: 13px; font-weight: 600;
    color: var(--color-text-secondary);
    text-decoration: none;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ws-switch-item:hover { background: var(--color-hover); color: var(--color-text); text-decoration: none; }
.ws-switch-item.active { color: var(--color-text); background: var(--color-hover); }
.ws-switch-empty {
    padding: 10px 12px;
    font-size: 12.5px;
    color: var(--color-text-tertiary);
}

#ws-ctx { overflow: visible !important; }
.ws-top-title-text { min-width: 0; flex: 1; overflow: hidden; }
.ws-top-title-main, .ws-top-title-sub {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Subtitle hidden on all sizes — it tends to overflow into the actions pill
   and the user already knows which workspace they're in (the main title is
   right there). Available again on very large screens if there's room. */
.ws-top-title-sub { display: none !important; }
@media (min-width: 1600px) {
    .ws-top-title-sub { display: block !important; }
}
@media (max-width: 1100px) {
    .ws-top-title {
        max-width: 240px !important;
    }
}
@media (max-width: 640px) {
    .ws-top-title {
        top: 10px !important;
        left: 60px !important;
        height: 40px;
        max-width: calc(100vw - 110px) !important;
    }
}

/* Workspace : barre de sélection du bas retirée (harmonisé avec Nuage —
   les actions multi-sélection passent par le menu contextuel / header). */
#ws-batch-bar { display: none !important; }

/* Workspace header — keep only the "Importer" toggle buttons icon-only to
   save space. The "Nouveau dossier" entries now live inside the dropdown
   menus, so they must keep their text label. */
.ws-page-header #ws-upload-toggle-btn,
.ws-page-header #ws-inline-upload-btn {
    font-size: 0 !important;
    padding: 8px 10px !important;
    gap: 4px !important;
}
.ws-page-header #ws-upload-toggle-btn svg,
.ws-page-header #ws-inline-upload-btn svg {
    width: 16px !important;
    height: 16px !important;
    display: inline-block !important;
    vertical-align: middle;
}

/* Mobile uniquement : on garde le padding-bottom pour que le dernier élément
   ne soit pas masqué par la pill flottante .header-actions (ancrée en bas).
   Le padding-top desktop a été retiré (les pills flottantes top n'ont plus
   besoin d'espace réservé dans le flux). En mobile, .app-no-sidebar n'a pas
   non plus besoin du padding-top (la règle parente .main-body sinon le
   réintroduit via la cascade). */
@media (max-width: 640px) {
    .app .main-body,
    .app-no-sidebar .main-body {
        padding-bottom: calc(72px + env(safe-area-inset-bottom, 0px)) !important;
    }
    .app-no-sidebar .main-body {
        padding-top: 0 !important;
    }
}

.onb-skip {
    position: absolute;
    top: 14px; right: 16px;
    background: transparent;
    border: none;
    color: var(--onb-muted);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    padding: 6px 10px;
    border-radius: 8px;
    transition: all 0.15s;
}
.onb-skip:hover {
    background: var(--color-bg);
    color: var(--color-text);
}

/* Pas de barre de progression (retiree 2026-10-03) : les points en bas disent deja ou on en est. */

/* Texte pour lecteurs d'ecran seulement : « Etape 2 sur 5 », annonce a chaque changement d'etape. */
.onb-sr {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.onb-icon {
    font-size: 56px;
    line-height: 1;
    margin-bottom: 20px;
    animation: onbWave 0.6s ease-out 0.2s both;
}
@keyframes onbWave {
    0% { transform: scale(0.5) rotate(-10deg); opacity: 0; }
    60% { transform: scale(1.12) rotate(8deg); }
    100% { transform: scale(1) rotate(0); opacity: 1; }
}

.onb-title {
    font-size: 22px;
    font-weight: 800;
    color: var(--color-text);
    margin: 0 0 12px;
    letter-spacing: -0.02em;
}
.onb-body {
    font-size: 14px;
    line-height: 1.6;
    color: var(--onb-muted);
    margin: 0 0 20px;
}
.onb-body strong { color: var(--color-text); font-weight: 700; }

.onb-link {
    display: inline-block;
    color: var(--onb-link);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    padding: 8px 14px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    margin-bottom: 20px;
    transition: background 0.15s;
}
.onb-link:hover {
    background: color-mix(in srgb, var(--color-primary) 14%, transparent);
    text-decoration: none;
}

/* Pied : boutons + points. COLLANT en bas de la boite : quand elle defile (telephone en paysage, zoom, texte long) le bouton
   principal ne sort jamais de l'ecran. Au repos, rien ne change (meme espace sous les points qu'avant : 28 px). */
.onb-footer {
    position: sticky;
    bottom: 0;
    background: var(--color-surface);
    padding: 6px 0 28px;
}
.onb-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: center;
    margin-bottom: 20px;
}
.onb-btn {
    padding: 12px 24px;
    border-radius: 12px;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    border: none;
    transition: transform 0.15s, background 0.15s;
}
.onb-btn-primary {
    background: var(--onb-action);
    color: white;
    min-width: 140px;
}
.onb-btn-primary:hover {
    background: var(--onb-action-hover);
    transform: translateY(-1px);
}
.onb-btn-ghost {
    background: transparent;
    color: var(--onb-muted);
    border: 1px solid var(--color-border);
}
.onb-btn-ghost:hover {
    background: var(--color-bg);
    color: var(--color-text);
}

.onb-steps {
    display: flex;
    gap: 8px;
    justify-content: center;
}
.onb-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-text) 28%, var(--color-surface));
    transition: all 0.3s ease;
}
.onb-dot.done { background: var(--color-primary); opacity: 0.5; }
.onb-dot.active {
    background: var(--color-primary);
    width: 24px;
    border-radius: 4px;
}

/* La boite ne depasse jamais l'ecran (telephone en paysage, texte long, clavier) : elle defile au lieu d'etre coupee. */
.onb-card {
    max-height: calc(100vh - 48px);
    max-height: calc(100dvh - 48px);
    overflow-y: auto;
    overscroll-behavior: contain;
    /* CONTRASTE (WCAG AA, 4.5:1 pour du texte de cette taille), mesure le 2026-10-03 : sur le blanc, le texte courant
       --color-text-secondary donnait 3,6:1, « Passer » (tertiary) 2,2:1, le blanc sur --color-primary 4,0:1, le lien bleu
       sur sa teinte 3,5:1. Ces quatre valeurs sont CALCULEES a partir des jetons du theme : elles suivent le clair et le
       sombre (le melange va vers le noir en clair, vers le blanc en sombre) sans second jeu de couleurs. Portee : la boite
       du tour seulement, aucun jeton global touche. */
    --onb-muted: color-mix(in srgb, var(--color-text) 68%, var(--color-surface));
    --onb-action: color-mix(in srgb, var(--color-primary) 80%, #000);
    --onb-action-hover: color-mix(in srgb, var(--color-primary) 66%, #000);
    --onb-link: color-mix(in srgb, var(--color-primary) 78%, var(--color-text));
}
.onb-card:focus { outline: none; }

@media (max-width: 480px) {
    .onb-overlay { padding: 16px; }
    .onb-card {
        padding: 28px 22px 0;
        border-radius: 20px;
        max-height: calc(100vh - 32px);
        max-height: calc(100dvh - 32px);
    }
    .onb-icon { font-size: 44px; margin-bottom: 14px; }
    .onb-title { font-size: 19px; }
    .onb-body { font-size: 14px; }                     /* 14 px mini : sous 16 px iOS zoome seulement les champs, pas le texte */
    .onb-btn { padding: 11px 18px; font-size: 14px; min-height: 44px; }   /* cible tactile >= 44 px */
    .onb-skip { padding: 10px 12px; font-size: 13px; min-height: 44px; min-width: 44px; top: 8px; right: 10px; }   /* cible tactile >= 44 px */
    .onb-link { padding: 11px 16px; min-height: 44px; display: inline-flex; align-items: center; }
    .onb-footer { padding-bottom: 22px; }
}

/* Ecran tres etroit (zoom 200 % sur telephone : ~195 px) : les boutons s'empilent au lieu de deborder. */
@media (max-width: 340px) {
    .onb-card { padding-left: 14px; padding-right: 14px; }
    .onb-actions { flex-direction: column-reverse; align-items: stretch; }
    .onb-btn-primary { min-width: 0; }
}

/* Ecran BAS (telephone en paysage, fenetre ecrasee) : la boite se compacte (plus d'icone, textes resserres) ; si elle defile
   quand meme, le pied collant garde « Suivant » a l'ecran. */
@media (max-height: 560px) {
    .onb-card { padding-top: 22px; }
    .onb-icon { display: none; }
    .onb-title { font-size: 18px; margin-bottom: 8px; }
    .onb-body { font-size: 13.5px; line-height: 1.5; margin-bottom: 12px; }
    .onb-link { margin-bottom: 12px; }
    .onb-actions { margin-bottom: 12px; }
    .onb-footer { padding-bottom: 14px; }
    .onb-skip { top: 8px; }
}

@media (prefers-reduced-motion: reduce) {
    .onb-overlay, .onb-card, .onb-icon, .onb-dot, .onb-btn { animation: none !important; transition: none !important; }
}

/* ==============================================================
   ACCESSIBILITY — focus rings via :focus-visible
   Only show the ring when navigating with the keyboard, never on
   click — uses :focus-visible which mouse users don't trigger.
   ============================================================== */

/* Reset old browser default outline; we manage focus uniformly */
*:focus { outline: none; }

/* Generic ring for any interactive element reached by keyboard */
button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 6px;
    transition: outline-offset 0.12s ease;
}

/* Inputs: use only a soft glow (no hard outline). Cancels the generic rule above. */
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
.tag-picker-input:focus-visible {
    outline: none !important;
    outline-offset: 0;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 22%, transparent);
}

/* The search overlay already has its own elevated look — kill any extra ring on
   the input inside, and remove the dotted ring on the wrapping div too. */
.header > .search-bar.mobile-active:focus-visible,
.header > .search-bar.mobile-active input:focus-visible {
    outline: none !important;
    box-shadow: none !important;
}

/* Fichier mis en évidence à l'arrivée (« Ouvrir l'emplacement du fichier » de Scribe, ?highlight=<id>, public/js/revealFile.js) : le même
   anneau que le focus clavier ci-dessous. SEULEMENT box-shadow : la pulsation d'arrivée est faite en JS (API d'animation), car la propriété
   CSS animation de ces cartes porte déjà leur animation d'entrée (fadeInUp, opacity:0) -- la remplacer les rendait invisibles.
   Retiré au premier clic / à la première touche. */
.file-card.loc-highlight,
.file-list-row.loc-highlight,
.ws-list-row.loc-highlight {
    box-shadow: 0 0 0 2px var(--color-primary), 0 0 0 5px color-mix(in srgb, var(--color-primary) 22%, transparent);
}

/* Cards (file cards, request cards, plan cards…) — inset ring so card edges
   stay clean and shadow doesn't compete with the border-radius */
.file-card:focus-visible,
.file-list-row:focus-visible,
.search-result:focus-visible,
.req-card:focus-visible,
.pres-tpl:focus-visible,
.ckpt-feed-item:focus-visible,
.ckpt-file-row:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-primary), 0 0 0 5px color-mix(in srgb, var(--color-primary) 18%, transparent);
}

/* Tag chips, ws cards, app launcher items: subtle glow */
.tag-chip:focus-visible,
.tag-add-btn:focus-visible,
.tag-picker-item:focus-visible,
.ckpt-tag-chip:focus-visible,
.app-launcher-item:focus-visible,
.btn-icon:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-primary), 0 0 0 5px color-mix(in srgb, var(--color-primary) 20%, transparent);
}

/* Modal close button — keep ring inside the modal padding */
.modal-close:focus-visible,
.fislide-mode-btn:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

/* === Document scan editor — full-screen overlay with 4 draggable corners === */
.scan-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.92);
    z-index: 9999;
    display: flex;
    flex-direction: column;
}
.scan-overlay-bar {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 14px;
    /* PWA standalone iOS : la barre (donc le bouton "Enregistrer en PDF")
       se retrouvait sous l'encoche/la status bar -- invisible bien que
       techniquement présente. Même correctif que .qrscan-header. */
    padding-top: max(10px, env(safe-area-inset-top, 0px));
    background: rgba(0,0,0,0.6);
    backdrop-filter: blur(12px);
    color: #fff;
    flex-shrink: 0;
}
.scan-overlay-title { font-size: 13px; font-weight: 700; }
.scan-overlay-spacer { flex: 1; }
.scan-toggle {
    display: inline-flex; align-items: center; gap: 6px;
    color: #fff; font-size: 12px; cursor: pointer;
    user-select: none;
}
.scan-toggle input { accent-color: #3b82f6; cursor: pointer; }
.scan-btn-secondary, .scan-btn-primary {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 7px 14px;
    border: none; border-radius: 999px;
    cursor: pointer;
    font-size: 12px; font-weight: 700;
    transition: background .12s;
}
.scan-btn-secondary { background: rgba(255,255,255,0.1); color: #fff; }
.scan-btn-secondary:hover { background: rgba(255,255,255,0.18); }
.scan-btn-primary { background: #3b82f6; color: #fff; }
.scan-btn-primary:hover:not(:disabled) { background: #2563eb; }
.scan-btn-primary:disabled { opacity: 0.6; cursor: wait; }

.scan-canvas-wrap {
    flex: 1;
    position: relative;
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
}
.scan-canvas-wrap canvas {
    display: block;
    background: #fff;
    box-shadow: 0 10px 40px rgba(0,0,0,0.5);
    max-width: 100%; max-height: 100%;
}
.scan-overlay-svg {
    position: absolute;
    pointer-events: none;
    overflow: visible;
}
.scan-handle {
    position: absolute;
    width: 28px; height: 28px;
    border-radius: 50%;
    background: rgba(59,130,246,0.95);
    border: 3px solid #fff;
    box-shadow: 0 4px 14px rgba(0,0,0,0.5);
    transform: translate(-50%, -50%);
    cursor: grab;
    touch-action: none;
    z-index: 5;
}
.scan-handle:active { cursor: grabbing; transform: translate(-50%, -50%) scale(1.2); }
/* Loupe affichée au-dessus du doigt pendant le drag d'un coin (au toucher
   seulement) -- le doigt cache sinon le point exact qu'on essaie
   d'aligner sur l'angle du document. left/top = son CENTRE (translate
   -50%/-50%), positionnés par updateLoupe() dans scanEditor.js. */
.scan-loupe {
    position: absolute;
    width: 140px; height: 140px;
    border-radius: 50%;
    border: 3px solid #fff;
    box-shadow: 0 6px 20px rgba(0,0,0,0.55);
    overflow: hidden;
    pointer-events: none;
    transform: translate(-50%, -50%);
    background: #000;
    z-index: 8;
}
.scan-loupe canvas { display: block; width: 100%; height: 100%; }
.scan-hint {
    padding: 10px 16px;
    padding-bottom: max(10px, env(safe-area-inset-bottom, 0px));
    background: rgba(0,0,0,0.6);
    color: rgba(255,255,255,0.85);
    font-size: 11px;
    text-align: center;
    flex-shrink: 0;
}
@media (max-width: 640px) {
    /* padding-top explicite : le raccourci "padding" ci-dessous, plus bas
       dans la cascade que la regle de base .scan-overlay-bar, ecrasait
       silencieusement le padding-top: max(...,env(safe-area-inset-top))
       -- juste sur les largeurs mobiles ou l'encoche existe reellement,
       annulant le correctif (bouton "Enregistrer en PDF" de nouveau sous
       la status bar/encoche, constate en direct). */
    .scan-overlay-bar {
        flex-wrap: wrap; gap: 6px; padding: 8px 10px;
        padding-top: max(8px, env(safe-area-inset-top, 0px));
    }
    .scan-overlay-title { width: 100%; }
    .scan-handle { width: 32px; height: 32px; }
}

/* === Force header-actions to bottom on mobile/tablet (placed last to win
   cascade). Threshold raised 640->1024 : cf. commentaire plus haut sur la
   collision avec #breadcrumb (z-index 55) qui passe devant le pill entre
   ~768px et ~1000px de large. === */
@media (max-width: 1024px) {
    body .header-actions,
    .no-sidebar-layout .header-actions,
    .ws-page-header .header-actions {
        top: auto !important;
        bottom: calc(12px + env(safe-area-inset-bottom, 0px)) !important;
        /* Drop the transform-based centering. A `transform` on an ancestor
           makes it the containing block for any `position: fixed` descendant
           — that traps the dropdown menu inside the bar's overflow clip. */
        left: 0 !important;
        right: 0 !important;
        transform: none !important;
        margin-inline: auto;
        width: max-content;
        max-width: calc(100vw - 24px);
        overflow-x: auto;
    }
    body .header-actions::-webkit-scrollbar,
    .ws-page-header .header-actions::-webkit-scrollbar { display: none; }

    /* Mobile : la pill `.header-actions` est flippée en bas (cf. règle
       `@media (max-width: 1024px) { .header-actions { bottom: ... } }`).
       Le dropdown doit donc s'OUVRIR VERS LE HAUT depuis cette pill, sinon
       il se retrouve calé en haut de l'écran loin du bouton qui l'a déclenché.
       On ancre par `bottom` (44+4+4 hauteur pill + 12 safe-area + 8 gap = 72px)
       et `top:auto`. Le dropdown est reparented au <body> par initUploadDropdown
       côté JS, donc on échappe les transforms/overflow des ancêtres.
       body > #ws-upload-menu : copie du menu "Importer" propre a l'espace
       de travail (workspace-view.js, meme reparentage porte depuis cette
       version globale) -- restait invisible en tablette (769-1024px),
       piege dans l'overflow-x:auto de son ancetre .header-actions. */
    body > #upload-dropdown-menu,
    body > #ws-upload-menu,
    .header-actions .sort-dropdown-menu {
        position: fixed !important;
        top: auto !important;
        bottom: calc(72px + env(safe-area-inset-bottom, 0px)) !important;
        left: 50% !important;
        right: auto !important;
        transform: translateX(-50%) !important;
        width: calc(100vw - 32px) !important;
        max-width: 320px !important;
        max-height: 70vh !important;
        overflow-y: auto !important;
        min-width: 0 !important;
        padding: 8px !important;
    }
}

/* =========================================================================
   COFFRE-FORT (Vault) — couleur ambre, badge cadenas, modale unlock/setup
   ========================================================================= */

/* Folder ambre quand is_vault=1 (la couleur est passée via --folder-color
   inline depuis renderGrid pour ne pas dupliquer la palette). */
.file-card.is-vault .folder-card-icon {
    background: rgba(245, 158, 11, 0.10);
}
.file-card.is-vault:hover .folder-card-icon {
    background: rgba(245, 158, 11, 0.18);
}
.file-card.is-vault .folder-card-icon svg {
    filter: drop-shadow(0 2px 6px rgba(245, 158, 11, 0.35));
}

/* Cadenas overlay en haut-à-droite du folder du coffre */
.folder-card-icon { position: relative; }
.folder-lock-badge {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: #F59E0B;
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 6px rgba(245, 158, 11, 0.35);
    z-index: 2;
}

.folder-lock-badge.unlocked {
    background: #10b981;
    box-shadow: 0 2px 6px rgba(16, 185, 129, 0.35);
}

/* Liste : badge inline à côté du nom du dossier vault */
.file-list-row.is-vault .file-list-name::after {
    content: '🔒';
    margin-left: 8px;
    font-size: 12px;
    opacity: 0.7;
}

/* Indicateur discret "contenu du coffre" pour tout fichier/sous-dossier
   is_vault=1 une fois DÉJÀ à l'intérieur du coffre (pas la racine, qui a
   son propre badge amber proéminent ci-dessus) — confirme visuellement
   le chiffrement sans redondance avec la racine (signalé 2026-08-06). */
.file-card { position: relative; }
.file-card-vault-dot {
    position: absolute;
    bottom: 6px;
    right: 8px;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: rgba(245, 158, 11, 0.16);
    color: #F59E0B;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 2;
    pointer-events: none;
}
.file-list-row.is-vault-item .file-list-name::after {
    content: '🔒';
    margin-left: 6px;
    font-size: 10px;
    opacity: 0.45;
}

/* Indicateur "commentaires ouverts" -- contrairement au point Coffre-fort
   ci-dessus (décoratif), celui-ci est un vrai bouton : clic ouvre le
   panneau Info directement sur l'onglet Commentaires (signalé 2026-08-06 :
   aucun indice visuel avant, fallait passer par le menu contextuel). */
.file-card-comment-badge {
    position: absolute;
    bottom: 8px;
    right: 8px;
    display: flex;
    align-items: center;
    gap: 4px;
    height: 24px;
    padding: 0 9px 0 8px;
    border-radius: var(--radius-full);
    border: none;
    background: var(--color-primary-light, rgba(0,122,255,0.15));
    color: var(--color-primary);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    z-index: 2;
    transition: background var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
}
.file-card-comment-badge:hover {
    background: var(--color-primary);
    color: #fff;
    transform: scale(1.06);
}
.file-card-comment-badge svg { flex-shrink: 0; width: 13px; height: 13px; }

/* Variante vue liste -- pastille inline à côté du nom, même famille que
   .flr-star (voir plus haut dans ce fichier). */
.flr-comment-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 16px;
    padding: 0 5px 0 4px;
    border-radius: var(--radius-full);
    border: none;
    background: var(--color-primary-light, rgba(0,122,255,0.15));
    color: var(--color-primary);
    font-size: 9px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--transition-fast), color var(--transition-fast);
}
.flr-comment-badge:hover { background: var(--color-primary); color: #fff; }
.flr-comment-badge svg { flex-shrink: 0; }

/* =====================================================================
   AQIN Nébuleuse — Dossiers système (rose, icône thématique centrée +
   badge "Système"). Visible dans /files pour distinguer immédiatement
   AQIN Nébuleuse, Photothèque, Collections des dossiers utilisateur.
   ===================================================================== */
.file-card.is-nebula-system .folder-card-icon { position: relative; }

/* Icône thématique au centre du dossier (nebula / camera / albums) */
.folder-sys-icon {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%, -42%);
    width: 30px; height: 30px;
    color: var(--folder-color, #ec4899);
    pointer-events: none;
    filter: drop-shadow(0 1px 3px color-mix(in srgb, var(--folder-color, #ec4899) 35%, transparent));
}

/* Petit badge "Système" en haut-droite */
.folder-sys-badge {
    position: absolute;
    top: 8px; right: 8px;
    padding: 2px 8px;
    background: linear-gradient(135deg, #ec4899 0%, #db2777 100%);
    color: #fff;
    border-radius: 999px;
    font-size: 9px;
    font-weight: 600;
    letter-spacing: 0.4px;
    text-transform: uppercase;
    box-shadow: 0 2px 6px rgba(236, 72, 153, 0.4);
    z-index: 2;
    pointer-events: none;
}
/* Masquer badge SYSTÈME sur TOUTES les cartes de la section Espaces AQIN */
#nss-grid .file-card .folder-sys-badge {
    display: none !important;
}

/* Liste : badge inline à côté du nom des dossiers Nébuleuse */
.file-list-row.is-nebula-system .file-list-name::after {
    content: '✨';
    margin-left: 8px;
    font-size: 11px;
    opacity: 0.75;
}

/* Subtle pink glow au hover pour renforcer l'identité visuelle */
.file-card.is-nebula-system:hover {
    border-color: rgba(236, 72, 153, 0.35) !important;
    box-shadow:
        0 14px 32px rgba(0, 0, 0, 0.18),
        0 4px 12px rgba(236, 72, 153, 0.15) !important;
}

/* =====================================================================
   Album folder cards (.file-card.nebula-album-card)
   Rendu "polaroïd frame" pour les dossiers sous Collections, visibles
   depuis /files. Mosaïque des 4 premières photos en couverture,
   footer avatar + nom + nombre. Importé depuis templates/nebuleuse/albums.php
   pour être disponible globalement (notamment dans /files).
   ===================================================================== */
.file-card.nebula-album-card {
    background: linear-gradient(180deg,
        rgba(40, 40, 48, 0.6) 0%,
        rgba(26, 26, 31, 0.95) 100%);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 20px;
    padding: 14px;
    overflow: visible;
    box-shadow:
        0 4px 12px rgba(0, 0, 0, 0.22),
        0 1px 2px rgba(0, 0, 0, 0.18);
}
[data-theme="light"] .file-card.nebula-album-card {
    background: linear-gradient(180deg, #ffffff 0%, #faf7f3 100%);
    border-color: rgba(0, 0, 0, 0.06);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.05);
}
.file-card.nebula-album-card:hover {
    border-color: rgba(236, 72, 153, 0.35) !important;
    box-shadow:
        0 18px 40px rgba(0, 0, 0, 0.32),
        0 6px 18px rgba(236, 72, 153, 0.18) !important;
}

/* Frame (zone photo inset) */
.file-card.nebula-album-card .nebula-album-frame {
    position: relative;
    aspect-ratio: 4/3;
    border-radius: 14px;
    overflow: visible;
    background: rgba(0, 0, 0, 0.15);
    margin: 0;
}
.file-card.nebula-album-card .nebula-album-frame.is-empty {
    background: linear-gradient(135deg,
        rgba(236, 72, 153, 0.06) 0%,
        rgba(168, 85, 247, 0.04) 100%);
}
.file-card.nebula-album-card .nebula-album-photo {
    object-fit: cover;
    transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
}
.file-card.nebula-album-card .nebula-album-photo-single {
    width: 100%; height: 100%;
    border-radius: 14px;
    display: block;
}
.file-card.nebula-album-card:hover .nebula-album-photo-single { transform: scale(1.04); }

/* Mosaïque playful 1 main + 2 sub rotated */
.file-card.nebula-album-card .nebula-album-mosaic-v2 {
    position: relative;
    width: 100%; height: 100%;
}
.file-card.nebula-album-card .nebula-album-photo-main {
    position: absolute;
    top: 0; left: 0;
    width: 70%; height: 100%;
    border-radius: 14px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
    z-index: 1;
}
.file-card.nebula-album-card .nebula-album-photo-sub {
    position: absolute;
    width: 42%; height: 52%;
    border-radius: 12px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
    border: 2px solid var(--color-surface, #1a1a1f);
    z-index: 2;
}
[data-theme="light"] .file-card.nebula-album-card .nebula-album-photo-sub { border-color: #faf7f3; }
.file-card.nebula-album-card .nebula-album-photo-sub-1 {
    top: 8%; right: 4%;
    transform: rotate(3deg);
}
.file-card.nebula-album-card .nebula-album-photo-sub-2 {
    bottom: 4%; right: 8%;
    transform: rotate(-4deg);
}
.file-card.nebula-album-card:hover .nebula-album-photo-main { transform: scale(1.02); }
.file-card.nebula-album-card:hover .nebula-album-photo-sub-1 { transform: rotate(5deg) translateY(-2px); }
.file-card.nebula-album-card:hover .nebula-album-photo-sub-2 { transform: rotate(-6deg) translateY(2px); }

/* Empty state */
.file-card.nebula-album-card .nebula-album-empty-illu {
    width: 100%; height: 100%;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    gap: 8px;
    color: rgba(236, 72, 153, 0.55);
}
.file-card.nebula-album-card .nebula-album-empty-illu svg { width: 44px; height: 44px; opacity: 0.7; }
.file-card.nebula-album-card .nebula-album-empty-illu span {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    opacity: 0.6;
}

/* Footer (avatar + meta) */
.file-card.nebula-album-card .nebula-album-footer {
    display: flex; align-items: center; gap: 10px;
    margin-top: 14px;
    padding: 0 2px 2px;
}
.file-card.nebula-album-card .nebula-album-avatar {
    width: 30px; height: 30px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background: rgba(236, 72, 153, 0.12);
    display: flex; align-items: center; justify-content: center;
    color: #f472b6;
    border: 1px solid rgba(255, 255, 255, 0.08);
}
.file-card.nebula-album-card .nebula-album-avatar img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
}
.file-card.nebula-album-card .nebula-album-meta {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column; gap: 1px;
    text-align: left;
}
.file-card.nebula-album-card .nebula-album-meta strong {
    font-size: 14px; font-weight: 600;
    color: var(--color-text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    line-height: 1.25;
    text-align: left;
}
.file-card.nebula-album-card .nebula-album-meta span {
    font-size: 11.5px;
    color: var(--color-text-muted);
    line-height: 1.3;
    text-align: left;
}

/* Sur /files, on cache le file-card-name natif (le footer.meta affiche déjà le nom) */
.file-card.nebula-album-card > .file-card-name,
.file-card.nebula-album-card > .file-card-meta,
.file-card.nebula-album-card > .folder-card-icon { display: none; }

/* Mobile : 2 cols comme les vraies album cards */
@media (max-width: 600px) {
    .file-card.nebula-album-card {
        padding: 8px !important;
        border-radius: 14px !important;
    }
    .file-card.nebula-album-card .nebula-album-frame { border-radius: 10px !important; }
    .file-card.nebula-album-card .nebula-album-photo-single,
    .file-card.nebula-album-card .nebula-album-photo-main { border-radius: 10px !important; }
    .file-card.nebula-album-card .nebula-album-footer { margin-top: 8px !important; gap: 7px !important; }
    .file-card.nebula-album-card .nebula-album-avatar { width: 24px !important; height: 24px !important; }
    .file-card.nebula-album-card .nebula-album-meta strong { font-size: 12px !important; }
    .file-card.nebula-album-card .nebula-album-meta span { font-size: 10px !important; }
    .file-card.nebula-album-card .nebula-album-photo-sub { width: 38% !important; height: 48% !important; }
    /* La carte Souvenir n'a pas de mosaique a proteger par un cadre : ce
       padding est pense pour les vraies cartes album, pas pour elle -- sans
       ce contournement, il revenait sur mobile avec le meme !important
       (retour utilisateur 2026-08-29, "sur mobile oui il y a des bords"). */
    .file-card.nebula-memory-card { padding: 0 !important; }
}

/* Mobile : badge "Système" plus compact + icône centrée recalibrée */
@media (max-width: 768px) {
    .folder-sys-badge {
        padding: 1px 6px;
        font-size: 8px;
        top: 6px; right: 6px;
    }
    .folder-sys-icon {
        width: 22px; height: 22px;
    }
}

/* Modale Coffre-fort — setup PIN + unlock */
.vault-modal-intro {
    text-align: center;
    margin: 0 0 18px;
}
.vault-modal-intro h4 {
    margin: 8px 0 4px;
    font-size: 18px;
    font-weight: 700;
    color: var(--color-text-primary, #0f172a);
}
.vault-modal-intro p {
    margin: 0 16px;
    font-size: 13px;
    color: var(--color-text-secondary, #475569);
    line-height: 1.5;
}
.vault-modal-icon {
    width: 64px;
    height: 64px;
    margin: 0 auto 8px;
    border-radius: 50%;
    background: rgba(245, 158, 11, 0.12);
    color: #F59E0B;
    display: flex;
    align-items: center;
    justify-content: center;
}
.vault-modal-hint {
    margin: 12px 0 0;
    padding: 10px 12px;
    background: rgba(245, 158, 11, 0.08);
    border-left: 3px solid #F59E0B;
    border-radius: 6px;
    font-size: 12px;
    color: #92400e;
    line-height: 1.4;
}
[data-theme="dark"] .vault-modal-hint {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.12);
}

/* Champs PIN : grand, centré, monospace, letter-spacing pour lisibilité.
   On utilise type="text" (pas password) pour empêcher Chrome de proposer
   "Enregistrer le mot de passe", et on masque les digits via la propriété
   -webkit-text-security (supportée Chrome/Safari/Edge + Firefox 125+). */
.vault-pin-input {
    text-align: center;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 22px;
    letter-spacing: 8px;
    padding: 12px 16px !important;
}
.vault-pin-input::placeholder {
    /* Placeholder texte ("6 chiffres") — ton plus discret pour éviter
       toute confusion avec une saisie réelle. */
    letter-spacing: 0;
    font-family: var(--font-family, system-ui, sans-serif);
    font-size: 14px;
    font-weight: 400;
    color: #94a3b8;
    text-transform: none;
    opacity: 0.7;
}
[data-theme="dark"] .vault-pin-input::placeholder {
    color: #64748b;
}
/* Masquage du PIN affiché (le code email reste lisible — c'est un OTP) */
.vault-pin-mask {
    -webkit-text-security: disc;
    -moz-text-security: disc;
    text-security: disc;
    /* Fallback Firefox < 125 : on agrandit le letter-spacing pour compliquer
       la lecture par-dessus l'épaule. C'est imparfait mais le fallback est
       transitoire — Firefox supporte text-security depuis 2024. */
}
.vault-code-row {
    display: flex;
    gap: 8px;
    align-items: stretch;
}
.vault-code-row .vault-pin-input { flex: 1; }
.vault-code-row .btn-secondary { white-space: nowrap; }

/* Layout 2 colonnes : PIN | Code email — pour gagner de la place verticale
   et rapprocher visuellement les 2 champs qui forment ensemble la 2FA. */
.vault-fields-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}
.vault-fields-row .vault-field {
    margin-bottom: 0;
    min-width: 0; /* évite l'overflow horizontal */
}
.vault-status-help {
    display: block;
    margin-top: 6px;
    min-height: 16px;
    font-size: 12px;
}

/* Mobile : on repasse en 1 colonne — les inputs en 22px ne tiennent pas
   à 2 colonnes sur les petits écrans. */
@media (max-width: 540px) {
    .vault-fields-row {
        grid-template-columns: 1fr;
        gap: 10px;
    }
}

/* Label "Code email" en flex avec le bouton "Recevoir" aligné à droite —
   on récupère l'espace vertical occupé par l'ancien bouton externe et on
   garde une CTA accessible sans surcharger la modale. */
.vault-code-label {
    display: flex !important;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.vault-link-send-code {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 10px;
    border-radius: 999px;
    background: rgba(245, 158, 11, 0.10);
    border: 1px solid rgba(245, 158, 11, 0.25);
    color: #B45309;
    font-size: 11.5px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
    line-height: 1;
}
.vault-link-send-code:hover:not(:disabled) {
    background: rgba(245, 158, 11, 0.18);
    border-color: rgba(245, 158, 11, 0.4);
}
.vault-link-send-code:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}
[data-theme="dark"] .vault-link-send-code {
    color: #fbbf24;
    background: rgba(245, 158, 11, 0.12);
}

/* Bloc WebAuthn (vérification en cours / bouton biométrique) — volontairement
   plus léger que .vault-forgot-row (pas de séparateur pointillé) : c'est un
   état transitoire, pas une action distincte méritant sa propre section. */
.vault-webauthn-row {
    margin-top: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.vault-webauthn-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
}
.vault-mini-spinner {
    display: inline-block;
    width: 12px; height: 12px;
    border: 2px solid var(--color-border, rgba(0,0,0,.12));
    border-top-color: var(--color-text-secondary, #64748b);
    border-radius: 50%;
    animation: vault-spin 0.7s linear infinite;
}

/* Animation : shake quand erreur de code */
.vault-pin-input.shake {
    animation: vault-shake 0.35s cubic-bezier(.36,.07,.19,.97);
    border-color: #ef4444 !important;
    box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.15) !important;
}
@keyframes vault-shake {
    10%, 90%   { transform: translateX(-2px); }
    20%, 80%   { transform: translateX(4px); }
    30%, 50%, 70% { transform: translateX(-6px); }
    40%, 60%   { transform: translateX(6px); }
}

/* Animation : succès — le cadenas s'ouvre */
.vault-modal-icon { transition: background 0.3s, color 0.3s, transform 0.3s; }
.vault-modal-icon.vault-anim-success {
    background: rgba(16, 185, 129, 0.12);
    color: #10b981;
    transform: scale(1.1);
    animation: vault-pulse-success 0.6s ease-out;
}
.vault-modal-icon.vault-anim-success svg path[d^="M7 11"] {
    transform-origin: 12px 11px;
    animation: vault-shackle-open 0.5s ease-out forwards;
}
@keyframes vault-pulse-success {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.18); }
    100% { transform: scale(1.1); }
}
@keyframes vault-shackle-open {
    0%   { transform: rotate(0deg) translateY(0); }
    50%  { transform: rotate(-15deg) translateY(-2px); }
    100% { transform: rotate(-25deg) translateY(-4px); }
}

/* Bouton submit : état "succès" + spinner inline */
.btn-primary.vault-btn-success {
    background: #10b981 !important;
    border-color: #10b981 !important;
}
.vault-btn-spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    margin-left: 8px;
    border: 2px solid rgba(255, 255, 255, 0.4);
    border-top-color: #fff;
    border-radius: 50%;
    animation: vault-spin 0.7s linear infinite;
    vertical-align: -2px;
}
.vault-btn-spinner[hidden] { display: none; }
@keyframes vault-spin {
    to { transform: rotate(360deg); }
}

/* ----------- Boutons modale Coffre-fort : padding + radius plus généreux,
   pour matcher le ton "espace sécurisé" et faire la diff avec le bouton
   "Recevoir le code" inline. ----------- */
.vault-btn-cancel,
.vault-btn-submit {
    padding: 10px 20px !important;
    font-size: 14px !important;
    font-weight: 600 !important;
    border-radius: 12px !important;
    min-height: 42px;
}
.vault-btn-submit {
    box-shadow: 0 2px 8px rgba(245, 158, 11, 0.25);
    background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%) !important;
    color: #fff !important;
    border: none !important;
}
.vault-btn-submit:hover:not(:disabled) {
    background: linear-gradient(135deg, #FBBF24 0%, #F59E0B 100%) !important;
    box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);
    transform: translateY(-1px);
}
.vault-btn-submit:disabled {
    opacity: 0.7;
    cursor: not-allowed;
    transform: none;
}
.vault-btn-submit.vault-btn-success {
    background: linear-gradient(135deg, #34D399 0%, #10b981 100%) !important;
    box-shadow: 0 2px 10px rgba(16, 185, 129, 0.35);
}
.vault-btn-cancel {
    background: transparent !important;
    border: 1px solid var(--color-border) !important;
    color: var(--color-text-secondary, #64748b) !important;
}
.vault-btn-cancel:hover {
    background: var(--color-border-light, #f1f5f9) !important;
    color: var(--color-text-primary, #0f172a) !important;
}
[data-theme="dark"] .vault-btn-cancel {
    border-color: rgba(255, 255, 255, 0.12) !important;
    color: #cbd5e1 !important;
}
[data-theme="dark"] .vault-btn-cancel:hover {
    background: rgba(255, 255, 255, 0.06) !important;
    color: #fff !important;
}

/* Bouton "Recevoir le code" — style différent (utility, pas action principale) */
.vault-btn-send-code {
    padding: 0 14px !important;
    font-size: 13px !important;
    font-weight: 500 !important;
    border-radius: 10px !important;
    background: rgba(245, 158, 11, 0.10) !important;
    border: 1px solid rgba(245, 158, 11, 0.25) !important;
    color: #B45309 !important;
    transition: all 0.15s;
}
.vault-btn-send-code:hover:not(:disabled) {
    background: rgba(245, 158, 11, 0.18) !important;
    border-color: rgba(245, 158, 11, 0.4) !important;
}
.vault-btn-send-code:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}
[data-theme="dark"] .vault-btn-send-code {
    color: #fbbf24 !important;
    background: rgba(245, 158, 11, 0.12) !important;
}

/* Footer : gap horizontal plus généreux + alignement à droite */
.modal-backdrop .modal:has(.vault-modal-intro) .modal-footer {
    gap: 10px;
    padding-top: 16px;
}

/* Cache les icônes "password manager" que Chrome injecte parfois */
.vault-pin-input::-webkit-credentials-auto-fill-button,
.vault-pin-input::-webkit-strong-password-auto-fill-button,
.vault-pin-input::-webkit-contacts-auto-fill-button,
.vault-pin-input::-ms-reveal,
.vault-pin-input::-ms-clear {
    display: none !important;
    visibility: hidden !important;
    pointer-events: none !important;
    position: absolute !important;
    right: 0 !important;
}

/* Cache les UI Mes Fichiers (chips, breadcrumb, recherches sauvegardées,
   tag-filter-banner) quand le placeholder vault est affiché. Évite toute
   fuite des compteurs / contenus persos derrière le coffre verrouillé. */
.hidden-vault-context {
    display: none !important;
}

/* =========================================================================
   BANDEAU COOKIES — conforme CNIL, non-bloquant (cookies essentiels seulement)
   ========================================================================= */
#aqin-cookies-banner {
    position: fixed;
    left: 16px;
    right: 16px;
    bottom: 16px;
    max-width: 720px;
    margin: 0 auto;
    padding: 16px 18px;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, rgba(0,0,0,0.08));
    border-radius: 14px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.15);
    z-index: 9999;
    transform: translateY(120%);
    transition: transform 0.35s cubic-bezier(0.32, 0.72, 0, 1);
}
#aqin-cookies-banner.visible {
    transform: translateY(0);
}
[data-theme="dark"] #aqin-cookies-banner {
    background: #1c1c1f;
    border-color: rgba(255,255,255,0.1);
}
#aqin-cookies-banner .cookies-content {
    display: flex;
    align-items: flex-start;
    gap: 14px;
}
#aqin-cookies-banner .cookies-icon {
    font-size: 24px;
    flex-shrink: 0;
    margin-top: 2px;
}
#aqin-cookies-banner .cookies-text {
    flex: 1;
    min-width: 0;
}
#aqin-cookies-banner .cookies-title {
    display: block;
    font-size: 14px;
    font-weight: 700;
    color: var(--color-text-primary, #0f172a);
    margin: 0 0 4px;
}
[data-theme="dark"] #aqin-cookies-banner .cookies-title {
    color: #fff;
}
#aqin-cookies-banner .cookies-body {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--color-text-secondary, #64748b);
}
[data-theme="dark"] #aqin-cookies-banner .cookies-body {
    color: #94a3b8;
}
#aqin-cookies-banner .cookies-text a {
    color: var(--color-primary, #3B82F6);
    text-decoration: underline;
}
#aqin-cookies-banner .cookies-ok {
    flex-shrink: 0;
    padding: 8px 18px;
    border: none;
    border-radius: 999px;
    background: var(--color-primary, #3B82F6);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
    align-self: center;
}
#aqin-cookies-banner .cookies-ok:hover {
    background: var(--color-primary-hover, #2563EB);
    transform: translateY(-1px);
}
@media (max-width: 540px) {
    #aqin-cookies-banner .cookies-content {
        flex-direction: column;
    }
    #aqin-cookies-banner .cookies-ok {
        align-self: stretch;
    }
}

/* =========================================================================
   COFFRE-FORT — placeholder plein écran "Fort verrouillé"
   Affiché quand l'utilisateur arrive sur /files?vault=1 mais que le
   coffre est encore verrouillé. Évite d'exposer Mes Fichiers en fond
   derrière la modale d'unlock (promesse de confidentialité).
   ========================================================================= */
.vault-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 80px 24px;
    text-align: center;
    min-height: 400px;
    animation: vault-placeholder-in 0.35s ease-out;
}
@keyframes vault-placeholder-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
.vault-placeholder-logo {
    width: 120px;
    height: 120px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 24px;
    filter: drop-shadow(0 12px 32px rgba(245, 158, 11, 0.25));
}
.vault-placeholder-logo svg {
    border-radius: 26px;
}
.vault-placeholder-title {
    font-size: 28px;
    font-weight: 700;
    margin: 0 0 10px;
    color: var(--color-text-primary, #0f172a);
    letter-spacing: -0.3px;
}
[data-theme="dark"] .vault-placeholder-title {
    /* Force le contraste : sur fond très sombre, le var() peut tomber sur
       une valeur trop faible. Blanc pur garantit la lisibilité. */
    color: #fff;
}
.vault-placeholder-text {
    font-size: 16px;
    font-weight: 600;
    color: #B45309;
    margin: 0 0 6px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
[data-theme="dark"] .vault-placeholder-text {
    color: #fbbf24;
}
.vault-placeholder-text::before {
    content: '🔒';
    font-size: 14px;
}
/* État neutre "Vérification…" (_renderVaultLoadingState) -- délibérément
   SANS le 🔒 de .vault-placeholder-text : on ne sait pas encore si le
   coffre est verrouillé, l'afficher à tort créerait le même flash trompeur
   que le fix qu'il corrige (cf _openVaultDirect(), 2026-08-02). */
.vault-placeholder-text-checking {
    font-size: 16px;
    font-weight: 600;
    color: var(--color-text-secondary, #64748b);
    margin: 0 0 6px;
}
.vault-placeholder-logo-pulse {
    animation: vault-placeholder-logo-pulse-anim 1.4s ease-in-out infinite;
}
@keyframes vault-placeholder-logo-pulse-anim {
    0%, 100% { opacity: 0.55; }
    50%      { opacity: 1; }
}
.vault-placeholder-sub {
    font-size: 13.5px;
    color: var(--color-text-secondary, #64748b);
    margin: 0 0 32px;
    max-width: 380px;
    line-height: 1.55;
}
[data-theme="dark"] .vault-placeholder-sub {
    color: #94a3b8;
}
.vault-placeholder-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 11px 24px;
    border-radius: 12px;
    border: none;
    background: linear-gradient(135deg, #F59E0B 0%, #D97706 100%);
    color: #fff;
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.2s;
    box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3);
}
.vault-placeholder-btn:hover {
    background: linear-gradient(135deg, #FBBF24 0%, #F59E0B 100%);
    transform: translateY(-1px);
    box-shadow: 0 6px 16px rgba(245, 158, 11, 0.4);
}

/* =========================================================================
   COFFRE-FORT — bouton "Verrouiller" + compte à rebours, DANS la toolbar
   (aligné avec la barre de quota/header-actions, pas une bannière flottante
   séparée en dessous — déplacé le 2026-08-01 sur demande explicite).
   ========================================================================= */
/* Sélecteur #id (pas juste la classe) pour battre la spécificité de
   .header-actions .btn-icon (carré 30px transparent) — même stratagème que
   #neb-backup-btn plus haut. Fond+bordure ambre visibles au repos (pas
   seulement au hover) pour se lire comme sa propre "case", pas une icône
   neutre de plus dans la rangée. */
#vault-lock-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    width: auto;
    height: 30px;
    padding: 0 12px;
    border-radius: 999px;
    background: rgba(245, 158, 11, 0.14);
    border: 1px solid rgba(245, 158, 11, 0.35);
    color: #B45309;
}
#vault-lock-btn:hover {
    background: rgba(245, 158, 11, 0.22);
    border-color: rgba(245, 158, 11, 0.5);
    color: #B45309;
}
[data-theme="dark"] #vault-lock-btn {
    background: rgba(245, 158, 11, 0.16);
    border-color: rgba(245, 158, 11, 0.4);
    color: #fbbf24;
}
[data-theme="dark"] #vault-lock-btn:hover {
    background: rgba(245, 158, 11, 0.24);
    border-color: rgba(245, 158, 11, 0.55);
    color: #fbbf24;
}
.vault-lock-btn-countdown {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-weight: 700;
    font-size: 11.5px;
    letter-spacing: .3px;
    white-space: nowrap;
}
.vault-lock-btn-countdown.vault-countdown-warn {
    color: #ef4444;
    animation: vault-countdown-pulse 1.2s ease-in-out infinite;
}
[data-theme="dark"] .vault-lock-btn-countdown.vault-countdown-warn {
    color: #fca5a5;
}
@keyframes vault-countdown-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.05); }
}

/* =========================================================================
   COFFRE-FORT — pill nav : compteur de fichiers + drop-zone
   ========================================================================= */
.ctx-tab-vault-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    margin-left: 6px;
    padding: 0 5px;
    border-radius: 9px;
    background: rgba(245, 158, 11, 0.18);
    color: #B45309;
    font-size: 11px;
    font-weight: 700;
    line-height: 1;
}
[data-theme="dark"] .ctx-tab-vault-count {
    background: rgba(245, 158, 11, 0.25);
    color: #fbbf24;
}
.ctx-tab-vault-count[hidden] { display: none; }

/* Drop-hover sur le pill : ring ambre + scale léger pour signaler qu'on
   peut lâcher le fichier ici. */
.ctx-tab-vault.ctx-tab-vault-drop-hover {
    background: rgba(245, 158, 11, 0.20) !important;
    box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.35), 0 4px 14px rgba(245, 158, 11, 0.25);
    transform: scale(1.03);
    color: #92400e !important;
    transition: transform 0.15s, box-shadow 0.15s, background 0.15s;
}
[data-theme="dark"] .ctx-tab-vault.ctx-tab-vault-drop-hover {
    background: rgba(245, 158, 11, 0.25) !important;
    color: #fbbf24 !important;
}

/* =========================================================================
   COFFRE-FORT — modale unlock : lien "PIN oublié ?" sous les inputs
   ========================================================================= */
.vault-forgot-row {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px dashed var(--color-border, rgba(0,0,0,0.08));
    text-align: center;
}
.vault-link-forgot {
    background: none;
    border: none;
    color: var(--color-text-secondary, #64748b);
    font-size: 12.5px;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 6px;
    transition: all 0.15s;
}
.vault-link-forgot:hover {
    color: #F59E0B;
    background: rgba(245, 158, 11, 0.08);
    text-decoration: underline;
}

/* === QR Scanner — modale plein écran avec viseur ============================ */
.qrscan-overlay {
    position: fixed; inset: 0;
    z-index: 99999;
    background: #000;
    display: flex; flex-direction: column;
    overflow: hidden;
    animation: qrscan-fade .2s ease;
}
@keyframes qrscan-fade { from { opacity: 0; } to { opacity: 1; } }
.qrscan-video {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
}
/* Masque sombre 4 coins + zone claire au centre (le viseur) en flexbox */
.qrscan-mask {
    position: absolute; inset: 0;
    display: flex; flex-direction: column;
    pointer-events: none;
}
.qrscan-mask-row { flex: 1; background: rgba(0, 0, 0, 0.55); }
.qrscan-mask-mid { display: flex; }
.qrscan-mask-side { flex: 1; background: rgba(0, 0, 0, 0.55); }
.qrscan-frame {
    width: min(70vw, 280px);
    aspect-ratio: 1;
    position: relative;
    border-radius: 18px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.18) inset;
}
.qrscan-corner {
    position: absolute;
    width: 28px; height: 28px;
    border: 3px solid #fff;
}
.qrscan-corner-tl { top: -2px; left: -2px;  border-right: none; border-bottom: none; border-top-left-radius: 18px; }
.qrscan-corner-tr { top: -2px; right: -2px; border-left: none;  border-bottom: none; border-top-right-radius: 18px; }
.qrscan-corner-bl { bottom: -2px; left: -2px;  border-right: none; border-top: none; border-bottom-left-radius: 18px; }
.qrscan-corner-br { bottom: -2px; right: -2px; border-left: none;  border-top: none; border-bottom-right-radius: 18px; }
.qrscan-laser {
    position: absolute;
    left: 6%; right: 6%;
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--color-primary, #3b82f6), transparent);
    box-shadow: 0 0 8px var(--color-primary, #3b82f6);
    border-radius: 2px;
    animation: qrscan-laser 2.4s ease-in-out infinite;
    top: 0;
}
@keyframes qrscan-laser {
    0%   { top: 6%;  opacity: 0.3; }
    50%  { top: 92%; opacity: 1;   }
    100% { top: 6%;  opacity: 0.3; }
}
.qrscan-header {
    position: absolute;
    top: env(safe-area-inset-top, 0);
    left: 0; right: 0;
    padding: 16px 18px;
    display: flex; align-items: center; gap: 8px;
    color: #fff;
    background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent);
}
.qrscan-title { font-size: 14px; font-weight: 700; letter-spacing: 0.2px; }
.qrscan-header-spacer { flex: 1; }
.qrscan-gallery, .qrscan-torch {
    width: 34px; height: 34px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.14);
    border: none;
    color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    transition: background .12s, transform .12s;
}
.qrscan-gallery:hover, .qrscan-torch:hover { background: rgba(255, 255, 255, 0.25); transform: scale(1.05); }
.qrscan-torch.active { background: #f59e0b; color: #1a1a1a; }
.qrscan-close {
    width: 38px; height: 38px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.14);
    border: none;
    color: #fff;
    display: inline-flex; align-items: center; justify-content: center;
    cursor: pointer;
    backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
    transition: background .12s, transform .12s;
}
.qrscan-close:hover { background: rgba(255, 255, 255, 0.25); transform: scale(1.05); }
.qrscan-hint {
    position: absolute;
    bottom: calc(28px + env(safe-area-inset-bottom, 0));
    left: 0; right: 0;
    text-align: center;
    color: #fff;
    font-size: 13px;
    font-weight: 500;
    text-shadow: 0 1px 4px rgba(0,0,0,0.6);
    pointer-events: none;
}

/* =====================================================================
   Sections AQIN Nébuleuse root (Albums / Photothèque / Dossiers)
   ===================================================================== */
.nebula-section {
    margin-bottom: 36px;
}

/* ─── Section Espaces (racines Galaxie possédées) — même style que section Albums ─ */
.nuage-system-section {
    padding-left: 20px;
    padding-right: 20px;
}
/* Nombre de racines d'espaces variable (1 à N) depuis le retrait des
   raccourcis d'apps (Nébuleuse/Scribe/Ardoise, qui imposaient un figeage à
   3 colonnes ici -- devenu incorrect maintenant que la grille n'affiche
   plus jamais ce trio fixe). Layout responsive normal de .file-grid. */
.nuage-system-section .file-grid {
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.nebula-section-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 14px;
    padding-bottom: 10px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    margin-top: 20px;
}
[data-theme="light"] .nebula-section-header {
    border-bottom-color: rgba(0, 0, 0, 0.07);
}
.nebula-section-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-text-muted, #94a3b8);
}
.nebula-section-count {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-text-muted, #94a3b8);
    opacity: 0.55;
}
/* Les grilles de sections héritent du layout .file-grid existant */
.nebula-section-grid {
    margin-bottom: 16px;
    margin-top: 20px;
}
/* Éléments masqués initialement (albums en trop) */
.nebula-section-extra {
    /* hidden via hidden attr, pas besoin de CSS supplémentaire */
}
.nebula-section-extra .file-grid,
.nebula-section-extra > .file-card,
.nebula-section-extra > div {
    /* révélés quand extra.hidden = false via JS */
}
/* Bouton "Voir plus" */
.nebula-section-more-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 14px auto 0;
    padding: 9px 20px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.09);
    border-radius: 24px;
    color: var(--color-text-muted);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.18s, border-color 0.18s, color 0.18s;
}
.nebula-section-more-btn:hover {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.18);
    color: var(--color-text);
}
[data-theme="light"] .nebula-section-more-btn {
    background: rgba(0, 0, 0, 0.04);
    border-color: rgba(0, 0, 0, 0.08);
}
[data-theme="light"] .nebula-section-more-btn:hover {
    background: rgba(0, 0, 0, 0.07);
    border-color: rgba(0, 0, 0, 0.14);
}

/* Mobile : .content a padding:0 à ≤768px — on réinjecte le padding
   horizontal sur les sections pour que titres + grille ne collent pas au bord.
   padding-bottom sur .tag-bar (pas margin-top sur la section) pour éviter
   le margin-collapse qui remontait le space en dehors de #file-container. */
@media (max-width: 768px) {
    .tag-bar {
        padding-bottom: 16px;
    }
    .nebula-section {
        padding-left: 0px;
        padding-right: 0px;
    }
    .nebula-section:first-child {
        margin-top: 0;
    }
    .nebula-section-more-btn {
        width: auto;
    }
}

/* =====================================================================
   Section SOUVENIRS — AQIN Nébuleuse (vue Nuage)
   Réutilise la mosaïque + footer des vraies cartes album (.nebula-album-*,
   cf app.css plus haut) pour "l'aperçu des photos comme avant" en plus
   grand (gabarit 340px via le :has() étendu ci-dessus) -- demande
   utilisateur 2026-08-24, deux passes : d'abord simplifié vers l'icône
   plate façon ESPACES, jugée trop sobre, puis "avec l'aperçus des [photos]
   comme avant et plus grand le card". Seule différence avec un album réel :
   pas de bouton partage, avatar = icône étincelle plutôt qu'une photo (pas
   de "contributeur" pour un souvenir), teinte violette plutôt que rose. */
/* Specificite (0,3,0) pour battre .file-card.nebula-album-card
   .nebula-album-avatar (meme poids) tout en gagnant par ordre de source. */
.file-card.nebula-memory-card .nebula-album-avatar {
    background: rgba(167, 139, 250, 0.14);
    color: #a78bfa;
}
/* Pas de padding (herite de .file-card, invisible par defaut car le fond de
   la carte est transparent -- ne devient visible qu'au survol quand la
   bordure/l'ombre apparaissent, "ca apparais au survol de la souris
   seulement", retour utilisateur 2026-08-24). La mosaique va bord a bord ;
   seul le pied de page (nom/meta) garde un leger insert pour rester lisible. */
.file-card.nebula-memory-card .nebula-album-frame {
    /* .nebula-album-card force overflow:visible pour laisser les photos en
       biais de la mosaique deborder du cadre -- inutile ici (plus de
       mosaique), et .file-card:hover applique un scale() a toute la carte :
       cette combinaison rendait par endroits les coins carres au survol
       (retour utilisateur 2026-08-29, "bord carre quand on approche la
       souris"). Meme traitement que .nebula-featured-card : le cadre
       se coupe lui-meme a son propre rayon, quoi qu'il se passe dedans. */
    overflow: hidden;
}
.file-card.nebula-memory-card {
    padding: 0;
    /* .nebula-album-card pose un contour permanent (border + fond degrade)
       pense pour la mosaique encadree -- avec le cadre agrandi au format
       "A la une" (.82, cf plus haut), ce contour devenait visible tout
       autour de la photo, la que la vraie carte "A la une" n'en a aucun
       (juste une ombre). Retour utilisateur 2026-08-29, "pas de bord la
       comme la card a la une". */
    border: none;
    background: transparent;
    box-shadow: var(--shadow-sm);
}
[data-theme="light"] .file-card.nebula-memory-card { background: transparent; }
.file-card.nebula-memory-card:hover {
    border: none !important;
}
/* Le pied de page separe a disparu (cf app.js, 2026-08-29) : le texte
   flotte desormais sur la photo, comme .nfc-scrim/.nfc-bottom des cartes
   "A la une" -- meme construction (scrim degrade + overlay ancre en bas),
   mais toujours visible plutot que revele au survol : "Il y a 9 ans"
   identifie le souvenir, ce n'est pas une info secondaire a decouvrir. */
.nebula-memory-scrim {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: linear-gradient(to top, rgba(0,0,0,.75), rgba(0,0,0,0) 55%);
    pointer-events: none;
}
.nebula-memory-overlay {
    position: absolute;
    left: 12px; right: 12px; bottom: 12px;
    display: flex; align-items: center; gap: 10px;
    z-index: 1;
}
.file-card.nebula-memory-card .nebula-memory-overlay .nebula-album-meta strong {
    color: #fff;
    text-shadow: 0 1px 4px rgba(0,0,0,.4);
}
.file-card.nebula-memory-card .nebula-memory-overlay .nebula-album-meta span {
    color: rgba(255,255,255,.82);
    text-shadow: 0 1px 4px rgba(0,0,0,.4);
}
/* 3 par rangee plutot que 4 (retour utilisateur 2026-08-24, "comme Nuage" --
   cf section ESPACES de dashboard.php, qui montre ses cartes par 3). Regle
   dediee (et non le :has(.nebula-album-card) ci-dessus, qui reste a 4 pour
   les vrais albums) : une carte Souvenir porte AUSSI .nebula-album-card
   (pour reutiliser sa CSS de mosaique) donc les deux :has() matchent son
   conteneur -- meme specificite, celle-ci gagne en arrivant apres dans la
   feuille de style. */
.file-grid:has(.nebula-memory-card) {
    grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 1100px) {
    .file-grid:has(.nebula-memory-card) { grid-template-columns: repeat(2, 1fr); }
}
/* Cadre au format des cartes "A la une" (.82, portrait) plutot que le 4/3
   paysage herite de la mosaique -- chaque photo de la rangee occupe alors
   quasiment toute la largeur de la carte (meme ratio que le cadre), pour
   une vraie "slide" plutot que 2 vignettes serrees cote a cote (retour
   utilisateur 2026-08-29, "en full comme la carte A la une"). */
.file-card.nebula-memory-card .nebula-album-frame {
    aspect-ratio: .82;
}
/* Rangee de vignettes plates defilable (remplace la mosaique biaisee pour
   les souvenirs, cf app.js) -- meme langage visuel que .nfc-img des cartes
   "A la une" : photo carree, coins arrondis, object-fit cover. Scrollbar
   masquee : le defilement se decouvre au doigt/trackpad, pas par une barre
   qui alourdirait une carte deja dense (nom + meta en pied de page). */
.nebula-memory-photo-strip {
    /* Ancre absolue sur la boite reelle du frame (position: relative, cf
       .nebula-album-frame) plutot qu'un height:100% en cascade -- le frame
       garde overflow:visible pour la mosaique des vraies cartes album, et
       sous ce regime un height:100% ne se resout pas depuis la taille
       intrinseque des <img>, la carte s'etirait a la hauteur de la 1ere
       photo (~1100px) au lieu de tenir dans son gabarit 4/3. */
    position: absolute;
    inset: 0;
    display: flex;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    /* mandatory + center (pas proximity/start) : un glisse partiel repart
       toujours vers la photo la plus proche, recentree -- sinon le
       defilement s'arretait la ou le doigt le lachait, jamais aligne
       (retour utilisateur 2026-08-29, "il faut un aimant qui la tire"). */
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.nebula-memory-photo-strip::-webkit-scrollbar { display: none; }
.nebula-memory-strip-photo {
    flex: 0 0 auto;
    height: 100%;
    aspect-ratio: .82;
    border-radius: 14px;
    object-fit: cover;
    scroll-snap-align: center;
    scroll-snap-stop: always;
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.file-card.nebula-memory-card:hover .nebula-memory-strip-photo { transform: scale(1.02); }
.nebula-memories-section .nebula-section-header {
    align-items: center;
}
.nebula-memories-see-all {
    margin-left: auto;
    font-size: 12px;
    color: #f472b6;
    text-decoration: none;
    font-weight: 500;
    flex-shrink: 0;
}
.nebula-memories-see-all:hover { text-decoration: underline; }

/* Bouton "Ignorer ce souvenir" -- même position/gabarit que .favorite-btn
   sur une carte fichier classique, révélé au survol (comme le reste des
   affordances de carte, cf @media hover:none pour le tactile). */
.nebula-memory-dismiss-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-full);
    border: none;
    background: rgba(0,0,0,0.3);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    color: #fff;
    padding: 0;
    opacity: 0;
    z-index: 3;
    transition: opacity .15s, background .15s;
}
.nebula-memory-card:hover .nebula-memory-dismiss-btn { opacity: 1; }
.nebula-memory-dismiss-btn:hover { background: #ef4444; }
.nebula-memory-dismiss-btn:disabled { opacity: .5; cursor: default; }
@media (hover: none) {
    .nebula-memory-dismiss-btn { opacity: 1; }
}

/* =====================================================================
   Hero Album — AQIN Nébuleuse
   Affiché en haut d'un dossier contenant des images (album photo).
   Background = première image du dossier floutée + darkened overlay.
   Design inspiré des apps sociales dark premium (bold typo + frosted badge).
   ===================================================================== */

/* En-tête simple pour dossiers (Nuage, Fort) — titre + nombre fichiers */
.folder-header-simple {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 20px 22px;
    margin-bottom: 24px;
    border-bottom: 1px solid var(--color-border, rgba(255, 255, 255, 0.1));
}

.folder-header-title {
    font-size: 24px;
    font-weight: 700;
    color: #ffffff;
    margin: 0;
    line-height: 1.1;
}

.folder-header-count {
    font-size: 13px;
    color: rgba(255, 255, 255, 0.6);
    font-weight: 500;
}

/* En-tête simple (titre + compteur) d'un album/dossier Nébuleuse -- sans
   effet de fond (remplace le hero flou retiré le 2026-08-01). */
.nebula-simple-header {
    margin: 4px 0 20px;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.nebula-simple-header-title {
    font-size: 22px;
    font-weight: 700;
    color: var(--color-text, #e8eaed);
    margin: 0;
    line-height: 1.2;
}
.nebula-simple-header-count {
    font-size: 12px;
    color: #f472b6;
    background: rgba(236, 72, 153, 0.12);
    padding: 3px 8px;
    border-radius: 8px;
    width: fit-content;
}

/* =====================================================================
   Réglages de l'album (Nébuleuse) — écran dédié façon Apple Invitations
   (demande utilisateur 2026-08-17), ouvert à la demande depuis
   #neb-album-settings-btn, jamais affiché en permanence -- l'en-tête de
   navigation par défaut de l'album (.nebula-simple-header ci-dessus) ne
   change pas (cf commit 5ad8095 : ancien hero flou permanent retiré pour
   incohérence avec le reste de l'app). .modal-backdrop/.modal (classes
   déjà posées dans le HTML, dashboard.php) fournissent déjà l'ouverture/
   fermeture animée + le plein écran mobile générique (body.modal-open
   .modal { inset:0 }, plus haut dans ce fichier) -- seule la largeur/le
   contenu interne sont propres à cet écran. */
.nebula-album-settings-panel.modal {
    max-width: 860px;
    padding: 0;
    /* overflow-y:auto/overflow-x:hidden hérités de .modal -- laissent le
       contenu (hero + grille + supprimer) scroller si ça ne tient pas en
       hauteur, ET clippent proprement les coins carrés du bas du hero
       contre le border-radius arrondi du panneau (pas besoin de le
       redéfinir ici, juste ne pas l'écraser). */
}
.nas-close-btn {
    position: absolute;
    top: 14px; right: 14px;
    z-index: 5;
    width: 34px; height: 34px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: none;
    color: #fff;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
}
.nas-close-btn:hover { background: rgba(0, 0, 0, 0.6); transform: scale(1.05); }

.nas-hero {
    position: relative;
    min-height: 300px;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    background: linear-gradient(135deg, #1e1e2e, #2a1e2e) center/cover no-repeat;
    display: flex; flex-direction: column; justify-content: space-between;
    padding: 18px 22px 22px;
    overflow: hidden;
}
/* Overlay dégradé bas→haut pour la lisibilité du titre sur une photo
   quelconque -- jamais de blur supplémentaire (l'ancien hero flou a été
   retiré précisément pour cet effet, cf commentaire de section ci-dessus). */
.nas-hero::after {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(0,0,0,0) 35%, rgba(0,0,0,0.75) 100%);
    pointer-events: none;
}
.nas-hero-badge {
    align-self: flex-start;
    position: relative; z-index: 1;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px;
    border-radius: var(--radius-full);
    background: rgba(0, 0, 0, 0.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    font-size: 12px; font-weight: 700;
}
.nas-hero-bg-btn {
    align-self: flex-start;
    position: relative; z-index: 1;
    margin-top: auto;
    padding: 9px 16px;
    border-radius: var(--radius-full);
    background: rgba(0, 0, 0, 0.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    border: none;
    color: #fff;
    font-size: 13px; font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s;
}
.nas-hero-bg-btn:hover { background: rgba(0, 0, 0, 0.6); }
.nas-hero-bottom {
    position: relative; z-index: 1;
    margin-top: 14px;
}
.nas-hero-title {
    font-size: 26px;
    font-weight: 800;
    color: #fff;
    line-height: 1.15;
    outline: none;
    margin: 0 0 8px;
    /* contenteditable : évite un caret invisible / un fond de sélection
       qui casserait la lisibilité sur une photo sombre */
    caret-color: #fff;
}
.nas-hero-title:empty::before {
    content: 'Nom de l\'album';
    opacity: 0.5;
}
.nas-hero-meta {
    display: flex; align-items: center; gap: 6px;
    color: rgba(255, 255, 255, 0.85);
    font-size: 13px; font-weight: 500;
}

.nas-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    padding: 18px 22px;
}
.nas-card {
    display: flex; flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 20px 16px 16px;
    border-radius: var(--radius-xl);
    background: var(--color-bg);
    text-align: center;
    cursor: pointer;
    transition: background 0.15s;
    min-height: 148px;
}
button.nas-card { border: none; font-family: inherit; }
.nas-card:hover { background: var(--color-hover); }
.nas-card-static { cursor: default; }
.nas-card-static:hover { background: var(--color-bg); }
.nas-card-head {
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    color: var(--color-text-secondary);
}
/* Badge coloré façon icône d'app (référence Apple Invitations) -- une
   teinte distincte par carte, jamais de border (règle projet). */
.nas-card-icon {
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    width: 40px; height: 40px;
    border-radius: 11px;
    color: #fff;
}
.nas-card-icon-collab { background: #3b82f6; }
.nas-card-icon-link { background: #06b6d4; }
.nas-card-icon-desc { background: #f59e0b; }
.nas-card-icon-stats { background: #8b5cf6; }
.nas-card-title { font-size: 13px; font-weight: 700; color: var(--color-text); }
.nas-card-sub {
    font-size: 12.5px;
    color: var(--color-text-tertiary);
    line-height: 1.4;
    margin: 0;
    overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
    -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.nas-card-cta {
    margin-top: auto;
    padding: 8px 16px;
    border-radius: 999px;
    /* Teinte translucide indépendante de --color-hover -- .nas-card:hover
       passe déjà à --color-hover, un fond identique sur le CTA le rendrait
       invisible pile au moment où la carte est survolée. */
    background: rgba(127, 127, 127, 0.16);
    color: var(--color-text);
    font-size: 12px; font-weight: 600;
    white-space: nowrap;
}
.nas-card-static .nas-card-cta { display: none; }
.nas-card-desc-editing {
    width: 100%;
    min-height: 44px;
    text-align: left;
    background: transparent;
    border: none;
    outline: none;
    resize: vertical;
    color: var(--color-text);
    font-size: 12.5px;
    font-family: inherit;
    line-height: 1.4;
    padding: 0;
}

.nas-delete-link {
    display: flex; align-items: center; justify-content: center; gap: 7px;
    width: calc(100% - 44px);
    margin: 4px 22px 20px;
    padding: 11px;
    border-radius: 12px;
    background: none;
    border: none;
    color: var(--color-danger, #ef4444);
    font-size: 13px; font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background 0.15s;
}
.nas-delete-link:hover { background: rgba(239, 68, 68, 0.1); }

/* Mini-grille de sélection de couverture (clic sur "Modifier
   l'arrière-plan") -- réutilise les photos déjà chargées avec l'album
   (aucun appel réseau supplémentaire), simple choix en un clic. */
.nas-cover-picker {
    position: absolute; inset: 0;
    z-index: 2;
    background: rgba(0, 0, 0, 0.82);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
    gap: 6px;
    padding: 16px;
    overflow-y: auto;
}
.nas-cover-pick-item {
    aspect-ratio: 1;
    border-radius: 10px;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    transition: border-color 0.15s;
    background-size: cover;
    background-position: center;
}
.nas-cover-pick-item:hover { border-color: #fff; }

@media (max-width: 640px) {
    .nas-grid { grid-template-columns: 1fr; padding: 14px 16px; }
    .nas-hero { min-height: 220px; padding: 16px; border-radius: 0; }
    .nas-hero-title { font-size: 22px; }
    .nas-delete-link { width: calc(100% - 32px); margin: 4px 16px 16px; }
}

/* Bascule "Mes albums / Albums partagés" (racine Nébuleuse) -- pilule
   segmentée, séparation par fond+ombre uniquement (jamais de border
   visible sur une barre d'onglets, cf règle projet). Boutons : classe
   .nebula-album-tab directement réutilisée (ex-bascule Photos/Activité
   d'un album ouvert, supprimée le 2026-08-14), cf plus bas. Classe de
   conteneur dédiée (pas .nss-filters, déjà pris par la bascule Espaces
   Nuage/Galaxie de dashboard.php -- même nom de conteneur, même ancêtre
   .nebula-section-header, collision réelle si partagé). */
.nebula-albums-filters {
    display: inline-flex;
    gap: 4px;
    padding: 4px;
    background: var(--color-bg);
    border-radius: var(--radius-full);
}

/* Pilule segmentée Mes albums/Albums partagés -- séparation par fond+ombre
   uniquement (jamais de border visible sur une barre d'onglets, cf règle
   projet). Ex-bascule Photos/Activité d'un album ouvert : supprimée
   (fusionnées sur une seule page, demande utilisateur 2026-08-14) -- cette
   classe .nebula-album-tab reste utilisée par .nebula-albums-filters. */
.nebula-album-tab {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--color-text-secondary);
    font-size: 13px;
    font-weight: 600;
    padding: 7px 20px;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background 0.2s, color 0.2s, box-shadow 0.2s;
}
.nebula-album-tab:hover { color: var(--color-text); }
.nebula-album-tab.active {
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--shadow-sm);
}

/* Vignette photo dans la grille d'un album Nébuleuse -- photo pleine
   vignette (jamais de card blanche/padding autour, cf règle projet "préfère
   déborder que contenir"), nom+avatar+réactions révélés au survol via un
   dégradé plutôt que toujours visibles sous la photo (grille dense,
   demande utilisateur 2026-08-14). Étoile/menu/case à cocher déjà
   positionnés par .favorite-btn/.card-menu-btn/.file-card-checkbox, non
   touchés ici -- seule la zone .file-card-thumb change. */
.file-card.nebula-photo-tile {
    padding: 0;
}
.file-card.nebula-photo-tile .file-card-thumb {
    border-radius: 20px;
    position: relative;
}
.file-card.nebula-photo-tile .npt-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0,0,0,.72), rgba(0,0,0,0) 55%);
    opacity: 0;
    transition: opacity .2s;
}
.file-card.nebula-photo-tile:hover .npt-scrim,
.file-card.nebula-photo-tile:hover .npt-bottom,
.file-card.nebula-photo-tile.npt-revealed .npt-scrim,
.file-card.nebula-photo-tile.npt-revealed .npt-bottom {
    opacity: 1;
}
/* Conteneur commun réactions+légende, révélé au survol (grille dense --
   demande utilisateur 2026-08-14). La barre de réactions (.nebula-reaction-bar,
   générique, définie plus bas dans ce fichier) vient se placer au-dessus de
   la légende via ce flex column, sans offsets en dur. */
.file-card.nebula-photo-tile .npt-bottom {
    position: absolute;
    left: 10px; right: 10px; bottom: 8px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    opacity: 0;
    transform: translateY(4px);
    transition: opacity .2s, transform .2s;
}
.file-card.nebula-photo-tile:hover .npt-bottom,
.file-card.nebula-photo-tile.npt-revealed .npt-bottom { transform: translateY(0); }
/* Tactile : pas de survol fiable pour révéler réactions/commentaire/légende
   (audit Nébuleuse 2026-08-15). Un affichage permanent réglait le problème
   de joignabilité mais encombrait la grille en permanence (retour
   utilisateur 2026-08-24, "toujours visible sur mobile") -- remplacé par
   .npt-reveal-btn (⋯, toujours visible mais discret) qui bascule
   .npt-revealed sur la vignette au tap, cf _wireNebulaTileReveal(). */
/* Générique -- montée à la fois sur .file-card.nebula-photo-tile (grille) et
   .nebula-featured-card ("À la une", cf .nfc-reveal-btn), même bouton. */
.npt-reveal-btn {
    position: absolute;
    top: 8px; right: 8px;
    width: 26px; height: 26px;
    border-radius: 50%;
    border: none;
    background: rgba(0,0,0,.45);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: 0;
    z-index: 2;
    transition: background .15s;
}
.npt-reveal-btn:hover { background: rgba(0,0,0,.65); }
@media (hover: hover) {
    /* Souris/trackpad : le survol révèle déjà tout, le bouton ⋯ serait
       redondant -- reste dans le DOM (accessibilité clavier) mais masqué. */
    .npt-reveal-btn { opacity: 0; pointer-events: none; }
    .file-card.nebula-photo-tile:hover .npt-reveal-btn,
    .file-card.nebula-photo-tile.npt-revealed .npt-reveal-btn,
    .nebula-featured-card:hover .npt-reveal-btn,
    .nebula-featured-card.npt-revealed .npt-reveal-btn { opacity: 1; pointer-events: auto; }
}
/* Réactions + bouton Commenter côte à côte (même ligne que l'ex-fil
   Activité, .nebula-activity-photo-actions supprimée). */
.file-card.nebula-photo-tile .npt-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.file-card.nebula-photo-tile .npt-caption {
    display: flex;
    align-items: center;
    gap: 6px;
}
.file-card.nebula-photo-tile .npt-avatar {
    width: 18px; height: 18px;
    border-radius: var(--radius-full);
    flex-shrink: 0;
    background: rgba(255,255,255,.25);
    color: #fff;
    font-size: 8px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.file-card.nebula-photo-tile .npt-avatar img {
    width: 100%; height: 100%;
    object-fit: cover;
}
.file-card.nebula-photo-tile .npt-name {
    font-size: 11px;
    font-weight: 500;
    color: #fff;
    text-shadow: 0 1px 3px rgba(0,0,0,.4);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
/* Barre de réactions compacte pour la vignette de grille (la définition de
   base .nebula-reaction-pill/-count/-add, dimensionnée pour l'ex-fil
   Activité plus spacieux, reste plus bas dans ce fichier -- surchargée ici). */
.file-card.nebula-photo-tile .nebula-reaction-pill {
    font-size: 11px;
    padding: 3px 7px;
    gap: 3px;
}
.file-card.nebula-photo-tile .nebula-reaction-count { font-size: 10px; }
.file-card.nebula-photo-tile .nebula-reaction-add {
    width: 22px;
    height: 22px;
}
/* Bouton Commenter compact -- même paire base spacieuse/surcharge compacte
   que la barre de réactions ci-dessus (base = carte "à la une", surcharge
   ici = vignette de grille dense). */
.file-card.nebula-photo-tile .nebula-comment-btn {
    font-size: 11px;
    padding: 5px 9px;
}

/* Bouton Commenter -- même verre dépoli sombre que les pilules de réaction
   (photo en fond, jamais --color-surface), icône bulle + compteur. Taille
   de base pensée pour la carte "à la une" (spacieuse) ; surchargée en
   compact ci-dessus pour la grille dense. */
.nebula-comment-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    border: none;
    background: rgba(0,0,0,.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    font-size: 13px;
    font-weight: 700;
    padding: 6px 11px;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background 0.15s;
}
.nebula-comment-btn:hover { background: color-mix(in srgb, var(--color-primary) 45%, rgba(0,0,0,.4)); }

/* Section "À la une" -- grandes cartes éditoriales en haut d'un album
   (manuel + repli auto, cf PhotoAlbum::getFeatured). Avatar + titre
   toujours visibles (pas au survol, contrairement à la grille dense
   ci-dessus) -- à cette taille (3 cartes/ligne) ça ne surcharge pas. */
.nebula-featured-section {
    margin: -4px 0 24px;
}
.nebula-featured-label {
    font-size: 11px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    text-transform: uppercase;
    letter-spacing: .08em;
    margin: 0 0 10px;
    padding: 0 2px;
}
/* Remplace l'ancienne grille cote-a-cote (1 a 5 cartes de meme taille) par
   un hero defilable, une carte a la fois (demande utilisateur 2026-09-24,
   "fusionner en slide hero") -- cf _wireNebulaFeaturedHero() dans app.js. */
.nebula-featured-hero {
    position: relative;
}
/* Titre + compteur du dossier (.nebula-simple-header-title/-count),
   DEPLACES ici -- memes noeuds DOM, jamais redessines -- par
   _renderNebulaAlbumFeatured() quand ce hero existe (demande utilisateur
   2026-09-25, "deplace le titre dans le card A la une", puis "il doit etre
   dans le bas a gauche" -- en bas, pas en haut comme au premier essai).
   Toujours visible (pas de reveal-au-survol comme .nfc-bottom plus bas) :
   c'est le titre de la page, pas une legende par photo -- il ne doit pas
   disparaitre/reapparaitre au survol ni changer en glissant entre les
   cartes. flex-direction:column reproduit la mise en page de
   .nebula-simple-header (perdue en quittant ce parent). Degrade du BAS :
   .nfc-bottom (legende par photo, revelee au survol/tap) partage la meme
   zone -- repousse a bottom:70px (etait 26px) pour rester AU-DESSUS de ce
   bandeau, jamais superposee, cf plus bas .nfc-bottom. */
.nfh-title-overlay {
    position: absolute;
    bottom: 0; left: 0; right: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 24px 16px 14px;
    background: linear-gradient(to top, rgba(0,0,0,.6), rgba(0,0,0,0) 100%);
    z-index: 1;
    pointer-events: none;
}
.nfh-title-overlay .nebula-simple-header-title {
    color: #fff;
    text-shadow: 0 1px 4px rgba(0,0,0,.5);
    max-width: 60%;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.nfh-title-overlay .nebula-simple-header-count {
    text-shadow: 0 1px 3px rgba(0,0,0,.4);
}
.nfh-track {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.nfh-track::-webkit-scrollbar { display: none; }
.nfh-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    border: none;
    border-radius: var(--radius-full);
    background: rgba(0,0,0,.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 2;
    transition: background .15s;
}
.nfh-arrow:hover { background: rgba(0,0,0,.6); }
.nfh-prev { left: 12px; }
.nfh-next { right: 12px; }
.nfh-dots {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 10px;
    display: flex;
    justify-content: center;
    gap: 6px;
    z-index: 2;
}
.nfh-dot {
    width: 6px;
    height: 6px;
    padding: 0;
    border: none;
    border-radius: var(--radius-full);
    background: rgba(255,255,255,.5);
    cursor: pointer;
    transition: background .15s, transform .15s;
}
.nfh-dot.active {
    background: #fff;
    transform: scale(1.3);
}
.nebula-featured-card {
    position: relative;
    flex: 0 0 100%;
    scroll-snap-align: start;
    /* Plafonnee (pas un aspect-ratio pur) : le conteneur album peut friser
       la pleine largeur d'un grand ecran, un ratio 16/9 y donnerait un hero
       de 700px+ de haut qui ecraserait la grille Photos juste en dessous.
       Le plancher 240px evite l'inverse sur mobile (30vw d'un ecran de
       390px ne fait que 117px). */
    height: clamp(240px, 30vw, 440px);
    border-radius: 20px;
    overflow: hidden;
    cursor: pointer;
    box-shadow: var(--shadow-sm);
}
.nfc-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .3s cubic-bezier(0.4,0,0.2,1);
}
.nebula-featured-card:hover .nfc-img { transform: scale(1.04); }
.nfc-play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}
.nfc-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0,0,0,.78), rgba(0,0,0,0) 48%);
    opacity: 0;
    transition: opacity .2s;
}
.nebula-featured-card:hover .nfc-scrim,
.nebula-featured-card:hover .nfc-bottom,
.nebula-featured-card.npt-revealed .nfc-scrim,
.nebula-featured-card.npt-revealed .nfc-bottom {
    opacity: 1;
}
.nfc-avatar {
    position: absolute;
    top: 10px; left: 10px;
    width: 24px; height: 24px;
    border-radius: var(--radius-full);
    background: rgba(0,0,0,.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    font-size: 9px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.nfc-avatar img { width: 100%; height: 100%; object-fit: cover; }
/* Réactions + bouton Commenter au-dessus du titre (demande utilisateur
   2026-08-15, "il manque les bouton réaction et commentaire sur les
   images à la une") -- même empilement vertical que .npt-bottom sur la
   vignette de grille. Etait "toujours visible" (pas de survol requis) ;
   retour utilisateur 2026-08-24 ("toujours visible sur mobile", grille
   encombrée) -- révélé au survol/tap comme .npt-bottom désormais, via le
   même bouton .npt-reveal-btn (cf .nfc-reveal-btn) et _wireNebulaTileReveal().
   bottom:70px (était 26px, puis 26px depuis le passage en hero défilable
   2026-09-24) -- depuis le titre d'album toujours visible en bas-gauche du
   hero (.nfh-title-overlay, 2026-09-25), ce panneau doit rester AU-DESSUS
   de lui quand il se révèle, jamais superposé. Toujours au-dessus des
   points .nfh-dots aussi (cf valeur précédente). */
.nfc-bottom {
    position: absolute;
    left: 12px; right: 12px; bottom: 70px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    opacity: 0;
    transition: opacity .2s;
}
.nfc-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.nfc-title {
    font-size: 13px;
    font-weight: 500;
    color: #fff;
    text-shadow: 0 1px 4px rgba(0,0,0,.4);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Réactions emoji sur une photo (bar sous chaque vignette + picker flottant,
   mirroir de .ws-chat-reaction-picker/-opt côté Flow). Montée directement
   sur chaque vignette de la grille (ex-fil Activité fusionné, demande
   utilisateur 2026-08-14) -- taille compacte définie plus haut sous
   .file-card.nebula-photo-tile .nebula-reaction-bar. Fond verre dépoli
   sombre + texte blanc (même traitement que .npt-avatar/.nfc-avatar) :
   contrairement à l'ex-fil Activité (carte claire --color-surface), ces
   pilules ne vivent plus que sur un dégradé sombre au-dessus d'une photo. */
.nebula-reaction-bar {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
}
.nebula-reaction-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    border: none;
    background: rgba(0,0,0,.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    font-size: 15px;
    padding: 5px 10px;
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.nebula-reaction-pill:hover { background: rgba(0,0,0,.55); }
.nebula-reaction-pill.mine {
    background: color-mix(in srgb, var(--color-primary) 60%, black 40%);
    color: #fff;
}
.nebula-reaction-count { font-weight: 700; font-size: 13px; }
.nebula-reaction-add {
    width: 30px;
    height: 30px;
    border: none;
    border-radius: 50%;
    background: rgba(0,0,0,.4);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}
.nebula-reaction-add:hover {
    background: color-mix(in srgb, var(--color-primary) 45%, rgba(0,0,0,.4));
}
.nebula-reaction-picker {
    position: absolute;
    display: flex;
    gap: 2px;
    padding: 4px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    box-shadow: var(--shadow-lg);
    z-index: 60;
}
.nebula-reaction-opt {
    width: 30px;
    height: 30px;
    border: none;
    background: transparent;
    border-radius: 6px;
    font-size: 18px;
    cursor: pointer;
    transition: background 0.1s;
    line-height: 1;
}
.nebula-reaction-opt:hover { background: var(--color-bg); }

/* Vue "Doublons" (quasi-doublons, hash perceptuel) */
.nebula-dup-group {
    background: var(--color-surface);
    border-radius: 20px;
    padding: 14px;
    margin-bottom: 16px;
}
.nebula-dup-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}
.nebula-dup-cell {
    position: relative;
    width: 110px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}
.nebula-dup-cell img {
    width: 110px;
    height: 110px;
    object-fit: cover;
    border-radius: 14px;
    display: block;
}
.nebula-dup-cell input[type="checkbox"] {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 18px;
    height: 18px;
    accent-color: #ef4444;
    cursor: pointer;
}
.nebula-dup-cell-meta {
    font-size: 11px;
    color: var(--color-text-muted);
}
.nebula-dup-actionbar {
    display: flex;
    justify-content: flex-end;
    margin-top: 8px;
}

/* Éditeur photo minimal (recadrer + pivoter) -- même conventions visuelles
   que .preview-overlay (fond sombre fixe, z-index modal-backdrop). */
.ne-overlay {
    position: fixed;
    inset: 0;
    background: rgba(10, 10, 10, 0.96);
    z-index: var(--z-modal-backdrop);
    display: none;
    flex-direction: column;
    align-items: center;
    overscroll-behavior: none;
}
.ne-overlay.visible { display: flex; }
.ne-loading { margin: auto; }
.ne-toolbar {
    display: flex;
    align-items: center;
    gap: 6px;
    width: 100%;
    padding: 14px 18px;
    flex-shrink: 0;
}
.ne-spacer { flex: 1; }
.ne-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 38px; height: 38px;
    padding: 0;
    border-radius: 50%;
    background: transparent;
    border: none;
    color: rgba(255,255,255,.75);
    cursor: pointer;
    transition: all .15s;
}
.ne-btn:hover { color: #fff; background: rgba(255,255,255,.12); }
.ne-btn-text {
    width: auto; height: 38px; border-radius: 19px; padding: 0 18px;
    font-size: 13px; font-weight: 600;
}
.ne-btn-primary {
    width: auto; height: 38px; border-radius: 19px; padding: 0 20px;
    font-size: 13px; font-weight: 700;
    background: var(--color-primary, #f472b6); color: #fff;
}
.ne-btn-primary:hover { background: var(--color-primary, #f472b6); filter: brightness(1.1); }
.ne-btn:disabled { opacity: .5; cursor: default; }
.ne-stage {
    flex: 1;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
    padding: 10px 20px 30px;
}
.ne-canvas-wrap { position: relative; }
.ne-canvas { display: block; border-radius: 4px; }
.ne-crop-box {
    position: absolute;
    box-shadow: 0 0 0 2000px rgba(0,0,0,0.55);
    border: 1.5px solid #fff;
    cursor: move;
    touch-action: none;
}
.ne-crop-edge { position: absolute; }
.ne-edge-n, .ne-edge-s { left: 0; right: 0; height: 1px; background: rgba(255,255,255,.4); }
.ne-edge-n { top: 33%; } .ne-edge-s { top: 66%; }
.ne-edge-e, .ne-edge-w { top: 0; bottom: 0; width: 1px; background: rgba(255,255,255,.4); }
.ne-edge-w { left: 33%; } .ne-edge-e { left: 66%; }
.ne-handle {
    position: absolute;
    width: 22px; height: 22px;
    margin: -11px;
    touch-action: none;
}
.ne-handle::after {
    content: '';
    position: absolute; inset: 7px;
    background: #fff;
    border-radius: 3px;
}
.ne-h-nw { top: 0; left: 0; cursor: nwse-resize; }
.ne-h-ne { top: 0; right: 0; margin-right: -11px; cursor: nesw-resize; }
.ne-h-sw { bottom: 0; left: 0; margin-bottom: -11px; cursor: nesw-resize; }
.ne-h-se { bottom: 0; right: 0; margin-right: -11px; margin-bottom: -11px; cursor: nwse-resize; }

/* =====================================================================
   Modal "Album vs Dossier simple" — AQIN Nébuleuse
   Picker 2 cartes : Album (indexé) | Dossier simple (non indexé).
   ===================================================================== */
.nebula-folder-type-picker {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.nf-type-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 16px 12px;
    background: rgba(255, 255, 255, 0.04);
    border: 1.5px solid rgba(255, 255, 255, 0.08);
    border-radius: 14px;
    cursor: pointer;
    transition: border-color 0.18s, background 0.18s, transform 0.15s;
    text-align: center;
    color: var(--color-text);
}
.nf-type-card:hover {
    background: rgba(255, 255, 255, 0.07);
    border-color: rgba(255, 255, 255, 0.16);
    transform: translateY(-1px);
}
.nf-type-card.selected {
    border-color: #ec4899;
    background: rgba(236, 72, 153, 0.08);
    box-shadow: 0 0 0 3px rgba(236, 72, 153, 0.15);
}
[data-theme="light"] .nf-type-card {
    background: #f8f8fa;
    border-color: rgba(0, 0, 0, 0.08);
    color: #1e293b;
}
[data-theme="light"] .nf-type-card:hover {
    background: #f1f1f5;
    border-color: rgba(0, 0, 0, 0.14);
}
[data-theme="light"] .nf-type-card.selected {
    border-color: #ec4899;
    background: rgba(236, 72, 153, 0.06);
}
.nf-type-icon {
    width: 52px; height: 52px;
    border-radius: 14px;
    background: rgba(236, 72, 153, 0.1);
    display: flex; align-items: center; justify-content: center;
    color: #ec4899;
    transition: background 0.18s;
}
.nf-type-card:not([data-type="album"]) .nf-type-icon {
    background: rgba(139, 92, 246, 0.1);
    color: #8b5cf6;
}
.nf-type-card.selected .nf-type-icon,
.nf-type-card[data-type="album"].selected .nf-type-icon {
    background: rgba(236, 72, 153, 0.18);
}
.nf-type-card[data-type="simple"].selected .nf-type-icon {
    background: rgba(139, 92, 246, 0.18);
}
.nf-type-title {
    font-size: 13.5px;
    font-weight: 600;
    line-height: 1.2;
}
.nf-type-desc {
    font-size: 11.5px;
    color: var(--color-text-muted);
    line-height: 1.4;
}
@media (max-width: 480px) {
    .nebula-folder-type-picker { grid-template-columns: 1fr; }
    .nf-type-card { flex-direction: row; text-align: left; padding: 12px; }
    .nf-type-icon { width: 40px; height: 40px; flex-shrink: 0; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Scribe — Layout plein-écran, liste, éditeur, panneau de format
   ═══════════════════════════════════════════════════════════════════════ */

/* ── Contraindre la page Scribe en mode plein-écran fixe ──────────────
   Le layout par défaut (no-sidebar-layout) impose body-scroll avec
   !important.  On surclasse via spécificité supérieure + !important.
   JS ajoute .scribe-html sur <html> et .scribe-page sur <body>.
   ─────────────────────────────────────────────────────────────────── */
html.scribe-html {
    height: 100vh !important;
    overflow: hidden !important;
}
body.no-sidebar-layout.scribe-page {
    overflow: hidden !important;
    height: 100vh !important;
    min-height: 0 !important;
}
body.scribe-page .app-no-sidebar {
    display: flex !important;
    flex-direction: column !important;
    height: 100vh !important;
    min-height: 0 !important;
    overflow: hidden !important;
}
body.scribe-page .app-no-sidebar .main {
    display: flex !important;
    flex-direction: column !important;
    flex: 1 !important;
    height: 0 !important;
    min-height: 0 !important;
    overflow: hidden !important;
    width: 100% !important;
}
body.scribe-page .app-no-sidebar .main-body {
    display: flex !important;
    flex-direction: column !important;
    flex: 1 !important;
    height: 0 !important;
    overflow: hidden !important;
    margin: 0 !important;
    /* Contrairement aux autres pages no-sidebar (scroll body-level, le
       padding-top standard défile avec le contenu), .main-body ne défile
       PAS ici — seul .scribe-a4-scroll (descendant) défile. Un padding-top
       hérité resterait donc une bande figée en permanence à l'écran.
       On le retire ici et on le redistribue plus bas (media desktop) sur
       .scribe-a4-scroll (padding-top, défile avec la note) -- .scribe-sidebar
       compense séparément, directement via son propre top:72px en
       position:absolute (cf. plus bas), pas via un margin-top ici : les deux
       mécanismes avaient fini par coexister un temps (margin-top:72px ici +
       top:8px là-bas), s'additionnant en un décalage de 80px au lieu de 72px
       voulus (repéré en direct 2026-08-15). Une seule source de vérité pour
       la sidebar maintenant, au plus près de sa règle position:absolute. */
    padding-top: 0;
}
/* Desktop uniquement : redistribue les 72px retirés de .main-body ci-dessus,
   sur .scribe-a4-scroll uniquement -- .scribe-sidebar gère sa propre
   clearance via top:72px directement dans sa règle position:absolute
   (cf. plus bas), pas ici. Mobile gère déjà sa propre clearance
   indépendamment (sidebar en position:fixed, a4-scroll via
   env(safe-area-inset-top)) — ne pas dupliquer. */
@media (min-width: 769px) {
    body.scribe-page .scribe-a4-scroll { padding-top: 72px; }
}

/* ── Bouton "Nouvelle note" dans la header pill ──────────────────────── */
.scribe-new-header-btn {
    display: flex;
    align-items: center;
    gap: 5px;
    background: var(--color-primary, #3b82f6);
    color: #fff;
    border: none;
    border-radius: 20px;
    padding: 6px 13px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background .15s, transform .1s;
    white-space: nowrap;
}
.scribe-new-header-btn:hover  { background: #2563eb; }
.scribe-new-header-btn:active { transform: scale(.97); }

/* ── Layout split-pane ──────────────────────────────────────────────── */
.scribe-layout {
    flex: 1;
    overflow: hidden;
    position: relative;
}

/* ── Colonne gauche : liste ─────────────────────────────────────────── */
.scribe-sidebar {
    width: 272px;
    min-width: 200px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Barre de recherche */
.scribe-sidebar-top {
    padding: 12px 14px 2px;
    flex-shrink: 0;
}
.scribe-notes-count {
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    user-select: none;
}
.scribe-search-wrap {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 10px 12px;
    flex-shrink: 0;
}
.scribe-search {
    flex: 1;
    background: none;
    border: none;
    outline: none;
    font-size: 13px;
    color: var(--color-text-primary, #fff);
    min-width: 0;
}
.scribe-search::placeholder { color: var(--color-text-muted); }
/* Masquer le bouton clear natif sur webkit */
.scribe-search::-webkit-search-cancel-button { display: none; }

/* Liste scrollable */
.scribe-notes-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px 0 12px;
    /* overflow visible horizontal pour que les ombres des cartes ne soient pas coupées */
    overflow-x: visible;
}
.scribe-notes-list::-webkit-scrollbar { width: 3px; }
.scribe-notes-list::-webkit-scrollbar-thumb {
    background: var(--color-border);
    border-radius: 2px;
}

.scribe-list-label {
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--color-text-muted);
    padding: 10px 14px 3px;
}
.scribe-list-empty {
    padding: 32px 16px;
    text-align: center;
    font-size: 13px;
    color: var(--color-text-muted);
    line-height: 1.7;
}
.scribe-list-loading {
    display: flex;
    justify-content: center;
    padding: 28px;
}

/* Item de note — style carte (aligné sur sh-card du home) */
.scribe-note-item {
    padding: 14px 15px 13px;
    cursor: pointer;
    border-radius: 18px;
    margin: 0 8px 10px;
    border: none;
    background: var(--color-surface);
    box-shadow: 0 2px 10px rgba(0,0,0,0.13), 0 1px 3px rgba(0,0,0,0.07);
    transition: transform 0.2s cubic-bezier(0.4,0,0.2,1), box-shadow 0.2s ease;
    position: relative;
    overflow: hidden;
}
.scribe-note-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 22px rgba(0,0,0,0.18), 0 2px 6px rgba(0,0,0,0.09);
    background: var(--color-surface);
}
.scribe-note-item.active {
    box-shadow: 0 4px 16px rgba(59,130,246,0.18), 0 1px 4px rgba(59,130,246,0.1);
    outline: 2px solid rgba(59,130,246,0.35);
    outline-offset: -2px;
}
.scribe-note-head {
    display: flex;
    align-items: center;
    gap: 6px;
}
.scribe-note-title {
    flex: 1;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--color-text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.scribe-pin-btn {
    background: none;
    border: none;
    padding: 2px 3px;
    color: var(--color-text-muted);
    cursor: pointer;
    opacity: 0;
    border-radius: 4px;
    transition: opacity .15s, color .15s, background .12s;
    flex-shrink: 0;
    display: flex;
    align-items: center;
}
.scribe-note-item:hover .scribe-pin-btn,
.scribe-pin-btn.pinned { opacity: 1; }
.scribe-pin-btn.pinned { color: var(--color-primary, #3b82f6); }
.scribe-pin-btn:hover  { background: var(--color-surface-hover); }
.scribe-note-preview {
    font-size: 11.5px;
    color: var(--color-text-muted);
    margin-top: 5px;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    opacity: .85;
    line-height: 1.55;
}
.scribe-note-date {
    font-size: 9px;
    color: var(--color-text-muted);
    margin-top: 9px;
    opacity: .6;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    font-weight: 600;
}
/* Badge dossier — affiché sous la date si la note appartient à un dossier */
.scribe-note-folder {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 10px;
    color: var(--color-text-tertiary);
    margin-top: 5px;
    opacity: .75;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.scribe-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ── Bouton fermer / rouvrir le panneau gauche ──────────────────────── */
.scribe-sidebar-close-btn {
    position: fixed;
    left: 230px;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 48px;
    border: 1px solid var(--color-border);
    border-left: none;
    border-radius: 0 8px 8px 0;
    background: var(--color-surface);
    cursor: pointer;
    color: var(--color-text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 200;
    transition: background .15s, color .15s;
    flex-shrink: 0;
}
.scribe-sidebar-close-btn:hover { background: var(--color-hover); color: var(--color-text); }
.scribe-layout:has(.scribe-sidebar-hidden) .scribe-sidebar-close-btn { display: none; }

.scribe-sidebar-open-btn {
    display: none;
    position: fixed;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 20px;
    height: 48px;
    border: 1px solid var(--color-border);
    border-left: none;
    border-radius: 0 8px 8px 0;
    background: var(--color-surface);
    cursor: pointer;
    color: var(--color-text-secondary);
    align-items: center;
    justify-content: center;
    z-index: 200;
    transition: background .15s, color .15s;
}
.scribe-sidebar-open-btn:hover { background: var(--color-hover); color: var(--color-text); }
.scribe-sidebar-open-btn.visible { display: flex; }

.scribe-sidebar {
    position: relative;
    transition: width .22s cubic-bezier(.4,0,.2,1), min-width .22s cubic-bezier(.4,0,.2,1);
}
.scribe-sidebar.scribe-sidebar-hidden {
    width: 0 !important;
    min-width: 0 !important;
    overflow: hidden;
    padding: 0;
}

/* Pied de sidebar (bouton nouvelle note) */
.scribe-sidebar-footer {
    flex-shrink: 0;
    padding: 8px 10px;
}
.scribe-sidebar-new-btn {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: rgba(59,130,246,.1);
    color: var(--color-primary, #3b82f6);
    border: 1px solid rgba(59,130,246,.25);
    border-radius: 10px;
    padding: 7px 12px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background .15s;
}
.scribe-sidebar-new-btn:hover { background: rgba(59,130,246,.18); }

/* ── Colonne centre : éditeur ───────────────────────────────────────── */
.scribe-editor-pane {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: background .25s;
    border-radius: 16px;
}

/* État vide */
.scribe-editor-empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    text-align: center;
    padding: 40px;
    color: var(--color-text-muted);
    font-size: 14px;
}

/* Inner éditeur */
.scribe-editor-inner {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Verrou collaboratif -- alerte "quelqu'un d'autre edite" au-dessus de la
   feuille A4. Contenu passe en lecture seule tant que le banner est visible. */
.scribe-lock-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    background: rgba(245, 158, 11, .12);
    color: #b45309;
    font-size: 12.5px;
    font-weight: 600;
    flex-shrink: 0;
}
.scribe-lock-banner[hidden] { display: none; }

/* Indicateur sauvegarde — positionné en absolu en bas de l'éditeur */
.scribe-saved-indicator {
    position: absolute;
    bottom: 12px;
    left: 16px;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    font-weight: 500;
    opacity: 0;
    transition: opacity .25s;
    pointer-events: none;
}
.scribe-saved-indicator.saved,
.scribe-saved-indicator.visible { opacity: 1; color: #22c55e; }
.scribe-saved-indicator.saving  { opacity: 1; color: var(--color-text-muted); }
.scribe-save-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}
.scribe-saved-indicator.saving .scribe-save-dot {
    animation: scribe-dot-pulse 1.2s ease-in-out infinite;
}
@keyframes scribe-dot-pulse {
    0%, 100% { opacity: .35; }
    50%       { opacity: 1; }
}

/* ── Barre de zoom Scribe ─────────────────────────────────────────────── */
.scribe-zoom-bar {
    position: absolute;
    bottom: 16px;
    left: 50%;
    transform: translateX(-50%);
    display: none;
    align-items: center;
    gap: 2px;
    background: var(--color-surface-card, rgba(30,33,36,.95));
    border: 1px solid rgba(255,255,255,.1);
    border-radius: 20px;
    padding: 4px 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,.35);
    backdrop-filter: blur(10px);
    z-index: 80;
    user-select: none;
}
body.scribe-page .scribe-zoom-bar { display: flex; }
.scribe-zoom-btn, .scribe-zoom-reset {
    background: none; border: none; cursor: pointer;
    color: var(--color-text-secondary, rgba(255,255,255,.6));
    font-size: 16px; font-weight: 600; line-height: 1;
    padding: 3px 9px; border-radius: 14px;
    transition: background .12s, color .12s;
    min-width: 30px; text-align: center;
}
.scribe-zoom-btn:hover, .scribe-zoom-reset:hover {
    background: rgba(255,255,255,.1);
    color: var(--color-text-primary, #fff);
}
.scribe-zoom-reset {
    font-size: 12px; font-weight: 700; min-width: 46px;
    letter-spacing: .02em;
}

/* Bouton retour mobile — caché sur desktop, positionné via mobile query */
.scribe-back-btn { display: none; }

/* ══════════════════════════════════════════════════════════════════════
   COLONNE DROITE — Panneau de mise en forme (240 px)
   ══════════════════════════════════════════════════════════════════════ */
.scribe-format-panel {
    width: 300px;
    height: 70%;
    align-self: center;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    border-radius: 10px;
    /* Même habillage "verre" que .ard-tools (Ardoise) / .scribe-sidebar */
    background: var(--color-surface);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
            backdrop-filter: blur(6px) saturate(120%);
    border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
    box-shadow: 0 2px 10px rgba(0,0,0,.10), 0 1px 3px rgba(0,0,0,.06);
}
[data-theme="dark"] .scribe-format-panel {
    border-color: color-mix(in srgb, var(--color-border) 100%, transparent);
    box-shadow: 0 4px 18px rgba(0,0,0,.38), 0 1px 4px rgba(0,0,0,.18);
}
.sfp-inner {
    flex: 1;
    overflow-y: auto;
    padding: 18px 16px 34px;
}
.sfp-inner::-webkit-scrollbar { width: 3px; }
.sfp-inner::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 2px; }

/* Section — rythme vertical aéré + fin séparateur entre sections */
.sfp-section { margin-bottom: 22px; }
.sfp-section + .sfp-section {
    border-top: 1px solid var(--color-border, rgba(255,255,255,0.06));
    padding-top: 20px;
}
.sfp-section-title {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--color-text-tertiary, var(--color-text-muted));
    padding: 0 2px 11px;
    display: block;
}

/* Grille de boutons */
.sfp-grid { display: grid; gap: 7px; }
.sfp-grid-4 { grid-template-columns: repeat(4, 1fr); }
.sfp-grid-3 { grid-template-columns: repeat(3, 1fr); }

/* ── Couleur du texte / surlignage — rangées de pastilles ── */
.sfp-swatch-row {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 9px;
    padding: 0 2px;
}
.sfp-swatch-label {
    font-size: 12px;
    font-weight: 700;
    color: var(--color-text-secondary);
    width: 16px;
    text-align: center;
    flex-shrink: 0;
}
.sfp-swatch-label-mark {
    background: rgba(234, 179, 8, .38);
    border-radius: 4px;
}
.sfp-swatch {
    width: 19px;
    height: 19px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    transition: transform .1s, border-color .15s;
}
.sfp-swatch:hover {
    transform: scale(1.18);
    border-color: var(--color-text-secondary);
}
.sfp-swatch-reset {
    background:
        linear-gradient(135deg, transparent 44%, #ef4444 46%, #ef4444 54%, transparent 56%);
    border: 2px solid var(--color-border);
}

/* ── Pipette de couleur personnalisée (texte / surlignage / note) ── */
.sfp-color-picker {
    -webkit-appearance: none;
    appearance: none;
    width: 19px;
    height: 19px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    padding: 0;
    cursor: pointer;
    flex-shrink: 0;
    background: conic-gradient(#ef4444, #f59e0b, #eab308, #22c55e, #3b82f6, #8b5cf6, #ec4899, #ef4444);
    transition: transform .1s, border-color .15s;
}
.sfp-color-picker:hover {
    transform: scale(1.18);
    border-color: var(--color-text-secondary);
}
/* ── Carte color-picker AQIN (remplace le picker natif) ── */
.aq-color-pop {
    position: fixed;
    z-index: 11000;
    width: 208px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 16px;
    box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
    padding: 12px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.scribe-bg-pop {
    position: fixed;
    z-index: 11000;
    width: 176px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 14px;
    box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
    padding: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
.scribe-bg-opt {
    width: 34px;
    height: 34px;
    border-radius: 8px;
    border: 1.5px solid var(--color-border);
    background: var(--color-bg);
    color: var(--color-text-secondary);
    cursor: pointer;
    padding: 4px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform .1s, border-color .1s;
    flex-shrink: 0;
}
.scribe-bg-opt:hover { transform: scale(1.08); color: var(--color-text); }
.scribe-bg-opt.active { border-color: var(--color-primary, #3b82f6); border-width: 2px; color: var(--color-primary, #3b82f6); }
.aq-cp-sv {
    position: relative;
    height: 130px;
    border-radius: 10px;
    cursor: crosshair;
    touch-action: none;
}
.aq-cp-dot {
    position: absolute;
    width: 14px; height: 14px;
    border: 2.5px solid #fff;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .5);
    pointer-events: none;
}
.aq-cp-hue {
    position: relative;
    height: 12px;
    border-radius: 999px;
    background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
    cursor: pointer;
    touch-action: none;
}
.aq-cp-thumb {
    position: absolute;
    top: 50%;
    width: 16px; height: 16px;
    border: 2.5px solid #fff;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 1px 4px rgba(0, 0, 0, .5);
    pointer-events: none;
}
.aq-cp-row { display: flex; align-items: center; gap: 8px; }
.aq-cp-preview {
    width: 26px; height: 26px;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    flex-shrink: 0;
}
.aq-cp-hex {
    flex: 1; min-width: 0;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 10px;
    color: var(--color-text);
    font-family: ui-monospace, monospace;
    font-size: 12.5px;
    padding: 7px 9px;
    outline: none;
}
.aq-cp-hex:focus { border-color: var(--color-primary, #3b82f6); }
.aq-cp-ok {
    background: var(--color-primary, #3b82f6);
    color: #fff;
    border: none;
    border-radius: 10px;
    font-size: 12.5px;
    font-weight: 600;
    padding: 7px 12px;
    cursor: pointer;
    transition: filter .15s;
}
.aq-cp-ok:hover { filter: brightness(1.12); }

/* ── Police / taille — selects compacts ── */
.sfp-selects {
    display: flex;
    gap: 7px;
    margin-top: 9px;
}
.sfp-select {
    flex: 1;
    min-width: 0;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 11px;
    color: var(--color-text);
    font-size: 12.5px;
    font-family: inherit;
    padding: 9px 11px;
    outline: none;
    cursor: pointer;
    transition: border-color .15s, background .15s;
}
.sfp-select:hover { border-color: rgba(255,255,255,0.16); }
.sfp-select:focus { border-color: var(--color-primary, #3b82f6); }

/* ── Bloc navigation (Accueil / Nouvelle page / Partager) — en-tête ── */
.sfp-section-nav { margin-bottom: 20px; }
.sfp-section-nav .sfp-btn {
    min-height: 56px;
    background: var(--color-bg, rgba(255,255,255,0.02));
}
.sfp-section-nav .sfp-btn .sfp-icon { height: 20px; }
.sfp-section-nav .sfp-btn:hover {
    background: rgba(59,130,246,0.10);
    border-color: rgba(59,130,246,0.30);
    color: var(--color-primary, #3b82f6);
}

/* Bouton de format (icône + label) */
.sfp-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: var(--color-surface, rgba(255,255,255,0.025));
    border: 1px solid var(--color-border, rgba(255,255,255,0.07));
    border-radius: 13px;
    padding: 11px 4px 9px;
    cursor: pointer;
    color: var(--color-text-secondary, #aaa);
    transition: background .15s, border-color .15s, color .15s, transform .12s, box-shadow .15s;
    user-select: none;
    min-height: 60px;
}
.sfp-btn:hover {
    background: rgba(255,255,255,0.06);
    border-color: rgba(255,255,255,0.16);
    color: var(--color-text-primary);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(0,0,0,0.18);
}
.sfp-btn.active {
    background: rgba(59,130,246,0.14);
    border-color: rgba(59,130,246,0.4);
    color: var(--color-primary, #3b82f6);
    box-shadow: 0 0 0 1px rgba(59,130,246,0.25) inset;
}
.sfp-btn:active {
    transform: translateY(0);
    background: rgba(59,130,246,0.20);
    border-color: rgba(59,130,246,0.45);
}
.sfp-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 15px;
    font-weight: 600;
    line-height: 1;
    height: 22px;
    flex-shrink: 0;
}
.sfp-icon svg { width: 16px; height: 16px; }
.sfp-label {
    font-size: 10.5px;
    font-weight: 500;
    text-align: center;
    line-height: 1.15;
    letter-spacing: .01em;
    white-space: nowrap;
    color: inherit;
    opacity: .92;
}

/* Compteur de mots */
.sfp-stats-section { padding-bottom: 4px; }
.sfp-wordcount {
    font-size: 11px;
    color: var(--color-text-muted);
    text-align: center;
    letter-spacing: .02em;
    padding: 4px 0;
    user-select: none;
}

/* Zone danger */
.sfp-danger-zone {
    padding: 16px 0 4px;
    border-top: 1px solid var(--color-border, rgba(255,255,255,0.07));
    margin-top: 6px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.sfp-duplicate-btn {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    background: rgba(59,130,246,0.08);
    color: var(--color-primary, #3b82f6);
    border: 1px solid rgba(59,130,246,0.18);
    border-radius: 10px;
    padding: 8px 12px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background .15s, border-color .15s;
}
.sfp-duplicate-btn:hover {
    background: rgba(59,130,246,0.16);
    border-color: rgba(59,130,246,0.35);
}
.sfp-delete-btn {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    background: rgba(239,68,68,0.08);
    color: #ef4444;
    border: 1px solid rgba(239,68,68,0.18);
    border-radius: 10px;
    padding: 8px 12px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background .15s, border-color .15s;
}
.sfp-delete-btn:hover {
    background: rgba(239,68,68,0.16);
    border-color: rgba(239,68,68,0.35);
}

/* ── Swatches de couleur de note ─────────────────────────────────────── */
.sfp-colors {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    padding: 2px 0;
}
.scribe-color-btn {
    background: none;
    border: none;
    cursor: pointer;
    padding: 3px;
    border-radius: 50%;
    opacity: .55;
    transition: opacity .15s, transform .15s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.scribe-color-btn:hover    { opacity: 1; transform: scale(1.15); }
.scribe-color-btn.active   { opacity: 1; transform: scale(1.2); }
.scribe-color-btn.active .scribe-color-swatch {
    outline: 2px solid var(--color-text-primary, #fff);
    outline-offset: 1.5px;
}
.scribe-color-swatch {
    display: block;
    width: 18px;
    height: 18px;
    border-radius: 50%;
}
.scribe-color-swatch--none {
    background: transparent;
    border: 1.5px dashed var(--color-text-muted, #666);
}

/* ── Scroll A4 — fond gris type traitement de texte ────────────────── */
.scribe-a4-scroll {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    overscroll-behavior: contain;
}
.scribe-a4-scroll::-webkit-scrollbar { width: 4px; }
.scribe-a4-scroll::-webkit-scrollbar-thumb { background: rgba(0,0,0,.25); border-radius: 2px; }

/* ── Feuille A4 — centrée avec ombre, fond = couleur de l'app ───────── */
.scribe-a4-sheet {
    flex: none;
    width: 100%;
    max-width: 794px;
    min-height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--color-bg);
    box-shadow: 0 1px 4px rgba(0,0,0,.15), 0 4px 20px rgba(0,0,0,.10);
    border-radius: 16px;
}
html[data-theme="dark"] .scribe-a4-sheet {
    background: #1a1a1a !important;
    box-shadow: 0 1px 4px rgba(0,0,0,.5), 0 4px 20px rgba(0,0,0,.4);
}
/* .scribe-img n'avait aucune contrainte de taille — ça "marchait" par
   accident en vue normale car .scribe-a4-sheet a overflow:hidden, qui
   rogne l'image à la taille native au lieu de l'adapter. En plein écran,
   la feuille passe en overflow:visible (pour d'autres raisons), ce qui
   supprime ce rognage accidentel et affiche l'image à sa taille réelle
   (souvent plusieurs milliers de px) — d'où le zoom/recadrage inattendu. */
.scribe-img { max-width: 100%; height: auto; cursor: pointer; }
.scribe-img-frame { position: relative; display: block; overflow: hidden; border-radius: 6px; max-width: 100%; cursor: pointer; -webkit-user-drag: none; user-select: none; }
.scribe-img-frame.sh-img-selected { outline: 2px solid var(--color-primary, #3b82f6); outline-offset: 3px; }
.scribe-img-frame.sh-block-dragging { opacity: .5; }
/* -webkit-user-drag/user-select : sans ça, un mousedown+glisser directement
   sur l'image (contenteditable=false imbriquee dans #scribe-content qui est
   contenteditable=true) est intercepte par le "glisser la selection" natif
   du navigateur avant nos propres listeners mousemove -- le glisser-pour-
   recentrer (object-position) ne se declenchait donc jamais malgre une
   logique JS correcte (confirme par simulation d'evenements synthetiques).
   Meme fix deja utilise sur .scribe-sig-img dans ce fichier. */
.scribe-img-frame img { width: 100%; height: 100%; object-fit: cover; display: block; margin: 0; border-radius: 0; cursor: pointer; -webkit-user-drag: none; user-select: none; }
.scribe-img-handle { position: fixed; width: 14px; height: 14px; transform: translate(-50%, -50%); background: var(--color-primary, #3b82f6); border: 2px solid #fff; border-radius: 3px; z-index: 9999; box-shadow: 0 1px 4px rgba(0,0,0,.35); touch-action: none; }
.scribe-img-move-handle { position: fixed; width: 26px; height: 26px; transform: translate(-50%, -50%); background: var(--color-primary, #3b82f6); color: #fff; border: 2px solid #fff; border-radius: 8px; z-index: 9999; box-shadow: 0 1px 4px rgba(0,0,0,.35); touch-action: none; cursor: grab; display: flex; align-items: center; justify-content: center; font-size: 14px; line-height: 1; user-select: none; }
.scribe-img-move-handle:active { cursor: grabbing; }
/* Calque invisible superpose a l'image selectionnee, en dehors de
   #scribe-content (comme les poignees) pour recevoir de façon fiable le
   glisser de recentrage a la souris -- cf. commentaire detaille dans
   scribe.js (_makePanOverlay). z-index sous les poignees (9999) pour
   qu'elles restent cliquables la ou elles chevauchent son bord. */
.scribe-img-pan-overlay { position: fixed; z-index: 9997; cursor: crosshair; touch-action: none; background: transparent; }
.scribe-img-pan-overlay:active { cursor: grabbing; }

/* ── Fond de page (motifs) ──────────────────────────────────────────────
   !important requis : .scribe-editor-pane.scribe-fullpage .scribe-a4-sheet
   (mode plein ecran) pose un background:#fff en specificite superieure
   (3 classes vs 2) et sans !important -- sans ceci, n'importe quel motif
   choisi disparait des qu'on passe en plein ecran (theme clair). Meme
   traitement que les variantes [data-theme="dark"] plus bas. ── */
.scribe-a4-sheet[data-bg="dots"] {
    background-image: radial-gradient(circle, rgba(59,130,246,.25) 1.5px, transparent 1.5px) !important;
    background-size: 20px 20px !important;
}
.scribe-a4-sheet[data-bg="bigdots"] {
    background-image: radial-gradient(circle, rgba(59,130,246,.25) 3px, transparent 3px) !important;
    background-size: 40px 40px !important;
}
.scribe-a4-sheet[data-bg="grid"] {
    background-image:
        linear-gradient(rgba(59,130,246,.13) 1px, transparent 1px),
        linear-gradient(90deg, rgba(59,130,246,.13) 1px, transparent 1px) !important;
    background-size: 20px 20px !important;
}
.scribe-a4-sheet[data-bg="lines"] {
    background-image: linear-gradient(rgba(59,130,246,.2) 1px, transparent 1px) !important;
    background-size: 100% 32px !important;
    background-position: 0 24px !important;
}
.scribe-a4-sheet[data-bg="seyes"] {
    background-image:
        linear-gradient(rgba(59,130,246,.09) 1px, transparent 1px),
        linear-gradient(rgba(59,130,246,.22) 1px, transparent 1px),
        linear-gradient(90deg, rgba(59,130,246,.09) 1px, transparent 1px) !important;
    background-size: 100% 8px, 100% 32px, 56px 32px !important;
    background-position: 0 0, 0 0, 48px 0 !important;
}
.scribe-a4-sheet[data-bg="staff"] {
    background-image: repeating-linear-gradient(
        transparent 0px,   transparent 6px,
        rgba(59,130,246,.22) 6px,  rgba(59,130,246,.22) 7px,
        transparent 7px,   transparent 13px,
        rgba(59,130,246,.22) 13px, rgba(59,130,246,.22) 14px,
        transparent 14px,  transparent 20px,
        rgba(59,130,246,.22) 20px, rgba(59,130,246,.22) 21px,
        transparent 21px,  transparent 27px,
        rgba(59,130,246,.22) 27px, rgba(59,130,246,.22) 28px,
        transparent 28px,  transparent 34px,
        rgba(59,130,246,.22) 34px, rgba(59,130,246,.22) 35px,
        transparent 35px,  transparent 56px
    ) !important;
    background-size: 100% 56px !important;
}
.scribe-a4-sheet[data-bg="iso"] {
    background-image:
        linear-gradient(30deg,  rgba(59,130,246,.11) 1px, transparent 1px),
        linear-gradient(150deg, rgba(59,130,246,.11) 1px, transparent 1px),
        linear-gradient(90deg,  rgba(59,130,246,.11) 1px, transparent 1px) !important;
    background-size: 23px 40px, 23px 40px, 46px 40px !important;
}
/* html[data-theme="dark"] .scribe-a4-sheet utilise le raccourci "background"
   avec !important (pour forcer le fond sombre de l'app) — ce raccourci remet
   AUSSI background-image/size/position à leur valeur initiale, en !important
   implicite. Les règles de motif ci-dessous doivent donc être !important ET
   avoir une spécificité supérieure ([data-theme="dark"] + classe + attribut
   = 3 vs 2 pour la règle de fond) pour rester visibles en thème sombre. */
[data-theme="dark"] .scribe-a4-sheet[data-bg="dots"] {
    background-image: radial-gradient(circle, rgba(99,179,237,.22) 1.5px, transparent 1.5px) !important;
    background-size: 20px 20px !important;
}
[data-theme="dark"] .scribe-a4-sheet[data-bg="bigdots"] {
    background-image: radial-gradient(circle, rgba(99,179,237,.22) 3px, transparent 3px) !important;
    background-size: 40px 40px !important;
}
[data-theme="dark"] .scribe-a4-sheet[data-bg="grid"] {
    background-image:
        linear-gradient(rgba(99,179,237,.1) 1px, transparent 1px),
        linear-gradient(90deg, rgba(99,179,237,.1) 1px, transparent 1px) !important;
    background-size: 20px 20px !important;
}
[data-theme="dark"] .scribe-a4-sheet[data-bg="lines"] {
    background-image: linear-gradient(rgba(99,179,237,.15) 1px, transparent 1px) !important;
    background-size: 100% 32px !important;
    background-position: 0 24px !important;
}
[data-theme="dark"] .scribe-a4-sheet[data-bg="seyes"] {
    background-image:
        linear-gradient(rgba(99,179,237,.09) 1px, transparent 1px),
        linear-gradient(rgba(99,179,237,.22) 1px, transparent 1px),
        linear-gradient(90deg, rgba(99,179,237,.09) 1px, transparent 1px) !important;
    background-size: 100% 8px, 100% 32px, 56px 32px !important;
    background-position: 0 0, 0 0, 48px 0 !important;
}
[data-theme="dark"] .scribe-a4-sheet[data-bg="staff"] {
    background-image: repeating-linear-gradient(
        transparent 0px,   transparent 6px,
        rgba(99,179,237,.22) 6px,  rgba(99,179,237,.22) 7px,
        transparent 7px,   transparent 13px,
        rgba(99,179,237,.22) 13px, rgba(99,179,237,.22) 14px,
        transparent 14px,  transparent 20px,
        rgba(99,179,237,.22) 20px, rgba(99,179,237,.22) 21px,
        transparent 21px,  transparent 27px,
        rgba(99,179,237,.22) 27px, rgba(99,179,237,.22) 28px,
        transparent 28px,  transparent 34px,
        rgba(99,179,237,.22) 34px, rgba(99,179,237,.22) 35px,
        transparent 35px,  transparent 56px
    ) !important;
    background-size: 100% 56px !important;
}
[data-theme="dark"] .scribe-a4-sheet[data-bg="iso"] {
    background-image:
        linear-gradient(30deg,  rgba(99,179,237,.11) 1px, transparent 1px),
        linear-gradient(150deg, rgba(99,179,237,.11) 1px, transparent 1px),
        linear-gradient(90deg,  rgba(99,179,237,.11) 1px, transparent 1px) !important;
    background-size: 23px 40px, 23px 40px, 46px 40px !important;
}

/* ── Motifs fond de page sur les cartes de la liste ────────────────── */
.scribe-note-item[data-bg="dots"] {
    background-image: radial-gradient(circle, rgba(99,130,246,.28) 1.5px, transparent 1.5px);
    background-size: 20px 20px;
}
.scribe-note-item[data-bg="bigdots"] {
    background-image: radial-gradient(circle, rgba(99,130,246,.28) 3px, transparent 3px);
    background-size: 40px 40px;
}
.scribe-note-item[data-bg="grid"] {
    background-image:
        linear-gradient(rgba(99,130,246,.18) 1px, transparent 1px),
        linear-gradient(90deg, rgba(99,130,246,.18) 1px, transparent 1px);
    background-size: 20px 20px;
}
.scribe-note-item[data-bg="lines"] {
    background-image: linear-gradient(rgba(99,130,246,.25) 1px, transparent 1px);
    background-size: 100% 28px;
    background-position: 0 18px;
}
.scribe-note-item[data-bg="seyes"] {
    background-image:
        linear-gradient(rgba(99,130,246,.12) 1px, transparent 1px),
        linear-gradient(rgba(99,130,246,.28) 1px, transparent 1px),
        linear-gradient(90deg, rgba(99,130,246,.12) 1px, transparent 1px);
    background-size: 100% 7px, 100% 28px, 56px 28px;
    background-position: 0 0, 0 0, 48px 0;
}
.scribe-note-item[data-bg="staff"] {
    background-image: repeating-linear-gradient(
        transparent 0px, transparent 5px, rgba(99,130,246,.28) 5px, rgba(99,130,246,.28) 6px,
        transparent 6px, transparent 11px, rgba(99,130,246,.28) 11px, rgba(99,130,246,.28) 12px,
        transparent 12px, transparent 17px, rgba(99,130,246,.28) 17px, rgba(99,130,246,.28) 18px,
        transparent 18px, transparent 23px, rgba(99,130,246,.28) 23px, rgba(99,130,246,.28) 24px,
        transparent 24px, transparent 29px, rgba(99,130,246,.28) 29px, rgba(99,130,246,.28) 30px,
        transparent 30px, transparent 46px
    );
    background-size: 100% 46px;
}
.scribe-note-item[data-bg="iso"] {
    background-image:
        linear-gradient(30deg,  rgba(99,130,246,.15) 1px, transparent 1px),
        linear-gradient(150deg, rgba(99,130,246,.15) 1px, transparent 1px),
        linear-gradient(90deg,  rgba(99,130,246,.15) 1px, transparent 1px);
    background-size: 23px 40px, 23px 40px, 46px 40px;
}

/* ── Mobile : pleine largeur, pas de marges grises ─────────────────── */
@media (max-width: 640px) {
    .scribe-a4-scroll { padding: 0; background: transparent; align-items: stretch; }
    .scribe-a4-sheet  { max-width: 100%; min-height: 100dvh; box-shadow: none; border-radius: 0; }
    .scribe-img-frame { max-width: 100% !important; margin-left: 0 !important; }
    .scribe-img-frame img { height: 100% !important; }
}

/* ── Zone de texte riche ────────────────────────────────────────────── */
.scribe-content {
    flex: 1;
    padding: 56px 64px 64px;
    outline: none;
    font-size: 14.5px;
    line-height: 1.8;
    color: var(--color-text-primary);
    overflow-y: visible;   /* scroll géré par .scribe-a4-scroll */
    word-break: break-word;
    white-space: pre-wrap;
    min-height: 500px;
    /* Ancre les dessins flottants (.scribe-drawing-block.sh-floating,
       position:absolute) -- le conteneur grandit avec le contenu (jamais
       lui-même le scroller, cf. commentaire overflow-y ci-dessus), donc un
       dessin flottant reste ancré à son point de la page en défilant, pas
       juste au viewport. Etait position:static par défaut -- sans effet
       visuel sur le reste, aucune règle existante n'en dépendait. */
    position: relative;
}
.scribe-content:empty::before {
    content: attr(data-placeholder);
    color: var(--color-text-muted);
    pointer-events: none;
    display: block;
}

/* ── Signature insérée dans le document ─────────────────────────────── */
.scribe-signature {
    display: inline-block;
    margin: 18px 0 6px;
    padding-bottom: 3px;
    border-bottom: 1.5px solid currentColor;
    font-size: 20px;
    line-height: 1.3;
    opacity: .9;
}
.scribe-signature.sig-cursive  { font-family: 'Brush Script MT', 'Dancing Script', cursive; font-size: 24px; }
.scribe-signature.sig-elegant  { font-family: Georgia, 'Times New Roman', serif; font-style: italic; font-size: 21px; }
.scribe-signature.sig-mono     { font-family: 'Courier New', monospace; font-size: 16px; letter-spacing: 1px; }

/* ── Champ de saisie de signature ────────────────────────────────────── */
.sfp-signature-input {
    width: 100%;
    background: var(--color-surface-hover, rgba(255,255,255,0.05));
    border: 1px solid var(--color-border, rgba(255,255,255,0.1));
    border-radius: 8px;
    padding: 7px 10px;
    font-size: 13px;
    color: var(--color-text-primary);
    outline: none;
    box-sizing: border-box;
    margin-bottom: 2px;
}
.sfp-signature-input::placeholder { color: var(--color-text-muted); }
.sfp-signature-input:focus { border-color: rgba(59,130,246,0.45); }

.sfp-insert-sig-btn {
    width: 100%;
    margin-top: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: rgba(59,130,246,0.1);
    color: var(--color-primary, #3b82f6);
    border: 1px solid rgba(59,130,246,0.25);
    border-radius: 8px;
    padding: 7px 10px;
    font-size: 12.5px;
    font-weight: 500;
    cursor: pointer;
    transition: background .15s;
}
.sfp-insert-sig-btn:hover { background: rgba(59,130,246,0.18); }

/* Sous-section signature (Écrire / Dessiner) */
.sfp-sig-sub-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--color-text-muted);
    margin-bottom: 6px;
}
/* Miniatures signatures dessinées — fond blanc (encre sombre sur papier) */
.sfp-sig-thumb {
    position: relative;
    border: 1.5px solid var(--color-border);
    border-radius: 8px;
    background: #fff;          /* fond blanc pour rendre l'encre visible en dark mode */
    cursor: pointer;
    padding: 4px 8px;
    transition: border-color .15s, box-shadow .15s;
    display: flex;
    align-items: center;
    justify-content: center;
    max-width: 90px;
    height: 42px;
    overflow: hidden;
}
.sfp-sig-thumb:hover { border-color: var(--color-primary, #3b82f6); box-shadow: 0 0 0 2px rgba(59,130,246,.25); }
.sfp-sig-thumb img { max-height: 34px; max-width: 80px; object-fit: contain; display: block; }
.sfp-sig-thumb-del {
    position: absolute;
    top: 2px; right: 2px;
    width: 16px; height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0,0,0,.06);
    border: none;
    border-radius: 50%;
    color: var(--color-text-muted);
    font-size: 12px;
    cursor: pointer;
    line-height: 1;
    padding: 0;
    opacity: .55;
    transition: opacity .15s, background .15s, color .15s;
}
.sfp-sig-thumb:hover .sfp-sig-thumb-del { opacity: 1; }
.sfp-sig-thumb-del:hover { background: rgba(239,68,68,.18); color: #ef4444; }

/* ── Impression / Export PDF ─────────────────────────────────────────── */
@media print {
    /* Masquer tout sauf la feuille A4 */
    html, body { background: #fff !important; overflow: visible !important; height: auto !important; }
    .header, .scribe-sidebar, .scribe-format-panel,
    .scribe-back-btn, .scribe-saved-indicator,
    .scribe-a4-scroll { background: transparent !important; padding: 0 !important; }
    .scribe-a4-sheet {
        box-shadow: none !important;
        border: none !important;
        border-radius: 0 !important;
        min-height: 0 !important;
        width: 100% !important;
        background: #fff !important;
        color: #000 !important;
        overflow: visible !important;
    }
    .scribe-content {
        color: #000 !important;
        overflow: visible !important;
        padding: 0 !important;
    }
    .scribe-content h1, .scribe-content h2, .scribe-content h3 { color: #000 !important; }
    .scribe-content th, .scribe-content td { border-color: #bbb !important; color: #000 !important; }
    .scribe-content th { background: #f2f2f2 !important; }
    .scribe-content table.scribe-cols td { border: none !important; }
    /* Saut de page : invisible mais effectif à l'impression */
    .scribe-content .scribe-page-break {
        page-break-after: always !important;
        break-after: page !important;
        height: 0 !important;
        margin: 0 !important;
        overflow: hidden !important;
    }
    .scribe-content .scribe-page-break::before,
    .scribe-content .scribe-page-break::after,
    .scribe-content .scribe-page-break span { display: none !important; }
    .scribe-signature { color: #000 !important; border-color: #000 !important; }
    /* En-tête / pied de page — retrait des paddings d'écran, style épuré */
    .scribe-doc-header { padding: 0 0 8px !important; margin-bottom: 12px !important; color: #555 !important; }
    .scribe-doc-footer { padding: 8px 0 0 !important; margin-top: 20px !important; color: #555 !important; }
    .scribe-hf-label   { display: none !important; }
    .scribe-hf-textarea { color: #555 !important; font-size: 11px !important; padding: 0 !important; }
    @page { size: A4; margin: 20mm; }
}

/* Styles de contenu riche */
.scribe-content h1 { font-size: 22px; font-weight: 700; margin: 20px 0 8px; letter-spacing: -.02em; }
.scribe-content h2 { font-size: 18px; font-weight: 600; margin: 16px 0 6px; }
.scribe-content h3 { font-size: 15px; font-weight: 600; margin: 12px 0 4px; }
.scribe-content p  { margin: 0 0 12px; }
.scribe-content ul,
.scribe-content ol { padding-left: 22px; margin: 5px 0; }
.scribe-content li { margin: 2px 0; }
.scribe-content blockquote {
    border-left: 3px solid var(--color-primary, #3b82f6);
    padding-left: 14px;
    margin: 10px 0;
    color: var(--color-text-secondary);
    font-style: italic;
    opacity: .85;
}
.scribe-content hr {
    border: none;
    border-top: 1px solid var(--color-border, rgba(255,255,255,.12));
    margin: 16px 0;
}
.scribe-content b,
.scribe-content strong { font-weight: 700; }
.scribe-content i,
.scribe-content em { font-style: italic; }
.scribe-content u  { text-decoration: underline; }
.scribe-content s,
.scribe-content strike { text-decoration: line-through; opacity: .7; }
.scribe-content a  { color: var(--color-primary, #3b82f6); text-decoration: underline; }
.scribe-content code {
    background: rgba(255,255,255,.07);
    border-radius: 4px;
    padding: 1px 5px;
    font-family: monospace;
    font-size: .9em;
}
/* Tableaux (import Markdown notamment) — cadrés dans la page A4 :
   largeur 100 % max, colonnes fixes, contenu des cellules qui wrappe. */
.scribe-content table {
    width: 100%;
    max-width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    margin: 10px 0;
    font-size: .95em;
}
.scribe-content th,
.scribe-content td {
    border: 1px solid var(--color-border, rgba(255,255,255,.14));
    padding: 7px 10px;
    text-align: left;
    vertical-align: top;
    word-break: break-word;
    overflow-wrap: break-word;
    white-space: normal;
}
.scribe-content th {
    font-weight: 600;
    background: rgba(255,255,255,.04);
}
/* Colonnes de mise en page — invisible par défaut (ce sont des colonnes de
   mise en page, pas un vrai tableau de données) ; guide pointillé affiché
   seulement au survol/focus, pour retrouver les limites des colonnes si
   elles sont encore vides. Jamais de bordure à l'impression / export
   (cf. @media print + _buildPrintHtml). */
.scribe-content table.scribe-cols td {
    border: 1px dashed transparent;
    /* Le padding par défaut des cellules (pensé pour un vrai tableau de
       données) décale le texte vers l'intérieur -- ici les colonnes sont
       une mise en page, le contenu doit toucher les mêmes marges que le
       reste de la page (titre, signature...). Padding gardé seulement
       entre les deux colonnes, pas sur les bords extérieurs. */
    padding-top: 7px;
    padding-bottom: 7px;
    padding-left: 0;
    padding-right: 0;
}
.scribe-content table.scribe-cols td:first-child { padding-right: 24px; }
.scribe-content table.scribe-cols td:last-child  { padding-left: 24px; }
.scribe-content table.scribe-cols:hover td,
.scribe-content table.scribe-cols:focus-within td {
    border-color: rgba(128,128,128,.30);
}
/* Badge logo cliquable des modèles (cercle "VOTRE LOGO" / "Logo") — clic
   ouvre le sélecteur d'image (cf. scribe.js), léger effet au survol. */
.scribe-content .scribe-logo-placeholder {
    transition: opacity .15s;
}
.scribe-content .scribe-logo-placeholder:hover {
    opacity: .72;
}
/* Saut de page — séparateur visuel dans l'éditeur ; vraie nouvelle page
   à l'impression / export PDF / volet pages. */
.scribe-content .scribe-page-break {
    display: block;
    height: 0;
    margin: 40px 0;
    border-top: 1.5px dashed var(--color-border);
    user-select: none;
    cursor: default;
}
.scribe-content .scribe-page-break::before,
.scribe-content .scribe-page-break::after { content: none; }
.scribe-content .scribe-page-break span { display: none; }

/* Bloc Mémo — chip compact cliquable dans l'A4 ; édition via panneau flottant */
.scribe-memo-block {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 12px 4px 10px;
    border-radius: 20px;
    margin: 6px 0;
    background: color-mix(in srgb, var(--color-primary, #6366f1) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-primary, #6366f1) 22%, transparent);
    cursor: pointer;
    user-select: none;
    transition: background .12s, border-color .12s;
    vertical-align: middle;
}
.scribe-memo-block::before {
    content: '📝  MÉMO';
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--color-primary, #6366f1);
    pointer-events: none;
}
/* Le contenu est géré par le panneau flottant — caché dans l'A4 */
.scribe-memo-block-body { display: none; }
/* Impression : restaurer le contenu en plein bloc */
@media print {
    .scribe-memo-block {
        display: block;
        padding: 0;
        border-radius: 12px;
        background: #f1f5f9 !important;
        border: none;
        box-shadow: none !important;
    }
    .scribe-memo-block::before {
        display: flex; align-items: center;
        padding: 7px 14px;
        font-size: 10px;
        color: #64748b !important;
        border-bottom: 1px solid #e2e8f0;
    }
    .scribe-memo-block-body {
        display: block !important;
        padding: 10px 14px 12px;
        font-size: 13px;
        line-height: 1.6;
        color: #1e293b !important;
    }
}

/* Wrapper de signature — flux inline, respecte les sauts de page. Fond
   transparent voulu (pas de "carte" blanche autour du trait) -- la
   visibilité sur theme sombre se règle via la couleur du trait
   (bouton couleur du canvas de dessin), pas via un fond force. */
.scribe-sig-block {
    display: inline-block;
    vertical-align: bottom;
    line-height: 0;
    break-inside: avoid;
    page-break-inside: avoid;
    margin: 8px 0;
    max-width: 100%;
    cursor: default;
    -webkit-user-drag: none;
    user-select: none;
}
.scribe-sig-block.sh-block-dragging { opacity: .5; }
.scribe-sig-block.sig-selected {
    outline: 2px solid var(--color-primary, #3b82f6);
    outline-offset: 3px;
    cursor: grab;
}
.scribe-sig-block.sig-selected:active { cursor: grabbing; }
.scribe-sig-img {
    width: 100%;
    height: auto;
    display: block;
    border-radius: 2px;
    -webkit-user-drag: none;
    user-select: none;
    pointer-events: none;
}

/* Dessin libre inséré dans la note — même wrapper/comportement (flux inline,
   fond transparent, redimensionnable/déplaçable) que .scribe-sig-block
   ci-dessus, cf. la même IIFE JS qui gère les deux via un sélecteur commun. */
.scribe-drawing-block {
    display: inline-block;
    vertical-align: bottom;
    line-height: 0;
    break-inside: avoid;
    page-break-inside: avoid;
    margin: 8px 0;
    max-width: 100%;
    cursor: default;
    -webkit-user-drag: none;
    user-select: none;
}
.scribe-drawing-block.sh-block-dragging { opacity: .5; }
.scribe-drawing-block.sig-selected {
    outline: 2px solid var(--color-primary, #3b82f6);
    outline-offset: 3px;
    cursor: grab;
}
.scribe-drawing-block.sig-selected:active { cursor: grabbing; }
/* Dessin FLOTTANT (2026-09-01, demande utilisateur "déplaçable dans toute
   la page") -- variante posée n'importe où sur .scribe-content
   (position:relative, cf. plus haut), au lieu du flux inline ci-dessus.
   Nouveaux dessins seulement (cf. _insertDrawingIntoNote, scribe.js) --
   les .scribe-drawing-block déjà existants sans cette classe restent en
   flux, inchangés. */
.scribe-drawing-block.sh-floating {
    position: absolute;
    display: block;
    margin: 0;
    z-index: 5;
}
.scribe-drawing-img {
    width: 100%;
    height: auto;
    display: block;
    border-radius: 2px;
    -webkit-user-drag: none;
    user-select: none;
    pointer-events: none;
}
/* Galerie de photos d'un message DM converti en Mémo (2026-09-29, retour
   utilisateur : "il faut plutôt les rager en galerie" -- capture
   comparative à l'appui, les pièces jointes s'empilaient pleine largeur
   les unes sous les autres). cf DirectMessageController::
   convertMessageToMemo(), un seul <img> isolé garde l'ancien rendu simple.
   column-count plutôt que grid : proportions des photos jamais connues à
   l'avance (portrait/paysage mélangés), une grille à cellules fixes les
   aurait recadrées ou laissé des trous. */
.scribe-memo-gallery {
    column-count: 2;
    column-gap: 8px;
    margin: 8px 0;
}
.scribe-memo-gallery-img {
    display: block;
    width: 100%;
    margin: 0 0 8px;
    border-radius: var(--radius-lg);
    break-inside: avoid;
    -webkit-user-drag: none;
    user-select: none;
}
/* ── Collage d'un document HTML complet dans un mémo (ex: template mail) --
   voir aurore-memo.js, écouteur "paste" de #sh-memo-edit-content. Bloc non
   éditable, distinct du texte du mémo (comme .scribe-drawing-block
   ci-dessus), qui garde le rendu visuel d'origine (couleurs, mise en page)
   plutôt que de le fondre dans le style du mémo. ── */
.sh-memo-html-embed {
    display: block;
    margin: 10px 0;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    overflow: hidden;
    cursor: default;
    -webkit-user-drag: none;
    user-select: none;
}
.sh-memo-html-embed-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    font-size: 12px;
    font-weight: 600;
    color: var(--color-text-secondary);
    background: var(--color-hover);
}
.sh-memo-html-embed-body {
    /* fond fixe (pas var(--color-bg)) : un mail suppose un canevas clair,
       comme dans un vrai client mail, indépendamment du thème sombre de
       l'app -- sinon les zones sans fond explicite dans le mail collé
       laisseraient apparaître le thème sombre en dessous. */
    background: #fff;
    max-height: 480px;
    overflow: auto;
}
#scribe-sig-handle {
    position: fixed;
    width: 14px;
    height: 14px;
    transform: translate(-50%, -50%);
    background: var(--color-primary, #3b82f6);
    border: 2px solid #fff;
    border-radius: 3px;
    cursor: se-resize;
    z-index: 9990;
    box-shadow: 0 1px 4px rgba(0,0,0,0.35);
    touch-action: none;
}
/* Suppression d'une signature/dessin insere dans la note -- coin oppose de
   #scribe-sig-handle (haut-droit). Meme poignee flottante position:fixed,
   meme convention visuelle (cercle rouge, croix blanche) que
   .pdfsign-placed-del cote Scribe PDF. */
#scribe-sig-del-handle {
    position: fixed;
    width: 20px;
    height: 20px;
    padding: 0;
    transform: translate(-50%, -50%);
    background: #ef4444;
    color: #fff;
    border: 2px solid #fff;
    border-radius: 50%;
    font-size: 15px;
    line-height: 16px;
    font-family: inherit;
    cursor: pointer;
    z-index: 9990;
    box-shadow: 0 1px 4px rgba(0,0,0,0.35);
    touch-action: none;
}
#scribe-sig-del-handle:hover { background: #dc2626; }
/* ── Séparateurs de pages DOM — ligne fine "saut de page auto" ── */
.scribe-pg-spacer {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 40px;
    margin: 0;
    background: transparent;
    position: relative;
    pointer-events: none;
    user-select: none;
    -webkit-user-select: none;
    cursor: default;
}
.scribe-pg-spacer::before {
    content: '';
    position: absolute;
    left: 0; right: 0; top: 50%;
    height: 1px;
    background: var(--color-border);
}
.scribe-pg-spacer::after {
    content: attr(data-page);
    position: relative;
    z-index: 1;
    font-size: 10px;
    font-weight: 700;
    color: var(--color-text-tertiary);
    background: var(--color-surface);
    padding: 3px 12px;
    border-radius: 99px;
    border: 1px solid var(--color-border);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    font-family: var(--font-family);
}
@media print {
    .scribe-pg-spacer { display: none !important; }
}

/* ── Bloc d'info fichier (mode édition directe .md depuis le Nuage) ───── */
.spg-file-info {
    padding: 14px 12px 10px;
    border-bottom: 1px solid rgba(0,0,0,.07);
}
[data-theme="dark"] .spg-file-info { border-bottom-color: rgba(255,255,255,.07); }
.spg-file-back {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 12px; font-weight: 500;
    color: rgba(0,0,0,.45); text-decoration: none;
    padding: 4px 8px 4px 6px;
    border-radius: 8px; margin-bottom: 8px;
    transition: background .15s, color .15s;
}
.spg-file-back:hover { background: rgba(0,0,0,.06); color: rgba(0,0,0,.75); }
[data-theme="dark"] .spg-file-back { color: rgba(255,255,255,.4); }
[data-theme="dark"] .spg-file-back:hover { background: rgba(255,255,255,.07); color: rgba(255,255,255,.75); }
.spg-file-back svg { flex-shrink: 0; }
.spg-file-name {
    font-size: 13px; font-weight: 700;
    color: var(--color-text-primary, #1a1a1a);
    line-height: 1.3;
    padding: 0 4px;
    overflow: hidden; display: -webkit-box;
    -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
[data-theme="dark"] .spg-file-name { color: rgba(255,255,255,.85); }

/* ── Volet PAGES de l'éditeur (façon lecteur PDF) ────────────────────── */
.spg-pages {
    display: flex;
    flex-direction: column;
    gap: 12px;
    align-items: stretch;
    padding: 14px 12px 24px;
}
/* Carte de page — même langage visuel que les cartes de notes des dossiers :
   coins 20px, ombre portée, titre gras + extrait, page active en bleu. */
.spg-thumb.spg-card {
    cursor: pointer;
    background: var(--color-surface);
    border-radius: 20px;
    padding: 15px 16px 13px;
    box-shadow: 0 3px 14px rgba(0,0,0,.16), 0 1px 3px rgba(0,0,0,.10);
    transition: transform .18s ease, box-shadow .18s ease;
}
.spg-thumb.spg-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 28px rgba(0,0,0,.24), 0 2px 6px rgba(0,0,0,.12);
}
.spg-thumb.spg-card.active {
    outline: 2px solid var(--color-primary, #3b82f6);
    outline-offset: -1px;
}
.spg-card-title {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: -.01em;
    color: var(--color-text);
    margin-bottom: 6px;
}
.spg-thumb.spg-card.active .spg-card-title {
    color: var(--color-primary, #3b82f6);
}
.spg-card-body {
    font-size: 11.5px;
    line-height: 1.6;
    color: var(--color-text-secondary);
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
    word-break: break-word;
}
.spg-card-empty {
    opacity: .5;
    font-style: italic;
}
/* ── Onglets Pages / Sommaire (en tête du volet, note ouverte seule) ── */
.spg-tabs {
    display: flex;
    gap: 4px;
    padding: 6px 12px 4px;
}
.spg-tab {
    flex: 1;
    padding: 7px 10px;
    border: none;
    border-radius: 10px;
    background: transparent;
    color: var(--color-text-tertiary);
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    transition: background .12s, color .12s;
}
.spg-tab:hover { background: color-mix(in srgb, var(--color-text) 6%, transparent); color: var(--color-text); }
.spg-tab.active { background: color-mix(in srgb, var(--color-primary, #3b82f6) 14%, transparent); color: var(--color-primary, #3b82f6); }
/* ── Bouton "Toutes les notes" -- entrée de nav distincte, pas un 3e onglet
   à égalité avec Pages/Sommaire : contrairement à eux (sous-vues de la note
   OUVERTE), il quitte complètement ce contexte pour la bibliothèque. Réutilise
   la classe .spg-tab pour le wiring générique de _bindSidebarPanelTabs (même
   data-panel, même délégation de clic) -- DOIT rester déclaré APRÈS .spg-tab
   ci-dessus : même spécificité (une classe), donc l'ordre de déclaration
   tranche, et .spg-tab-primary doit gagner sur font-size/color/background
   (repéré en direct 2026-08-15 : déclaré avant, il perdait silencieusement
   la cascade face à .spg-tab). ── */
/* Pas de bleu par défaut : au repos elle a le même langage que .spg-tab
   (transparent/texte tertiaire) -- un bleu permanent, actif ou pas, laissait
   croire à tort que "Toutes les notes" était la vue affichée alors qu'on
   pouvait être sur Pages/Sommaire (repéré en direct 2026-08-15). Le bleu
   n'apparaît donc que sur .active, exactement comme Pages/Sommaire ; seuls
   la taille pleine largeur et le poids de police la distinguent au repos. */
.spg-tab-primary {
    display: block;
    width: calc(100% - 24px);
    margin: 10px 12px 2px;
    padding: 10px 14px;
    border-radius: 12px;
    background: transparent;
    color: var(--color-text-tertiary);
    font-size: 13px;
    font-weight: 700;
    text-align: left;
}
.spg-tab-primary:hover { background: color-mix(in srgb, var(--color-text) 6%, transparent); color: var(--color-text); }
.spg-tab-primary.active { background: color-mix(in srgb, var(--color-primary, #3b82f6) 14%, transparent); color: var(--color-primary, #3b82f6); }
/* ── Volet SOMMAIRE (titres H1/H2/H3 du document, clic = scroll) ── */
.spg-outline {
    display: flex;
    flex-direction: column;
    gap: 1px;
    padding: 6px 10px 24px;
}
.spg-outline-item {
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    border-radius: 9px;
    padding: 7px 10px;
    font-size: 12.5px;
    color: var(--color-text-secondary);
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    transition: background .12s, color .12s;
}
.spg-outline-item:hover { background: color-mix(in srgb, var(--color-text) 6%, transparent); color: var(--color-text); }
.spg-outline-lvl1 { font-weight: 700; font-size: 13px; color: var(--color-text); margin-top: 6px; }
.spg-outline-lvl2 { padding-left: 20px; }
.spg-outline-lvl3 { padding-left: 32px; font-size: 12px; color: var(--color-text-tertiary); }
.spg-outline-empty {
    padding: 20px 14px;
    text-align: center;
    font-size: 12px;
    color: var(--color-text-tertiary);
    font-style: italic;
    line-height: 1.5;
}
/* ── Barre d'édition rapide — pilule flottante au-dessus de la feuille ── */
.scribe-quickbar {
    position: sticky;
    top: 10px;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 2px;
    width: fit-content;
    max-width: calc(100% - 24px);
    flex-wrap: wrap;
    margin: 0 auto 16px;
    padding: 5px 8px;
    border-radius: 16px;
    /* Même habillage "verre" que .ard-tools (Ardoise) */
    background: var(--color-surface);
    -webkit-backdrop-filter: blur(6px) saturate(120%);
            backdrop-filter: blur(6px) saturate(120%);
    border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
    box-shadow: 0 2px 10px rgba(0,0,0,.10), 0 1px 3px rgba(0,0,0,.06);
}
[data-theme="dark"] .scribe-quickbar {
    border-color: color-mix(in srgb, var(--color-border) 100%, transparent);
    box-shadow: 0 4px 18px rgba(0,0,0,.38), 0 1px 4px rgba(0,0,0,.18);
}
/* ── Pastilles quickbar (classe autonome, aucun conflit avec le format panel) ── */
.sqb-dot {
    display: block;
    width: 20px;
    height: 20px;
    min-width: 20px;
    max-width: 20px;
    min-height: 20px;
    max-height: 20px;
    border-radius: 50%;
    border: 2px solid transparent;
    background: transparent;
    padding: 0;
    cursor: pointer;
    flex-shrink: 0;
    flex-grow: 0;
    box-sizing: border-box;
    transition: transform .1s, border-color .15s;
}
.sqb-dot:hover { transform: scale(1.18); border-color: var(--color-text-secondary); }
.sqb-dot.active { outline: 2px solid var(--color-text-primary, #fff); outline-offset: 2px; }
.sqb-dot-reset {
    background: linear-gradient(135deg, transparent 44%, #ef4444 46%, #ef4444 54%, transparent 56%);
    border-color: var(--color-border, rgba(255,255,255,.2));
}
.sqb-dot-picker {
    background: conic-gradient(#ef4444, #f59e0b, #eab308, #22c55e, #3b82f6, #8b5cf6, #ec4899, #ef4444);
    border-color: var(--color-border, rgba(255,255,255,.2));
}

.sqb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 9px;
    background: transparent;
    color: var(--color-text-secondary);
    font-size: 13.5px;
    cursor: pointer;
    transition: background .13s, color .13s;
}
.sqb-btn:hover {
    background: color-mix(in srgb, var(--color-text) 8%, transparent);
    color: var(--color-text);
}
.sqb-btn.active {
    background: #10b981;
    color: #fff;
}
.sqb-b { font-weight: 800; }
.sqb-i { font-style: italic; font-family: Georgia, serif; }
.sqb-u { text-decoration: underline; text-underline-offset: 2px; }
.sqb-s { text-decoration: line-through; }
.sqb-sep {
    width: 1px;
    height: 18px;
    background: var(--color-border);
    margin: 0 5px;
    flex-shrink: 0;
}

/* ── Picker "Depuis le Nuage" (insertion d'image, scribe.js) --
   harmonisé sur le style du picker "Joindre un fichier" de Flow
   (templates/pages/workspace-view.php, .ws-fsp-*) : mêmes onglets
   pilule, même bouton Mon PC, même barre de recherche. La zone de
   résultats reste une GRILLE de vignettes (pas une liste) : c'est un
   picker uniquement dédié aux images, où reconnaître visuellement la
   photo prime sur lire son nom de fichier. */
.scribe-fsp-toolbar {
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
.scribe-fsp-tab {
    padding: 6px 12px; border-radius: 999px;
    background: transparent; border: 1px solid var(--color-border, rgba(255,255,255,.14));
    color: var(--color-text-secondary, #94a3b8);
    font-size: 12px; font-weight: 600; cursor: pointer;
    transition: background .12s, color .12s, border-color .12s;
    flex-shrink: 0;
}
.scribe-fsp-tab:hover { background: color-mix(in srgb, var(--color-text) 8%, transparent); color: var(--color-text); }
.scribe-fsp-tab.active { background: var(--color-primary, #007aff); border-color: var(--color-primary, #007aff); color: #fff; }
.scribe-fsp-upload-btn {
    margin-left: auto;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 6px 12px; border-radius: 999px;
    background: var(--color-bg, transparent); border: 1px solid var(--color-border, rgba(255,255,255,.14));
    color: var(--color-text-secondary, #94a3b8);
    font-size: 12px; font-weight: 600; cursor: pointer;
    transition: background .12s, color .12s;
    flex-shrink: 0; white-space: nowrap;
}
.scribe-fsp-upload-btn:hover { background: color-mix(in srgb, var(--color-text) 8%, transparent); color: var(--color-text); }
.scribe-fsp-upload-btn:disabled { opacity: .55; cursor: not-allowed; }
.scribe-fsp-upload-btn svg { flex-shrink: 0; }
.scribe-fsp-search {
    padding: 8px 12px; border-radius: 8px;
    border: 1.5px solid var(--color-border, rgba(0,0,0,.12));
    font-size: 13px; outline: none; width: 100%; box-sizing: border-box;
}
/* display:flex + taille de tuile calculee en JS (pas aspect-ratio) --
   aspect-ratio sur un item de grille CSS peut ne pas etre pris en compte
   correctement pour le dimensionnement des lignes implicites (constate en
   direct : tuiles qui se chevauchent verticalement) ; meme mecanisme deja
   fiable dans aurore-memo.js/_shMemoNuagePicker et filePanel.js. */
.scribe-fsp-grid {
    display: flex; flex-wrap: wrap; align-content: flex-start;
    gap: 8px; min-height: 180px; max-height: 48vh; overflow-y: auto;
    scrollbar-gutter: stable;
}
.scribe-fsp-tile {
    cursor: pointer; border-radius: 10px; overflow: hidden;
    background: var(--color-surface-2, #f3f4f6); position: relative;
    transition: transform .12s, box-shadow .12s; flex-shrink: 0;
}
.scribe-fsp-tile:hover { transform: scale(1.04); box-shadow: 0 4px 16px rgba(0,0,0,.14); }
.scribe-fsp-tile img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.scribe-fsp-tile img.thumb-broken { display: none; }
.scribe-fsp-tile-name {
    position: absolute; bottom: 0; left: 0; right: 0; padding: 4px 6px;
    font-size: 10px; background: rgba(0,0,0,.45); color: #fff;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.scribe-fsp-status { width: 100%; text-align: center; padding: 24px; color: #888; font-size: 13px; }
.scribe-fsp-err { color: #e44 !important; }

/* ── Panneaux flottants des dropdowns custom (Police/Taille/Interligne,
   Insérer un bloc) -- UNIVERSEL, PAS dans le @media desktop ci-dessous.
   Ces panneaux étaient à l'origine décrits seulement dans le bloc
   desktop (proximité avec le reste de la mise en forme du rail) : sous
   769px, .sqb-select-panel n'avait donc plus aucun position:fixed --
   position retombait à static, où top/right posés en JS (sqb-font-btn
   etc., scribe.js) n'ont AUCUN effet, et le panneau se retrouvait à
   étaler en flux normal (position "aléatoire", pleine largeur) au lieu
   de flotter à côté du bouton. Idem pour .sqb-tile-panel (menu Insérer),
   qui porte aussi la classe .sqb-select-panel. */
.sqb-select-panel {
    position: fixed;
    background: var(--color-surface-2, #1e293b);
    border: 1px solid var(--color-border, rgba(255,255,255,.12));
    border-radius: 10px;
    padding: 4px;
    z-index: 9999;
    min-width: 130px;
    box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
.sqb-select-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 7px 10px;
    font-size: 12px;
    border: none;
    background: none;
    color: var(--color-text);
    cursor: pointer;
    border-radius: 7px;
}
.sqb-select-item:hover {
    background: color-mix(in srgb, var(--color-text) 8%, transparent);
}
/* Variante grille de tuiles icône (menu "Insérer un bloc") — mêmes
   tuiles carrées que le panneau contextuel des tableaux, plutôt que
   la liste texte utilisée pour Police/Taille/Interligne. */
.sqb-tile-panel { display: flex; gap: 4px; min-width: 0; }
/* display:flex ci-dessus a plus de spécificité que le [hidden]{display:none}
   natif du navigateur -- sans cette règle, le panel reste visible même
   une fois hidden=true posé en JS (fermeture "silencieuse" qui ne se voit pas). */
.sqb-tile-panel[hidden] { display: none; }
.sqb-tile-item {
    display: flex; align-items: center; justify-content: center;
    width: 40px; height: 40px;
    border: none; border-radius: 9px;
    background: color-mix(in srgb, var(--color-text) 5%, transparent);
    color: var(--color-text);
    cursor: pointer;
}
.sqb-tile-item:hover {
    background: color-mix(in srgb, var(--color-text) 12%, transparent);
}
/* ── Desktop : colonne VERTICALE façon Ardoise collée au bord droit,
   quasi pleine hauteur. Le panneau de format est MASQUÉ par défaut et
   coulisse à gauche de la colonne via l'onglet flèche (.sfp-panel-tab),
   exactement comme le panneau outils d'Ardoise. ── */
@media (min-width: 769px) {
    /* Rail droit EN FLUX : réserve l'emplacement de l'ancien panneau
       (colonne d'outils + onglet + panneau coulissant y vivent). Il FLEXE :
       c'est lui qui se comprime sur les petites fenêtres, jamais la feuille. */
    body.scribe-page .scribe-layout::after {
        content: '';
        flex: 0 1 440px;
        min-width: 180px;   /* toujours la place de la colonne d'outils (3 colonnes) */
        transition: flex-basis .35s cubic-bezier(0.25, 0.46, 0.45, 0.94),
                    min-width  .35s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    }
    /* Panel ouvert : le rail se réduit à la largeur de la quickbar seule */
    body.sfp-panel-open.scribe-page .scribe-layout::after {
        flex-basis: 116px;
        min-width: 116px;
    }
    /* ── Sidebar absolu : ::before réserve l'espace dans le flux flex,
       symétrique au ::after de la quickbar — pas de padding-left ── */
    /* top:72px, pas 8px : .header est réduit à height:0 partout depuis le
       refactor "floating header" (cf. plus haut dans ce fichier) -- ses
       éléments visibles (breadcrumb, actions) flottent en position:fixed à
       top:14px/height:44px, donc bas réel du bandeau = 58px. .scribe-layout
       ne démarre PAS sous un header en flux (un ancien commentaire ici
       affirmait le contraire, invalidé par ce refactor) : sans compensation
       explicite, la sidebar recouvre le bandeau flottant. 72px = 58 + 14px
       de respiration, même valeur que .scribe-a4-scroll juste au-dessus
       (repéré en direct 2026-08-15, après un premier correctif qui avait
       supprimé cette compensation en la croyant redondante). */
    body.scribe-page .scribe-sidebar {
        position: absolute;
        left: 12px;
        top: 72px;
        bottom: 8px;
        width: 218px;
        overflow-y: auto;
        z-index: 10;
    }
    body.scribe-page .scribe-layout::before {
        content: '';
        flex: 0 0 230px;
        transition: flex-basis .22s cubic-bezier(.4,0,.2,1),
                    min-width  .22s cubic-bezier(.4,0,.2,1);
    }
    body.scribe-page .scribe-layout:has(.scribe-sidebar-hidden)::before {
        flex: 0 0 0px;
        min-width: 0;
    }
    body.scribe-page .scribe-sidebar.scribe-sidebar-hidden {
        width: 0 !important;
        min-width: 0 !important;
    }
    /* ScribePDF : volet retreci pour coller aux vignettes (160px), au lieu
       de la largeur 218px pensee pour la liste de notes de Scribe Notes. */
    body.spdf-qb-desktop.scribe-page .scribe-sidebar:not(.scribe-sidebar-hidden) {
        width: 172px !important;
    }
    body.spdf-qb-desktop.scribe-page .scribe-layout::before {
        flex: 0 0 184px;
    }
    /* 184px supposait un volet retreci a 172px (regle juste au-dessus) --
       jamais atteint en pratique : min-width:200px herite de la regle de
       base .scribe-sidebar (pensee pour Scribe Notes) plafonne le rendu a
       200px quel que soit le width !important pose ici (min-width prime
       toujours sur width, quelle que soit la specificite). La fleche
       restait donc a 28px du vrai bord du volet, flottant sur le contenu
       -- signale par l'utilisateur ("ne se ferme pas", en realite
       decrochee). Repose sur --spdf-sidebar-w (_syncSidebarOffset(),
       largeur REELLEMENT rendue) plutot qu'une constante qui a deja
       divergé une fois : ne peut plus se re-decrocher si la largeur
       change encore. */
    body.spdf-qb-desktop .scribe-sidebar-close-btn {
        left: calc(12px + var(--spdf-sidebar-w, 200px));
    }
    body.scribe-page .scribe-editor-pane:not(.scribe-fullpage) {
        height: 100%;
        overflow: hidden;
    }
    /* La feuille = vraie page A4 stable (~794px + marges intérieures),
       prioritaire sur le rail. Sur fenêtre étroite elle cède en dernier. */
    body.scribe-page .scribe-editor-pane {
        min-width: min(940px, calc(100vw - 560px));
    }
    /* ── Page A4 — feuille centrée, sans fond derrière ── */
    body.scribe-page .scribe-editor-pane:not(.scribe-fullpage) .scribe-a4-scroll {
        overflow-x: auto;
        background: transparent;
        align-items: flex-start;
    }
    body.scribe-page .scribe-editor-pane:not(.scribe-fullpage) .scribe-a4-sheet {
        max-width: 794px;
        min-height: 1123px;
        flex: none;
        margin: 0 auto;
        width: 100%;
    }

    .scribe-quickbar {
        position: fixed;
        /* Meme enveloppe verticale que .ard-tools-wrap desktop (top:70px /
           bottom:8px) et meme hauteur relative (70% de cette enveloppe),
           centree via margin auto. */
        top: 70px;
        bottom: 8px;
        height: calc((100vh - 78px) * 0.7);
        margin-top: auto;
        margin-bottom: auto;
        right: 12px;
        display: grid;
        grid-template-columns: 44px;
        align-content: flex-start;
        justify-content: center;
        width: auto;
        max-width: none;
        margin-left: 0;
        margin-right: 0;
        padding: 8px;
        gap: 4px;
        border-radius: 10px;
        overflow-y: auto;
        scrollbar-width: none;
        z-index: 90;
    }
    .scribe-quickbar::-webkit-scrollbar { display: none; }
    .scribe-quickbar .sqb-sep { grid-column: 1/-1; width: 100%; height: 1px; margin: 2px 0; }
    /* Boutons desktop : même gabarit qu'Ardoise (44×44, radius 11, icônes 20px) */
    .scribe-quickbar .sqb-btn {
        width: 44px; height: 44px;
        border-radius: 11px;
        font-size: 15px;
        color: var(--color-text-tertiary);
        flex-shrink: 0;
    }
    .scribe-quickbar .sqb-btn svg { width: 20px; height: 20px; }
    .scribe-quickbar .sqb-btn:hover {
        background: color-mix(in srgb, var(--color-text) 8%, transparent);
        color: var(--color-text);
    }
    /* Heading text buttons */
    .scribe-quickbar .sqb-h1 { font-size: 14px; font-weight: 700; }
    .scribe-quickbar .sqb-h2 { font-size: 13px; font-weight: 700; }
    .scribe-quickbar .sqb-h3 { font-size: 12px; font-weight: 700; }
    .scribe-quickbar .sqb-p  { font-size: 16px; }
    /* Swatch groups et éléments pleine largeur */
    .scribe-quickbar .sqb-swatch-group {
        grid-column: 1/-1;
        display: flex;
        flex-wrap: wrap;
        gap: 3px;
        padding: 3px 0;
        justify-content: center;
        width: 100%;
        flex-shrink: 0;
    }
    .scribe-quickbar .sqb-wordcount { grid-column: 1/-1; }
    .scribe-quickbar .sqb-color-label {
        grid-column: 1/-1;
        font-size: 9px;
        font-weight: 600;
        letter-spacing: .05em;
        text-transform: uppercase;
        color: var(--color-text-tertiary);
        text-align: center;
        padding: 2px 0 0;
        line-height: 1;
    }
    /* Custom dropdowns — boutons Police/Taille/Interligne, glyphes courts
       (Aa / A A / icône) plutôt que le libellé complet — cohérent avec les
       autres boutons icône de la barre, et tient sans troncature dans les
       44px du bouton. */
    .scribe-quickbar .sqb-custom-select { grid-column: 1/-1; width: 100%; }
    .scribe-quickbar .sqb-select-btn {
        width: 100%;
        font-size: 14px;
        font-weight: 600;
    }
    .scribe-quickbar .sqb-font-btn { font-family: Georgia, serif; }
    .scribe-quickbar .sqb-size-btn { gap: 1px; }
    .scribe-quickbar .sqb-size-btn span:first-child { font-size: 10px; }
    .scribe-quickbar .sqb-size-btn span:last-child { font-size: 16px; }
    /* .sqb-select-panel/.sqb-select-item/.sqb-tile-panel/.sqb-tile-item :
       déplacés en règles universelles avant ce @media (cf commentaire
       là-bas) -- ces panneaux flottants doivent aussi fonctionner sous
       769px, pas seulement sur le rail desktop. */
    /* Word count display — sticky au bas du panel */
    .scribe-quickbar .sqb-wordcount {
        position: sticky;
        bottom: 0;
        grid-column: 1/-1;
        font-size: 9px;
        color: var(--color-text-tertiary);
        text-align: center;
        padding: 5px 4px 6px;
        line-height: 1.3;
        background: var(--color-surface);
        border-top: 1px solid var(--color-border, rgba(255,255,255,.08));
        z-index: 2;
    }
    /* Delete button — danger colour */
    .scribe-quickbar .sqb-delete { color: #ef4444; }
    .scribe-quickbar .sqb-delete:hover { background: rgba(239,68,68,.12) !important; color: #ef4444; }
    /* Active indicator for note-color swatches in quickbar */
    .scribe-quickbar .sfp-swatch.scribe-color-btn.active {
        outline: 2px solid var(--color-text-primary, #fff);
        outline-offset: 2px;
    }
    /* ── Force taille exacte sur chaque bouton de swatch-group ──────────────
       .scribe-color-btn injecte padding:3px + background:none + border:none
       qui écrase sfp-swatch/sfp-swatch-reset/sfp-color-picker dans le quickbar.
       Ces !important rétablissent la bonne apparence 19×19 px. */
    .scribe-quickbar .sqb-swatch-group > button {
        width: 19px !important;
        height: 19px !important;
        min-width: 19px !important;
        max-width: 19px !important;
        min-height: 19px !important;
        max-height: 19px !important;
        flex-shrink: 0 !important;
        flex-grow: 0 !important;
        box-sizing: border-box !important;
        padding: 0 !important;
        opacity: 1 !important;
    }
    /* Rétablir le fond diagonale "pas de couleur" que scribe-color-btn efface */
    .scribe-quickbar .sqb-swatch-group .sfp-swatch-reset {
        background: linear-gradient(135deg, transparent 44%, #ef4444 46%, #ef4444 54%, transparent 56%) !important;
        border: 2px solid var(--color-border, rgba(255,255,255,.15)) !important;
    }
    /* Rétablir le dégradé arc-en-ciel (conic-gradient) */
    .scribe-quickbar .sqb-swatch-group .sfp-color-picker {
        background: conic-gradient(#ef4444, #f59e0b, #eab308, #22c55e, #3b82f6, #8b5cf6, #ec4899, #ef4444) !important;
        border: 2px solid var(--color-border, rgba(255,255,255,.2)) !important;
        border-radius: 50% !important;
    }

    /* Panneau de format : EN FLUX — il POUSSE la feuille au lieu de la
       recouvrir. Fermé : largeur 0. Ouvert : volet 340px devant le rail
       (sur grand écran c'est le couloir vide qui absorbe, la feuille ne
       bouge pas ; sur petit écran la feuille cède en douceur). */
    .scribe-format-panel {
        width: 0;
        min-width: 0;
        flex-shrink: 0;
        opacity: 0;
        overflow: hidden;
        pointer-events: none;
        margin: 0;
        border: 1px solid transparent;
        border-radius: 16px;
        background: var(--color-surface, #16191d);
        transition: width  .35s cubic-bezier(0.25, 0.46, 0.45, 0.94),
                    opacity .28s cubic-bezier(0.25, 0.46, 0.45, 0.94),
                    margin  .35s cubic-bezier(0.25, 0.46, 0.45, 0.94);
    }
    /* Contenu à largeur figée : pas de re-wrap pendant l'animation */
    .scribe-format-panel .sfp-inner { width: 338px; }
    body.sfp-panel-open .scribe-format-panel {
        width: 340px;
        opacity: 1;
        pointer-events: auto;
        margin-left: 10px;
        border-color: var(--color-border, rgba(255,255,255,.08));
        box-shadow: 0 14px 44px rgba(0,0,0,.35);
    }
    /* Panneau ouvert : la feuille peut céder si la fenêtre est étroite */
    body.sfp-panel-open .scribe-editor-pane {
        min-width: min(940px, calc(100vw - 920px));
    }

    /* sfp-panel-tab masqué sur desktop (collab accessible via le bouton dans la quickbar) */
    .sfp-panel-tab { display: none !important; }

    /* ── Onglet toggle quickbar ── */
    .scribe-qb-tab {
        position: fixed;
        top: 50%;
        transform: translateY(-50%);
        right: 72px; /* bord gauche de la quickbar quand ouverte (1 colonne) */
        width: 20px; height: 48px;
        border-radius: 8px 0 0 8px;
        border: 1px solid var(--color-border);
        border-right: none;
        background: var(--color-surface);
        cursor: pointer;
        color: var(--color-text-secondary);
        display: flex; align-items: center; justify-content: center;
        padding: 0;
        z-index: 91;
        transition: right .26s cubic-bezier(.4,0,.2,1), color .12s, background .12s;
        flex-shrink: 0;
    }
    .scribe-qb-tab:hover { background: var(--color-hover); color: var(--color-text); }
    .scribe-qb-tab svg { transition: transform .26s ease; }
    /* Quickbar cachée → tab se déplace au bord droit, flèche se retourne */
    body.scribe-qb-hidden .scribe-qb-tab { right: 0; }
    body.scribe-qb-hidden .scribe-qb-tab svg { transform: rotate(180deg); }
    /* Quickbar → glisse hors écran à droite */
    .scribe-quickbar {
        transition: transform .26s cubic-bezier(.4,0,.2,1), opacity .22s ease;
    }
    body.scribe-qb-hidden .scribe-quickbar {
        transform: translateX(calc(100% + 20px));
        opacity: 0;
        pointer-events: none;
    }
    /* Ajuste la marge droite de l'éditeur quand quickbar masquée */
    body.scribe-page.scribe-qb-hidden .scribe-editor-pane:not(.scribe-fullpage) {
        margin-right: 0;
    }
}
@media (max-width: 768px) {
    /* sfp-panel-tab : même onglet flèche que desktop, accroché au bord gauche
       de la quickbar mobile (44px + 6px gap = 50px depuis la droite). */
    .sfp-panel-tab {
        position: fixed;
        top: 50%;
        transform: translateY(-50%);
        right: 50px;
        width: 20px; height: 48px;
        border-radius: 8px 0 0 8px;
        background: color-mix(in srgb, var(--color-surface) 78%, transparent);
        -webkit-backdrop-filter: saturate(180%) blur(18px);
                backdrop-filter: saturate(180%) blur(18px);
        border: 1px solid color-mix(in srgb, var(--color-border) 80%, transparent);
        border-right: none;
        color: var(--color-text-tertiary);
        cursor: pointer;
        display: flex; align-items: center; justify-content: center;
        padding: 0;
        z-index: 1201;
    }
}

/* Lecture seule (invité) : pas d'outils d'édition */
body:has(.scribe-layout.scribe-readonly) .scribe-quickbar { display: none; }
@media (max-width: 768px) {
    /* Mobile : 1 colonne, comme Ardoise (harmonisation visuelle ET dimension).
       Meme enveloppe verticale que .ard-tools-wrap (top:70px / bottom:70px+
       safe-area) et meme hauteur relative (70% de cette enveloppe), centree
       via margin auto (top+bottom+height tous fixes -> les deux marges auto
       se partagent l'espace restant a parts egales = centrage exact, sans
       avoir besoin d'un wrapper dedie comme Ardoise). height calc() plutot
       que height:70% : un % sur un position:fixed avec top ET bottom fixes
       resout contre le viewport (pas l'enveloppe top/bottom) et rend "bottom"
       sur-contraint donc ignore -- calc() explicite evite ce piege. */
    .scribe-quickbar {
        position: fixed;
        top: 70px;
        bottom: calc(70px + env(safe-area-inset-bottom, 0px));
        height: calc((100dvh - 140px - env(safe-area-inset-bottom, 0px)) * 0.7);
        margin-top: auto;
        margin-bottom: auto;
        right: 6px;
        left: auto;
        display: grid;
        grid-template-columns: 44px;
        border-radius: 10px;
        align-content: flex-start;
        justify-content: center;
        width: 68px;
        max-width: none;
        gap: 2px;
        overflow-x: hidden;
        overflow-y: auto;
        scrollbar-width: none;
        padding: 8px;
        z-index: 1200;
    }
    /* Transition + masquage mobile */
    .scribe-quickbar { transition: transform .26s cubic-bezier(.4,0,.2,1), opacity .22s ease; }
    body.scribe-qb-hidden .scribe-quickbar {
        transform: translateX(calc(100% + 22px));
        opacity: 0;
        pointer-events: none;
    }
    .scribe-quickbar::-webkit-scrollbar { display: none; }
    .scribe-quickbar .sqb-sep { grid-column: 1/-1; width: 100%; height: 1px; margin: 2px 0; flex-shrink: 0; }
    .scribe-quickbar .sqb-swatch-group {
        grid-column: 1/-1;
        display: flex;
        flex-wrap: wrap;
        gap: 3px;
        padding: 3px 0;
        justify-content: center;
        width: 100%;
        flex-shrink: 0;
    }
    .scribe-quickbar .sqb-swatch-group > button {
        width: 19px !important;
        height: 19px !important;
        min-width: 19px !important;
        max-width: 19px !important;
        min-height: 19px !important;
        max-height: 19px !important;
        flex-shrink: 0 !important;
        flex-grow: 0 !important;
        box-sizing: border-box !important;
        padding: 0 !important;
        opacity: 1 !important;
    }
    .scribe-quickbar .sqb-swatch-group .sfp-swatch-reset {
        background: linear-gradient(135deg, transparent 44%, #ef4444 46%, #ef4444 54%, transparent 56%) !important;
        border: 2px solid var(--color-border, rgba(255,255,255,.15)) !important;
    }
    .scribe-quickbar .sqb-swatch-group .sfp-color-picker {
        background: conic-gradient(#ef4444, #f59e0b, #eab308, #22c55e, #3b82f6, #8b5cf6, #ec4899, #ef4444) !important;
        border: 2px solid var(--color-border, rgba(255,255,255,.2)) !important;
        border-radius: 50% !important;
    }
    .scribe-quickbar .sqb-wordcount { grid-column: 1/-1; }
    .scribe-quickbar .sqb-custom-select { grid-column: 1/-1; width: 100%; }
    .scribe-quickbar .sqb-color-label {
        grid-column: 1/-1;
        font-size: 9px;
        font-weight: 600;
        letter-spacing: .05em;
        text-transform: uppercase;
        color: var(--color-text-tertiary);
        text-align: center;
        padding: 2px 0 0;
        line-height: 1;
    }
    /* Boutons identiques à .ard-tool-btn */
    .sqb-btn {
        width: 44px; height: 44px;
        border-radius: 11px;
        flex-shrink: 0;
        font-size: 15px;
    }
    /* Icônes SVG agrandies pour correspondre à la taille Ardoise */
    .scribe-quickbar .sqb-btn svg { width: 18px !important; height: 18px !important; }
    /* Dupliquer/Supprimer/Pages/Collaboration retires du Quickbar mobile
       (restent disponibles sur desktop) -- demande explicite, alleger le
       rail mobile. */
    .scribe-quickbar #scribe-duplicate-btn,
    .scribe-quickbar #scribe-delete-btn,
    .scribe-quickbar #sqb-pages-toggle,
    .scribe-quickbar #sfp-format-toggle-btn,
    .scribe-quickbar .sqb-danger-sep,
    .scribe-quickbar .sqb-mobile-pages-sep { display: none !important; }
    body.scribe-page .scribe-a4-scroll { padding-right: 0; padding-bottom: 0; }
}

/* ── Skeleton de chargement de note (lazy-fetch) ─────────────────────── */
.scribe-load-skeleton { padding: 4px 0; }
.scribe-skel-line {
    height: 14px;
    border-radius: 6px;
    background: var(--color-border, rgba(255,255,255,.08));
    margin-bottom: 10px;
    animation: scribe-skel-pulse 1.4s ease-in-out infinite;
}
@keyframes scribe-skel-pulse {
    0%,100% { opacity: .45; }
    50%      { opacity: .9; }
}

/* ── En-tête & Pied de page du document ──────────────────────────────── */
.scribe-doc-header {
    border-bottom: 1.5px dashed var(--color-border);
    /* Reprend le même padding latéral que .scribe-content (64px) et porte
       lui-même la clearance du haut de page (52px) -- voir la règle
       #scribe-doc-header:not(.hf-hidden) + .scribe-content ci-dessous qui
       réduit le padding-top du contenu en conséquence, sinon les deux
       s'additionnent et créent un espace excessif avant le titre. */
    padding: 52px 64px 10px;
}
.scribe-doc-footer {
    border-top: 1.5px dashed var(--color-border);
    padding: 10px 64px 20px;
}
/* En-tête visible juste au-dessus : il porte déjà la clearance du haut de
   page, donc le contenu n'a plus besoin de la sienne (56px) -- seulement
   un espacement modeste sous le séparateur en tirets. */
#scribe-doc-header:not(.hf-hidden) + .scribe-content {
    padding-top: 24px;
}
.scribe-hf-label {
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin-bottom: 5px;
    user-select: none;
    pointer-events: none;
}
.scribe-hf-textarea {
    display: block;
    width: 100%;
    border: none;
    background: transparent;
    resize: none;
    font-family: inherit;
    font-size: 12px;
    line-height: 1.55;
    color: var(--color-text-secondary);
    padding: 0;
    min-height: 22px;
    overflow: hidden;
    outline: none;
    caret-color: var(--color-primary, #3b82f6);
}
.scribe-hf-textarea::placeholder { color: var(--color-text-muted); font-style: italic; }

/* ── Mode plein-page (bouton plein écran toggle) ─────────────────────── */
.scribe-editor-pane.scribe-fullpage {
    position: fixed !important;
    inset: 0 !important;
    z-index: 200 !important;
    border-radius: 0 !important;
    border: none !important;
}

/* Fond gris type "traitement de texte" — visible uniquement en fullpage */
.scribe-editor-pane.scribe-fullpage .scribe-a4-scroll {
    background: #c8cdd3;
    padding: 48px 24px 80px;
    align-items: center;
    display: flex;
    flex-direction: column;
}
/* Meme teinte que .scribe-a4-sheet ci-dessous (#1a1a1a) -- #2a2d31 creait
   une couture visible entre le fond et la page en mode sombre (demande
   utilisateur 2026-09-26). La separation reste lisible via l'ombre portee
   de la feuille, pas via une difference de couleur. */
[data-theme="dark"] .scribe-editor-pane.scribe-fullpage .scribe-a4-scroll {
    background: #1a1a1a;
}

/* Feuille A4 centrée avec ombre — 210 mm = 794 px à 96 dpi */
.scribe-editor-pane.scribe-fullpage .scribe-a4-sheet {
    width: 794px;
    max-width: calc(100vw - 80px);
    min-height: 1123px;   /* 297 mm à 96 dpi */
    flex: 0 0 auto;
    background: #ffffff;
    border-radius: 2px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.18), 0 8px 32px rgba(0,0,0,0.12);
    overflow: visible;
}

/* Mobile : la feuille prend tout l'écran — pas de marge grise autour */
@media (max-width: 768px) {
    .scribe-editor-pane.scribe-fullpage .scribe-a4-scroll {
        padding: 0;
        padding-top: env(safe-area-inset-top, 0px);
    }
    .scribe-editor-pane.scribe-fullpage .scribe-a4-sheet {
        width: 100%;
        max-width: 100%;
        min-height: 100%;
        border-radius: 0;
        box-shadow: none;
    }
}
[data-theme="dark"] .scribe-editor-pane.scribe-fullpage .scribe-a4-sheet {
    background: #1a1a1a;
    box-shadow: 0 2px 8px rgba(0,0,0,0.4), 0 8px 32px rgba(0,0,0,0.3);
}
/* Contenu : forcer la couleur texte sur fond blanc en light mode */
.scribe-editor-pane.scribe-fullpage .scribe-content {
    color: #1a1a1a;
}
[data-theme="dark"] .scribe-editor-pane.scribe-fullpage .scribe-content {
    color: var(--color-text-primary);
}

/* Barre d'actions plein écran — haut-droite, visible uniquement en .scribe-fullpage */
.scribe-fullpage-bar {
    display: none;
    position: fixed;
    top: 14px;
    right: 16px;
    z-index: 210;
    align-items: center;
    gap: 8px;
}
.scribe-editor-pane.scribe-fullpage .scribe-fullpage-bar { display: flex; }
/* Bouton icône générique dans la barre (ex : imprimer) */
.scribe-fullpage-bar-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255,255,255,0.18);
    border-radius: 10px;
    color: #fff;
    cursor: pointer;
    transition: background .15s;
}
.scribe-fullpage-bar-btn:hover { background: rgba(0,0,0,0.75); }
/* Bouton sortie plein écran — déplacé dans .scribe-fullpage-bar */
.scribe-exit-fullpage {
    display: flex;
    align-items: center;
    gap: 6px;
    background: rgba(0,0,0,0.55);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(255,255,255,0.18);
    border-radius: 10px;
    padding: 7px 12px;
    font-size: 12.5px;
    font-weight: 500;
    color: #fff;
    cursor: pointer;
    transition: background .15s;
}
.scribe-exit-fullpage:hover { background: rgba(0,0,0,0.75); }

/* ── Mode lecture — vraies pages A4 (remplace la feuille éditable en fullpage) */
.scribe-read-pages {
    flex: 1;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 32px;
}
.scribe-read-page {
    width: 100%;
    max-width: 794px;
    min-height: 1123px;
    background: #fff;
    padding: 56px 64px 64px;
    box-shadow: 0 1px 4px rgba(0,0,0,.15), 0 4px 20px rgba(0,0,0,.10);
    border-radius: 2px;
    font-size: 14.5px;
    line-height: 1.8;
    color: #1a1a1a;
    word-break: break-word;
    position: relative;
    box-sizing: border-box;
}
[data-theme="dark"] .scribe-read-page {
    /* Même couleur que la feuille éditable (.scribe-a4-sheet, mode Edition)
       -- #1e2124 était une valeur distincte, non harmonisée. */
    background: #1a1a1a;
    color: var(--color-text-primary);
    box-shadow: 0 2px 8px rgba(0,0,0,0.4), 0 8px 32px rgba(0,0,0,0.3);
}
.scribe-read-page::after {
    content: attr(data-page);
    position: absolute;
    bottom: 18px;
    right: 24px;
    font-size: 11px;
    opacity: .4;
    pointer-events: none;
}
/* Typography — miroir exact de .scribe-content */
.scribe-read-page h1 { font-size: 22px; font-weight: 700; margin: 20px 0 8px; letter-spacing: -.02em; }
.scribe-read-page h2 { font-size: 18px; font-weight: 600; margin: 16px 0 6px; }
.scribe-read-page h3 { font-size: 15px; font-weight: 600; margin: 12px 0 4px; }
.scribe-read-page p  { margin: 0 0 12px; }
.scribe-read-page ul,
.scribe-read-page ol { padding-left: 22px; margin: 5px 0; }
.scribe-read-page li { margin: 2px 0; }
.scribe-read-page blockquote {
    border-left: 3px solid var(--color-primary, #3b82f6);
    padding-left: 14px;
    margin: 10px 0;
    color: var(--color-text-secondary, #666);
    font-style: italic;
    opacity: .85;
}
.scribe-read-page hr { border: none; border-top: 1px solid rgba(0,0,0,.12); margin: 16px 0; }
[data-theme="dark"] .scribe-read-page hr { border-top-color: rgba(255,255,255,.12); }
.scribe-read-page b,
.scribe-read-page strong { font-weight: 700; }
.scribe-read-page i,
.scribe-read-page em { font-style: italic; }
.scribe-read-page u  { text-decoration: underline; }
.scribe-read-page s,
.scribe-read-page strike { text-decoration: line-through; opacity: .7; }
.scribe-read-page a  { color: var(--color-primary, #3b82f6); text-decoration: underline; }
.scribe-read-page code {
    background: rgba(0,0,0,.05);
    border-radius: 4px;
    padding: 1px 5px;
    font-family: monospace;
    font-size: .9em;
}
[data-theme="dark"] .scribe-read-page code { background: rgba(255,255,255,.07); }
.scribe-read-page table {
    width: 100%; max-width: 100%; table-layout: fixed;
    border-collapse: collapse; margin: 10px 0; font-size: .95em;
}
.scribe-read-page th,
.scribe-read-page td { border: 1px solid rgba(0,0,0,.18); padding: 6px 9px; text-align: left; word-break: break-word; white-space: normal; }
[data-theme="dark"] .scribe-read-page th,
[data-theme="dark"] .scribe-read-page td { border-color: rgba(255,255,255,.14); }
.scribe-read-page th { font-weight: 600; background: rgba(0,0,0,.04); }
[data-theme="dark"] .scribe-read-page th { background: rgba(255,255,255,.04); }
/* Colonnes de mise en page (.scribe-cols) — même exception qu'en édition
   (cf. .scribe-content table.scribe-cols td) : ce n'est pas un vrai tableau
   de données, la bordure doit rester invisible. Le mode lecture (plein
   écran paginé) n'a pas de survol/focus possible pour la révéler comme
   dans l'éditeur -- elle reste donc invisible en permanence ici. Sans
   cette règle le rendu plein écran (et l'impression déclenchée depuis ce
   mode, qui imprime ce DOM tel quel) affichait à tort une bordure pleine. */
.scribe-read-page table.scribe-cols td {
    border: 1px dashed transparent;
    padding-top: 6px;
    padding-bottom: 6px;
    padding-left: 0;
    padding-right: 0;
}
.scribe-read-page table.scribe-cols td:first-child { padding-right: 24px; }
.scribe-read-page table.scribe-cols td:last-child  { padding-left: 24px; }
@media (max-width: 768px) {
    .scribe-read-pages { gap: 0; }
    .scribe-read-page {
        max-width: 100%; min-height: 100dvh;
        box-shadow: none; border-radius: 0;
        padding: 32px 16px 80px;
    }
}

/* ── Responsive ≤ 900 px — panneau droit masqué, bouton Format visible ── */
@media (max-width: 900px) {
    .scribe-format-panel { display: none; }
    .scribe-editor-pane  { border-right: none; }

    /* Bouton Format — mobile seulement (invisible sur desktop où le panneau
       est toujours visible). */
    #sfp-format-toggle-btn { display: inline-flex !important; }

    /* Panneau ouvert en bottom sheet */
    .scribe-format-panel.mobile-open {
        display: flex !important;
        position: fixed;
        left: 0; right: 0; bottom: 0; top: auto;
        width: 100% !important;        /* pleine largeur — override 300px desktop */
        max-width: none !important;
        height: 72vh;
        flex-direction: column;
        border-radius: 20px 20px 0 0;
        border: 1px solid var(--color-border);
        border-bottom: none;
        background: var(--color-surface);
        box-shadow: 0 -10px 50px rgba(0,0,0,.45);
        z-index: 150;
        overflow: hidden;
        animation: sfp-slide-up .28s cubic-bezier(.22,1,.36,1);
    }
    /* Grille 4 colonnes pleine largeur sur mobile */
    .scribe-format-panel.mobile-open .sfp-grid {
        grid-template-columns: repeat(4, 1fr) !important;
    }
    /* Un peu plus de padding horizontal pour respirer */
    .scribe-format-panel.mobile-open .sfp-inner {
        padding: 8px 16px calc(20px + env(safe-area-inset-bottom, 0px));
    }
    @keyframes sfp-slide-up {
        from { transform: translateY(40%); opacity: 0; }
        to   { transform: translateY(0);   opacity: 1; }
    }
    /* Drag handle en haut du bottom sheet */
    .scribe-format-panel.mobile-open::before {
        content: '';
        display: block;
        width: 40px; height: 4px;
        background: var(--color-border);
        border-radius: 2px;
        margin: 10px auto 4px;
        flex-shrink: 0;
    }
    /* Contenu scrollable */
    .scribe-format-panel.mobile-open .sfp-inner {
        overflow-y: auto;
        flex: 1;
        padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    }

    /* Backdrop supprimé — plus de flou ni de blocage de l'édition. */
    .sfp-mobile-backdrop { display: none !important; }

    /* Bouton ✕ — positionné coin supérieur droit, style identique à .modal-close */
    .sfp-mobile-close {
        position: absolute;
        top: 12px;
        right: 14px;
        z-index: 3;
        /* width/height/border-radius/bg/border viennent de .modal-close */
    }
}

/* Sur desktop, le bouton Format est caché (le panneau est toujours visible) */
#sfp-format-toggle-btn { display: none; }
/* sfp-section-nav : nav rapide dans le panneau.
   Desktop = header-actions, donc on cache la section dans le panneau.
   Mobile bottom-sheet = seul endroit accessible, donc on la montre. */
@media (min-width: 769px) {
    .sfp-section-nav { display: none !important; }
    /* sfp-section-nav reste dans le DOM → le sélecteur + lui applique border-top sur son frère ; on l'annule */
    .sfp-section-nav + .sfp-section { border-top: none; padding-top: 0; }
}

/* ── Drawer pages Scribe (mobile) — même pattern que PDF viewer sidebar ── */
.scribe-pages-drawer  { display: none; }
.scribe-pages-backdrop { display: none; }
.sqb-mobile-pages-btn, .sqb-mobile-pages-sep { display: none; }

@media (max-width: 768px) {
    /* Drawer — slide depuis la gauche */
    .scribe-pages-drawer {
        display: flex;
        flex-direction: column;
        position: fixed;
        top: 0; left: -210px; bottom: 0;
        width: 200px;
        background: var(--color-surface, #16191d);
        border-right: 1px solid var(--color-border, rgba(255,255,255,.08));
        box-shadow: 6px 0 22px rgba(0,0,0,.45);
        z-index: 201;
        transition: left .28s cubic-bezier(0.25, 0.46, 0.45, 0.94);
        overflow: hidden;
    }
    .scribe-pages-drawer.open { left: 0; }

    /* Backdrop */
    .scribe-pages-backdrop {
        display: block;
        visibility: hidden; opacity: 0;
        position: fixed; inset: 0;
        background: rgba(0,0,0,.45);
        z-index: 200;
        transition: opacity .25s, visibility .25s;
    }
    .scribe-pages-backdrop.visible { visibility: visible; opacity: 1; }

    /* Header du drawer */
    .spd-header {
        display: flex; align-items: center; justify-content: space-between;
        padding: 14px 14px 10px;
        border-bottom: 1px solid var(--color-border, rgba(255,255,255,.08));
        flex-shrink: 0;
    }
    .spd-title {
        font-size: 13px; font-weight: 600;
        color: var(--color-text, #f1f5f9);
    }
    .spd-close-btn {
        width: 28px; height: 28px;
        border: none; background: transparent;
        color: var(--color-text-secondary, #94a3b8);
        border-radius: 6px; cursor: pointer;
        display: flex; align-items: center; justify-content: center;
    }
    .spd-close-btn:hover { background: var(--color-hover); color: var(--color-text); }

    /* Contenu scrollable */
    .spd-content {
        flex: 1; overflow-y: auto;
        padding: 10px 8px;
        scrollbar-width: thin;
    }

    /* Cartes de pages — clone du style desktop (spg-card) */
    .spd-content .spg-pages { display: flex; flex-direction: column; gap: 8px; }
    .spd-content .spg-thumb {
        border-radius: 12px; padding: 10px 10px 8px;
        background: var(--color-hover, rgba(255,255,255,.06));
        cursor: pointer; transition: background .12s;
    }
    .spd-content .spg-thumb:hover { background: rgba(59,130,246,.1); }
    .spd-content .spg-thumb.active {
        background: rgba(59,130,246,.18);
        outline: 1.5px solid rgba(59,130,246,.4);
    }
    .spd-content .spg-card-title {
        font-size: 12px; font-weight: 600;
        color: var(--color-text, #f1f5f9);
        margin-bottom: 4px;
    }
    .spd-content .spg-card-body {
        font-size: 11px; color: var(--color-text-secondary, #94a3b8);
        line-height: 1.4; overflow: hidden;
        display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
    }
    .spd-content .spg-card-empty { font-style: italic; opacity: .5; }

    /* Bouton pages dans quickbar visible sur mobile */
    .sqb-mobile-pages-btn, .sqb-mobile-pages-sep { display: inline-flex; flex-shrink: 0; }
}

/* ── Responsive ≤ 768 px — layout mono-colonne (liste / éditeur) ─────── */
@media (max-width: 768px) {
    /* header-actions masqué sur tout l'éditeur mobile — les actions (Accueil, Nouveau,
       Partager) vivent dans la quickbar. La règle .header.scribe-mobile-editor-open
       plus bas ne doit plus le réactiver. */
    body.scribe-page .header-actions,
    body.scribe-page .header.scribe-mobile-editor-open .header-actions { display: none !important; }
    /* Pastille "Galaxie / Nuage / Scribe" (lanceur d'app en haut à gauche) —
       flotte par-dessus le contenu de la note pendant l'édition plein écran
       mobile, sans utilité à ce moment (retour possible via "Accueil" dans
       le panneau de mise en forme). Devrait déjà être couverte par la règle
       générique ".header.scribe-mobile-editor-open > :not(.header-actions)"
       plus bas, mais on la cible aussi explicitement ici en filet de
       sécurité — même niveau de spécificité/!important, donc sans risque de
       conflit si l'autre règle fonctionne déjà. Scopée à .scribe-mobile-
       editor-open (pas body.scribe-page tout court) pour ne PAS la masquer
       en mode liste des notes, où elle reste utile pour naviguer. */
    body.scribe-page .header.scribe-mobile-editor-open .breadcrumb.context-switcher { display: none !important; }
    /* Bouton hamburger (ouvre le volet gauche global de l'app) — lui aussi
       flotte par-dessus le contenu pendant l'édition mobile. Contrairement
       à la pastille breadcrumb ci-dessus, ce bouton a PLUSIEURS règles
       ".header > .btn-sidebar-toggle { display:flex !important }" ailleurs
       (chrome globale "no-sidebar-layout", cf plus haut dans ce fichier) à
       seulement 2 classes de spécificité — on utilise donc l'ID pour être
       certain de gagner ce bras de fer de spécificité, peu importe l'ordre
       des règles dans le fichier. */
    body.scribe-page .header.scribe-mobile-editor-open #sidebar-toggle-btn { display: none !important; }
    /* Pas de padding layout — les cartes sont en position:fixed */
    .scribe-layout { padding: 0; }

    /* ── Liste des notes = carte flottante (même boîte que le chat Flow) ── */
    .scribe-sidebar {
        position: fixed;
        top: 60px;
        left: 8px;
        right: 8px;
        bottom: calc(8px + env(safe-area-inset-bottom, 0px));
        width: auto;
        min-width: unset;
        border-right: none;
        margin-top: 0;
        border-radius: 20px;
        border: 1px solid var(--color-border);
        background: var(--color-surface);
        box-shadow: 0 12px 40px rgba(0,0,0,.25);
        overflow: hidden;
        z-index: 10;
    }

    /* Fleches fixes du volet pages -- SEUL point d'entree mobile pour
       ouvrir/fermer le tiroir : #sqb-pages-toggle (bouton Pages du
       quickbar) est volontairement masque sur mobile depuis une demande
       anterieure ("alleger le rail mobile", cf. regle .scribe-quickbar
       #sqb-pages-toggle plus haut) -- ne pas les cacher aussi.
       #scribe-sidebar-close-btn (fleche ‹, visible volet ouvert) est
       recollee au bord reel du tiroir mobile (200px, cf.
       .scribe-pages-drawer) plutot que le 230px pense pour le panneau
       desktop, qui la laissait detachee du volet. #scribe-sidebar-open-btn
       (fleche ›, visible volet ferme) est deja en left:0, independant de
       cette largeur -- pas de changement necessaire. */
    .scribe-sidebar-close-btn { left: 200px; }

    /* Barre de zoom (bas de l'ecran) : superflue sur mobile, le pincement
       tactile fait deja zoomer la page -- et elle chevauchait la quickbar. */
    body.scribe-page .scribe-zoom-bar { display: none !important; }

    /* ── Éditeur = vrai plein écran, barre du bas flotte par-dessus ──────── */
    .scribe-editor-pane {
        display: none;
        position: fixed;
        top: 0; left: 0; right: 0; bottom: 0;  /* plein écran sans gap */
        border-radius: 0;
        border: none;
        background: var(--color-surface);
        box-shadow: none;
        overflow: hidden;
        z-index: 60;
        flex-direction: column;
    }

    /* JS ajoute .mobile-editor pour basculer sur l'éditeur */
    .scribe-layout.mobile-editor .scribe-sidebar     { display: none; }
    .scribe-layout.mobile-editor .scribe-editor-pane { display: flex; }

    /* Éditeur ouvert : masque le contenu de la nav (breadcrumb, toggle)
       MAIS garde .header-actions (barre du bas) toujours visible.
       z-index:65 = au-dessus du panneau éditeur (z-index:60) → la barre
       du bas (header-actions) s'affiche devant le contenu. */
    .header.scribe-mobile-editor-open {
        background: transparent !important;
        border: none !important;
        box-shadow: none !important;
        padding: 0 !important;
        height: 0 !important;
        min-height: 0 !important;
        overflow: visible !important;
        z-index: 65 !important;
    }
    /* Cache tout sauf la barre d'actions flottante */
    .header.scribe-mobile-editor-open > :not(.header-actions) {
        display: none !important;
    }
    /* La barre d'actions : même style que le bouton ← (fond sombre solide,
       bordure, pas de glassmorphisme) — contraste élevé, cliquable. */
    .header.scribe-mobile-editor-open .header-actions {
        display: flex !important;
        z-index: 70 !important;
        background: var(--color-bg, #0f1117) !important;
        border: 1px solid var(--color-border) !important;
        backdrop-filter: none !important;
        -webkit-backdrop-filter: none !important;
        box-shadow: 0 4px 24px rgba(0,0,0,.5) !important;
        border-radius: 16px !important;
        padding: 6px 10px !important;
        gap: 4px !important;
    }
    /* Icônes de la barre : même taille que le ← */
    .header.scribe-mobile-editor-open .header-actions .btn-icon,
    .header.scribe-mobile-editor-open .header-actions button {
        width: 38px !important;
        height: 38px !important;
        border-radius: 10px !important;
        color: var(--color-text-secondary) !important;
    }
    .header.scribe-mobile-editor-open .header-actions button:active {
        background: var(--color-hover) !important;
        transform: scale(.93);
    }

    /* ── Bouton retour — masqué sur mobile (navigation via header-actions) ── */
    .scribe-back-btn { display: none !important; }

    /* ── Onglet quickbar — visible sur mobile, repositionné. right doit
       coller au bord gauche du rail (6px de decalage + 68px de largeur) --
       112px etait une valeur figee d'avant le passage du rail a 1 colonne
       68px, d'ou l'onglet qui "flottait seul" loin du rail. ── */
    .scribe-qb-tab {
        position: fixed;
        display: flex !important;
        align-items: center;
        justify-content: center;
        right: 74px;
        top: 50%;
        transform: translateY(-50%);
        width: 20px;
        height: 48px;
        border-radius: 8px 0 0 8px;
        border: 1px solid var(--color-border);
        border-right: none;
        background: var(--color-surface);
        cursor: pointer;
        color: var(--color-text-secondary);
        padding: 0;
        z-index: 1201;
        transition: right .26s cubic-bezier(.4,0,.2,1), color .12s, background .12s;
    }
    body.scribe-qb-hidden .scribe-qb-tab { right: 0; }
    body.scribe-qb-hidden .scribe-qb-tab svg { transform: rotate(180deg); }

    /* ── sfp-panel-tab flottant masqué sur mobile — remplacé par le bouton
       intégré dans la quickbar (sqb-fmt-inline / sfp-format-toggle-btn) ── */
    .sfp-panel-tab { display: none !important; }

    /* ── Bouton Format intégré dans la quickbar — visible sur mobile ── */
    #sfp-format-toggle-btn { display: inline-flex !important; }

    /* ── Feuille A4 en FULL sur mobile : pas de marges papier ───────────── */
    /* Le scroll gère juste le débordement vertical, le titre/contenu ont
       leurs propres paddings pour couvrir le bouton ← et la barre du bas. */
    /* Flex container → scribe-a4-sheet { flex: 1 } peut s'étirer pour
       remplir toute la hauteur visible — plus de fond noir sous une note courte. */
    .scribe-a4-scroll { padding: 0; padding-top: env(safe-area-inset-top, 0px); }
    /* min-height: 100dvh → le sheet remplit toujours le viewport visible,
       fond = transparent → la couleur du pane (note color via JS) transparaît. */
    body.scribe-page .scribe-a4-sheet { min-height: 100dvh; }
    /* En-tête/pied de page du document (optionnels) */
    .scribe-doc-header { padding: 58px 16px 10px; }
    .scribe-doc-footer { padding: 10px 16px 16px; }
    /* Corps : padding-right = quickbar (44px) + gap (6px) + 4px = 54px.
       Le card A4 est pleine largeur ; la quickbar flotte par-dessus le bord
       droit. Le texte s'arrête avant les boutons. */
    .scribe-content {
        font-size: 15px;
        line-height: 1.7;
        padding: 16px;
    }

    /* ── Barre de recherche dans la liste — top de la carte ──────────────── */
    .scribe-sidebar-top { padding: 14px 14px 4px; }

    /* ── Barre du bas (header-actions flippé ≤640px) ──────────────────────── */
    /* Tous les boutons Scribe visibles en icône seule (labels cachés via
       .scribe-hdr-btn .shb-label → display:none dans scribe.php). */
    .header-actions .scribe-hdr-sep { display: none !important; }

    /* ── Bloquer le scroll du body sur mobile ────────────────────────────────
       body { overflow-y: auto } + app { height: 100vh } peut dépasser
       le viewport réel sur iOS (address bar visible) → body scrollable.
       On verrouille : seul scribe-a4-scroll défile, le body reste figé. */
    html.scribe-html {
        overflow: hidden !important;
        height: 100% !important;
    }
    body.scribe-page {
        overflow: hidden !important;
        height: 100% !important;
    }
    body.scribe-page .app {
        height: 100%;
    }
    body.scribe-page .main-body.scribe-main-body {
        overflow: hidden;
        padding: 0;
    }

    /* ── Mode "full" : feuille A4 pleine largeur, sans bordures papier ──────
       Sur mobile l'éditeur est déjà position:fixed plein écran — on retire
       le look "feuille blanche" (ombre, coins arrondis, largeur A4 limitée)
       pour une expérience native "note" sans marges latérales visuelles.
       min-height: 100% : la feuille remplit toujours le scroll-container
       (évite le fond noir sous une note courte). */
    body.scribe-page .scribe-a4-sheet {
        width: 100%;
        max-width: 100%;
        min-height: 100%;
        border-radius: 0;
        box-shadow: none;
    }
}


/* ══════════════════════════════════════════════════════════════════════
   Souvenirs Nébuleuse — grille photos style "cartes flottantes" Scribe
   (masonry multi-colonnes + légère rotation + survol qui redresse/soulève)
   ══════════════════════════════════════════════════════════════════════ */
.neb-back-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    color: var(--color-text-secondary);
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    padding: 6px 4px 14px;
    transition: color 0.15s;
}
.neb-back-btn:hover { color: var(--color-text); }

.neb-header-action-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background: rgba(255,255,255,.06);
    border: 1px solid var(--color-border);
    border-radius: 8px;
    padding: 4px 10px;
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background .15s, color .15s;
    white-space: nowrap;
}
[data-theme="light"] .neb-header-action-btn { background: rgba(0,0,0,.04); }
.neb-header-action-btn:hover { background: var(--color-hover, var(--color-bg)); color: var(--color-text); }

.neb-memory-masonry { columns: 5 220px; column-gap: 18px; }
@media (max-width: 900px) { .neb-memory-masonry { columns: 3 180px; } }
@media (max-width: 560px) { .neb-memory-masonry { columns: 2 140px; } }

.neb-memory-photo {
    display: inline-block;
    width: 100%;
    margin-bottom: 18px;
    border-radius: 18px;
    overflow: hidden;
    break-inside: avoid;
    cursor: pointer;
    position: relative;
    background: var(--color-surface);
    box-shadow: 0 3px 14px rgba(0,0,0,.35), 0 1px 3px rgba(0,0,0,.22);
    transform: rotate(var(--neb-rot, 0deg));
    transition: transform .24s cubic-bezier(.34,1.2,.64,1), box-shadow .24s ease;
    animation: neb-mem-fade .32s ease both;
    will-change: transform;
}
.neb-memory-masonry > .neb-memory-photo:nth-child(6n+1) { --neb-rot: -1.6deg; }
.neb-memory-masonry > .neb-memory-photo:nth-child(6n+2) { --neb-rot:  0.9deg; }
.neb-memory-masonry > .neb-memory-photo:nth-child(6n+3) { --neb-rot: -0.5deg; }
.neb-memory-masonry > .neb-memory-photo:nth-child(6n+4) { --neb-rot:  1.3deg; }
.neb-memory-masonry > .neb-memory-photo:nth-child(6n+5) { --neb-rot: -1.1deg; }
.neb-memory-masonry > .neb-memory-photo:nth-child(6n+6) { --neb-rot:  0.4deg; }

.neb-memory-photo:hover {
    transform: rotate(0deg) translateY(-6px) scale(1.015) !important;
    box-shadow: 0 20px 48px rgba(0,0,0,.55), 0 4px 10px rgba(0,0,0,.3);
    z-index: 20;
}
.neb-memory-photo:active { transform: rotate(0deg) translateY(-2px) scale(1) !important; }

.neb-memory-photo img,
.neb-memory-photo video {
    width: 100%; height: auto; display: block;
}
.neb-memory-photo .neb-mem-play {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(0,0,0,.18); pointer-events: none;
}
.neb-memory-photo .neb-mem-play svg {
    width: 44px; height: 44px;
    filter: drop-shadow(0 2px 6px rgba(0,0,0,.5));
}

@keyframes neb-mem-fade {
    from { opacity: 0; transform: rotate(var(--neb-rot,0deg)) translateY(8px); }
    to   { opacity: 1; }
}

/* ── Vue souvenir plein écran : masque toolbar + recherche + chips ── */
body.neb-memory-fullscreen .header-actions,
body.neb-memory-fullscreen .search-bar,
body.neb-memory-fullscreen #tag-bar-wrap,
body.neb-memory-fullscreen .tag-bar-wrap {
    display: none !important;
}

/* Vue souvenir : remonte le contenu (header masqué) → photos plein espace */
body.neb-memory-fullscreen .main-body { padding-top: 60px; }

/* ── Mobile : gouttières cohérentes pour la section Espaces AQIN + contenu ── */
@media (max-width: 640px) {
    .nuage-system-section {
        padding-left: 16px !important;
        padding-right: 16px !important;
        box-sizing: border-box;
    }
    .main-body > .content,
    .content.drop-zone {
        padding-left: 16px !important;
        padding-right: 16px !important;
    }
}

/* ═══════════════════════════════════════════════════════════════
   Mémo — améliorations 2026-06
   ═══════════════════════════════════════════════════════════════ */

/* Tailles de cartes mémo */
.sh-card-memo.memo-large { grid-column: span 2; }
.sh-card-memo.memo-small .sh-card-memo-body {
    -webkit-line-clamp: 3;
    font-size: 11px;
}
.sh-card-memo.memo-small .sh-card-memo-hd {
    padding-top: 30px;
    font-size: 11px;
}

/* Date d'échéance sur la carte */
.sh-memo-due { font-size: 10px; color: var(--color-text-tertiary, rgba(0,0,0,.35)); }
.sh-memo-due.overdue { color: #ef4444; font-weight: 600; }

/* Chips de tags -- toujours nichés dans .sh-card-memo-foot, qui pose déjà
   son propre padding (16px de chaque côté, cf scribe-home.php) : un
   padding/margin ici en plus était redondant et décalait la pastille vers
   la droite par rapport au titre/corps du mémo juste au-dessus (retour
   utilisateur 2026-09-02, capture d'écran annotée). */
.sh-memo-tags { display: flex; flex-wrap: wrap; gap: 3px; }
.sh-memo-tag {
    font-size: 9px; padding: 1px 6px; border-radius: 99px;
    background: rgba(255,255,255,.18); color: var(--color-text-secondary, rgba(0,0,0,.5));
    border: 1px solid rgba(0,0,0,.08);
}
[data-theme="dark"] .sh-memo-tag { background: rgba(255,255,255,.1); border-color: rgba(255,255,255,.1); }

.sh-filter-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    padding: 14px 32px 0;
}

/* Bouton punaise (épingler) sur la carte mémo */
.sh-card-pin-btn {
    position: absolute; top: 8px; right: 8px;
    opacity: 0; background: none; border: none;
    cursor: pointer; font-size: 14px;
    transition: opacity .15s; padding: 2px;
    z-index: 3; line-height: 1;
}
.sh-card-memo:hover .sh-card-pin-btn { opacity: 0.6; }
.sh-card-pin-btn.pinned { opacity: 1 !important; }

/* Items checklist dans le panneau flottant mémo */
.scribe-memo-float-body .memo-check-item {
    display: flex; align-items: flex-start; gap: 6px; margin: 2px 0;
}
.scribe-memo-float-body .memo-check-item input[type="checkbox"] {
    margin-top: 3px; flex-shrink: 0; cursor: pointer;
}
.scribe-memo-float-body .memo-check-item.checked span {
    text-decoration: line-through; opacity: 0.5;
}

/* Panneau flottant mémo — ligne méta unique (échéance + tags) */
.smf-meta-row {
    display: flex; align-items: center; gap: 4px;
    padding: 4px 8px; border-top: 1px solid rgba(0,0,0,.06);
    flex-shrink: 0; min-height: 0;
}
[data-theme="dark"] .smf-meta-row { border-top-color: rgba(255,255,255,.06); }
.smf-meta-sep { width: 1px; height: 14px; background: var(--color-border); margin: 0 2px; flex-shrink: 0; }
/* Panneau flottant mémo — champs supplémentaires */
.smf-extra-row {
    display: flex; align-items: center; gap: 6px;
    padding: 4px 12px; border-top: 1px solid rgba(0,0,0,.06);
    flex-wrap: wrap;
}
[data-theme="dark"] .smf-extra-row { border-top-color: rgba(255,255,255,.06); }
.smf-extra-label {
    font-size: 9px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: rgba(150,75,0,.55);
    flex-shrink: 0;
}
[data-theme="dark"] .smf-extra-label { color: rgba(249,115,22,.45); }
.smf-due-input {
    font-size: 11px; padding: 3px 6px; border-radius: 6px;
    border: 1px solid rgba(0,0,0,.15); background: rgba(255,255,255,.5);
    color: #334155; outline: none; cursor: pointer;
    font-family: inherit;
}
[data-theme="dark"] .smf-due-input {
    background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.18);
    color: rgba(255,240,210,.8); color-scheme: dark;
}
.smf-due-input.overdue { border-color: #ef4444; color: #ef4444; }

/* Tags input dans le panneau */
.smf-tags-input {
    font-size: 11px; padding: 3px 7px; border-radius: 6px;
    border: 1px solid rgba(0,0,0,.15); background: rgba(255,255,255,.5);
    color: #334155; outline: none; min-width: 80px; flex: 1;
    font-family: inherit;
}
[data-theme="dark"] .smf-tags-input {
    background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.18);
    color: rgba(255,240,210,.8);
}
.smf-tag-chip {
    display: inline-flex; align-items: center; gap: 3px;
    font-size: 10px; padding: 2px 7px; border-radius: 99px;
    background: rgba(249,115,22,.15); color: rgba(150,60,0,.9);
    border: none; cursor: pointer; flex-shrink: 0;
}
[data-theme="dark"] .smf-tag-chip { background: rgba(249,115,22,.22); color: rgba(255,200,130,.9); }
.smf-tag-chip:hover { background: rgba(239,68,68,.2); }

/* Sélecteur taille carte (S/M/L) */
.smf-size-group { display: flex; gap: 3px; align-items: center; }
.smf-size-btn {
    font-size: 10px; font-weight: 800;
    padding: 2px 7px; border-radius: 6px;
    border: 1.5px solid rgba(0,0,0,.15); background: none;
    color: rgba(100,50,0,.55); cursor: pointer;
    transition: background .12s, border-color .12s;
}
.smf-size-btn:hover { background: rgba(249,115,22,.1); }
.smf-size-btn.active, .smf-size-btn.smf-size-active {
    background: rgba(249,115,22,.18); border-color: rgba(249,115,22,.5);
    color: #c2590f;
}
[data-theme="dark"] .smf-size-btn { border-color: rgba(255,255,255,.2); color: rgba(249,115,22,.6); }
[data-theme="dark"] .smf-size-btn.active,
[data-theme="dark"] .smf-size-btn.smf-size-active { background: rgba(249,115,22,.25); color: #f97316; }

/* Sélecteur taille fonte dans la barre d'outils */
.smf-fontsize-select {
    font-size: 10px; padding: 2px 4px; border-radius: 5px;
    border: 1px solid rgba(0,0,0,.15); background: rgba(255,255,255,.4);
    color: #334155; outline: none; cursor: pointer;
    font-family: inherit; flex-shrink: 0;
}
[data-theme="dark"] .smf-fontsize-select {
    background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.18);
    color: rgba(255,240,210,.8);
}

/* Boutons checklist et image dans le panneau flottant mémo (scribe.php) */
.scribe-memo-fmt-btn#smf-checklist-btn.smf-active {
    background: color-mix(in srgb, var(--color-primary,#6366f1) 15%, transparent);
    color: var(--color-primary,#6366f1);
}

/* Tags chips dans le panneau flottant mémo (scribe.php) */
.smf-tags-area {
    display: flex; flex-wrap: wrap; align-items: center; gap: 4px; flex: 1;
}
.smf-tags-chips { display: flex; flex-wrap: wrap; gap: 3px; }
.smf-tag-chip {
    display: inline-flex; align-items: center; gap: 2px;
    font-size: 9px; padding: 1px 6px 1px 4px; border-radius: 99px;
    background: rgba(99,102,241,.15); color: var(--color-primary,#6366f1);
}
[data-theme="dark"] .smf-tag-chip { background: rgba(99,102,241,.2); }
.smf-tag-del {
    background: none; border: none; color: rgba(99,102,241,.5);
    font-size: 11px; cursor: pointer; padding: 0 1px; line-height: 1;
}
.smf-tag-del:hover { color: #ef4444; }
.smf-tags-input {
    font-size: 11px; background: transparent; border: none;
    color: #334155; outline: none; font-family: inherit; min-width: 80px;
}
[data-theme="dark"] .smf-tags-input { color: rgba(255,240,210,.7); }
.smf-tags-input::placeholder { color: rgba(0,0,0,.25); }
[data-theme="dark"] .smf-tags-input::placeholder { color: rgba(255,255,255,.2); }

/* Bouton effacer l'échéance */
.smf-extra-clear {
    font-size: 11px; background: none; border: none; color: rgba(0,0,0,.3);
    cursor: pointer; padding: 1px 4px; border-radius: 4px; line-height: 1;
}
[data-theme="dark"] .smf-extra-clear { color: rgba(255,255,255,.25); }
.smf-extra-clear:hover { color: #ef4444; background: rgba(239,68,68,.1); }

/* ── Mode picker (modal création mémo) ──────────────────────────────── */
.sh-memo-mode-pick {
    display: flex; gap: 8px; margin-bottom: 14px;
}
.sh-mode-pick-btn {
    flex: 1; padding: 9px 12px; border-radius: 10px;
    border: 1.5px solid var(--color-border, rgba(0,0,0,.12));
    background: none; cursor: pointer; font-size: 13px;
    color: var(--color-text-secondary, rgba(0,0,0,.55));
    transition: .14s; font-weight: 500;
}
.sh-mode-pick-btn.active { background: #6366f1; border-color: #6366f1; color: #fff; }
.sh-mode-pick-btn:not(.active):hover { background: var(--color-hover, rgba(0,0,0,.05)); }

/* ── Bouton mode en bas du modal éditeur mémo ───────────────────────── */
.sh-memo-mode-foot-btn {
    font-size: 12px; padding: 6px 14px; border-radius: 8px;
    border: 1.5px solid var(--color-border, rgba(0,0,0,.1));
    background: none; cursor: pointer;
    color: var(--color-text-secondary, rgba(0,0,0,.5));
    transition: .13s; font-weight: 500;
}
.sh-memo-mode-foot-btn:hover { background: rgba(99,102,241,.08); border-color: #6366f1; color: #6366f1; }
.sj-card-hint {
    font-size: 11px; color: var(--color-text-tertiary, rgba(0,0,0,.35));
    font-style: italic;
}

/* ── Journal Timeline — modal ───────────────────────────────────────── */
.sj-container {
    display: flex; flex-direction: column;
    height: 80vh; max-height: 800px; min-height: 320px;
    overflow: hidden; padding-bottom: 10px;
}
.sj-header {
    display: flex; align-items: center; gap: 8px;
    padding: 0 2px 12px; flex-shrink: 0;
    border-bottom: 1px solid var(--color-border, rgba(0,0,0,.09));
}
.sj-date-badge {
    font-size: 12px; font-weight: 600; color: var(--color-text-secondary, rgba(0,0,0,.55));
    text-transform: capitalize;
}
.sj-mode-switch {
    margin-left: auto; font-size: 11px; padding: 4px 10px;
    border-radius: 7px; border: 1px solid var(--color-border, rgba(0,0,0,.1));
    background: none; cursor: pointer; color: var(--color-text-secondary, rgba(0,0,0,.5));
    transition: background .12s;
}
.sj-mode-switch:hover { background: var(--color-hover, rgba(0,0,0,.05)); }
.sj-timeline {
    flex: 1; overflow-y: auto; padding: 14px 2px 4px;
    display: flex; flex-direction: column; gap: 0;
}
.sj-loading, .sj-empty {
    text-align: center; padding: 32px 16px;
    font-size: 13px; color: var(--color-text-tertiary, rgba(0,0,0,.35));
    line-height: 1.6;
}
.sj-empty-wrap { display: flex; flex-direction: column; align-items: center; padding: 28px 16px; gap: 16px; }
.sj-empty-hint { font-size: 13px; color: var(--color-text-tertiary, rgba(0,0,0,.35)); text-align: center; line-height: 1.6; margin: 0; }
.sj-tpl-grid { display: flex; gap: 7px; flex-wrap: wrap; justify-content: center; }
.sj-tpl-btn {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 13px; border-radius: 99px; cursor: pointer;
    border: 1px solid var(--color-border, rgba(0,0,0,.1));
    background: transparent;
    font-size: 12px; font-weight: 500; color: var(--color-text-secondary, rgba(0,0,0,.5));
    transition: .14s; white-space: nowrap;
}
.sj-tpl-btn > :first-child { font-size: 14px; line-height: 1; }
.sj-tpl-btn:hover { border-color: #6366f1; color: #6366f1; background: rgba(99,102,241,.06); }
.sj-tpl-btn:disabled { opacity: .5; cursor: default; }
[data-theme="dark"] .sj-tpl-btn { border-color: rgba(255,255,255,.12); }
[data-theme="dark"] .sj-tpl-btn:hover { border-color: #6366f1; background: rgba(99,102,241,.1); }
.sj-entry {
    display: flex; gap: 10px; align-items: flex-start;
    margin-bottom: 12px; position: relative;
}
.sj-entry::after {
    content: ''; position: absolute;
    left: 36px; top: 28px; bottom: -12px;
    width: 0; border-left: 1.5px dashed var(--color-border, rgba(0,0,0,.1));
}
.sj-entry:last-child::after { display: none; }
.sj-entry-time {
    flex-shrink: 0; font-size: 11px; font-weight: 600;
    color: var(--color-text-secondary, rgba(0,0,0,.5));
    background: var(--color-surface-2, #f1f5f9);
    border: 1px solid var(--color-border, rgba(0,0,0,.08));
    border-radius: 6px; padding: 3px 6px;
    min-width: 44px; text-align: center; line-height: 1.4;
}
.sj-entry-body {
    flex: 1; background: var(--color-surface-2, #f8fafc);
    border-radius: 10px; padding: 8px 32px 8px 12px;
    font-size: 13px; line-height: 1.55; color: var(--color-text);
    position: relative;
    border: 1px solid var(--color-border, rgba(0,0,0,.06));
}
.sj-entry-text { white-space: pre-wrap; word-break: break-word; }
.sj-entry-img { max-width: 100%; border-radius: 7px; display: block; }
.sj-entry-del {
    position: absolute; top: 6px; right: 6px;
    width: 20px; height: 20px; border: none; background: none;
    cursor: pointer; opacity: 0; font-size: 11px; line-height: 1;
    color: var(--color-text-tertiary, rgba(0,0,0,.35));
    border-radius: 4px; transition: opacity .12s;
    display: flex; align-items: center; justify-content: center;
}
.sj-entry-body:hover .sj-entry-del { opacity: 1; }
.sj-entry-del:hover { background: rgba(239,68,68,.1); color: #ef4444; }
/* Bloc tâches embarqué dans le mémo */
.sh-memo-task-block {
    margin: 6px 0; padding: 10px 14px 10px 26px;
    border-radius: 10px;
    background: var(--color-surface-2, rgba(0,0,0,.04));
    border: 1px solid var(--color-border, rgba(0,0,0,.07));
    cursor: default; user-select: none;
    position: relative;
}
[data-theme="dark"] .sh-memo-task-block { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.09); }
.sh-memo-block-drag {
    position: absolute; left: 4px; top: 50%; transform: translateY(-50%);
    width: 18px; height: 28px; cursor: grab; opacity: 0;
    color: var(--color-text-tertiary, rgba(255,255,255,.3));
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; border-radius: 4px;
    transition: opacity .12s; user-select: none;
}
.sh-memo-task-block.sh-block-hovered .sh-memo-block-drag { opacity: 0.45; }
.sh-memo-block-drag:hover { opacity: 1 !important; }
.sh-memo-task-block.sh-block-dragging { opacity: 0.35; }
.sh-drop-indicator {
    height: 2px; background: var(--color-primary, #6366f1);
    border-radius: 2px; margin: 3px 0; pointer-events: none;
}
.sh-memo-block-del {
    position: absolute; top: 6px; right: 8px;
    width: 22px; height: 22px; border: none; background: none;
    cursor: pointer; opacity: 0; font-size: 12px; line-height: 1;
    color: var(--color-text-tertiary, rgba(0,0,0,.4));
    border-radius: 4px; transition: opacity .12s, background .12s, color .12s;
    display: flex; align-items: center; justify-content: center;
}
.sh-memo-task-block.sh-block-hovered .sh-memo-block-del { opacity: 0.45; }
.sh-memo-block-del:hover { opacity: 1 !important; background: rgba(239,68,68,.12); color: #ef4444; }
/* Overlay templates démarrage mémo */
.sh-memo-tpl-overlay {
    padding: 12px 4px 18px; text-align: center;
}
.sh-memo-tpl-hint {
    font-size: 13px; color: var(--color-text-tertiary, rgba(0,0,0,.38));
    margin: 0 0 12px;
}
.sj-task-list { display: flex; flex-direction: column; gap: 4px; }
.sj-task-item {
    display: flex; align-items: center; gap: 8px;
    cursor: pointer; font-size: 13px;
}
.sj-task-item span { flex: 1; min-width: 0; }
.sj-task-item input[type="checkbox"] { width: 14px; height: 14px; cursor: pointer; flex-shrink: 0; }
.sj-task-item.done > span { text-decoration: line-through; opacity: .45; }
.sj-task-item-del {
    opacity: 0; background: none; border: none; padding: 0 2px;
    color: var(--color-text-muted, rgba(0,0,0,.4)); cursor: pointer;
    font-size: 11px; line-height: 1; transition: opacity .15s, color .15s; flex-shrink: 0;
}
.sj-task-item:hover .sj-task-item-del { opacity: 1; }
.sj-task-item-del:hover { color: #e74c3c; }
[data-theme="dark"] .sj-task-item-del { color: rgba(255,255,255,.4); }
.sj-task-item span[contenteditable="true"] {
    outline: 1px solid var(--color-primary, #5b6af8); border-radius: 4px; padding: 0 4px; cursor: text;
}
.sj-entry-text { cursor: text; border-radius: 8px; transition: background .15s; }
.sj-entry-text:hover { background: var(--color-surface-2, rgba(0,0,0,.04)); }
.sj-entry-text[contenteditable="true"] {
    outline: none; background: var(--color-surface-2, rgba(0,0,0,.04)); padding: 4px 8px; margin: -4px -8px;
}
[data-theme="dark"] .sj-entry-text:hover { background: rgba(255,255,255,.06); }
[data-theme="dark"] .sj-entry-text[contenteditable="true"] { background: rgba(255,255,255,.06); }
.sj-task-add-row { margin-top: 6px; padding-top: 6px; border-top: 1px solid rgba(0,0,0,.07); }
.sj-task-add-input { width: 100%; border: none; background: transparent; font-size: 13px; color: var(--color-text); outline: none; padding: 2px 0; }
.sj-task-add-input::placeholder { color: var(--color-text-tertiary, rgba(0,0,0,.3)); font-style: italic; }
[data-theme="dark"] .sj-task-add-row { border-top-color: rgba(255,255,255,.08); }
/* Input bar */
.sj-input-bar {
    display: flex; flex-direction: column; gap: 6px;
    padding: 10px 12px 8px;
    border-radius: 14px;
    background: var(--color-surface-2, #f1f5f9);
    border: 1px solid var(--color-border, rgba(0,0,0,.08));
    flex-shrink: 0;
}
[data-theme="dark"] .sj-input-bar {
    background: rgba(255,255,255,.05);
    border-color: rgba(255,255,255,.07);
}
.sj-input-ctx {
    display: flex; align-items: center;
    padding-bottom: 7px;
    border-bottom: 1px solid var(--color-border, rgba(0,0,0,.07));
}
[data-theme="dark"] .sj-input-ctx { border-bottom-color: rgba(255,255,255,.07); }
.sj-input-footer { display: flex; align-items: center; justify-content: space-between; }
.sj-time-wrap { position: relative; flex-shrink: 0; margin-top: 0; align-self: auto; }
.sj-now-badge {
    font-size: 11px; font-weight: 700;
    color: #6366f1; background: rgba(99,102,241,.1);
    border-radius: 6px; padding: 3px 8px;
    min-width: 44px; max-width: 120px;
    cursor: pointer; outline: none; white-space: nowrap; overflow: hidden;
    border: 1px solid rgba(99,102,241,.15); transition: background .12s;
    display: block;
}
.sj-now-badge:focus { background: rgba(99,102,241,.18); border-color: #6366f1; }
[data-theme="dark"] .sj-now-badge { color: #818cf8; background: rgba(99,102,241,.15); border-color: rgba(99,102,241,.25); }
[data-theme="dark"] .sj-now-badge:focus { background: rgba(99,102,241,.25); }
.sj-time-presets {
    position: absolute; bottom: calc(100% + 8px); left: 0;
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, rgba(0,0,0,.1));
    border-radius: 12px; padding: 6px;
    display: flex; flex-direction: column; gap: 2px;
    box-shadow: 0 6px 20px rgba(0,0,0,.14);
    z-index: 100; min-width: 140px;
}
.sj-tp {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 10px; border: none; background: none;
    cursor: pointer; font-size: 12px; border-radius: 7px;
    color: var(--color-text); text-align: left; width: 100%;
    transition: background .1s;
}
.sj-tp:hover { background: var(--color-hover, rgba(0,0,0,.05)); }
[data-theme="dark"] .sj-time-presets { background: var(--color-surface-2, #1e293b); }
.sj-type-btns { display: flex; flex-direction: row; gap: 2px; }
.sj-type-btn {
    width: 30px; height: 28px; border: none;
    border-radius: 7px; background: transparent; cursor: pointer;
    font-size: 13px; font-weight: 600; color: var(--color-text-secondary, rgba(0,0,0,.4));
    display: flex; align-items: center; justify-content: center; transition: .12s;
}
.sj-type-btn.active { background: rgba(99,102,241,.13); color: #6366f1; }
.sj-type-btn:hover:not(.active) { background: var(--color-hover, rgba(0,0,0,.06)); }
[data-theme="dark"] .sj-type-btn { color: rgba(255,255,255,.35); }
[data-theme="dark"] .sj-type-btn.active { background: rgba(99,102,241,.22); color: #818cf8; }
[data-theme="dark"] .sj-type-btn:hover:not(.active) { background: rgba(255,255,255,.07); }
.sj-ce-wrap { flex: 1; }
.sj-ce {
    min-height: 22px; max-height: 100px; overflow-y: auto;
    border: none; background: transparent; padding: 0;
    font-size: 13.5px; outline: none; color: var(--color-text);
    line-height: 1.5;
}
.sj-ce:empty::before {
    content: attr(data-placeholder);
    color: var(--color-text-tertiary, rgba(0,0,0,.3));
    pointer-events: none;
}
[data-theme="dark"] .sj-ce:empty::before { color: rgba(255,255,255,.22); }
.sj-add-btn {
    flex-shrink: 0; width: 32px; height: 32px;
    border-radius: 9px; background: #6366f1; border: none;
    cursor: pointer; color: #fff; font-size: 16px;
    display: flex; align-items: center; justify-content: center;
    transition: background .12s;
}
.sj-add-btn:hover { background: #4f46e5; }
/* Image picker overlay inside modal */
.sj-img-picker {
    position: absolute; inset: 0; z-index: 9999;
    background: var(--color-surface, #fff);
    border-radius: inherit; display: flex; flex-direction: column; overflow: hidden;
}
.sj-img-picker-hd {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 14px; border-bottom: 1px solid var(--color-border, rgba(0,0,0,.09));
    font-weight: 600; font-size: 14px; flex-shrink: 0;
}
.sj-img-picker-hd button {
    background: none; border: none; cursor: pointer; font-size: 16px;
    color: var(--color-text-secondary); padding: 2px 6px; border-radius: 5px;
}
/* Dark mode adjustments */
[data-theme="dark"] .sj-entry-time { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.08); }
[data-theme="dark"] .sj-entry-body { background: rgba(255,255,255,.04); border-color: rgba(255,255,255,.06); }

/* ── Picker pièce jointe DM Aurore (filePanel.js _openDmFilePicker) --
   harmonisé sur le style du picker "Joindre un fichier" de Flow
   (.ws-fsp-*) : onglets Mon Nuage/Nébuleuse, lignes à vignette. Reste
   un popover flottant multi-sélection (pas une modale) -- spécifique à
   ce composeur, coché plutôt qu'inséré au clic. */
.fp-fsp-toolbar { display: flex; align-items: center; gap: 5px; padding: 8px 10px 6px; flex-shrink: 0; }
.fp-fsp-tab { flex: 1; padding: 5px 3px; border-radius: 7px; border: none; background: transparent; color: var(--color-text-tertiary); font-size: 11px; font-weight: 700; cursor: pointer; transition: background .12s, color .12s; }
.fp-fsp-tab:hover { background: var(--color-hover); color: var(--color-text); }
.fp-fsp-tab.active { background: var(--color-primary); color: #fff; }
.fp-fsp-row-thumb { position: relative; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; background: var(--color-bg); border-radius: 6px; color: var(--color-text-tertiary); flex-shrink: 0; overflow: hidden; font-size: 9px; font-weight: 700; }
.fp-fsp-row-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.fp-fsp-row-thumb img.thumb-broken { display: none; }

/* =============================================================
   PWA STANDALONE — safe-area pour le notch/Dynamic Island iOS.
   En mode "app" (ajouté à l'écran d'accueil), il n'y a plus de chrome
   navigateur pour repousser le contenu sous l'encoche -- la webview est
   plein écran (viewport-fit=cover, layouts/main.php).

   CAUSE REELLE (diagnostic live du 2026-07-21, PAS une supposition) :
   sur mobile (≤640px), l'espacement entre le header flottant et le
   contenu n'est PAS géré par `.main-body`'s padding-top (qui vaut
   délibérément 0 !important sur mobile, cf plus loin dans ce fichier)
   -- il vient de `.header`/`.ws-page-header`/`.profile-page-header`/
   `.admin-page-header` qui ont `min-height:56px !important` (mobile
   audit block), poussant le contenu suivant via le FLUX NORMAL du
   document, independamment des icones flottantes (position:fixed).
   Une premiere version de ce correctif ajoutait EN PLUS un
   padding-top sur .main-body -- resultat : DOUBLE espacement (le
   min-height de 56px du flux + mon padding-top redondant), confirme
   par un script de debug temporaire affichant getBoundingClientRect()
   en direct sur l'appareil de l'utilisateur (tag-bar-wrap tombait a
   top=182 au lieu de ~124 attendu).

   Le bon correctif est donc a DEUX niveaux, tous deux inertes hors
   standalone :
   1. Les icones flottantes (position:fixed) descendent de l'inset :
      top: env(safe-area-inset-top).
   2. Le min-height:56px du flux (qui EST le mecanisme d'espacement
      reel sur mobile) grandit du meme inset, pour que le flux pousse
      le contenu d'autant sans qu'on touche a .main-body. */
@media (display-mode: standalone) {
    /* Contenu de la page Admin (stats, formulaires) : meme clearance que
       .home-page/.plans-popup-overlay, valeur de base = celle deja en
       vigueur (32px desktop, cf regle plus haut dans ce fichier). max()
       degrade proprement a 32px sur desktop (env=0 sans encoche) -- pas
       besoin de restreindre cette regle au mobile comme les autres
       ci-dessous. */
    .admin-page-content {
        padding-top: max(32px, env(safe-area-inset-top, 0px)) !important;
    }
}
@media (display-mode: standalone) and (max-width: 640px) {
    /* Ces selecteurs etaient auparavant dans le bloc standalone SANS
       restriction de largeur -- or leur valeur de base desktop est
       top:14px!important (cf .btn-sidebar-toggle/.ws-top-title/
       .admin-page-header-center plus haut dans ce fichier), pas 0. Hors
       mobile, l'ecraser par env(safe-area-inset-top, 0px) (= 0px sans
       encoche) decalait ces elements de 14px vers le haut, jusqu'a
       toucher le bord de la fenetre -- desaligne sur PWA desktop (aucune
       encoche a compenser la-bas). Deplace ici, sous la meme restriction
       mobile que le bloc juste en dessous (meme cause reelle : notch/
       Dynamic Island iOS, jamais desktop). */
    .global-user-corner,
    .header > .btn-sidebar-toggle,
    .header > .breadcrumb,
    .no-sidebar-layout .btn-sidebar-toggle,
    .ws-page-header .btn-sidebar-toggle,
    .profile-page-header .btn-sidebar-toggle,
    .admin-page-header .btn-sidebar-toggle,
    .no-sidebar-layout .header:not(.ws-page-header) > .breadcrumb,
    .ws-top-title {
        top: env(safe-area-inset-top, 0px) !important;
    }
    /* Selecteur complet (pas la classe seule) : .admin-page-header
       .admin-page-header-center a deja top:14px!important a specificite
       (0,0,2,0) plus loin dans ce fichier -- la classe seule (0,0,1,0)
       perdait silencieusement la bataille de specificite malgre les deux
       !important (constate en direct, tabs admin sous l'encoche). */
    .admin-page-header .admin-page-header-center {
        top: env(safe-area-inset-top, 0px) !important;
    }
    /* Meme selecteurs, meme valeur de base (56px) que le bloc "MOBILE AUDIT"
       plus haut dans ce fichier -- on ne fait qu'y ajouter l'inset. */
    .no-sidebar-layout .header,
    .ws-page-header,
    .profile-page-header,
    .admin-page-header {
        min-height: calc(56px + env(safe-area-inset-top, 0px)) !important;
    }
    /* Meme raisonnement que .admin-page-content ci-dessus, valeur de base
       mobile (18px, bloc "MOBILE AUDIT" plus haut dans ce fichier). */
    .admin-page-content {
        padding-top: max(18px, env(safe-area-inset-top, 0px)) !important;
    }
}

/* Note-moi (Aurore, filePanel.js::_loadConversations) : rangee horizontale
   scrollable au lieu d'une grille 3 colonnes -- evite que la liste Messages
   soit repoussee/ecrasee plus bas quand il y a beaucoup de memos.
   Padding-top : overflow-x:auto rend aussi overflow-y non "visible", donc
   sans marge le hover translateY(-6px) scale(1.015) des cartes (memes
   valeurs que .file-card:hover) se faisait rogner en haut par le conteneur. */
.aurore-memo-slide {
    display: flex;
    gap: 8px;
    padding: 10px 4px 12px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    cursor: grab;
    /* Statique, pas juste sur .is-dragging : même correctif que
       .nebula-memory-slides -- basculer user-select via une classe ajoutée
       au pointerdown arrive trop tard dans certains navigateurs (rectangle
       de sélection bleu pendant le glissement au lieu d'un simple
       défilement). Audit 2026-08-15. */
    user-select: none;
}
.aurore-memo-slide::-webkit-scrollbar { display: none; }
/* Glisser à la souris sur PC (pas de scrollbar visible ni de trackpad) --
   meme pattern que .nebula-memory-slides (app.js), voir le pointerdown/
   pointermove branche dans _loadConversations(). */
.aurore-memo-slide.is-dragging { cursor: grabbing; }

/* Chargement liste Conversations (filePanel.js::_renderConversationsList) --
   logo Aurore (memes traits que #global-chat-btn, layouts/main.php) au lieu
   d'un sablier generique, respire doucement pendant l'attente. */
.fp-aurore-loading-icon {
    animation: fp-aurore-loading-pulse 1.6s ease-in-out infinite;
}
@keyframes fp-aurore-loading-pulse {
    0%, 100% { opacity: .35; transform: scale(.94); }
    50%      { opacity: 1; transform: scale(1); }
}

/* États du logo Aurore -- maquette validée par l'utilisateur (2026-09-25,
   artifact "États du logo Aurore AI") : MÊME logo, même couleur, même
   trait partout, seul le COMPORTEMENT (vitesse/amplitude de la respiration
   ci-dessus, ou une coupure nette) change selon ce qu'Aurore est en train
   de faire. Chaque état ci-dessous surcharge juste --pulse-dur/--min-scale
   sur .fp-aurore-loading-icon -- jamais un mécanisme différent.
   Câblage réel (2026-09-25) : .aurore-think sur la bulle "..." pendant
   qu'Aurore génère une réponse (filePanel.js::_sendDmMessage) et
   .aurore-unavailable sur l'icône des écrans paywall/403 (ex.
   _renderTasksErrorHtml). Les autres classes ci-dessous existent déjà
   pour un câblage futur (dictée vocale, action à confirmer, rappel
   proactif, alerte) mais ne sont pas encore posées quelque part --
   ne pas les croire actives ailleurs dans l'app sans le vérifier. */
.fp-aurore-loading-icon.aurore-think {
    animation: fp-aurore-loading-pulse .7s ease-in-out infinite;
    opacity: .88;
}
.fp-aurore-loading-icon.aurore-listen {
    animation: fp-aurore-loading-pulse .4s ease-in-out infinite;
}
.fp-aurore-loading-icon.aurore-alert {
    animation: fp-aurore-loading-pulse .35s ease-in-out infinite, fp-aurore-alert-shake 2.2s ease-in-out infinite;
}
@keyframes fp-aurore-alert-shake {
    0%, 100% { translate: 0 0; }
    20%      { translate: -1.4px 0; }
    40%      { translate: 1.4px 0; }
    60%      { translate: -1px 0; }
    80%      { translate: 1px 0; }
}
.fp-aurore-loading-icon.aurore-clarify {
    animation: fp-aurore-loading-pulse 2.2s ease-in-out infinite;
}
.fp-aurore-loading-icon.aurore-confirm {
    animation: fp-aurore-loading-pulse 2.4s ease-in-out infinite;
}
.fp-aurore-loading-icon.aurore-done {
    animation: fp-aurore-done-settle 3s ease-out infinite;
}
@keyframes fp-aurore-done-settle {
    0%       { opacity: .4; transform: scale(.9); }
    14%      { opacity: 1; transform: scale(1.05); }
    40%,100% { opacity: 1; transform: scale(1); }
}
/* Estompé et immobile -- seul état qui NE respire PAS du tout (le
   mouvement = vivant, l'immobilité = éteint/indisponible). */
.fp-aurore-loading-icon.aurore-unavailable {
    animation: none;
    opacity: .4;
}
.fp-aurore-loading-icon.aurore-unavailable path {
    stroke-dasharray: 2 3;
}

/* ===================== Appels audio/vidéo (CallManager, calls.js) ===================== */
/* Overlay plein écran independant du panneau Aurore (survit a la navigation
   SPA) -- voir public/js/calls.js, monte/demonte directement sur document.body. */
#call-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: var(--color-bg);
    display: flex;
    align-items: center;
    justify-content: center;
}

.call-avatar-img {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    object-fit: cover;
}
.call-avatar-fallback {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    background: var(--color-primary);
    color: #fff;
    font-size: 36px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
}

.call-ring-screen {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 24px;
}
.call-ring-screen .call-peer-name {
    font-size: 20px;
    font-weight: 700;
    color: var(--color-text);
}
.call-ring-screen .call-status-label {
    font-size: 14px;
    color: var(--color-text-secondary);
}
.call-ring-screen .call-avatar-img,
.call-ring-screen .call-avatar-fallback {
    animation: call-pulse 1.6s ease-in-out infinite;
}
@keyframes call-pulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--color-primary-light); }
    50%      { box-shadow: 0 0 0 14px transparent; }
}

.call-actions {
    display: flex;
    gap: 22px;
    margin-top: 18px;
}
.call-btn {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    transition: transform .12s, filter .12s;
}
.call-btn svg { width: 24px; height: 24px; }
.call-btn:hover { filter: brightness(1.08); transform: scale(1.04); }
.call-btn:active { transform: scale(.96); }
.call-btn-accept  { background: var(--color-success); }
.call-btn-decline { background: var(--color-danger); }
.call-btn-secondary {
    background: var(--color-surface);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    width: 48px;
    height: 48px;
}
.call-btn-secondary svg { width: 20px; height: 20px; }
.call-btn-secondary.is-off {
    background: var(--color-danger);
    color: #fff;
    border-color: var(--color-danger);
}

/* Écran d'appel actif */
.call-active-screen {
    position: relative;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    background: #000;
}
.call-active-screen.is-audio {
    background: var(--color-bg);
    justify-content: center;
}
.call-video-remote {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #000;
}
.call-active-screen.is-audio .call-video-remote { display: none; }
.call-video-local {
    position: absolute;
    top: 16px;
    right: 16px;
    width: 110px;
    height: 150px;
    border-radius: 14px;
    object-fit: cover;
    box-shadow: 0 4px 16px rgba(0,0,0,.4);
    z-index: 1;
    background: #111;
}
.call-audio-avatar {
    margin-bottom: 24px;
}
.call-active-header {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    margin-bottom: 18px;
    text-shadow: 0 1px 3px rgba(0,0,0,.5);
}
.call-active-screen.is-audio .call-active-header { text-shadow: none; }
.call-active-header .call-peer-name {
    font-size: 18px;
    font-weight: 700;
    color: #fff;
}
.call-active-screen.is-audio .call-active-header .call-peer-name { color: var(--color-text); }
.call-active-header .call-status-label {
    font-size: 13px;
    color: rgba(255,255,255,.85);
    font-variant-numeric: tabular-nums;
}
.call-active-screen.is-audio .call-active-header .call-status-label { color: var(--color-text-secondary); }
.call-active-screen .call-actions {
    position: relative;
    z-index: 1;
    margin-bottom: 36px;
}

@media (max-width: 640px) {
    .call-video-local { width: 84px; height: 116px; top: 12px; right: 12px; }
    .call-btn { width: 52px; height: 52px; }
    .call-btn-secondary { width: 44px; height: 44px; }
}

/* Réduire l'appel (2026-09-15) -- demande utilisateur : l'overlay plein
   écran empêchait toute interaction avec le reste de l'app pendant un
   appel actif. #call-overlay passe d'un plein écran (inset:0) à une
   pastille flottante en bas a droite ; .call-active-screen (video/audio
   compris) n'est jamais retiré du DOM ni display:none -- juste "visually
   hidden" (clip + 1px) pour ne jamais risquer qu'un moteur suspende la
   lecture audio en cours (piège iOS deja rencontre sur d'autres flux media
   de ce projet, cf reference_pwa_ios_download_web_share/debug notch). */
.call-minimize-btn {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 2;
}
#call-overlay.is-minimized .call-minimize-btn { display: none; }
#call-overlay.is-minimized {
    inset: auto;
    top: auto;
    left: auto;
    right: 16px;
    bottom: 16px;
    width: auto;
    height: auto;
    background: transparent;
    z-index: 2001;
}
#call-overlay.is-minimized .call-active-screen {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
.call-minibar {
    display: none;
    align-items: center;
    gap: 10px;
    padding: 8px 10px 8px 8px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    box-shadow: 0 8px 24px rgba(0,0,0,.18);
    cursor: grab;
    min-width: 224px;
    /* Glisser-deposer (Pointer Events) : empeche le navigateur de capter le
       geste comme un scroll/pan tactile, et la selection de texte pendant
       le drag (souris). */
    touch-action: none;
    user-select: none;
}
.call-minibar.is-dragging { cursor: grabbing; }
#call-overlay.is-minimized .call-minibar { display: flex; }
.call-minibar .call-avatar-img,
.call-minibar .call-avatar-fallback { width: 36px; height: 36px; font-size: 14px; flex-shrink: 0; }
.call-minibar-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.call-minibar-name {
    font-size: 13px; font-weight: 600; color: var(--color-text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.call-minibar-status { font-size: 11px; color: var(--color-text-secondary); font-variant-numeric: tabular-nums; }
.call-minibar-actions { display: flex; gap: 6px; flex-shrink: 0; }
.call-minibar .call-btn { width: 34px; height: 34px; }
.call-minibar .call-btn svg { width: 16px; height: 16px; }
.call-minibar .call-btn-secondary svg { width: 15px; height: 15px; }

@media (max-width: 640px) {
    #call-overlay.is-minimized { right: 12px; bottom: 12px; }
    .call-minibar { min-width: 0; max-width: calc(100vw - 24px); }
}

/* ============== Appels de groupe (GroupCallManager, calls-group.js) ==============
   2026-09-15 -- overlay independant de #call-overlay (systeme parallele,
   jamais actif simultanement). Reutilise .call-btn/.call-avatar-img/
   .call-avatar-fallback tel quel (generiques), ajoute juste la liste
   participants absente du 1-a-1. */
#gcall-overlay {
    position: fixed; inset: 0; z-index: 2000;
    background: var(--color-bg);
    display: flex; align-items: center; justify-content: center;
}
.gcall-screen {
    display: flex; flex-direction: column; align-items: center;
    gap: 18px; padding: 24px; max-width: 420px; width: 100%; box-sizing: border-box;
}
.gcall-title { font-size: 18px; font-weight: 700; color: var(--color-text); text-align: center; }
.gcall-status-label { font-size: 13px; color: var(--color-text-secondary); font-variant-numeric: tabular-nums; text-align: center; }
.gcall-roster {
    display: flex; flex-direction: column; gap: 8px;
    width: 100%; max-height: 46vh; overflow-y: auto;
}
.gcall-participant {
    display: flex; align-items: center; gap: 12px;
    padding: 8px 10px; border-radius: 12px; background: var(--color-surface);
}
.gcall-participant .call-avatar-img,
.gcall-participant .call-avatar-fallback { width: 40px; height: 40px; font-size: 15px; flex-shrink: 0; }
.gcall-participant-name {
    font-size: 14px; font-weight: 600; color: var(--color-text); flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gcall-participant-status { font-size: 11px; color: var(--color-text-tertiary); flex-shrink: 0; }
.gcall-participant-status.is-connected { color: var(--color-success); }
.gcall-participant-status.is-left { color: var(--color-text-tertiary); }

/* Réduire l'appel de groupe -- meme principe et meme markup (.call-minibar/
   .call-minimize-btn generiques, cf bloc 1-a-1 plus haut) que #call-overlay,
   juste reancre sur #gcall-overlay. Le bouton reduire n'apparait qu'une fois
   REELLEMENT rejoint (.is-joined, pose par acceptCall()/startGroupCall()) --
   jamais pendant l'ecran de sonnerie. */
.gcall-minimize-btn {
    position: absolute;
    top: 16px;
    right: 16px;
    z-index: 2;
    display: none;
}
#gcall-overlay.is-joined .gcall-minimize-btn { display: flex; }
#gcall-overlay.is-minimized .gcall-minimize-btn { display: none; }
#gcall-overlay.is-minimized {
    inset: auto;
    top: auto;
    left: auto;
    right: 16px;
    bottom: 16px;
    width: auto;
    height: auto;
    background: transparent;
    z-index: 2001;
}
#gcall-overlay.is-minimized .gcall-screen {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}
#gcall-overlay.is-minimized .call-minibar { display: flex; }

@media (max-width: 640px) {
    #gcall-overlay.is-minimized { right: 12px; bottom: 12px; }
}

/* Rangée "Épinglés" du panneau Contacts (groupes + favoris) -- scroll
   horizontal façon carrousel, cf. .nm-pinned-row dans filePanel.js. */
.nm-pinned-row::-webkit-scrollbar { display: none; }




/* ══════════════════════════════════════════════════════════════════
   CARTE FAMILLE — lignes de parent et d'enfant
   ------------------------------------------------------------------
   Ces lignes etaient ecrites en style="…" dans profile.php, sans une
   seule classe : rien n'etait reutilisable, et le theme clair ne
   pouvait pas les atteindre. Elles passent ici.

   Le principe : une ligne FERMEE repond sans qu'on l'ouvre -- niveau,
   mode, parent principal en pastilles de texte -- et n'expose qu'une
   action, celle qu'un parent fait tous les jours. Les reglages et les
   gestes d'administration descendent dans un tiroir.
   ══════════════════════════════════════════════════════════════════ */
.fam-rang {
    background: var(--color-surface-secondary, rgba(255,255,255,.04));
    border-radius: 12px;
    padding: 12px 14px;
}
.fam-haut {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
}
.fam-qui { display: flex; align-items: center; gap: 10px; min-width: 0; }
.fam-pastille {
    width: 32px; height: 32px; border-radius: 50%; flex: 0 0 auto;
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 13px;
    background: rgba(167,139,250,.18);
    border: 1px solid rgba(167,139,250,.28);
    color: #a78bfa;
}
.fam-pastille.fam-parent {
    background: rgba(96,165,250,.18);
    border-color: rgba(96,165,250,.28);
    color: #60a5fa;
}
.fam-nom { font-size: 14px; font-weight: 600; color: var(--color-text); }
/* Prenom en gras, nom de famille en gris : un seul traitement pour
   toute la liste. Avant, deux traitements differents cohabitaient. */
.fam-nom-famille { color: var(--color-text-secondary); font-weight: 400; }

/* Les pastilles d'etat : ce qu'il fallait derouler trois menus pour
   savoir se lit maintenant sur la ligne. */
.fam-etats { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.fam-et {
    font-size: 11.5px; line-height: 1.4; padding: 3px 9px; border-radius: 100px;
    border: 1px solid var(--color-border); color: var(--color-text-secondary);
    display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
}
.fam-et b { color: var(--color-text); font-weight: 600; }
.fam-et-vert { border-color: rgba(48,209,88,.35); color: var(--color-success, #30d158); }
.fam-et-vert b { color: inherit; }
/* L'ambre ne sert qu'a un manque REEL : deux parents et aucun designe.
   Un enfant a un seul parent n'a rien a arbitrer -- pas d'alerte la ou
   il n'y a pas de choix. */
.fam-et-ambre { border-color: rgba(255,159,10,.35); color: var(--color-warning, #ff9f0a); }
.fam-et-ambre b { color: inherit; }
.fam-et-pt { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: 0 0 auto; }

.fam-actes {
    display: flex; align-items: center; gap: 8px;
    flex-wrap: wrap; justify-content: flex-end;
}
.fam-actes .btn { padding: 6px 14px; font-size: 12.5px; }
.fam-chevron { padding: 6px 10px !important; line-height: 1; }
.fam-chevron svg { display: block; transition: transform .18s ease; }
.fam-chevron[aria-expanded="true"] svg { transform: rotate(180deg); }

/* Le tiroir. Ce qui s'y trouve n'a pas disparu : il est range. */
.fam-tiroir {
    margin-top: 12px; padding-top: 12px;
    border-top: 1px solid var(--color-border);
    display: grid; gap: 10px;
}
.fam-tiroir[hidden] { display: none; }
.fam-tiroir-lbl {
    font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
    color: var(--color-text-tertiary); font-weight: 600;
}
.fam-reglage {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    font-size: 12.5px; color: var(--color-text-secondary);
}
.fam-reglage > .fam-reglage-lbl { min-width: 118px; }
.fam-reglage .form-input {
    width: auto; padding: 3px 24px 3px 10px; font-size: 12px;
    height: auto; min-height: 0;
}
.fam-aide { font-size: 11.5px; color: var(--color-text-tertiary); }
.fam-tiroir-actes { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* L'action destructive cesse de ressembler a « Fiche ». */
.fam-b-danger {
    background: none !important; border-color: transparent !important;
    color: var(--color-danger, #ff453a) !important;
}
.fam-b-danger:hover {
    background: rgba(255,69,58,.1) !important;
    border-color: rgba(255,69,58,.35) !important;
}

/* Les pastilles sont soeurs de .fam-haut, pas filles du nom : sur grand
   ecran elles s'alignent sous lui grace a ce retrait, sur telephone
   elles prennent la largeur. */
.fam-etats { padding-left: 42px; }
.fam-etats:empty { display: none; }

/* ── Telephone ────────────────────────────────────────────────────
   A 375 px, la ligne fermee refaisait 147 px -- la hauteur d'avant la
   refonte. Les actions passaient a la ligne parce que les pastilles,
   alors imbriquees sous le nom, poussaient tout. Sorties de la, le nom
   et les deux boutons tiennent ensemble sur la premiere ligne. */
/* Deux libelles portent une forme longue et une forme courte. Sur
   telephone la carte ne laisse que 277 px utiles : « Ouvrir son
   espace » (129) et le nom (141) ne tenaient pas ensemble, et les trois
   pastilles faisaient 283. Les formes courtes ramenent l'un a 242 et
   les autres a 253 -- une ligne chacun. */
.fam-court { display: none; }

@media (max-width: 560px) {
    .fam-long  { display: none; }
    .fam-court { display: inline; }
    .fam-etats { padding-left: 0; margin-top: 8px; }

    /* Le nom de famille reste au grand ecran. Un « Prenom NOM » et ses
       actions faisaient 265 px pour 277 utiles -- plus la gouttiere de
       12, et la ligne se coupait en deux. Dans une meme famille le
       prenom suffit a designer, et c'est d'ailleurs ainsi que le reste
       de l'application nomme les enfants. */
    .fam-nom-famille { display: none; }
    .fam-haut { gap: 8px; }

    /* Dans le tiroir, l'etiquette passe AU-DESSUS de son controle, qui
       prend toute la largeur : la colonne de 118 px ne laissait rien
       sur 347 px utiles. L'interrupteur fait exception -- il n'a pas
       besoin d'une ligne pour lui. */
    .fam-reglage-choix {
        flex-direction: column; align-items: stretch; gap: 5px;
    }
    .fam-reglage-choix > .fam-reglage-lbl {
        min-width: 0; font-size: 11.5px;
        text-transform: uppercase; letter-spacing: .06em;
        color: var(--color-text-tertiary);
    }
    .fam-reglage-choix .form-input {
        width: 100%; padding: 8px 28px 8px 12px; font-size: 13px;
    }
    .fam-reglage-bascule > .fam-reglage-lbl { min-width: 0; }
    .fam-reglage-bascule { flex-wrap: wrap; }
    .fam-reglage-bascule .fam-aide { flex-basis: 100%; }

    /* Trois boutons de 64, 112 et 125 px sur deux rangs : une grille a
       largeur egale se lit mieux qu'un alignement ragged. */
    .fam-tiroir-actes {
        display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    }
    .fam-tiroir-actes .btn { width: 100%; justify-content: center; }
}
