/*
 * La charpente d'une fiche : deux colonnes, des onglets, et des champs qui se corrigent là où
 * ils se lisent.
 *
 * **Ce fichier ne connaît aucun écran.** Il dessine la forme que partagent la fiche d'un projet
 * et celle d'un papier — et celles qui suivront. Ce qui ne vaut que pour un écran reste dans sa
 * feuille à lui : la conversation et les étapes dans `project/show.css`, l'aperçu du papier dans
 * `document/show.css`. La règle pour trancher tient en une question : est-ce que ça aurait un
 * sens sur une fiche dont je ne sais rien ?
 *
 * La forme vient de la page projet, où elle a été mise au point. Elle en garde le principe :
 * **sans cadres**. Un filet sépare la colonne de gauche du contenu, un autre sépare ses sections
 * entre elles, et c'est tout — une carte par champ redonnerait l'empilement de bordures qu'on a
 * justement retiré.
 *
 * Rien n'est écrit en dur : chaque couleur, chaque espacement et chaque rayon vient d'un alias
 * du design system, ce qui fait suivre les palettes sans une règle de plus.
 */

/*
 * Le paquet borne le contenu à `--app-content-width`, ce qui convient à une page qui se lit en
 * une colonne. Ici deux colonnes se partagent l'écran, et tout plafond de largeur se paie en
 * bordure : la place qu'il refuse s'accumule d'un seul côté, où elle se voit comme une marge
 * démesurée.
 *
 * Ciblé par ce que la page contient, plutôt que par une classe posée sur le corps : le gabarit
 * du paquet n'offre pas d'emplacement pour en ajouter une, et le recopier entier pour ça
 * coûterait bien plus que cette règle.
 */
.app-main:has(.sheet-layout) {
    max-width: none;
}

/*
 * Le bouton à trois points de la barre de titre. Renommer et effacer sont des gestes rares : la
 * commande qui les porte reste en retrait, à la taille d'un dessin plutôt qu'à celle d'un mot,
 * et ne s'allume qu'au survol comme les autres commandes discrètes de la page.
 */
.app-btn.sheet-actions {
    /* Le carré des autres commandes sans texte de l'application. Les marges du bouton du paquet
       le rendraient plus haut que la barre qui le porte, qu'il repousserait d'autant. */
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    font-size: var(--app-text-lg);
    color: var(--app-ink-muted);
}

.app-btn.sheet-actions:hover {
    color: var(--app-ink);
}

/*
 * Deux colonnes : ce qu'est le projet à gauche, ce qu'il porte à droite.
 *
 * Empilées par défaut : sur un téléphone, deux colonnes rendraient les deux illisibles. Le
 * résumé reste au-dessus, ce qui est le bon ordre — on regarde de quoi il s'agit avant d'en
 * parler.
 *
 * La colonne de gauche est étroite et fixe : elle porte des champs et des nombres, qui n'ont
 * pas besoin de plus, et tout ce qu'on lui donnerait serait pris à ce qui se lit à droite.
 */
.sheet-layout {
    display: grid;
    gap: var(--app-space-lg);
    grid-template-columns: minmax(0, 1fr);
}

/*
 * Sur un écran assez large pour les deux colonnes, elles descendent jusqu'au bas de la fenêtre :
 * la charpente donne déjà au contenu la hauteur qui reste sous la barre du haut, et la
 * disposition n'a qu'à la prendre entière. Rien n'est laissé vide en dessous — c'est la place
 * que la conversation prend en hauteur.
 *
 * `min-height: 0` parce qu'un enfant flexible refuse de rétrécir sous la hauteur de son contenu :
 * sans lui, un long fil rendrait la disposition plus haute que la fenêtre.
 */
@media (min-width: 64rem) {
    .app-main:has(.sheet-layout) {
        display: flex;
        flex-direction: column;
    }

    .sheet-layout {
        grid-template-columns: 19rem minmax(0, 1fr);
        flex: 1;
        min-height: 0;
    }

    /* Un filet plutôt qu'une carte : la colonne se distingue de ce qu'elle borde sans ajouter
       une bordure de plus à l'intérieur d'une page qui en portait cinq. */
    .sheet-rail {
        min-height: 0;
        overflow-y: auto;
        padding: 0 var(--app-space-lg) 0 0;
        border-right: 1px solid var(--app-line);
        border-bottom: 0;
        /* La barre de défilement se fait discrète : elle traverse une colonne de lecture. */
        scrollbar-width: thin;
        scrollbar-color: var(--app-line-strong) transparent;
    }
}

/*
 * Sur un grand écran, la colonne s'élargit : une description de trois lignes tenait sur six dans
 * dix-neuf rems, et c'est le champ qu'on lit le plus souvent. Ce que la colonne prend là, le
 * contenu ne le perd pas — il en reste plus de mille pixels.
 */
@media (min-width: 100rem) {
    .sheet-layout {
        grid-template-columns: 25rem minmax(0, 1fr);
    }

    /* La valeur gagne tout l'élargissement : l'intitulé, lui, n'a pas grandi. */
    .sheet-rail .field,
    .summary-field {
        grid-template-columns: 7rem minmax(0, 1fr);
    }
}

/* ═══ La colonne de gauche ═════════════════════════════════════════════════════════════ */

/*
 * La colonne de gauche : les champs qui définissent le projet, puis ce qu'il porte en nombres.
 *
 * Sans cadres. Un filet la sépare du contenu, un autre sépare ses sections entre elles, et
 * c'est tout : une carte par champ redonnerait l'empilement de bordures qu'on vient de retirer.
 */
.sheet-rail {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-lg);
    padding-bottom: var(--app-space-lg);
    border-bottom: 1px solid var(--app-line);
}

/* L'écart du conteneur passe devant le filet, le retrait passe derrière : le trait tombe au
   milieu, à la même distance de ce qu'il sépare des deux côtés. */
.summary-group + .summary-group {
    padding-top: var(--app-space-lg);
    border-top: 1px solid var(--app-line);
}

/*
 * L'intitulé de section, et le chevron qui dit s'il y a quelque chose dessous. Le marqueur du
 * navigateur est retiré : il se pose avant le texte, sans mesure qu'on puisse régler, et le
 * chevron dit la même chose à la place qu'on lui donne.
 */
.summary-head {
    display: flex;
    align-items: center;
    gap: var(--app-space-2xs);
    list-style: none;
    cursor: pointer;
    font-size: var(--app-text-xs);
    font-weight: var(--app-weight-semibold);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--app-ink-muted);
}

.summary-head::-webkit-details-marker {
    display: none;
}

.summary-head:hover {
    color: var(--app-ink);
}

.summary-chevron {
    display: inline-flex;
    font-size: var(--app-text-sm);
    transition: transform var(--app-duration-fast, .15s) ease;
}

.summary-group:not([open]) .summary-chevron {
    transform: rotate(-90deg);
}

@media (prefers-reduced-motion: reduce) {
    .summary-chevron {
        transition: none;
    }
}

.summary-body {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-2xs);
    margin-top: var(--app-space-sm);
}

/* Les intitulés tiennent une colonne plus étroite qu'ailleurs : celle-ci fait dix-neuf rems à
   elle toute seule, et sept pour le mot ne laisseraient plus rien à la valeur. */
.sheet-rail .field,
.summary-field {
    grid-template-columns: 5.5rem minmax(0, 1fr);
}

/*
 * Une ligne qui se lit sans se corriger. Elle prend les mesures du champ modifiable d'à côté —
 * même colonne, même retrait, même liseré invisible — sans quoi les valeurs ne seraient pas
 * alignées entre elles.
 */
.summary-field {
    display: grid;
    gap: var(--app-space-sm);
    align-items: start;
}

.summary-label {
    padding-top: .35rem;
    font-size: var(--app-text-xs);
    font-weight: var(--app-weight-medium);
    line-height: 1.4;
    color: var(--app-ink-muted);
}

.summary-value {
    padding: var(--app-space-xs) var(--app-space-2xs);
    border: 1px solid transparent;
    line-height: 1.5;
}

/*
 * Un nombre, et de quoi aller voir. Les onglets disent la même chose au-dessus du contenu, et
 * ce n'est pas un doublon : là-haut, un compteur signale ce qui vient d'arriver ; ici, il dit
 * où en est le projet avant même qu'on ait choisi ce qu'on regarde.
 */
.summary-glance {
    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    width: 100%;
    padding: var(--app-space-xs) var(--app-space-2xs);
    border: 0;
    border-radius: var(--app-radius-ui);
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.summary-glance:hover {
    background: var(--app-hover);
}

.summary-glance-icon {
    display: inline-flex;
    flex: 0 0 auto;
    color: var(--app-ink-muted);
}

.summary-glance-label {
    flex: 1 1 auto;
    min-width: 0;
}

.summary-glance-count {
    flex: 0 0 auto;
    font-variant-numeric: tabular-nums;
    font-weight: var(--app-weight-medium);
    color: var(--app-ink-muted);
}

.summary-glance:hover .summary-glance-count {
    color: var(--app-ink);
}

/*
 * Ce qui reste à régler, sous le nom de la liste plutôt qu'à côté du total : deux montants sur
 * une même ligne d'une colonne étroite se lisent l'un pour l'autre.
 */
.summary-glance-note {
    display: block;
    color: var(--app-ink-muted);
    font-size: var(--app-text-xs);
    font-variant-numeric: tabular-nums;
}

/* ═══ Ce qu'on ajoute à la colonne ═════════════════════════════════════════════════════════ */

/*
 * Un geste d'ajout, replié tant qu'on ne le demande pas.
 *
 * **La colonne dit ce qui est, pas ce qu'on pourrait écrire.** Les formulaires d'ajout y étaient
 * dépliés en permanence — une saisie, deux listes et un bouton sous une section qui en porte trois
 * lignes. Leurs cadres se lisaient comme des valeurs vides, et la colonne paraissait à remplir
 * alors qu'elle était renseignée.
 *
 * **Sans script**, parce que c'est un dépliant et rien d'autre : le navigateur sait l'ouvrir seul,
 * et un ajout doit rester possible quand rien n'a chargé.
 *
 * Le repli revient de lui-même à chaque fois que la colonne va rechercher sa version à jour —
 * c'est-à-dire après chaque ajout, ce qui est exactement le moment où le formulaire n'a plus rien
 * à dire.
 */
.summary-add {
    margin-top: var(--app-space-sm);
}

/*
 * Le mot qui déplie : un verbe et son signe, à la mesure d'une commande discrète.
 *
 * La flèche du système est retirée : le « + » dit déjà ce qui va se passer, et deux signes pour
 * une seule commande feraient hésiter sur celui qu'on vise.
 */
.summary-add-open {
    display: inline-flex;
    align-items: center;
    gap: var(--app-space-xs);
    padding: var(--app-space-xs) var(--app-space-2xs);
    border-radius: var(--app-radius-ui);
    color: var(--app-accent);
    font-size: var(--app-text-sm);
    font-weight: var(--app-weight-medium);
    cursor: pointer;
    list-style: none;
}

.summary-add-open::-webkit-details-marker {
    display: none;
}

.summary-add-open:hover,
.summary-add-open:focus-visible {
    background: var(--app-hover);
}

/* Déplié, le mot a fait son office : il devient le moyen de refermer, et cesse d'appeler. */
.summary-add[open] > .summary-add-open {
    color: var(--app-ink-muted);
}

/* ═══ Les onglets ══════════════════════════════════════════════════════════════════════════ */

/*
 * Les cinq faces du projet. Une barre en tête du cadre, et sous elle le seul panneau qu'on ait
 * demandé : cinq cartes empilées donnaient cinq bordures pour trois lignes de contenu.
 *
 * Elle défile pour elle-même sur un écran étroit, sans barre visible : cinq onglets tiennent
 * rarement dans la largeur d'un téléphone, et les replier sur deux lignes ferait sauter tout ce
 * qui est dessous à chaque fois qu'un compteur change de chiffre.
 */
.sheet-tabs {
    display: flex;
    gap: var(--app-space-2xs);
    padding: var(--app-space-sm) var(--app-space-sm) 0;
    border-bottom: 1px solid var(--app-line);
    overflow-x: auto;
    scrollbar-width: none;
}

.sheet-tab {
    display: inline-flex;
    align-items: center;
    gap: var(--app-space-xs);
    padding: var(--app-space-sm) var(--app-space-md);
    border: 0;
    border-bottom: 2px solid transparent;
    background: none;
    color: var(--app-ink-muted);
    font: inherit;
    white-space: nowrap;
    cursor: pointer;
}

.sheet-tab:hover {
    color: var(--app-ink);
}

.sheet-tab[aria-selected="true"] {
    border-bottom-color: var(--app-accent);
    color: var(--app-ink);
    font-weight: var(--app-weight-semibold);
}

.sheet-tab-icon {
    display: inline-flex;
    font-size: var(--app-text-lg);
}

.sheet-tab-count {
    min-width: 1.25rem;
    padding: 0 var(--app-space-2xs);
    border-radius: var(--app-radius-pill);
    background: var(--app-hover);
    color: var(--app-ink-muted);
    font-size: var(--app-text-xs);
    font-weight: var(--app-weight-semibold);
    font-variant-numeric: tabular-nums;
    text-align: center;
}

/*
 * Ce qui a été modifié dans un onglet fermé, et n'a pas encore été vu. Le compteur s'allume quand
 * il y en a un ; les autres onglets reçoivent un point, qui dit la même chose sans nombre à
 * donner.
 */
.sheet-tab[data-unseen] .sheet-tab-count {
    background: var(--app-accent);
    color: var(--app-on-accent);
}

.sheet-tab[data-unseen]:not(:has(.sheet-tab-count))::after {
    content: "";
    width: .4rem;
    height: .4rem;
    border-radius: var(--app-radius-pill);
    background: var(--app-accent);
}

/* ═══ Les panneaux ═════════════════════════════════════════════════════════════════════════ */

/*
 * Tant que le comportement n'a pas tourné, les panneaux se lisent tous, à la suite : la page
 * reste entière sans JavaScript. C'est le contrôleur qui marque ce conteneur, et la feuille de
 * style n'en montre plus qu'un à partir de là — rien n'est caché avant que quelque chose sache
 * le remontrer.
 */
.sheet-panes {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.sheet-panes[data-tabs] > .sheet-pane:not([data-open]) {
    display: none;
}

.sheet-pane {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-md);
    flex: 1 1 auto;
    min-height: 0;
    padding: var(--app-space-lg);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--app-line-strong) transparent;
}

/*
 * Ce qui sépare deux groupes dans un même panneau — ce qui reste à faire, puis ce qui est fait.
 * Un intitulé discret, à la mesure des sections du résumé : c'est un repère, pas un titre de
 * plus dans une page qui vient d'en perdre cinq.
 */
.pane-subtitle {
    margin: var(--app-space-sm) 0 0;
    font-size: var(--app-text-xs);
    font-weight: var(--app-weight-semibold);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--app-ink-muted);
}

/* ═══ Le cadre de droite ═══════════════════════════════════════════════════════════════ */

/*
 * Le cadre de droite : les onglets, et le panneau ouvert sous eux.
 *
 * L'allure d'une carte, sans en être une : les onglets touchent les bords, et chaque panneau
 * porte son propre retrait. Le retrait d'une carte les décollerait tous du liseré, et la barre
 * d'onglets cesserait de tenir le haut du cadre.
 *
 * Ce que le cadre porte à l'intérieur ne le regarde pas : une conversation, un aperçu de papier
 * ou une liste s'y posent sans qu'une règle d'ici ne bouge. Un écran qui a besoin d'une variable
 * à lui la pose sur ce même sélecteur, depuis sa propre feuille.
 */
.sheet-content {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--app-surface);
    border: 1px solid var(--app-line);
    border-radius: var(--app-radius);
    box-shadow: var(--app-shadow-sm);
    overflow: hidden;
    /*
     * En colonne unique, le cadre prend la hauteur de la fenêtre sous la barre du haut,
     * gouttières comprises : le panneau défile pour lui-même, et ce qui est ancré sous lui ne
     * bouge pas.
     *
     * En deux colonnes, la grille le fait descendre jusqu'au bas de la page, et cette hauteur
     * cesse de servir.
     */
    height: calc(100dvh - var(--app-topbar-height) - var(--app-space-lg) * 2);
    min-height: 26rem;
}

@media (min-width: 64rem) {
    .sheet-content {
        height: auto;
    }
}

/* ═══ Les champs qui se corrigent là où ils se lisent ══════════════════════════════════ */

/*
 * La forme est celle du titre d'affaire de Pipedrive, dont ce motif vient : **rien ne bouge
 * quand le champ s'ouvre**. La saisie occupe exactement la boîte de la lecture — même fonte,
 * même retrait, même fond, même rayon — et il ne s'ajoute qu'un liseré d'accent. Ce qui rend
 * le geste agréable est précisément qu'il ne déplace rien sous l'œil.
 *
 * L'intitulé tient une colonne étroite à gauche, aligné à droite, hors du surlignage : c'est
 * la valeur qu'on va corriger, pas le mot qui la nomme.
 *
 * Le repli est l'état par défaut, et non quelque chose qu'un script vient demander : sinon la
 * page montrerait toutes les saisies et tous les boutons le temps que les contrôleurs
 * démarrent, et battrait à chaque chargement.
 *
 * Le champ réclame donc le JavaScript pour s'ouvrir. Le serveur continue de rendre le
 * formulaire entier — c'est lui qui possède le balisage, et c'est ce qui permet d'éprouver le
 * renommage par une simple requête, sans navigateur.
 */
.field [data-edit] {
    display: none;
}

.field[data-open] [data-read] {
    display: none;
}

.field[data-open] [data-edit] {
    display: block;
}

/* Sur une ligne simple, Entrée et le départ du champ enregistrent : les boutons n'existent que
   pour qui n'a pas de script. */
.field-acts,
.field-acts--spare {
    display: none;
}

.field[data-open] .field-acts:not(.field-acts--spare) {
    display: flex;
}

.field {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr);
    gap: var(--app-space-sm);
    align-items: start;
}

.field form {
    margin: 0;
    min-width: 0;
}

/* L'intitulé : petit, en retrait, aligné à gauche sur une colonne fixe — la mesure du CRM, où
   des intitulés alignés se parcourent d'un coup d'œil. Il prend la couleur d'accent quand le
   champ est ouvert, ce qui dit lequel on corrige. */
.field-label {
    padding-top: .35rem;
    font-size: var(--app-text-xs);
    font-weight: var(--app-weight-medium);
    line-height: 1.4;
    color: var(--app-ink-muted);
}

.field[data-open] .field-label {
    color: var(--app-accent);
}

/*
 * La boîte tient les deux états et le crayon. Elle est le repère commun : c'est parce que la
 * lecture et la saisie partagent ce cadre — et les mêmes mesures — que l'ouverture ne déplace
 * rien.
 */
.field-box {
    position: relative;
    display: block;
}

/*
 * Les mesures communes aux deux états. Toute valeur changée ici doit l'être pour les deux, sans
 * quoi le texte saute d'un ou deux pixels à l'ouverture — c'est peu, et cela se voit.
 *
 * Le retrait de droite réserve la place du crayon, posé par-dessus. Le liseré transparent en
 * lecture retient la place de celui, coloré, qui apparaît à la saisie.
 *
 * Le retrait vertical n'est pas au plus juste : deux pixels suffisaient à l'œil, mais les
 * jambages descendants — le g, le p, le q — s'appuyaient contre le bord selon la police du
 * système. Ce qui se lit doit avoir de l'air sous la dernière ligne, et la commande gagne au
 * passage une hauteur qu'on vise sans hésiter.
 */
.field-read,
.field-edit [data-input] {
    display: block;
    width: 100%;
    padding: var(--app-space-xs) 2rem var(--app-space-xs) var(--app-space-2xs);
    border-radius: var(--app-radius-ui);
    font: inherit;
    line-height: 1.5;
    text-align: left;
    color: var(--app-ink);
}

/*
 * La lecture porte un liseré invisible, et la saisie le sien, qui vient de `editable.css`.
 *
 * Le premier n'est pas une décoration : il réserve la place que le second prendra. Sans lui,
 * ouvrir le champ décalerait le texte d'un pixel — et tout le geste tient à ce que rien ne bouge.
 * Il se déclare ici seul, et non avec la saisie : une bordure posée pour les deux écraserait
 * celle de la référence commune, qui compte moins qu'elle dans la cascade.
 */
.field-read {
    border: 1px solid transparent;
}

.field-read {
    background: none;
    cursor: pointer;
}

.field-read > [data-value] {
    display: block;
    /* Le texte tel qu'il a été écrit, sauts de ligne compris : c'est de la prose. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Un champ vide se lit comme le geste qui le remplit, pas comme un manque. */
.field-read[data-empty] > [data-value] {
    color: var(--app-accent);
    font-weight: var(--app-weight-medium);
}

/* Une échéance dépassée se signale : la laisser se lire comme les autres cacherait un retard. */
.field-read[data-late] > [data-value] {
    color: var(--app-danger, var(--app-ink));
    font-weight: var(--app-weight-semibold);
}

.field-read:hover,
.field-read:focus-visible {
    background: var(--app-hover);
}

/* La teinte et le filet de la saisie viennent de `editable.css`, qui les tient pour la fiche
   comme pour la cellule d'un tableau. */

.field-edit textarea {
    resize: vertical;
    min-height: 5rem;
}

/*
 * La liste de choix ouverte dans la boîte du champ.
 *
 * **Elle garde le dessin du système**, flèche comprise : c'est ce qui dit qu'on désigne au lieu
 * d'écrire, à l'instant où la boîte s'ouvre. Ne se décide ici que ce qui la remet aux mesures
 * communes — un navigateur donne au choix sa propre hauteur, et le texte sauterait à l'ouverture.
 *
 * Le coin droit est à la flèche : le crayon s'y efface déjà, comme devant le calendrier d'une date.
 */
.field-edit select[data-input] {
    height: auto;
    cursor: pointer;
}

/*
 * Le crayon d'une fiche : posé dans le coin droit de la boîte, par-dessus la zone de lecture.
 *
 * **Son dessin vient de `editable.css`**, qui le tient pour toute l'application. Ne se décide ici
 * que ce qui lui est propre : où il se pose, et quand il paraît.
 *
 * Il reste visible pendant qu'on écrit : il n'annonce pas seulement qu'on peut corriger, il
 * marque aussi que le champ n'est pas un formulaire de plus dans la page.
 */
.field-pencil {
    position: absolute;
    top: calc(var(--app-space-xs) + 1px);
    /*
     * L'écart de droite répond à celui du haut et du bas.
     *
     * Ceux-là ne viennent pas d'un retrait mais du centrage : le dessin est plus petit que la
     * ligne, et il reste une dizaine de pixels au-dessus et en dessous. À `2xs`, il en restait
     * deux à droite — le dessin se collait au bord là où il avait de l'air partout ailleurs, et
     * la ligne penchait à l'œil. `sm` est le jeton qui approche cet écart ; l'écrire en pixels
     * l'accorderait à une taille de texte et le désaccorderait de toutes les autres.
     */
    right: var(--app-space-xs);
    /* Le clic traverse : le crayon couvre le bord droit de la zone de lecture, et l'atteindre
       ne doit pas empêcher de l'ouvrir. Ce qu'on vise ici est la valeur. */
    pointer-events: none;
}

/*
 * Il paraît au survol de la BOÎTE du champ, et cède alors la place à la marque d'origine, qui
 * s'efface au même instant : les deux occupent le même coin, l'un est une commande et l'autre un
 * constat, et les montrer ensemble les rendrait interchangeables à l'œil.
 */
.field-box:hover .field-pencil,
.field-read:focus-visible ~ .field-pencil,
.field[data-open] .field-pencil {
    opacity: 1;
}

/*
 * La date fait exception : elle porte son propre calendrier, dans le coin même où vit le
 * crayon. Deux dessins l'un sur l'autre ne diraient plus rien — le crayon s'efface donc le
 * temps de la saisie, et le retrait qui lui était réservé revient au calendrier.
 */
.field[data-native][data-open] .field-pencil {
    opacity: 0;
}

.field[data-native] .field-edit [data-input] {
    padding-right: var(--app-space-2xs);
}

/* La saisie et son calendrier dans la même boîte : le bouton se pose au bout du champ, là où
   le navigateur posait le sien. */
.field-date {
    display: flex;
    align-items: center;
    gap: var(--app-space-2xs);
}

.field-date [data-input] {
    flex: 1;
    min-width: 0;
}

/* Le bouton du calendrier et le calendrier lui-même sont dans `app.css` : deux écrans les
   emploient, la fiche d'un projet et celle d'une activité. */

/* Les deux commandes sous la saisie, poussées à droite : elles referment le geste, elles ne
   l'annoncent pas. Leur `display` est décidé plus haut, avec le repli — le redire ici le
   défairait. */
.field-acts {
    justify-content: flex-end;
    align-items: center;
    gap: var(--app-space-xs);
    margin-top: var(--app-space-xs);
}

.field-refusal {
    margin: var(--app-space-2xs) 0 0;
    font-size: var(--app-text-sm);
    color: var(--app-danger, var(--app-ink));
}

/*
 * Le nom du projet, en tête de page, et ce qu'on peut en faire au bout de la ligne. La barre du
 * haut nomme la section ; ce titre nomme ce qu'on regarde, et il a ici la place d'être grand.
 */
/*
 * Les commandes du bout de la ligne, tenues ensemble. La barre écarte ses enfants aux deux
 * bouts : sans cette boîte, un bouton et le menu à trois points se retrouveraient séparés par
 * tout ce que la barre a de large. Elle les colle l'un à l'autre et les pousse à droite, quel
 * que soit le nombre de pastilles posées entre eux et le titre.
 */
.sheet-head-side {
    display: flex;
    align-items: center;
    gap: var(--app-space-sm);
    margin-left: auto;
}

.sheet-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--app-space-md);
    margin-bottom: var(--app-space-lg);
}

/*
 * ── Le geste qui tranche, au bout du titre ───────────────────────────────────────────────────
 * Ce qui termine ce qu'on regarde — un projet qui aboutit, une activité qu'on coche — et ce qui
 * le défait. Ce sont les seules décisions qu'on prend sans rien lire de la fiche, d'où leur
 * place contre le nom plutôt qu'au fond d'un résumé ou d'un menu.
 *
 * Un dessin franc et court : ces boutons doivent s'attraper du coin de l'œil sans peser plus que
 * le titre qu'ils accompagnent.
 */
.sheet-verdict {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: var(--app-space-sm);
}

.sheet-verdict button {
    height: 32px;
    padding: 0 15px;
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    font: inherit;
    font-size: 14px;
    font-weight: 600;
    white-space: nowrap;
}

/*
 * L'aplat vient du ton, et une seule règle sert les six : aucune couleur n'est écrite ici, parce
 * qu'un blanc en dur devient illisible dès que l'aplat s'éclaircit d'une palette à l'autre. Le
 * paquet nomme déjà l'encre qui se pose sur chaque aplat — c'est elle qu'on prend.
 */
.sheet-verdict button[data-tone] {
    background: var(--app-tone);
    color: var(--app-tone-on);
}

/* Sans ton, le geste qui défait : il ne tranche rien, il revient en arrière, et se lit comme les
   autres commandes discrètes de la page. */
.sheet-verdict button:not([data-tone]) {
    border: 1px solid var(--app-line-control);
    background: var(--app-surface);
    color: var(--app-ink);
}

.sheet-verdict button:hover {
    filter: brightness(.92);
}

/*
 * Pas d'intitulé — la ligne dit déjà de quoi il s'agit — et la boîte épouse le texte au lieu de
 * prendre la ligne entière.
 *
 * Tout y tient sur une ligne. Le champ ne s'étire pas à la largeur qu'on lui accorde : il prend
 * celle de son texte, et c'est ce qui empêche le titre de se replier en deux lignes parce qu'un
 * crayon lui a pris trois millimètres. Trop long, il se coupe par des points de suspension — la
 * barre n'est pas l'endroit où lire un nom de trente mots.
 */
.sheet-title,
.sheet-title .field,
.sheet-title .field-box {
    display: inline-flex;
    min-width: 0;
    max-width: 100%;
}

/* La mesure d'un titre de fiche : assez grand pour qu'on sache où l'on est, sans le gras d'un
   titre de document — la page en porte déjà assez. */
.sheet-title {
    font-size: var(--app-text-2xl);
    font-weight: var(--app-weight-medium);
    line-height: 1.2;
}

.sheet-title .field {
    grid-template-columns: minmax(0, 1fr);
}

.sheet-title .field-label {
    display: none;
}

.sheet-title .field-read,
.sheet-title .field-edit [data-input] {
    width: auto;
    max-width: 100%;
    /* Ni marge négative ni retrait à gauche : une marge négative se retranche de la mesure que
       le titre transmet à la barre, et le nom se coupait de quelques millimètres pour cette
       seule raison. */
    padding: 0 1.5rem 0 var(--app-space-2xs);
    margin: 0;
    font: inherit;
}

.sheet-title .field-read > [data-value] {
    /* Sa largeur naturelle, et non celle qu'on lui accorde : un enfant en `flex: 1` ne compte
       pas sa propre mesure dans celle de son parent, et le titre se coupait sans raison. */
    flex: 0 1 auto;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.sheet-title .field-pencil {
    top: 50%;
    right: var(--app-space-2xs);
    transform: translateY(-50%);
}

/*
 * À l'ouverture, le champ prend un peu plus que son texte : épousé au caractère près, il se
 * lirait comme une valeur figée plutôt que comme une place où écrire. Ce qui déborde de la
 * barre reste borné par la largeur disponible.
 */
.sheet-title .field-edit [data-input] {
    width: 100%;
    min-width: min(24rem, 100%);
}


/*
 * Un cadre qui n'a pas pu se remettre à jour.
 *
 * Ce qu'il montre reste — un cadre vide vaudrait moins que du contenu périmé — mais il cesse
 * de se faire passer pour l'état courant. Sans ce signal, on ne distingue pas « le souvenir
 * n'a pas été retenu » de « il l'a été, mais l'affichage n'a pas suivi », et on refait le
 * geste.
 *
 * Discret volontairement : la panne est celle de l'affichage, pas celle du projet.
 */
[data-controller~="panel"][data-stale] {
    opacity: 0.55;
}

[data-controller~="panel"][data-stale]::before {
    content: attr(data-stale-message);
    display: block;
    padding: var(--app-space-2xs) var(--app-space-xs);
    border-radius: var(--app-radius-sm);
    background: var(--app-surface-sunken, transparent);
    color: var(--app-text-muted);
    font-size: var(--app-font-size-sm);
    text-align: center;
}

/* Le choix du parcours prend la largeur qui reste, son bouton la sienne : sans ça, un nom
   d'étape long pousse le bouton hors de la colonne. */
.summary-field .app-field {
    flex: 1 1 auto;
    min-width: 0;
}

/* ═══ La marque d'origine ══════════════════════════════════════════════════════════════════ */

/*
 * D'où vient la valeur, dit au bout de sa ligne.
 *
 * **Au même endroit que le crayon d'édition, et c'est voulu** : les deux ne se voient jamais
 * ensemble. Au repos, la marque dit d'où vient ce qu'on lit ; au survol, elle s'efface et le
 * crayon prend sa place pour dire qu'on peut corriger. Un seul coin, deux moments — plutôt que
 * deux dessins côte à côte dont on ne saurait lequel est une commande.
 *
 * Elle a d'abord vécu à côté de l'intitulé, où elle repoussait le mot : les intitulés sont calés
 * sur leur bord droit, et « Montant ✎ » ne s'alignait plus avec « Notes » en dessous.
 *
 * Discrète, et c'est la condition pour qu'elle serve : à la taille d'un mot, elle ferait une
 * colonne de symboles qu'on cesserait de voir. L'intitulé complet vit dans son infobulle, et dans
 * un texte que les lecteurs d'écran annoncent — une infobulle ne s'entend pas.
 */
.field-mark {
    position: absolute;
    top: calc(var(--app-space-xs) + 1px);
    /* Exactement la boîte du crayon, retrait ET remplissage : les deux se relaient au même
       endroit, et un décalage de quelques pixels au survol se verrait. */
    right: var(--app-space-xs);
    display: inline-flex;
    padding: var(--app-space-xs);
    color: var(--app-ink-subtle, var(--app-ink-muted));
    font-size: var(--app-text-sm);
    /* Elle accompagne la valeur, elle ne la concurrence pas : une colonne de symboles au même
       poids que le texte tire l'œil hors de ce qu'on est venu lire. */
    opacity: .55;
    transition: opacity 150ms var(--app-ease);
    /* Le clic traverse : la marque couvre le bord droit de la zone de lecture, et l'atteindre ne
       doit pas empêcher de l'ouvrir. */
    pointer-events: none;
}

/* Elle cède la place au crayon, exactement quand il apparaît. */
.field-box:hover .field-mark,
.field-read:focus-visible ~ .field-mark,
.field[data-open] .field-mark {
    opacity: 0;
}

/*
 * **Sur une ligne simple, les dessins du coin droit se centrent sur le texte.**
 *
 * Ils sont calés en haut, ce qu'il faut pour une zone de texte de quatre lignes : le crayon doit
 * y rester en vue de la première. Mais sur « Montant » ou « Date du document », qui tiennent sur
 * une ligne, ce même calage les posait au-dessus du mot — une rangée de symboles qui flottent
 * au lieu d'accompagner ce qu'ils désignent.
 */
.field:not([data-multiline]) .field-mark,
.field:not([data-multiline]) .field-pencil {
    top: 50%;
    transform: translateY(-50%);
}

/* ═══ Personnes et organisations ═══════════════════════════════════════════════════════════ */

/*
 * Le champ qui cherche — dans l'annuaire, dans le coffre —, et ce qu'il propose dessous.
 *
 * **La même section sur un papier, une activité, un projet.** C'est le même geste : lui donner
 * trois formes ferait croire à trois mécanismes.
 */
.suggest-form {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--app-space-xs);
    margin-top: var(--app-space-sm);
}

.suggest-form .app-field {
    flex: 1 1 8rem;
    min-width: 0;
}

/*
 * Les suggestions flottent au-dessus de la page plutôt que de la pousser : une liste qui
 * s'insère fait sauter tout ce qui est en dessous à chaque lettre tapée.
 */
.suggest-panel {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 20;
    margin-top: var(--app-space-2xs);
    padding: var(--app-space-2xs);
    border: 1px solid var(--app-line);
    border-radius: var(--app-radius);
    background: var(--app-surface);
    box-shadow: var(--app-shadow-pop);
    max-height: 18rem;
    overflow-y: auto;
    scrollbar-width: thin;
}

.suggestions {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-3xs, 2px);
}

/* Chaque ligne est un bouton d'envoi : sans JavaScript, on arrive sur la page des suggestions et
   on clique. Le comportement ne fait que poser la liste sous le champ. */
.suggestion {
    display: flex;
    align-items: center;
    gap: var(--app-space-xs);
    width: 100%;
    padding: var(--app-space-xs);
    border: 0;
    border-radius: var(--app-radius-ui);
    background: none;
    color: var(--app-ink);
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.suggestion:hover,
.suggestion:focus-visible {
    background: var(--app-hover);
}

/* Créer vient en dernier et se distingue : c'est un geste qui ajoute au carnet, pas un choix
   parmi ce qu'il porte. */
.suggestions-make {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-3xs, 2px);
    margin: var(--app-space-2xs) 0 0;
    padding-top: var(--app-space-2xs);
    border-top: 1px solid var(--app-line);
}

.suggestion--make {
    color: var(--app-accent);
}

.suggestions-none {
    margin: 0;
    padding: var(--app-space-xs);
    font-size: var(--app-text-sm);
    color: var(--app-ink-muted);
}

/* ═══ La fiche sur un écran qu'on tient d'une main ═════════════════════════════════════ */

/*
 * Un champ cesse d'être une ligne et devient deux étages.
 *
 * L'intitulé tenait une colonne de cinq rems et demi ; sur trois cent vingt pixels, il en prenait
 * un tiers, et la valeur se lisait sur quatre lignes dans ce qui restait. Posé au-dessus, il ne
 * coûte qu'une ligne et rend toute la largeur à ce qu'on vient lire.
 *
 * La lecture y perd l'alignement des valeurs entre elles — un balayage de colonne, qui ne se
 * fait pas sur un écran de cette taille.
 */
@media (max-width: 37.5rem) {
    .field,
    .sheet-rail .field,
    .summary-field {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--app-space-2xs);
    }

    .summary-label {
        padding-top: 0;
    }

    /*
     * Le nom de ce qu'on regarde passe avant ce qu'on en fait : côte à côte, deux boutons et un
     * menu lui laissaient trois lettres suivies de points — « B.. » pour un projet qui s'appelle
     * Basile. Il prend donc la ligne entière, et les gestes se rangent en dessous.
     */
    .sheet-head {
        flex-wrap: wrap;
    }

    .sheet-title {
        flex-basis: 100%;
        font-size: var(--app-text-xl);
    }

    .sheet-head-side {
        margin-left: 0;
    }

    /* Ce qui tranche se vise du doigt comme le reste. */
    .sheet-verdict button {
        height: var(--app-touch);
        padding-inline: var(--app-space-md);
    }

    /*
     * Tout ce qui s'ouvre d'une touche sur une fiche prend la mesure du doigt : la valeur qu'on
     * corrige, le titre d'une section qui se replie, la ligne qui mène ailleurs.
     *
     * Ces cibles-là étaient les plus petites de l'écran parce qu'elles n'ont pas l'air de
     * boutons — une date écrite sur une ligne, un intitulé en petites capitales —, et c'est
     * justement ce qui les rend faciles à manquer : rien ne dit où finit la zone sensible.
     */
    :is(.field-read, .summary-head, .summary-glance, .summary-add-open) {
        min-height: var(--app-touch);
    }
}
