/* ════════════════════════════════════════════════════════════════════════════
   EDUCATED — PORTAIL APPRENANT
   Boîte de réception en cartes

   Tout est porté sous .edm-cards, une classe que le script pose sur la grille.
   Sans lui — ou avec window.EDUCATED_MESSAGES_CARDS = false — la grille XAF
   reprend son apparence d'origine, sans qu'aucune règle d'ici ne s'applique.
   ════════════════════════════════════════════════════════════════════════════ */

/* ── L'en-tête reste, invisible ──────────────────────────────────
   Les <th> portent le tri de XAF. On les masque à l'œil sans les
   retirer du flux : un en-tête supprimé, c'est le tri perdu. */
.eds-hidden-head,
.edm-cards thead {
    position: absolute !important;
    width: 1px; height: 1px;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
    white-space: nowrap;
}

/* ── Une ligne de données ne montre que la cellule du sujet ──────
   Les autres restent dans le DOM : c'est d'elles que le script lit
   l'expéditeur, la pièce jointe et l'état lu. Elles ne sont masquées
   que sur les lignes de données — une ligne de groupe n'a pas de
   cellule hôte, et la même règle la rendrait muette. */
.edm-cards tbody tr:not(.dxbl-grid-group-row) > td:not(.edm-host) {
    display: none !important;
}

/* ── La cellule hôte ─────────────────────────────────────────────
   Le sujet d'origine est un nœud texte que le script vide. La taille
   nulle est une ceinture : si un passage tarde, rien n'apparaît sous
   la carte. Les trois classes répétées ne sont pas une coquette —
   c'est ce qu'il faut pour passer devant grid.css, qui vise
   td.xaf-action avec ses propres !important. */
.edm-cards td.edm-host.edm-host.edm-host {
    display: table-cell !important;
    font-size: 0 !important;
    line-height: 0 !important;
    color: transparent !important;
    background: transparent !important;
    border: 0 !important;
    padding: 0 !important;
    width: 100% !important;
    text-align: left !important;
}

.edm-cards td.edm-host > *:not(.edm-card) {
    display: none !important;
}

/* L'espace entre cartes appartient à la carte, pas au tableau :
   border-spacing ajoute de l'espace avant la première ligne et après
   la dernière, et laisse un vide sous la barre de l'écran. */
.edm-cards,
.edm-cards table {
    border-collapse: separate !important;
    border-spacing: 0 !important;
}

.edm-cards tbody tr { background: transparent !important; }


/* ── LA CARTE ────────────────────────────────────────────────────
   Trois colonnes : l'avatar, le texte, les indicateurs. Deux rangées :
   l'en-tête (expéditeur + sujet) et l'extrait. L'avatar et les
   indicateurs s'étendent sur les deux rangées. */
.edm-cards .edm-card {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr) auto;
    grid-template-areas:
        "av head side"
        "av body side";
    column-gap: 13px;
    align-items: center;

    font-size: 15px;
    line-height: 1.45;
    color: var(--ink-1, #0F172A);

    background: var(--surface-1, #FFFFFF);
    border: 1px solid var(--line, #E5E7EB);
    border-radius: 12px;
    padding: 13px 15px;
    margin-bottom: 9px;
    position: relative;
    transition: border-color .12s ease, box-shadow .12s ease;
}

.edm-cards tr.cursor-pointer:hover .edm-card {
    border-color: var(--brand-soft-2, #DAD4FF);
    box-shadow: 0 1px 2px rgba(15,23,42,.04), 0 8px 20px -12px rgba(31,27,90,.30);
}

/* ── Le non lu ───────────────────────────────────────────────────
   Trois signaux pour une seule information : un liseré, un fond
   teinté, le sujet en gras. Un non lu doit se voir en parcourant la
   liste du coin de l'œil, sans la lire — c'est la seule chose qui
   fait revenir l'apprenant sur cet écran. */
.edm-cards .edm-card.unread {
    background: var(--brand-soft, #EEF0FE);
    border-color: var(--brand-soft-2, #DAD4FF);
}

.edm-cards .edm-card.unread::before {
    content: "";
    position: absolute;
    left: 0; top: 12px; bottom: 12px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--gradient-brand, linear-gradient(135deg,#4F46E5,#6D5DE8));
}

/* ── L'avatar ────────────────────────────────────────────────────
   Les initiales de l'expéditeur, dans une teinte tirée de son nom :
   le même correspondant garde sa couleur d'un tri à l'autre, ce qui
   permet de le reconnaître sans lire. */
.edm-cards .edm-av {
    grid-area: av;
    width: 40px; height: 40px;
    border-radius: 11px;
    display: grid; place-items: center;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 12.5px;
    font-weight: 700;
    letter-spacing: .02em;
}

.edm-cards .edm-av.tint-indigo { background: var(--brand-soft-2, #DAD4FF); color: var(--brand, #4F46E5); }
.edm-cards .edm-av.tint-blue   { background: var(--info-soft, #DCEAFE);   color: var(--info, #2563EB); }
.edm-cards .edm-av.tint-teal   { background: var(--success-soft, #D0F4E2); color: var(--success, #059669); }
.edm-cards .edm-av.tint-amber  { background: var(--warning-soft, #FBE9CC); color: var(--warning, #B45309); }
.edm-cards .edm-av.tint-rose   { background: #FFE4E9;                      color: #E11D48; }
.edm-cards .edm-av.tint-violet { background: #EDE4FE;                      color: #7C3AED; }

/* Expéditeur inconnu : gris, sans couleur propre. Une teinte le
   ferait passer pour un correspondant identifié. */
.edm-cards .edm-av.anon {
    background: var(--surface-3, #F3F5F9) !important;
    color: var(--ink-3, #94A3B8) !important;
}

/* ── L'en-tête de la carte ───────────────────────────────────────── */
.edm-cards .edm-head {
    grid-area: head;
    display: flex;
    align-items: baseline;
    gap: 9px;
    flex-wrap: wrap;
    min-width: 0;
}

.edm-cards .edm-from {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink-2, #475569);
    flex: 0 0 auto;
}

.edm-cards .edm-subject {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -.005em;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.edm-cards .edm-card.unread .edm-subject { font-weight: 800; }

.edm-cards .edm-new {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #047857;
    background: #D1FAE5;
    border-radius: 20px;
    padding: 3px 8px;
    white-space: nowrap;
    flex: 0 0 auto;
}

/* ── L'extrait ───────────────────────────────────────────────────
   Une ligne, coupée net. Un extrait qui passe à la ligne fait varier
   la hauteur des cartes, et une liste dont les cartes n'ont pas la
   même hauteur se parcourt beaucoup moins vite. */
.edm-cards .edm-excerpt {
    grid-area: body;
    font-size: 13.5px;
    color: var(--ink-3, #94A3B8);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-top: 1px;
}

.edm-cards .edm-side {
    grid-area: side;
    display: flex;
    align-items: center;
    gap: 12px;
    padding-left: 14px;
}

.edm-cards .edm-clip {
    display: flex;
    color: var(--ink-3, #94A3B8);
}

.edm-cards .edm-clip svg { width: 16px; height: 16px; }


/* ── LA BANDE DE DATE ────────────────────────────────────────────
   La mise en page est ICI et non dans le script. Posée en JS, elle
   n'existerait qu'après son passage : entre le rendu de DevExpress et
   ce passage, la ligne reprendrait sa disposition de tableau, le
   libellé brut réapparaîtrait poussé à droite et la bande se
   raccourcirait. Un dixième de seconde, mais visible à chaque repli.

   Les cellules sont visées par leur POSITION : une ligne fraîchement
   rendue n'a pas encore nos classes, et c'est précisément celle-là
   qu'il faut habiller. */
.edm-cards tr.dxbl-grid-group-row.dxbl-grid-group-row {
    background: var(--surface-3, #F3F5F9) !important;
    border-radius: 10px;
    padding: 9px 13px !important;
    margin-top: 6px;
    display: flex !important;
    align-items: center !important;
    width: 100% !important;
}

.edm-cards tr.dxbl-grid-group-row > td:first-child {
    /* « width: 1% » — la ruse pour « aussi étroit que possible » — n'a de
       sens que dans un tableau. Dans une ligne passée en flex, 1 % se
       calcule vraiment : la cellule tombe à dix pixels, son bouton en
       déborde et vient se poser SUR la première lettre du libellé. */
    width: auto !important;
    flex: 0 0 auto !important;
    white-space: nowrap;
    border: 0 !important;
    background: transparent !important;
    padding: 0 12px 0 0 !important;
    display: flex !important;
    align-items: center !important;
}

.edm-cards tr.dxbl-grid-group-row > td:nth-child(2) {
    flex: 1 1 auto !important;
    width: auto !important;
    min-width: 0 !important;
    text-align: left !important;
    border: 0 !important;
    background: transparent !important;
    padding: 0 !important;
    /* Le libellé d'origine ne s'affiche jamais, même le temps d'un rendu. */
    font-size: 0 !important;
    display: flex !important;
    align-items: center !important;
}

.edm-cards tr.dxbl-grid-group-row > td.dxbl-grid-empty-cell {
    display: none !important;
}

/* Le bouton de repli : une cible carrée plutôt qu'un glyphe de
   quelques pixels, pénible à viser à la souris comme au doigt. */
.edm-cards tr.dxbl-grid-group-row button.dxbl-grid-expand-button {
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    width: 22px !important;
    min-width: 22px !important;
    height: 22px !important;
    margin: 0 !important;
    padding: 0 !important;
    line-height: 1 !important;
    border-radius: 6px;
    color: var(--ink-3, #64748B) !important;
    transition: background-color .12s ease, color .12s ease;
}

.edm-cards tr.dxbl-grid-group-row button.dxbl-grid-expand-button:hover {
    background: rgba(79, 70, 229, .10) !important;
    color: var(--brand, #4F46E5) !important;
}

.edm-cards .edm-grp {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
    line-height: 1.3;
    align-self: center;
}

.edm-cards .edm-grp-name {
    font-size: 14.5px;
    font-weight: 700;
    color: var(--ink-1, #0F172A);
    letter-spacing: -.01em;
}

.edm-cards .edm-grp-n {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px;
    color: var(--ink-3, #94A3B8);
}


/* ── LA BARRE DE L'ÉCRAN ─────────────────────────────────────────── */

.edm-bar {
    padding: 2px 0 14px;
}

.edm-bar-top {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}

.edm-h1 {
    font-size: 21px;
    font-weight: 800;
    letter-spacing: -.015em;
    margin: 0;
    color: var(--ink-1, #0F172A);
}

.edm-total {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--ink-2, #475569);
    background: var(--surface-3, #F3F5F9);
    border-radius: 20px;
    padding: 3px 10px;
}

.edm-total.unread {
    background: var(--brand, #4F46E5);
    color: #fff;
}

.edm-chips {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 12px;
}

.edm-sp { flex: 1 1 auto; }

.edm-chip,
.edm-go {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 600;
    border-radius: 20px;
    padding: 7px 14px;
    background: var(--surface-1, #FFFFFF);
    border: 1px solid var(--line, #E5E7EB);
    color: var(--ink-2, #475569);
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}

.edm-chip:hover,
.edm-go:hover {
    border-color: var(--brand-soft-2, #DAD4FF);
    color: var(--ink-1, #0F172A);
}

.edm-chip.on {
    background: var(--brand, #4F46E5);
    border-color: transparent;
    color: #fff;
}

.edm-chip .n {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    font-weight: 700;
    opacity: .85;
}

.edm-go svg { width: 16px; height: 16px; }


/* ── Téléphone ───────────────────────────────────────────────────
   L'extrait passe sous l'en-tête et les indicateurs rejoignent la
   ligne du bas : à cette largeur, trois colonnes ne laissent plus
   assez de place au sujet, qui est ce qu'on lit. */
@media (max-width: 640px) {
    .edm-cards .edm-card {
        grid-template-columns: 36px minmax(0, 1fr);
        grid-template-areas:
            "av head"
            "av body"
            "side side";
        padding: 12px 13px;
    }

    .edm-cards .edm-av { width: 36px; height: 36px; }

    .edm-cards .edm-side {
        padding-left: 0;
        margin-top: 8px;
    }

    .edm-cards .edm-subject { white-space: normal; }
}


/* ════════════════════════════════════════════════════════════════════════════
   LA LECTURE D'UN MESSAGE

   Le formulaire de XAF n'est pas rhabillé : il est REMPLACÉ.

   J'ai d'abord voulu le transformer en lettre par la feuille — masquer les
   libellés, agrandir le sujet, effacer les cadres. Ça ne tient pas, et la
   raison mérite d'être écrite : XAF ne rend pas des valeurs mais des ÉDITEURS,
   dont DevExpress fixe la typographie avec ses propres !important à forte
   spécificité. La variable de thème, le sélecteur d'enfant direct, une règle
   sur « input » seul : aucune ne passe. Un style en ligne, lui, passe. C'est le
   piège n° 4 de notre journal appliqué à la typographie — ce qu'un composant
   calcule lui-même ne se corrige pas depuis la feuille.

   Le script lit donc les valeurs des éditeurs et compose sa propre lettre,
   exactement comme les cartes lisent les cellules de la grille. Le formulaire
   reste dans le DOM — c'est lui qui porte les droits et le chargement — mais
   il n'est plus affiché, et seulement une fois la lettre remplie : sans ce
   garde-fou, une lecture ratée laisserait un écran vide, bien pire que le
   formulaire brut.
   ════════════════════════════════════════════════════════════════════════════ */

.edm-read.edm-letter-ok .dxbl-fl { display: none !important; }

.edm-letter {
    background: var(--surface-1, #FFFFFF);
    border: 1px solid var(--line, #E5E7EB);
    border-radius: 14px;
    padding: 24px 26px 20px;
    max-width: 820px;
    color: var(--ink-1, #0F172A);
}

.edm-l-subject {
    font-size: 22px;
    font-weight: 800;
    letter-spacing: -.015em;
    line-height: 1.25;
    margin: 0 0 14px;
    text-wrap: balance;
}

/* ── L'expéditeur ────────────────────────────────────────────────
   Le même avatar que dans la liste, et la même teinte tirée du nom :
   on retrouve d'un coup d'œil de qui vient la lettre qu'on vient
   d'ouvrir. */
.edm-l-from {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--line, #E5E7EB);
    margin-bottom: 18px;
}

.edm-l-who {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.edm-l-who b {
    font-size: 14px;
    font-weight: 600;
}

.edm-l-who span {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px;
    color: var(--ink-3, #94A3B8);
}

/* ── Le corps ────────────────────────────────────────────────────
   Bornée à une soixantaine de caractères : au-delà, l'œil perd la
   ligne suivante en revenant à la marge. Les retours à la ligne du
   texte deviennent de vrais paragraphes — dans une zone de saisie ils
   n'étaient que des retours chariot. */
.edm-l-body {
    font-size: 15px;
    line-height: 1.75;
    color: var(--ink-2, #475569);
    max-width: 64ch;
}

.edm-l-body p { margin: 0 0 12px; }
.edm-l-body p:last-child { margin-bottom: 0; }
.edm-l-empty { color: var(--ink-4, #CBD5E1); font-style: italic; }

/* ── La pièce jointe ─────────────────────────────────────────────
   Le lien reprend le href produit par l'éditeur de fichier : aucune
   route nouvelle, aucun contrôle d'accès à reposer. */
.edm-l-file {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 20px;
    padding: 11px 13px;
    background: var(--surface-3, #F3F5F9);
    border-radius: 12px;
    text-decoration: none;
    color: inherit;
    max-width: 64ch;
}

.edm-l-file:hover { background: var(--brand-soft, #EEF0FE); }

.edm-l-ext {
    width: 38px; height: 38px;
    border-radius: 9px;
    display: grid; place-items: center;
    flex: 0 0 auto;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10.5px;
    font-weight: 700;
    background: var(--info-soft, #DCEAFE);
    color: var(--info, #2563EB);
}

.edm-l-fname {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13.5px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.edm-l-dl {
    width: 38px; height: 38px;
    border-radius: 10px;
    display: grid; place-items: center;
    flex: 0 0 auto;
    background: var(--gradient-brand, linear-gradient(135deg,#4F46E5,#6D5DE8));
    color: #fff;
}

.edm-l-dl svg { width: 17px; height: 17px; }

/* ── La trace de lecture ─────────────────────────────────────────
   Tout en bas et très discrète : c'est une trace, pas une information
   que l'apprenant est venu chercher. */
.edm-l-foot {
    margin-top: 22px;
    padding-top: 14px;
    border-top: 1px solid var(--line, #E5E7EB);
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px;
    color: var(--ink-4, #CBD5E1);
}

/* Il y avait ici une règle qui masquait les boutons « Enregistrer ».

   Elle est retirée avec le code qui la posait : masquer un bouton de ruban
   fausse la mesure que DevExpress fait de sa barre, et « Nouveau » héritait
   ensuite d'un conteneur large de 0 pixel. Les actions d'enregistrement sont
   désormais désactivées côté serveur (MessageToolbarController) : elles ne
   sont plus rendues du tout. */

@media (max-width: 640px) {
    .edm-letter { padding: 18px 16px 16px; }
    .edm-l-subject { font-size: 19px; }
}


/* ════════════════════════════════════════════════════════════════════════════
   LA FENÊTRE « ÉCRIRE À L'ADMINISTRATION »

   Ici on ne remplace rien : c'est un formulaire, et il doit le rester — on
   vient y saisir. Seule sa respiration est reprise.

   J'ai voulu aller plus loin : un champ par ligne, le libellé du message
   au-dessus. Prises séparément, chacune de ces règles se comporte bien ;
   ENSEMBLE elles poussent les contrôles hors du cadre et font apparaître une
   barre de défilement horizontale — les libellés restent, les champs partent
   à droite. Je n'ai pas isolé laquelle déclenche l'autre, et je préfère une
   fenêtre sobre qui marche à une mise en page ambitieuse qui casse.

   Ce qui suit est donc le sous-ensemble vérifié, mesuré dans le navigateur :
   champ du sujet à sa place, zone de message à 200 px, bandeau technique
   masqué.

   Le ciblage passe par le TYPE MÉTIER, pas par un nom de champ.

   Il s'appuyait sur la présence d'un « sujet ». Ces mots n'appartiennent à
   personne : l'écran Supports de cours a lui aussi une propriété Subject — le
   titre du cours — et une Description. Ouvrir un support lui appliquait donc
   la mise en page de la messagerie : deux formulaires sans rapport se
   mélangeaient. On vise maintenant la classe que XAF dérive du nom du type,
   seul repère qui dise DE QUOI parle l'écran plutôt que ce qu'il contient.
   Le script se cale sur les mêmes marqueurs.
   ════════════════════════════════════════════════════════════════════════════ */

/* Le nom de classe en tête de formulaire — « Message Student To School » —
   n'apprend rien à l'apprenant : le titre de la fenêtre dit déjà « Re: … ». */
.dxbl-modal-body:has([class*="xaf-item-messagestudenttoschool"]) .dxbl-group-header,
.detail-view-content:not(.edm-letter-ok):has([class*="xaf-item-messagestudenttoschool"]) .dxbl-group-header {
    display: none !important;
}

/* La zone de message prend la place : c'est le seul champ où l'apprenant écrit
   vraiment, et trois lignes l'invitent à faire court quand il aurait besoin
   d'être précis. */
.dxbl-modal-body:has([class*="xaf-item-messagestudenttoschool"]) textarea,
.detail-view-content:not(.edm-letter-ok):has([class*="xaf-item-messagestudenttoschool"]) textarea {
    min-height: 200px !important;
    resize: vertical !important;
}

.dxbl-modal-body:has([class*="xaf-item-messagestudenttoschool"]) {
    padding: 18px 20px !important;
}


/* ── LA BOÎTE D'ENVOI ────────────────────────────────────────────
   Même carte, deux différences qui comptent.

   Pas d'expéditeur : c'est toujours l'apprenant. L'avatar devient une
   flèche sortante — elle dit « parti d'ici » sans occuper la place
   d'un nom qui n'apprendrait rien.

   Un statut à la place du « Nouveau » : « Ouvert », « En cours de
   traitement », « Traité ». C'est la seule chose qu'on veuille savoir
   d'un message qu'on a écrit — est-ce que quelqu'un l'a lu, et où ça
   en est. Le champ existait en base et n'était affiché nulle part. */

.edm-cards .edm-av.sent {
    background: var(--surface-3, #F3F5F9);
    color: var(--ink-3, #94A3B8);
    font-size: 16px;
    font-weight: 600;
}

.edm-cards .edm-state {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    border-radius: 20px;
    padding: 3px 8px;
    white-space: nowrap;
    flex: 0 0 auto;
}

/* Trois états, trois lectures. « Ouvert » est neutre — le message est
   parti, rien ne s'est encore passé. « En cours » appelle la patience.
   « Traité » est la bonne nouvelle, et reprend le vert du « Nouveau »
   des reçus : dans les deux cas, c'est l'affaire qui avance. */
.edm-cards .edm-state.open { background: var(--info-soft, #DCEAFE); color: var(--info, #2563EB); }
.edm-cards .edm-state.prog { background: var(--warning-soft, #FBE9CC); color: var(--warning, #B45309); }
.edm-cards .edm-state.done { background: #D1FAE5; color: #047857; }

/* La date dans la fenêtre de rédaction.

   Elle doit RESTER dans la vue : c'est d'elle que la lettre d'un message
   envoyé tire son horodatage. Mais l'apprenant qui écrit n'a rien à en faire
   — elle est posée automatiquement à la création. On la masque donc ici, et
   seulement ici. */
.dxbl-modal-body:has([class*="xaf-item-messagestudenttoschool"]) .dxbl-fl-item:has([class*="xaf-item-messagedate"]),
.detail-view-content:not(.edm-letter-ok):has([class*="xaf-item-messagestudenttoschool"]) .dxbl-fl-item:has([class*="xaf-item-messagedate"]) {
    display: none !important;
}
