/* Styles de l'éditeur Ishtar.Markdown.
 *
 * Toutes les couleurs passent par des variables « --ishtar-md-* » avec valeur de repli :
 * l'application hôte redéfinit ce qu'elle veut, et le bundle JS n'a jamais à connaître de
 * palette. Repris de Cairn (Apache 2.0), dévariabilisé pour être réutilisable.
 */

/* --- Fonte de saisie -----------------------------------------------------------------------
 *
 * JetBrains Mono, embarquée dans le paquet — SIL Open Font License 1.1, dont le texte et la
 * liste des auteurs voyagent à côté des fichiers, dans « fonts/ ». Deux raisons de ne pas s'en
 * remettre à la chasse fixe du système :
 *   - elle est variable de 100 à 800, ce qui est la condition du corps de texte en maigre et de
 *     l'échelle de graisses des titres. Les mono système n'ont le plus souvent que le régulier
 *     et le gras, et toutes les valeurs intermédiaires y rendent le même tracé ;
 *   - ses ligatures sont portées par « calt », que les navigateurs activent par défaut :
 *     « -> », « != », « => » se composent sans réglage.
 *
 * Un seul fichier par style, grâce à « font-weight: 100 800 » qui déclare l'étendue de l'axe :
 * le navigateur interpole, là où seize fontes statiques auraient été nécessaires.
 */
@font-face {
    font-family: 'JetBrains Mono';
    /* « format('woff2') » et non « woff2-variations » : cette dernière est l'ancienne syntaxe,
       que les navigateurs récents ne reconnaissent plus — ils écarteraient la source et l'on
       retomberait silencieusement sur la fonte de repli. */
    src: url('../fonts/jetbrains-mono-variable.woff2') format('woff2');
    font-weight: 100 800;
    font-style: normal;
    /* Le texte s'affiche aussitôt dans la mono de repli, puis bascule : sur un carnet de notes,
       attendre le chargement d'une fonte pour relire sa liste de courses n'a pas de sens. */
    font-display: swap;
}

/* Vraie fonte italique, et non l'oblique synthétique que le navigateur fabriquerait en penchant
   le romain : l'italique porte ici du sens — emphase, citation, titres profonds. */
@font-face {
    font-family: 'JetBrains Mono';
    src: url('../fonts/jetbrains-mono-italic-variable.woff2') format('woff2');
    font-weight: 100 800;
    font-style: italic;
    font-display: swap;
}

/* --- Thème --------------------------------------------------------------------------------
 *
 * Un seul jeu de variables, posé sur l'enveloppe — pas sur l'éditeur : la barre d'outils et
 * l'encart des éléments cochés en sont des frères et n'hériteraient de rien s'il vivait plus
 * bas.
 *
 * Trois niveaux de personnalisation, du plus fin au plus large :
 *   1. redéfinir une couleur précise (« --ishtar-md-accent-link », par exemple) ;
 *   2. redéfinir la base (« --ishtar-md-surface », « --ishtar-md-color ») ;
 *   3. forcer le thème via l'attribut « data-ishtar-theme », que pose le paramètre Theme.
 *
 * Par défaut tout se déduit de « currentColor » : posé dans n'importe quelle page, l'éditeur
 * en adopte l'encre sans qu'on ait rien à régler.
 */
.ishtar-markdown,
.ishtar-tasklist {
    color-scheme: light;

    /* Encre et fond ont de vraies valeurs, pas « currentColor » et « transparent » : sinon
       forcer le thème sombre ne changerait ni le texte ni l'arrière-plan, tous deux hérités
       de la page hôte. Les gris se déduisent de l'encre, donc suivent le thème. */
    --ishtar-md-encre: var(--ishtar-md-color, #1b1f24);
    --ishtar-md-fond: var(--ishtar-md-surface, #ffffff);
    --ishtar-md-encre-douce: var(--ishtar-md-color-muted, color-mix(in srgb, var(--ishtar-md-encre) 55%, var(--ishtar-md-fond)));
    --ishtar-md-bord: var(--ishtar-md-border-color, color-mix(in srgb, var(--ishtar-md-encre) 25%, var(--ishtar-md-fond)));
    --ishtar-md-voile: var(--ishtar-md-highlight, color-mix(in srgb, var(--ishtar-md-encre) 7%, var(--ishtar-md-fond)));
    --ishtar-md-voile-moyen: var(--ishtar-md-selection, color-mix(in srgb, var(--ishtar-md-encre) 20%, var(--ishtar-md-fond)));

    color: var(--ishtar-md-encre);

    /* Chasse fixe de la saisie, en un seul endroit : la zone de texte, l'invite et le repli
       sans JavaScript doivent la partager, sinon le texte se réagence en passant de l'un à
       l'autre. Un hôte qui préfère sa propre fonte redéfinit « --ishtar-md-font-mono » et rien
       n'est téléchargé — les @font-face ne se chargent que si la famille est réclamée. */
    --ishtar-md-mono: var(--ishtar-md-font-mono, 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace);

    --ishtar-md-titre: var(--ishtar-md-accent-heading, #1c4f82);
    --ishtar-md-lien: var(--ishtar-md-accent-link, #1667b3);
    --ishtar-md-code-teinte: var(--ishtar-md-accent-code, #9c3350);
    --ishtar-md-puce: var(--ishtar-md-accent-list, #6b4fa8);
    --ishtar-md-citation: var(--ishtar-md-accent-quote, #4a7059);
}

/* Sombre automatique, sauf si l'hôte a forcé le clair. « color-scheme » compte autant que les
   couleurs : sans lui, la case à cocher native reste blanche sur fond sombre. */
@media (prefers-color-scheme: dark) {
    .ishtar-markdown:not([data-ishtar-theme="light"]),
    .ishtar-tasklist:not([data-ishtar-theme="light"]) {
        color-scheme: dark;

        --ishtar-md-encre: var(--ishtar-md-color, #e6e8eb);
        --ishtar-md-fond: var(--ishtar-md-surface, #1b1f24);

        --ishtar-md-titre: var(--ishtar-md-accent-heading, #7fb3e3);
        --ishtar-md-lien: var(--ishtar-md-accent-link, #6cb0f0);
        --ishtar-md-code-teinte: var(--ishtar-md-accent-code, #e58fa5);
        --ishtar-md-puce: var(--ishtar-md-accent-list, #b39ce8);
        --ishtar-md-citation: var(--ishtar-md-accent-quote, #8dc4a2);
    }
}

/* Sombre forcé, quel que soit le système. */
.ishtar-markdown[data-ishtar-theme="dark"],
.ishtar-tasklist[data-ishtar-theme="dark"] {
    color-scheme: dark;

    --ishtar-md-encre: var(--ishtar-md-color, #e6e8eb);
    --ishtar-md-fond: var(--ishtar-md-surface, #1b1f24);

    --ishtar-md-titre: var(--ishtar-md-accent-heading, #7fb3e3);
    --ishtar-md-lien: var(--ishtar-md-accent-link, #6cb0f0);
    --ishtar-md-code-teinte: var(--ishtar-md-accent-code, #e58fa5);
    --ishtar-md-puce: var(--ishtar-md-accent-list, #b39ce8);
    --ishtar-md-citation: var(--ishtar-md-accent-quote, #8dc4a2);
}

.ishtar-markdown-editor {
    max-width: 100%;
    overflow-x: hidden;
    border: 1px solid var(--ishtar-md-bord);
    border-radius: 0.25rem;
    background: var(--ishtar-md-fond);
    overflow: hidden;
}

.ishtar-markdown-editor:focus-within {
    border-color: var(--ishtar-md-encre-douce);
}

/* Onglet aperçu : l'éditeur est masqué mais reste monté, pour conserver l'historique
   d'annulation et la position du curseur d'un aller-retour à l'autre. */
.ishtar-markdown-editor.is-hidden { display: none; }

/* --- Aperçu (rendu pur) ------------------------------------------------------------------ */
.ishtar-markdown-preview {
    padding: 0.75rem;
    border: 1px solid var(--ishtar-md-bord);
    border-radius: 0.25rem;
    background: var(--ishtar-md-fond);
}

.ishtar-markdown-preview > :first-child { margin-top: 0; }
.ishtar-markdown-preview > :last-child { margin-bottom: 0; }

.ishtar-markdown-preview ul,
.ishtar-markdown-preview ol { padding-left: 1.5rem; }

/* Les listes de tâches perdent leur puce : la case à cocher en tient lieu. */
.ishtar-markdown-preview ul.contains-task-list { list-style: none; padding-left: 0.5rem; }
.ishtar-markdown-preview .task-list-item { list-style: none; }
.ishtar-markdown-preview .task-list-item input { margin-right: 0.4rem; }

.ishtar-markdown-preview code {
    font-family: var(--ishtar-md-mono);
    background: var(--ishtar-md-voile);
    border-radius: 0.2rem;
    padding: 0 0.2em;
}

.ishtar-markdown-preview blockquote {
    margin-left: 0;
    padding-left: 0.75rem;
    border-left: 3px solid var(--ishtar-md-bord);
    color: var(--ishtar-md-encre-douce);
}

.ishtar-markdown-preview img { max-width: 100%; height: auto; }

/* Repli sans JavaScript : le textarea occupe la place de l'éditeur, sans double bordure. */
.ishtar-markdown-editor > textarea {
    width: 100%;
    display: block;
    border: 0;
    padding: 0.75rem;
    background: transparent;
    color: inherit;
    resize: vertical;
    /* Même chasse, même taille et même graisse que l'éditeur : le texte ne se réagence pas
       quand celui-ci prend le relais. */
    font-family: var(--ishtar-md-mono);
    font-size: var(--ishtar-md-font-size, 0.9375rem);
    font-weight: var(--ishtar-md-text-weight, 300);
}

.ishtar-markdown-editor > textarea::placeholder { color: var(--ishtar-md-encre-douce); }
.ishtar-markdown-editor > textarea:focus::placeholder { color: transparent; }

/* La hauteur se donne à l'enveloppe, jamais à « .cm-content » : forcer le contenu désaccorde
   la mise en page interne de CodeMirror de son rendu, et le curseur se pose loin du texte. */
.ishtar-markdown-editor .cm-editor { background: transparent; color: var(--ishtar-md-encre); }

/* Posé sur le défileur et non sur « .cm-content » : c'est là que le thème de base de CodeMirror
   met sa chasse fixe, et le thème d'Ishtar donne « font-family: inherit » au contenu — la
   famille descend donc d'ici. Deux classes contre une, la règle l'emporte quel que soit l'ordre
   d'insertion des feuilles de CodeMirror.
   Les ligatures suivent la même variable que partout ailleurs : « none » les coupe pour un hôte
   qui les trouverait déroutantes dans un texte courant. */
.ishtar-markdown-editor .cm-scroller {
    font-family: var(--ishtar-md-mono);
    font-variant-ligatures: var(--ishtar-md-ligatures, contextual);
}

/* Hauteur minimale de la zone de saisie, redéfinissable par l'hôte. */
/* Corps de texte en maigre : c'est ce qui donne sa place à la graisse des titres et du gras.
   Le contraste se prend par le bas, la plupart des chasses fixes n'ayant qu'une seule graisse
   grasse au-dessus du régulier — pousser 600 puis 700 puis 800 ne rend qu'un seul et même
   tracé. Une police sans fonte maigre retombe sur le régulier, et l'on revient au rendu
   d'avant. */
.ishtar-markdown-editor .cm-content {
    min-height: var(--ishtar-md-min-height, 5rem);
    font-weight: var(--ishtar-md-text-weight, 300);
    /* Un cran sous le corps de texte de la page : à taille égale, une chasse fixe paraît plus
       grosse qu'une proportionnelle, son œil étant plus haut et ses caractères plus larges.
       Sous 16px, iOS zoome la page à chaque prise de focus. On accepte le zoom plutôt que
       d'imposer partout une taille dictée par un seul navigateur ; l'hôte qui vise iOS pose
       « --ishtar-md-font-size: 16px ».
       La taille vit ici plutôt que dans le thème JavaScript pour être redéfinissable : laissée
       là-bas, elle serait à égalité de spécificité avec cette règle et le gagnant dépendrait de
       l'ordre d'insertion des feuilles de CodeMirror. */
    font-size: var(--ishtar-md-font-size, 0.9375rem);
}
.ishtar-markdown-editor .cm-activeLine { background: var(--ishtar-md-voile); }
.ishtar-markdown-editor .cm-selectionBackground,
.ishtar-markdown-editor .cm-content ::selection { background: var(--ishtar-md-voile-moyen); }
.ishtar-markdown-editor .cm-cursor { border-left-color: var(--ishtar-md-encre); }

/* Chasse fixe, comme le texte qui prendra sa place : sinon l'invite se réagence au premier
   caractère tapé. */
.ishtar-markdown-editor .cm-placeholder {
    color: var(--ishtar-md-encre-douce);
    font-family: var(--ishtar-md-mono);
}

/* Retiré à la prise de focus, et non à la première frappe : la zone est déjà désignée par le
   caret, l'invite n'a plus rien à dire. */
.ishtar-markdown-editor .cm-editor.cm-focused .cm-placeholder { display: none; }

/* --- Coloration syntaxique ---------------------------------------------------------------
 *
 * Palette volontairement sobre : un carnet de notes n'est pas un IDE, la couleur sert à
 * distinguer les rôles, pas à faire un arc-en-ciel. Cinq teintes seulement, toutes
 * redéfinissables par l'hôte.
 *
 * Les titres portent une échelle de tailles : dans un outliner, le titre sert à retrouver une
 * section d'un coup d'œil, et la graisse seule ne hiérarchise pas au-delà de deux niveaux.
 * L'échelle reste courte — 1.45em à 1em — pour que le texte ne se réagence pas violemment
 * d'une ligne à l'autre.
 */
/* Hors de la ligne éditée, aucune couleur : on lit un texte, pas du code. Seules subsistent
   les indications de forme — graisse, italique, barré, soulignement des liens — qui font
   partie du rendu et non de la syntaxe.
   La couleur revient sur la ligne courante, où elle aide à repérer les marqueurs qu'on
   manipule. */
/* Tailles en em et non en rem : l'échelle suit la taille de base de la zone de saisie, que
   l'hôte peut avoir changée. Chacune passe par une variable — un hôte qui préfère des titres à
   taille fixe les remet toutes à 1em, sans avoir à réécrire les règles. */
.ishtar-markdown-editor .cm-md-h1 {
    font-size: var(--ishtar-md-h1-size, 1.45em);
    font-weight: 700;
}

.ishtar-markdown-editor .cm-md-h2 {
    font-size: var(--ishtar-md-h2-size, 1.25em);
    font-weight: 700;
}

.ishtar-markdown-editor .cm-md-h3 {
    font-size: var(--ishtar-md-h3-size, 1.1em);
    font-weight: 600;
}

/* h4 à h6 partagent une classe — voir le HighlightStyle d'outliner.js. Ils reviennent à la
   taille du texte et se signalent par l'italique : au-delà du troisième niveau, agrandir
   encore ne hiérarchise plus rien, et l'écart avec le corps de texte deviendrait illisible. */
.ishtar-markdown-editor .cm-md-h {
    font-size: var(--ishtar-md-h4-size, 1em);
    font-weight: 500;
    font-style: italic;
}

/* En chasse fixe, la plupart des polices n'ont qu'une graisse grasse, et le contraste avec le
   texte normal est faible. On pousse la graisse et on épaissit légèrement le tracé — plus net
   qu'une ombre portée, qui baverait. */
.ishtar-markdown-editor .cm-md-strong {
    font-weight: 800;
    -webkit-text-stroke: 0.03em currentColor;
}

.ishtar-markdown-editor .cm-md-em { font-style: italic; }
.ishtar-markdown-editor .cm-md-strike { text-decoration: line-through; opacity: 0.7; }

/* Le lien garde son soulignement partout : c'est ce qui le rend identifiable, et il est
   cliquable précisément là où la couleur a disparu. */
.ishtar-markdown-editor .cm-md-link { text-decoration: underline; }

.ishtar-markdown-editor .cm-md-code {
    font-family: var(--ishtar-md-mono);
    background: var(--ishtar-md-voile);
    border-radius: 0.2rem;
    padding: 0 0.2em;
}

.ishtar-markdown-editor .cm-md-quote { font-style: italic; }

/* --- Bloc de citation ----------------------------------------------------------------------
 *
 * En mode visuel le chevron part avec son espace, et l'italique seul ne suffisait plus à
 * distinguer une citation du texte courant. Le bloc se lit maintenant à son fond et à son
 * filet, comme dans l'aperçu.
 *
 * Habillage strictement horizontal : ni marge ni remplissage vertical. Les décorations de ligne
 * viennent d'un plugin de vue, à qui CodeMirror interdit de toucher à la structure en blocs —
 * changer la hauteur d'une ligne en fait partie.
 */
.ishtar-markdown-editor .ishtar-md-quote-line {
    /* Un filet par niveau d'imbrication, en calques de fond plutôt qu'en bordures : une bordure
       ne se répète pas, et elle participerait au calcul de boîte — qu'un hôte imposant
       « box-sizing: border-box » viendrait fausser. Chaque calque est un dégradé d'une seule
       couleur, dimensionné en barre et posé à son abscisse.
       La couleur de fond, elle, reste sous les calques : « background-color » et
       « background-image » sont deux propriétés distinctes. */
    --ishtar-md-quote-gouttiere: 1.5rem;

    background-color: var(--ishtar-md-voile);
    background-image: linear-gradient(var(--ishtar-md-citation), var(--ishtar-md-citation));
    background-size: 0.15rem 100%;
    background-position: 0 0;
    background-repeat: no-repeat;

    /* Laisse la place aux filets et au guillemet, qui vivent en absolu au-dessus. */
    padding-left: var(--ishtar-md-quote-gouttiere);
}

/* Deuxième et troisième niveaux. Le pas entre filets vaut 0.75rem — assez pour qu'on les
   compte d'un coup d'œil, assez peu pour qu'une citation imbriquée ne parte pas à droite de
   l'écran sur un téléphone. */
.ishtar-markdown-editor .ishtar-md-quote-2 {
    --ishtar-md-quote-gouttiere: 2.25rem;

    background-image:
        linear-gradient(var(--ishtar-md-citation), var(--ishtar-md-citation)),
        linear-gradient(var(--ishtar-md-citation), var(--ishtar-md-citation));
    background-size: 0.15rem 100%, 0.15rem 100%;
    background-position: 0 0, 0.75rem 0;
}

.ishtar-markdown-editor .ishtar-md-quote-3 {
    --ishtar-md-quote-gouttiere: 3rem;

    background-image:
        linear-gradient(var(--ishtar-md-citation), var(--ishtar-md-citation)),
        linear-gradient(var(--ishtar-md-citation), var(--ishtar-md-citation)),
        linear-gradient(var(--ishtar-md-citation), var(--ishtar-md-citation));
    background-size: 0.15rem 100%, 0.15rem 100%, 0.15rem 100%;
    background-position: 0 0, 0.75rem 0, 1.5rem 0;
}

/* Coins arrondis aux seules extrémités : c'est ce qui fait lire une suite de lignes comme un
   bloc unique plutôt que comme des lignes habillées une à une. */
.ishtar-markdown-editor .ishtar-md-quote-open { border-radius: 0.25rem 0.25rem 0 0; }
.ishtar-markdown-editor .ishtar-md-quote-close { border-radius: 0 0 0.25rem 0.25rem; }
.ishtar-markdown-editor .ishtar-md-quote-open.ishtar-md-quote-close { border-radius: 0.25rem; }

/* Guillemet ouvrant, sur la première ligne seulement. En absolu — « .cm-line » est déjà en
   « position: relative » pour les contrôles de droite : dans le flux, il décalerait le premier
   caractère et CodeMirror mesurerait le caret de début de ligne après lui.
   Un vrai guillemet typographique, et non le double apostrophe du clavier : c'est un ornement,
   autant qu'il soit dessiné. */
.ishtar-markdown-editor .ishtar-md-quote-open::before {
    content: "\201C";
    position: absolute;
    /* Calé sur la gouttière du niveau, donc juste avant le texte : posé à une abscisse fixe,
       il tomberait sur les filets d'une citation imbriquée. */
    left: calc(var(--ishtar-md-quote-gouttiere) - 1.15rem);
    top: 0;
    color: var(--ishtar-md-citation);
    font-size: 1.5em;
    /* Le guillemet monte haut dans son cadratin : sans cette ligne il flotterait au-dessus du
       texte de la ligne. */
    line-height: 1.35;
    opacity: 0.6;
    /* Le clic traverse jusqu'au texte : l'ornement ne doit pas voler le caret. */
    pointer-events: none;
    user-select: none;
    -webkit-user-select: none;
}

/* --- Couleurs -----------------------------------------------------------------------------
 *
 * Deux régimes, selon ce qu'on est en train de lire.
 *
 * Mode visuel : on lit un texte. La couleur se cantonne à la ligne en cours d'édition, la
 * seule où les marqueurs réapparaissent et où il est donc utile de les repérer. Partout
 * ailleurs ne subsistent que les indications de forme — taille, graisse, italique, barré,
 * soulignement — qui appartiennent au rendu et non à la syntaxe.
 *
 * Markdown brut : on lit de la syntaxe, et la colorer d'un bout à l'autre est tout l'intérêt
 * de la vue. La classe « is-source » est posée par le composant d'après son paramètre Mode.
 *
 * Les deux régimes partagent les mêmes règles, à leur portée près : une teinte définie une
 * fois se retrouve forcément dans les deux vues.
 */
.ishtar-markdown-editor .cm-activeLine :is(.cm-md-h1, .cm-md-h2, .cm-md-h3, .cm-md-h),
.ishtar-markdown-editor.is-source :is(.cm-md-h1, .cm-md-h2, .cm-md-h3, .cm-md-h) { color: var(--ishtar-md-titre); }

.ishtar-markdown-editor .cm-activeLine .cm-md-link,
.ishtar-markdown-editor.is-source .cm-md-link { color: var(--ishtar-md-lien); }

.ishtar-markdown-editor .cm-activeLine .cm-md-code,
.ishtar-markdown-editor.is-source .cm-md-code { color: var(--ishtar-md-code-teinte); }

.ishtar-markdown-editor .cm-activeLine .cm-md-quote,
.ishtar-markdown-editor.is-source .cm-md-quote { color: var(--ishtar-md-citation); }

.ishtar-markdown-editor .cm-activeLine .cm-md-rule,
.ishtar-markdown-editor.is-source .cm-md-rule { color: var(--ishtar-md-encre-douce); }

/* Puces et numéros : en markdown brut seulement. En mode visuel ils font partie du texte lu —
   ce sont les seuls marqueurs de structure qui ne sont jamais masqués — et les teinter
   piquerait l'œil à chaque ligne d'une liste. */
.ishtar-markdown-editor.is-source .cm-md-list { color: var(--ishtar-md-puce); }

/* Les marqueurs de syntaxe : atténués, pour qu'ils ne sautent pas aux yeux — sur la ligne
   courante en mode visuel, où ils viennent de réapparaître, et partout en markdown brut, où
   ils encombreraient la lecture s'ils avaient le même poids que le texte. */
.ishtar-markdown-editor .cm-activeLine .cm-md-mark,
.ishtar-markdown-editor.is-source .cm-md-mark {
    color: var(--ishtar-md-encre-douce);
    opacity: 0.7;
}

/* Case à cocher de l'éditeur. Mêmes dimensions que dans l'aperçu, pour que la bascule entre
   les deux vues ne fasse pas sauter la mise en page. */
/* Cible tactile de la case : c'est la zone qui la porte, jamais l'input lui-même. */
.ishtar-markdown-editor .ishtar-md-check-zone {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.45rem 0.5rem;
    margin: 0 0.1em 0 -0.5rem;
    vertical-align: -0.13em;
    cursor: pointer;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

/* La case elle-même ne reçoit pas les événements : c'est la zone qui les traite. */
.ishtar-markdown-editor .ishtar-md-check-zone input { pointer-events: none; }

.ishtar-markdown-editor input.ishtar-md-check {
    /* La case remplace la puce ET le marqueur : on récupère leur gouttière. */
    box-sizing: content-box;
    width: 1.05em;
    height: 1.05em;
    margin: 0;
    accent-color: var(--ishtar-md-puce);
    cursor: pointer;
}

.ishtar-markdown-preview .task-list-item input { accent-color: var(--ishtar-md-puce); }

/* --- Barre d'outils ---------------------------------------------------------------------
 *
 * En flux normal, sous l'éditeur.
 */
.ishtar-markdown-toolbar {
    /* Sans « min-width: 0 », un enfant flex en « nowrap » refuse de rétrécir : sa largeur
       intrinsèque remonte et déborde la page entière. */
    min-width: 0;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.35rem;
    border: 1px solid var(--ishtar-md-bord);
    border-top: 0;
    border-radius: 0 0 0.25rem 0.25rem;
    background: var(--ishtar-md-fond);
}

/* Par défaut — souris, écran large — les boutons passent à la ligne : un défilement horizontal
   sans barre visible ne se devine pas au pointeur. */
.ishtar-markdown-toolbar .ishtar-md-row {
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
}

/* Au doigt, la barre flotte au-dessus du clavier : sa hauteur doit rester constante, donc une
   seule rangée qui défile — le geste de glissement, lui, est naturel. */
@media (hover: none) {
    .ishtar-markdown-toolbar .ishtar-md-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;
        touch-action: pan-x;
    }

    .ishtar-markdown-toolbar .ishtar-md-row::-webkit-scrollbar { display: none; }
}

.ishtar-markdown-toolbar button {
    /* « width » et « flex » sont posés explicitement : un framework hôte (Bootstrap, entre
       autres) impose volontiers « width: 100% » aux enfants de ses conteneurs, ce qui
       empilerait les boutons verticalement. Une lib ne peut rien supposer de son hôte. */
    flex: 0 0 auto;
    width: auto;
    /* 44px : la cible tactile en dessous de laquelle on rate le bouton une fois sur trois. */
    min-width: 2.75rem;
    min-height: 2.75rem;
    padding: 0 0.5rem;
    border: 1px solid var(--ishtar-md-bord);
    border-radius: 0.25rem;
    background: transparent;
    color: inherit;
    font: inherit;
    line-height: 1;
    cursor: pointer;
}

.ishtar-markdown-toolbar button:hover:not(:disabled) { background: var(--ishtar-md-voile); }
.ishtar-markdown-toolbar button:disabled { opacity: 0.45; cursor: default; }
.ishtar-markdown-toolbar button.ishtar-md-more.is-on { background: var(--ishtar-md-voile-moyen); }
.ishtar-markdown-toolbar button.ishtar-md-ghost { border-color: transparent; }

/* --- Champs des modales (lien, image) ---------------------------------------------------- */
.ishtar-md-prompt-field {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    margin-bottom: 0.75rem;
}

.ishtar-md-prompt-field:last-child { margin-bottom: 0; }

.ishtar-md-prompt-field > span {
    font-size: 0.875rem;
    opacity: 0.75;
}

.ishtar-md-prompt-field input {
    width: 100%;
    min-height: 2.75rem;
    padding: 0 0.5rem;
    border: 1px solid var(--ishtar-md-border-color, color-mix(in srgb, currentColor 25%, transparent));
    border-radius: 0.25rem;
    background: transparent;
    color: inherit;
    /* 16px : en dessous, iOS zoome à la prise de focus — comme dans l'éditeur. */
    font-size: 16px;
}

/* La barre reste dans le flux, sous l'éditeur. */



/* --- Gestes ------------------------------------------------------------------------------
 *
 * « pan-y » au repos : le défilement vertical de la page reste natif, mais le glissement
 * horizontal nous appartient — c'est lui qui indente. Pendant un geste, le JS bascule
 * « touch-action: none » pour reprendre aussi la verticale.
 */
.ishtar-markdown-editor .cm-content {
    touch-action: pan-y;
}

/* Item saisi : la sélection de texte et le menu contextuel tactile parasiteraient le geste. */
.ishtar-markdown-editor .cm-content.ishtar-md-grabbing {
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
}

/* La ligne saisie est déjà désignée par la surélévation : lui rajouter le fond de ligne active
   écraserait celui du bloc, et n'en teinterait qu'une ligne sur toute la branche. */
.ishtar-markdown-editor .cm-content.ishtar-md-grabbing .cm-activeLine:not(.ishtar-md-lifted) {
    background: var(--ishtar-md-voile-moyen);
    border-radius: 0.2rem;
}

/* --- Poignée et suppression ---------------------------------------------------------------
 *
 * Le geste ne part que de la poignée, qui porte « touch-action: none ». Le reste de la ligne
 * garde son comportement natif — défilement, sélection, caret — et il n'y a plus rien à
 * arbitrer entre les deux, contrairement à l'appui long.
 */
/* Gouttière réservée aux contrôles de droite. Dimensionnée sur la ligne active — flèches plus
   poignée, la configuration la plus large — et appliquée à toutes : sinon le texte se
   reformaterait à chaque déplacement du caret. */
.ishtar-markdown-editor .cm-line { position: relative; padding-right: 5rem; }

.ishtar-markdown-editor .ishtar-md-grip {
    /* Explicite : un hôte qui pose « box-sizing: border-box » globalement — Bootstrap le fait —
       ferait rentrer le padding dans la largeur, ne laissant presque rien à dessiner. */
    box-sizing: content-box;
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.28em;
    /* Le dessin fait 0.9em ; le padding porte la cible tactile à ~40px, sans quoi on rate la
       poignée une fois sur deux au doigt. */
    width: 0.9em;
    height: 1.1em;
    padding: 0.35rem 0.4rem;
    color: var(--ishtar-md-encre-douce);
    opacity: 0.8;
    touch-action: none;
    cursor: grab;
    /* Sans cela, un appui sur la poignée démarre une sélection de texte dans l'éditeur. */
    user-select: none;
    -webkit-user-select: none;
    -webkit-user-drag: none;
    -webkit-touch-callout: none;
}

/* Deux traits, comme sur Quillpad : la trame de points se lisait mal aux petites tailles. */
.ishtar-markdown-editor .ishtar-md-grip::before,
.ishtar-markdown-editor .ishtar-md-grip::after {
    content: "";
    display: block;
    width: 100%;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
}

.ishtar-markdown-editor .ishtar-md-grip:hover { opacity: 1; }
.ishtar-markdown-editor .cm-content.ishtar-md-grabbing .ishtar-md-grip { cursor: grabbing; }

/* Actions de ligne, ancrées à droite plutôt que dans le flux : elles ne doivent pas suivre la
   fin du texte, sinon leur position saute à chaque frappe. */
/* Ancre de largeur nulle : c'est elle qui reste dans le flux du texte, pour que le caret de
   fin de ligne se mesure juste après le contenu et non au bord droit de l'éditeur. */
/* Hauteur d'une ligne, largeur nulle. Sur un item sans libellé, l'ancre se pose sur la fin de
   ligne : CodeMirror y mesure le caret, et un élément de hauteur nulle lui en donne un de
   hauteur nulle. */
.ishtar-markdown-editor .ishtar-md-controls-anchor {
    display: inline-block;
    width: 0;
    height: 1.375em;
    vertical-align: text-bottom;
    overflow: visible;
}

.ishtar-markdown-editor .ishtar-md-controls {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
}

.ishtar-markdown-editor .ishtar-md-act {
    box-sizing: content-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.1rem;
    height: 1.1rem;
    padding: 0.3rem;
    border-radius: 0.25rem;
    color: var(--ishtar-md-encre-douce);
    opacity: 0.6;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
}

.ishtar-markdown-editor .ishtar-md-act:hover {
    opacity: 1;
    background: var(--ishtar-md-voile);
}

/* Chevrons dessinés en CSS : ni police ni fichier d'icônes, comme le reste de la lib. */
.ishtar-markdown-editor .ishtar-md-act-in::before,
.ishtar-markdown-editor .ishtar-md-act-out::before {
    content: "";
    width: 0.45rem;
    height: 0.45rem;
    border-left: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
}

.ishtar-markdown-editor .ishtar-md-act-out::before {
    transform: rotate(45deg);
    margin-left: 0.15rem;
}

.ishtar-markdown-editor .ishtar-md-act-in::before {
    transform: rotate(-135deg);
    margin-right: 0.15rem;
}

.ishtar-markdown-editor .ishtar-md-act-del::before {
    content: "\00d7";
    font-size: 1.35rem;
    line-height: 1;
}

/* Trait de destination pendant un déplacement. Le texte ne bouge pas tant qu'on n'a pas
   relâché : on vise, puis on valide. */
.ishtar-markdown-editor .ishtar-md-drop {
    position: absolute;
    /* Aligné sur le texte, pas sur la boîte : collée au bord, la pastille était coupée en deux
       par la bordure de l'éditeur. */
    left: 0.75rem;
    right: 0.75rem;
    height: 2px;
    margin-top: -1px;
    background: var(--ishtar-md-puce);
    border-radius: 2px;
    pointer-events: none;
    z-index: 5;
}

/* Pastille en tête de trait, comme sur Keep : elle donne un point d'accroche visuel et rend
   la destination lisible même sur un fond chargé. */
.ishtar-markdown-editor .ishtar-md-drop::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    width: 0.65rem;
    height: 0.65rem;
    transform: translateY(-50%);
    border: 3px solid var(--ishtar-md-puce);
    border-radius: 50%;
    background: var(--ishtar-md-fond);
    box-sizing: border-box;
}

/* Item saisi : surélevé sur place. Pas de calque qui suit le doigt — il masquerait le trait
   de destination, qui porte l'information utile.
 *
 * Le geste emportant les enfants, ce qui est surélevé est une branche et non une ligne. Le fond
 * teinté la désigne d'un bout à l'autre ; l'arrondi et l'ombre verticale ne sont portés que par
 * ses extrémités, sans quoi on lirait une pile de cartes séparées au lieu d'un bloc.
 *
 * Le fond reste opaque — un voile posé sur « --ishtar-md-fond » et non une couleur translucide :
 * les lignes survolées doivent disparaître dessous, pas transparaître. */
.ishtar-markdown-editor .ishtar-md-lifted {
    /* Le cadre est tracé en ombres internes plutôt qu'en bordure ou en « outline » : celles-ci
       encadreraient chaque ligne, et le bloc se lirait rayé de liserés horizontaux. Ici chaque
       ligne ne porte que ses côtés, les extrémités ajoutant le haut et le bas — le cadre fait
       ainsi le tour du bloc et de lui seul. */
    --ishtar-md-lifted-bord: color-mix(in srgb, var(--ishtar-md-encre) 20%, transparent);

    /* Aucune ombre portée sur les côtés. Décalée horizontalement, une ombre déborde tout de même
       en hauteur, et sur une ligne de texte — une vingtaine de pixels — ce débordement dessine
       une bande à chaque jointure : le bloc se lisait comme des tranches empilées. Les côtés se
       contentent donc du trait, et l'ombre portée n'est donnée qu'au sommet et à la base, là où
       elle a la place de s'étaler. */
    --ishtar-md-lifted-cotes:
        inset 1px 0 0 var(--ishtar-md-lifted-bord),
        inset -1px 0 0 var(--ishtar-md-lifted-bord);
    --ishtar-md-lifted-haut: inset 0 1px 0 var(--ishtar-md-lifted-bord), 0 -8px 20px -6px rgb(0 0 0 / 55%);
    --ishtar-md-lifted-bas: inset 0 -1px 0 var(--ishtar-md-lifted-bord), 0 12px 24px -6px rgb(0 0 0 / 60%);

    z-index: 4;

    /* Voile moyen et non léger : sur un thème sombre, une teinte plus discrète ne se distingue
       pas du fond de l'éditeur, et la surélévation passe inaperçue. */
    background:
        linear-gradient(var(--ishtar-md-voile-moyen), var(--ishtar-md-voile-moyen)),
        var(--ishtar-md-fond);
    box-shadow: var(--ishtar-md-lifted-cotes);
}

.ishtar-markdown-editor .ishtar-md-lifted-first {
    border-top-left-radius: 0.35rem;
    border-top-right-radius: 0.35rem;
    box-shadow: var(--ishtar-md-lifted-cotes), var(--ishtar-md-lifted-haut);
}

.ishtar-markdown-editor .ishtar-md-lifted-last {
    border-bottom-left-radius: 0.35rem;
    border-bottom-right-radius: 0.35rem;
    box-shadow: var(--ishtar-md-lifted-cotes), var(--ishtar-md-lifted-bas);
}

/* Item sans enfant : les deux extrémités sont la même ligne, qui cumule les deux ombres. Sans
   cette règle, la dernière déclaration l'emporterait et le haut du bloc perdrait la sienne. */
.ishtar-markdown-editor .ishtar-md-lifted-first.ishtar-md-lifted-last {
    border-radius: 0.35rem;
    box-shadow:
        var(--ishtar-md-lifted-cotes),
        var(--ishtar-md-lifted-haut),
        var(--ishtar-md-lifted-bas);
}

/* Flèches de niveau, à gauche de l'item. Dans le flux : elles décalent le texte de la ligne
   courante, ce qui la distingue au passage. */
.ishtar-markdown-editor .ishtar-md-arrows-unused {
    display: inline-flex;
    align-items: center;
    gap: 0.05rem;
    margin-right: 0.15rem;
    vertical-align: -0.4em;
}

/* --- Éditeur de liste de tâches -----------------------------------------------------------
 *
 * Composé au-dessus de l'éditeur markdown : seul l'encart des éléments cochés est propre à ce
 * composant, tout le reste est l'éditeur lui-même.
 */
/* L'encart forme un bloc distinct : fond propre et bord arrondi, pour qu'on voie d'un coup
   d'œil où finit la liste active et où commence ce qui est fait. */
.ishtar-tasklist-checked-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0.5rem 0 0;
    padding: 0.4rem 0.75rem;
    border: 1px solid var(--ishtar-md-bord);
    border-bottom: 0;
    border-radius: 0.25rem 0.25rem 0 0;
    background: var(--ishtar-md-voile);
    color: var(--ishtar-md-encre-douce);
    font-size: 0.8125rem;
}

/* « Tout décocher » : au bout du bandeau, discret tant qu'on ne le cherche pas. Il vide l'encart
   d'un coup, donc il ne doit pas se prendre pour la case d'à côté — d'où le texte plutôt qu'une
   icône, et le contour qui ne se dessine qu'au survol. */
.ishtar-tasklist-uncheck-all {
    flex: none;
    padding: 0.15rem 0.5rem;
    border: 1px solid transparent;
    border-radius: 0.25rem;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.ishtar-tasklist-uncheck-all:hover:not(:disabled),
.ishtar-tasklist-uncheck-all:focus-visible {
    border-color: var(--ishtar-md-bord);
    color: var(--ishtar-md-encre);
}

.ishtar-tasklist-uncheck-all:disabled {
    opacity: 0.4;
    cursor: default;
}

.ishtar-tasklist-group {
    list-style: none;
    margin: 0;
    padding: 0.15rem 0;
    border: 1px solid var(--ishtar-md-bord);
    border-radius: 0 0 0.25rem 0.25rem;
    background: var(--ishtar-md-voile);
}

/* Plus serré que dans l'éditeur : ces lignes ne s'éditent pas, elles se relisent. Une case
   reste tout de même visable au doigt grâce au padding vertical.
 *
 * Le rang vient du composant, en nombre de crans : le décalage se calcule ici pour rester au
 * même endroit que le reste de la géométrie de l'encart. */
.ishtar-tasklist-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 1.9rem;
    padding: 0.1rem 0.75rem;
    padding-left: calc(0.75rem + var(--ishtar-md-rang, 0) * 1.1rem);
    font-size: 0.9375rem;
}

.ishtar-tasklist-row .ishtar-md-check {
    width: 1.05em;
    height: 1.05em;
    accent-color: var(--ishtar-md-puce);
    cursor: pointer;
}

/* Ancêtre encore à faire, montré pour situer les éléments cochés qu'il porte. Il se lit comme
   un en-tête de branche : pas de barré, une case inerte, et l'ensemble en retrait pour qu'on ne
   cherche pas à agir dessus. */
.ishtar-tasklist-row.is-context {
    color: var(--ishtar-md-encre-douce);
}

.ishtar-tasklist-row.is-context .ishtar-md-check {
    cursor: default;
    opacity: 0.55;
}

.ishtar-tasklist-row.is-context .ishtar-tasklist-text {
    text-decoration: none;
    opacity: 1;
}

/* Sursis au décochage, pendant que la ligne remonte dans l'éditeur. La durée suit
   « LeaveDelay » côté C#. */
.ishtar-tasklist-row.is-leaving {
    animation: ishtar-md-leave 450ms ease forwards;
}

@keyframes ishtar-md-leave {
    0% { opacity: 1; }
    35% { opacity: 1; }
    100% { opacity: 0.05; }
}

@media (prefers-reduced-motion: reduce) {
    .ishtar-tasklist-row.is-leaving { animation: none; opacity: 0.5; }
}

/* Coché : le libellé s'efface et se barre, comme dans l'aperçu markdown. */
.ishtar-tasklist-text {
    text-decoration: line-through;
    opacity: 0.6;
}

/* Ligne cochée, masquée dans l'éditeur et réaffichée par l'hôte dans son encart. */
.ishtar-markdown-editor .ishtar-md-line-hidden {
    display: none;
}

/* Barre tenant la place d'une suite d'items faits.
 *
 * Les masquer sans rien laisser rendait la liste trompeuse : leur place disparaissait, un enfant
 * paraissait rattaché à l'item visible du dessus, et un parent redevenu à faire ressurgissait
 * sans prévenir. La barre restitue la place et le niveau du groupe ; les libellés, eux, restent
 * dans l'encart des éléments cochés. */
.ishtar-markdown-editor .ishtar-md-done-bar {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    /* Bien plus basse qu'une ligne : elle signale sans peser. */
    height: 0.85rem;
    color: var(--ishtar-md-encre-douce);
    user-select: none;
    cursor: default;
}

.ishtar-markdown-editor .ishtar-md-done-bar::before {
    content: '';
    flex: 0 0 1.6rem;
    height: 2px;
    border-radius: 1px;
    background: var(--ishtar-md-voile-moyen);
}

.ishtar-markdown-editor .ishtar-md-done-count {
    font-size: 0.72em;
    line-height: 1;
    opacity: 0.75;
}

/* Sursis d'une ligne qu'on vient de cocher : elle s'estompe avant de disparaître, pour qu'on
   voie l'action au lieu de la subir. La durée suit HIDE_DELAY_MS côté JS. */
.ishtar-markdown-editor .ishtar-md-fading {
    animation: ishtar-md-fade 450ms ease forwards;
}

@keyframes ishtar-md-fade {
    0% { opacity: 1; }
    35% { opacity: 1; }
    100% { opacity: 0.05; }
}

@media (prefers-reduced-motion: reduce) {
    .ishtar-markdown-editor .ishtar-md-fading { animation: none; opacity: 0.5; }
}
