/*
 * Les écrans de liste : la barre du haut, les filtres, le tableau, le pied.
 *
 * Le tableau lui-même vient du paquet — le cadre, le quadrillage, l'entête qui range, la
 * pagination et l'état vide. Ne reste ici que ce qu'une feuille du paquet ne peut pas porter :
 * la largeur d'une colonne, qui est propre à cet écran et à cette personne, et la façon dont une
 * ligne se coupe.
 */

/* ═══ La largeur de la page ════════════════════════════════════════════════════════════ */

/*
 * La mesure que le paquet pose sur le contenu est une largeur de LECTURE : elle tient une ligne
 * de texte à une longueur où l'œil retrouve le début de la suivante. Un tableau ne se lit pas de
 * cette façon — il se balaye en colonnes, et chaque point repris est une colonne de plus visible
 * sans avoir à faire défiler.
 *
 * Une page qui porte un tableau reprend donc toute la largeur. Les autres — une fiche, une
 * conversation, un formulaire — gardent la mesure, qui les sert.
 *
 * `:has()` porte la règle, et c'est sans danger : là où il manque, la page garde la mesure du
 * paquet, c'est-à-dire ce qu'elle avait de toute façon — jamais une mise en page défaite.
 */
.app-main:has(> .table-screen) {
    max-width: none;
}

/*
 * Les deux mesures que l'écran de liste partage : la hauteur d'une rangée, et la largeur de la
 * colonne des outils. Elles sont posées ici parce que le tableau n'est pas seul à s'en servir —
 * ce qui se pose au-dessus de son entête doit s'y inscrire au point près.
 */
/*
 * Les deux mesures du tableau : la hauteur d'une rangée, et la largeur de la colonne des outils.
 * Posées sur l'écran parce que le tableau n'est pas seul à s'en servir — ce qui se pose au-dessus
 * de son entête doit s'y inscrire au point près.
 */
.table-screen {
    /* Deux marges et une ligne de texte : la mesure d'une rangée ordinaire. */
    --table-row-height: calc(var(--app-space-sm) * 2 + var(--app-text) * 1.6);
    --table-tools-width: 3rem;
}

/* ═══ La barre du haut ═════════════════════════════════════════════════════════════════ */

/*
 * LA SEULE LIGNE au-dessus du tableau : à gauche ce qu'on fait — changer de vue, ajouter ; à
 * droite ce qu'on regarde — le compte, puis les questions posées.
 *
 * Chaque bande de plus était une rangée de moins à l'écran, sur la seule page où le nombre de
 * rangées visibles est ce qu'on vient y chercher. Elle se replie quand la place manque vraiment :
 * mieux vaut deux lignes qu'un menu sorti de la page.
 */
.table-bar {
    /*
     * La mesure de tout ce qui s'y pose — onglets, bouton, compte, menus. Une seule, parce qu'ils
     * sont côte à côte sur une ligne : trois hauteurs voisines se lisent comme un défaut
     * d'alignement, même quand chacune est juste.
     *
     * Portée par la barre elle-même : la liste et le plateau la rendent tous deux, et une mesure
     * posée sur l'un d'eux aurait manqué à l'autre.
     */
    --table-bar-height: 2.25rem;

    /*
     * Le rayon de cette barre, plus serré que celui des commandes ordinaires : sur des boîtes de
     * cette hauteur, l'arrondi du produit mange les angles et les fait paraître molles.
     */
    --table-bar-radius: calc(var(--app-radius-ui) * .6);

    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--app-space-md);
    margin-bottom: var(--app-space-md);
}

/*
 * TOUT CE QUI EST SUR CETTE BARRE A LA MÊME HAUTEUR.
 *
 * Un onglet, un bouton, un menu et une phrase se mesurent chacun à leur contenu ; côte à côte sur
 * une ligne, trois hauteurs voisines se lisent comme un défaut d'alignement, même quand chacune
 * est juste. Elles s'inscrivent donc toutes dans la même bande, et s'y centrent.
 */
.table-bar :is(.app-tabs-item, .app-btn, .table-count) {
    display: inline-flex;
    align-items: center;
    /* Le dessin et son mot ne se touchent pas. Une boîte en ligne les séparait par l'espace du
       document ; une boîte flexible avale cet espace, et il faut le redire. */
    gap: var(--app-space-2xs);
    height: var(--table-bar-height);
    padding-block: 0;
}

/*
 * Le filet reste sous les seuls onglets, qui sont ce qu'il souligne.
 *
 * Étendu à la barre entière, il passait à la base du bouton, du compte et des cadres de
 * questions, et les barrait tous par le bas : un trait qui traverse ce qu'il n'accompagne pas se
 * lit comme un défaut d'alignement.
 */
/*
 * Les onglets gardent leur largeur tant qu'elle tient, et la cèdent quand elle ne tient plus :
 * ils défilent dans leur propre bande, et un refus de rétrécir aurait poussé la page entière à
 * déborder de côté plutôt que de faire glisser la bande.
 */
.table-bar .app-tabs {
    flex: 0 1 auto;
}

/*
 * Ce qu'on ajoute, à côté du choix de la vue.
 *
 * À gauche et non au bout : c'est un geste, et les gestes se tiennent ensemble, du côté où l'œil
 * commence sa ligne.
 */
.table-acts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--app-space-sm);
}

/* Le rayon de la barre, pour tout ce qui s'y pose : celui du produit creuse trop les angles sur
   des boîtes de cette hauteur. */
.table-bar .app-btn {
    border-radius: var(--table-bar-radius);
}

/*
 * Ce qu'on regarde, à l'autre bout de la même ligne : le compte, puis les questions posées.
 *
 * Séparé de ce qu'on fait par tout le blanc qui reste : un menu qui restreint une liste et un
 * bouton qui lui ajoute une ligne n'ont rien à voir l'un avec l'autre, et les mettre côte à côte
 * faisait hésiter avant de cliquer.
 */
.table-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--app-space-xs);
    margin-left: auto;
    min-width: 0;
}

/*
 * Le compte, en tête de ligne. Il se lit sans se lire : il est là pour répondre à « ai-je tout
 * vu ? », pas pour être la première chose qu'on voit au-dessus du tableau.
 *
 * Sa marge à droite sépare ce qu'on regarde de ce qu'on demande : sans elle, « 13 projets » se
 * lisait comme le premier des menus.
 */
.table-count {
    margin: 0 var(--app-space-sm) 0 0;
    font-size: var(--app-text-sm);
    color: var(--app-ink-soft);
}

/* Le menu ne s'étire ni ne se comprime : c'est un bouton, quelle que soit la place qui reste. */
.table-columns {
    flex: 0 0 auto;
}

/* ═══ La colonne des outils ════════════════════════════════════════════════════════════ */

/*
 * La colonne du bout : ce qui agit sur la rangée, et non ce qu'elle porte.
 *
 * Elle tient à la largeur d'un bouton, et ne bouge plus : les colonnes de données se partagent ce
 * qui reste. Sans largeur fixe, `table-layout: fixed` lui donnait une part égale aux autres, pour
 * y poser une seule icône.
 */
.app-table.table-fixed :is(th, td).table-tools {
    width: var(--table-tools-width);
    padding-inline: var(--app-space-xs);
    text-align: center;
}

/*
 * Le cadre du tableau et ce qui se pose par-dessus son coin : il sert d'ancre, et rien de plus.
 */
.table-frame {
    position: relative;
}

/*
 * Le réglage des colonnes, posé au-dessus de l'entête de la colonne des outils.
 *
 * HORS du cadre qui défile, et non dedans : ce cadre découpe ce qui dépasse de lui — c'est ce qui
 * le fait défiler — et le panneau du menu y était tranché à ras de l'entête. Ici, il s'ouvre en
 * entier, et reste à l'aplomb de la colonne dont il commande le contenu.
 *
 * Il ne défile pas avec la table : c'est voulu. Ce qu'on règle, ce sont les colonnes du tableau
 * entier, pas celles qu'on a sous les yeux.
 */
.table-tools-slot {
    position: absolute;
    top: 1px;
    right: 1px;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    /* La mesure de l'entête, pour que le bouton s'y inscrive sans le grandir. */
    width: var(--table-tools-width);
    height: var(--table-row-height);
}

/*
 * Le menu d'une ligne se voit toujours : il dit qu'il y a quelque chose à faire ici, et ce qui
 * n'apparaît qu'au survol ne se trouve que par hasard.
 *
 * En encre adoucie, parce qu'il accompagne la rangée sans en être : trois points à pleine encre
 * répétés sur cinquante rangées se liraient avant les données.
 */
.table-row-tools > summary {
    color: var(--app-ink-muted);
}

.table-fixed tbody tr:hover .table-row-tools > summary,
.table-row-tools[open] > summary {
    color: var(--app-ink);
}

/*
 * Le cadre du tableau cesse de découper tant qu'un menu de ligne est ouvert : c'est le même
 * découpage qui tranchait le panneau des colonnes, et un menu de rangée ne peut pas, lui, se
 * poser hors du cadre — il y en a un par ligne.
 */
.app-table-wrap:has(.table-row-tools[open]) {
    overflow: visible;
}

/* ═══ Le menu des colonnes ═════════════════════════════════════════════════════════════ */

/*
 * Le panneau ne s'étire pas à la plus longue étiquette : une colonne nommée « Se rapporte à »
 * élargirait la liste entière, et le menu déborderait de la page.
 */
.table-columns-panel {
    gap: var(--app-space-2xs);
    min-width: 16rem;
}

.table-columns-line {
    display: flex;
    align-items: center;
    gap: var(--app-space-2xs);
    padding: var(--app-space-2xs) var(--app-space-xs);
    border-radius: var(--app-radius-ui);
}

.table-columns-line:hover {
    background: var(--app-hover);
}

/* La case prend toute la largeur qu'il reste : c'est le nom de la colonne qu'on vise, et non
   les six millimètres de la case elle-même. */
.table-columns-line > .app-check {
    flex: 1;
    min-width: 0;
}

.table-columns-move {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    padding: var(--app-space-2xs);
    border: 0;
    border-radius: var(--app-radius-ui);
    background: none;
    color: var(--app-ink-soft);
    cursor: pointer;
}

.table-columns-move:hover:not(:disabled) {
    background: var(--app-raised);
    color: var(--app-ink);
}

/* Une flèche qui ne mène nulle part reste à sa place plutôt que de disparaître : les deux
   boutons sauteraient d'une ligne à l'autre au fil des rangs. */
.table-columns-move:disabled {
    opacity: .3;
    cursor: default;
}

.table-columns-acts {
    display: flex;
    align-items: center;
    gap: var(--app-space-xs);
    margin-top: var(--app-space-xs);
    padding-top: var(--app-space-xs);
    border-top: 1px solid var(--app-line);
}

/* ═══ Les filtres ══════════════════════════════════════════════════════════════════════ */

/*
 * Une question, repliée en menu. Elle ne s'étire ni ne se comprime : c'est un bouton, quelle que
 * soit la place qui reste, et réduit à trois lettres il ne se cliquerait plus.
 */
.table-filters {
    flex: 0 0 auto;
}

/*
 * Chaque question dans son cadre. Sans lui, trois menus posés côte à côte formaient une seule
 * traînée de mots où l'on ne voyait plus où finissait l'un et où commençait l'autre — c'est
 * précisément ce qu'un filtre ne doit pas faire, puisqu'il explique une liste plus courte
 * qu'attendu.
 */
.table-filters > summary {
    /* Le filet dense, et non celui qui sépare deux contenus : trois cadres posés sur le fond de
       la page s'y effaçaient, et une question qu'on ne voit pas ne peut pas expliquer une liste
       plus courte qu'attendu. */
    border-color: var(--app-line-strong);
    /* Un fond à part, qui n'est ni celui de la page ni celui du tableau : une question n'est pas
       du contenu, c'est ce qui décide du contenu. */
    background: var(--app-raised);
    color: var(--app-ink);
}

/* Au survol, le cadre sort de son fond : c'est ce qui dit qu'il s'ouvre. */
.table-filters > summary:hover {
    background: var(--app-surface);
    border-color: var(--app-ink-soft);
}

/* L'intitulé de la question, en retrait de sa réponse : c'est la réponse qu'on vient lire, et la
   question n'est là que pour dire à quoi elle répond quand trois menus se suivent. */
.table-filters-label {
    color: var(--app-ink-soft);
    font-weight: var(--app-weight-regular);
}

.table-filters-label::after {
    content: " :";
}

/* Ce qu'on regarde, sur le bouton fermé. Il ne se coupe pas : une réponse amputée ne dit plus
   laquelle elle est. */
.table-filters-chosen {
    white-space: nowrap;
}

/* Une question dont la réponse n'est plus celle d'origine se voit sans être ouverte : c'est ce
   qui explique une liste plus courte qu'attendu. Le cadre le dit avec le mot — une teinte seule
   ne se remarque pas au milieu de trois cadres identiques. */
.table-filters > summary[aria-current="page"] {
    border-color: var(--app-accent);
}

.table-filters > summary[aria-current="page"] .table-filters-chosen {
    color: var(--app-accent);
    font-weight: var(--app-weight-semibold);
}

/* Plus haut que ce que le paquet donne par défaut : un arbre se lit d'un coup d'œil, et six
   branches visibles sur trente obligeraient à faire défiler pour savoir ce qui existe. */
.table-filters .app-menu-body {
    --app-menu-height: 26rem;
}

/*
 * L'arbre se lit à son décalage. Le chemin n'est plus écrit sur chaque ligne — « Pièce › Argent »
 * répété quinze fois noyait le seul mot qui distingue les branches entre elles ; la mère est
 * juste au-dessus, et le décalage dit le reste.
 */
.table-filters-branch {
    padding-left: calc(var(--app-space-md) + var(--table-branch-depth, 0) * var(--app-space-lg));
}

/* La branche retenue se marque dans le menu aussi : on l'ouvre pour en changer, et il faut voir
   d'où l'on part. */
.table-filters-branch[aria-current="page"] {
    color: var(--app-accent);
    font-weight: var(--app-weight-medium);
}

/* ═══ Le tableau ═══════════════════════════════════════════════════════════════════════ */

/*
 * UNE LIGNE PAR LIGNE. Une cellule qui passerait sur deux lignes décalerait toute la rangée et
 * ferait perdre le balayage vertical, qui est la seule raison d'afficher un tableau plutôt que
 * des fiches.
 *
 * `table-layout: fixed` est ce qui la rend tenable : sans lui, le navigateur élargit la colonne
 * au plus long contenu, et aucune troncature ne se déclenche jamais. Les largeurs se déclarent
 * alors sur les entêtes, et le contenu entier reste dans l'infobulle de la cellule.
 */
.table-fixed {
    table-layout: fixed;
    /*
     * En dessous, un tableau de six colonnes ne montre plus rien : chacune tombe sous la marge
     * intérieure que le paquet lui donne, et il ne reste que des points de suspension. La table
     * dépasse alors son cadre, qui se met enfin à défiler — c'est ce qu'il est là pour faire, et
     * il ne s'y mettait jamais tant que les pour-cent la ramenaient à la largeur disponible.
     */
    min-width: 52rem;
}

/*
 * La densité d'une liste, plus serrée que celle d'une fiche : on y balaye des rangées, on n'y lit
 * pas un paragraphe. Le paquet donne la marge d'un contenu qu'on lit ; celle-ci rend cinq à six
 * rangées de plus par écran, ce qui est précisément ce qu'on vient chercher dans un tableau.
 */
.table-fixed :is(th, td) {
    padding: var(--app-space-sm) var(--app-space-md);
}

/*
 * TOUTES LES RANGÉES À LA MÊME HAUTEUR.
 *
 * Une cellule vide, une cellule de texte nu et une cellule qui porte une étiquette ou un dessin
 * ne mesurent pas la même chose : la rangée prenait celle de son contenu le plus haut, et le
 * tableau ondulait d'une ligne à l'autre. C'est ce qui casse le balayage vertical — la seule
 * raison d'afficher un tableau plutôt que des fiches.
 *
 * La hauteur est posée sur la cellule et non sur la rangée : dans une table, `height` est un
 * minimum, et il n'est respecté que là où la marge intérieure s'applique. Le contenu s'y centre,
 * quelle que soit sa nature.
 */
.table-fixed tbody td {
    height: var(--table-row-height);
    padding-block: 0;
}

/*
 * Un filet entre les colonnes.
 *
 * Un tableau se balaye autant de haut en bas que de gauche à droite : sans lui, l'œil qui suit
 * une colonne étroite coincée entre deux larges perd sa file dès la troisième rangée.
 *
 * Porté par le bord gauche et non par le droit : la dernière colonne n'a alors rien à ôter, et
 * le filet ne double jamais celui du cadre.
 */
.table-fixed :is(th, td):not(:first-child) {
    /* Plus pâle que le filet qui sépare deux rangées : il guide l'œil qui descend une colonne,
       il ne découpe pas la page en cases. */
    border-left: 1px solid color-mix(in srgb, var(--app-line) 55%, transparent);
}

/*
 * La largeur arrive par `--app-col-w`, posée sur l'entête par le serveur : elle est propre à
 * cette colonne, sur cet écran, pour cette personne — la seule chose qu'une feuille ne peut pas
 * porter. Une colonne qui n'en pose pas se partage ce qui reste.
 *
 * Les deux classes et l'attribut sont là pour le poids : le paquet serre la colonne d'actions à
 * un pour-cent, ce qui convient à un tableau dont les colonnes se dimensionnent seules, mais pas
 * à celui-ci, où chacune reçoit sa part. Sans ce poids, la colonne se réduit à un filet et ses
 * boutons sortent de la page.
 */
.app-table.table-fixed th[data-col] {
    width: var(--app-col-w);
}

.table-fixed :is(th, td) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Un lien remplit sa cellule pour se couper avec elle : sans bloc, il déborderait du cadre que
   la cellule lui donne. Un bouton garde sa forme : carré, il prendrait en hauteur toute la
   largeur de la colonne. */
.table-fixed td a:not(.app-btn) {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Un nombre se cadre du côté où la ligne se termine, et ne se coupe jamais : un montant amputé
   de ses centimes se lit comme un autre montant. */
.table-fixed :is(th, td)[data-align="number"] {
    text-align: right;
}

/*
 * Ce qui ne se coupe pas : un montant amputé de ses centimes se lit comme un autre montant.
 *
 * La cellule seulement, jamais l'entête : un intitulé plus large que sa colonne écrirait par-
 * dessus sa voisine, et c'est la colonne étroite — « Fait », « Ouverte le » — qui déborderait
 * en premier.
 */
.table-fixed td:is([data-align="number"], [data-align="tight"], [data-actions]) {
    overflow: visible;
    text-overflow: clip;
}

/* Ce qu'on fait de la ligne, rangé au bout et sur une seule ligne. */
.table-actions {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--app-space-2xs);
}

/*
 * Une ligne qui n'est plus d'actualité — une fiche archivée, une activité faite. Elle reste
 * lisible : elle s'estompe, elle ne disparaît pas, et ce qu'elle porte se lit encore.
 */
.table-row-muted :is(td) {
    color: var(--app-ink-soft);
}

/* L'entête qui range cadre son mot du même côté que ses valeurs, flèche comprise. */
.table-fixed th[data-align="number"] .app-table-sort {
    justify-content: flex-end;
}

/*
 * Le cadre qui défile s'atteint au clavier : il reçoit donc le halo comme n'importe quelle
 * commande, et non le contour épais que le navigateur pose par défaut sur une région.
 */
.app-table-wrap:focus-visible {
    outline: var(--app-focus-width) solid var(--app-accent);
    outline-offset: calc(var(--app-focus-offset) * -1);
}

/* ═══ Le pied ══════════════════════════════════════════════════════════════════════════ */

.table-pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--app-space-md);
    margin-top: var(--app-space-lg);
}

.table-pager > nav {
    margin-left: auto;
}

/* ═══ Ce que les écrans posent autour ══════════════════════════════════════════════════ */

/*
 * La ligne qui ajoute, sous le tableau. Les champs s'y suivent comme les colonnes qu'ils
 * rempliront, et le dernier pousse le bouton au bout.
 */
.table-add {
    margin-top: var(--app-space-lg);
}

/* Le formulaire d'une fenêtre de correction : un champ par ligne, avec son étiquette. */
.table-edit {
    display: flex;
    flex-direction: column;
    gap: var(--app-space-md);
}

/* Ce qui achève ou abandonne, au bout de la ligne : la validation en dernier, là où le regard
   termine sa descente. */
.table-edit-acts {
    display: flex;
    justify-content: flex-end;
    gap: var(--app-space-xs);
    margin-top: var(--app-space-sm);
}

/* Un type, un genre, une famille : son dessin suivi de son mot, à la taille du texte. */
.table-kind {
    display: inline-flex;
    align-items: center;
    gap: var(--app-space-2xs);
    min-width: 0;
}

/*
 * Une étiquette se coupe avec sa cellule, points de suspension compris.
 *
 * `inline-block` et non `inline-flex` : la coupure ne s'applique qu'à une boîte de bloc, et une
 * pastille laissée en flex se tranchait au milieu d'une lettre, à ras de son bord arrondi.
 *
 * **Seulement dans une colonne de texte.** Une colonne serrée ne coupe rien — c'est ce qu'elle
 * promet — et y couper l'étiquette rendrait « Proposée » en « Propos… » alors que la place ne
 * manque pas.
 */
.table-fixed td[data-align="text"] .app-badge {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* Posée sur la ligne, une boîte en bloc traîne la place de ses jambages sous elle et
       épaissit la rangée entière. */
    vertical-align: middle;
}

/*
 * La case d'une ligne : un bouton de formulaire déguisé en rond à cocher. Le dessin change avec
 * l'état, et c'est le serveur qui le choisit — la case n'a rien à deviner.
 */
/*
 * La case d'une ligne, à la taille du texte qu'elle accompagne : un jeton plus grand la posait
 * sous la ligne de base des cellules voisines.
 */
.table-check {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--app-space-2xs);
    margin: calc(var(--app-space-2xs) * -1);
    border: 0;
    background: none;
    color: var(--app-ink-soft);
    cursor: pointer;
}

.table-check:hover {
    color: var(--app-accent);
}

/* Le moment. Le retard se teinte : le voir sans le chercher est la seule raison d'afficher une
   date dans une liste. La teinte vient du ton, comme partout ailleurs. */
.table-when[data-tone] {
    color: var(--app-tone-ink);
    font-weight: var(--app-weight-medium);
}

/* ═══ La cellule qui se corrige ════════════════════════════════════════════════════════ */

/*
 * Une cellule qui s'ouvre à la saisie.
 *
 * La lecture garde sa place et ses liens ; le crayon se pose au bout, sur TOUTES les colonnes
 * corrigeables. Un crayon sur certaines et pas sur d'autres obligerait à essayer pour savoir.
 */
.table-cell {
    display: block;
    min-width: 0;
}

.table-cell > form {
    display: flex;
    align-items: center;
    gap: var(--app-space-2xs);
    min-width: 0;
    /* Le curseur dit qu'on peut écrire ici, là où aucun cadre ne le dit. */
    cursor: text;
}

/* La lecture prend la place, et se coupe comme la cellule qui la porte. */
.table-cell-view {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * Le lien tient la largeur de son texte, et pas un point de plus.
 *
 * Un lien de tableau occupe sa cellule entière — c'est ce qui lui permet de se couper avec elle.
 * Dans une cellule qui se corrige, ce même remplissage lui ferait recouvrir toute la surface : le
 * clic tomberait toujours sur le lien, et la saisie ne s'ouvrirait jamais. Ramené à son texte, il
 * laisse le reste de la cellule au clic qui ouvre, et c'est la vue qui se charge de la couper.
 *
 * Le sélecteur reprend `.table-fixed td` : sans lui, il pèse moins que la règle générale du
 * tableau, qui l'emporterait et remettrait le lien en bloc.
 */
.table-fixed td .table-cell-view a {
    display: inline;
    cursor: pointer;
}

/*
 * Le crayon d'une cellule : c'est LUI le bouton — la tabulation l'atteint, et il porte l'intitulé
 * que le lecteur d'écran annonce.
 *
 * **Son dessin vient de `editable.css`**, qui le tient pour toute l'application. Ne se décide ici
 * que ce qui lui est propre : le moment où il paraît.
 *
 * Il paraît au survol de SA cellule, et d'elle seule. Au survol de la rangée entière, une ligne
 * de cinq colonnes corrigeables s'allumait de cinq pastilles à la fois : on ne savait plus
 * laquelle on s'apprêtait à ouvrir, et le tableau se couvrait d'une guirlande. C'est aussi ce que
 * fait une fiche — le crayon y paraît au survol du champ, pas de la colonne.
 */
.table-cell-pen {
    /* La zone de touche que `editable.css` fait déborder du dessin se mesure depuis lui. */
    position: relative;
}

.table-cell:hover .table-cell-pen,
.table-cell-pen:focus {
    opacity: 1;
}

/*
 * La saisie occupe la boîte de la lecture : même fonte, même hauteur, et le filet d'accent pour
 * seule différence. C'est ce qui fait que rien ne se déplace sous l'œil.
 */
.table-cell-edit {
    flex: 1;
    display: flex;
    align-items: center;
    gap: var(--app-space-2xs);
    min-width: 0;
}

/* La teinte, le filet et la fonte viennent de `editable.css` : ne reste ici que la mesure d'une
   cellule, qui prend la largeur qu'on lui laisse et suit l'alignement de sa colonne. */
.table-cell-edit input {
    width: 100%;
    min-width: 0;
    padding: 0 var(--app-space-2xs);
    text-align: inherit;
}

/*
 * La saisie est repliée d'emblée, et non une fois le comportement en place.
 *
 * Attendre le script pour la replier la laissait paraître le temps qu'il charge : sur cinquante
 * lignes et cinq colonnes, la page s'ouvrait couverte de champs qui disparaissaient ensuite. Un
 * clignotement pareil se voit bien plus qu'il ne renseigne.
 *
 * Ce que cela coûte : sans script, les cellules se lisent mais ne se corrigent pas. Le reste du
 * tableau — ranger, filtrer, choisir les colonnes, tourner les pages — continue de marcher, et
 * chaque fiche garde ses champs.
 */
.table-cell:not([data-open]) .table-cell-edit,
.table-cell[data-open] :is(.table-cell-view, .table-cell-pen) {
    display: none;
}

/* Entrée enregistre : le bouton n'a rien à montrer de plus. */
.table-cell-save {
    display: none;
}

/* Ce que le serveur refuse se dit sous la cellule, qui reste ouverte pour qu'on corrige. */
.table-cell-refusal {
    display: block;
    font-size: var(--app-text-xs);
    color: var(--app-danger-ink);
}

/* ═══ La poignée de largeur ════════════════════════════════════════════════════════════ */

/*
 * Le filet qu'on tire pour élargir une colonne, posé sur le bord de son intitulé.
 *
 * Il déborde de part et d'autre du filet qu'il déplace : quelques points de chaque côté, sans
 * quoi il faudrait viser une ligne d'un point de large. Il ne se peint qu'au survol — une rangée
 * de traits verticaux ferait un quadrillage que le tableau n'a pas.
 *
 * L'intitulé se positionne pour lui : la poignée s'accroche à son bord, et non à la page.
 */
.table-fixed th {
    position: relative;
}

.table-grip {
    position: absolute;
    top: 0;
    /* Entièrement dans l'entête : celui-ci découpe ce qui dépasse, et une poignée posée à
       cheval sur son bord n'aurait montré ni son trait ni sa zone d'attrape. */
    right: 0;
    z-index: 1;
    width: calc(var(--app-space-2xs) * 4);
    height: 100%;
    cursor: col-resize;
    touch-action: none;
}

.table-grip::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 2px;
    background: var(--app-accent);
    opacity: 0;
}

.table-grip:hover::after,
.table-grip[data-pulled]::after {
    opacity: 1;
}

/*
 * Pendant qu'on tire, la page cesse de sélectionner du texte et garde le curseur du geste :
 * sans cela, le pointeur qui sort de la poignée reprend la flèche, et le glissement se lit
 * comme s'il avait été lâché.
 */
[data-resizing] {
    user-select: none;
    cursor: col-resize;
}

/* ═══ Sur un écran qu'on tient d'une main ══════════════════════════════════════════════ */

/*
 * LA RANGÉE DEVIENT UNE FICHE.
 *
 * Un tableau de huit colonnes mesure huit cents pixels ; l'écran en offre trois cent vingt. Le
 * cadre défile, donc rien ne déborde — mais lire une rangée demande alors deux gestes : descendre
 * pour trouver la ligne, puis la suivre de côté en perdant de vue ce qu'elle nomme.
 *
 * Empilée, la même rangée se lit d'un regard. Ce qui se perd est le balayage vertical — comparer
 * la même colonne d'une rangée à l'autre —, et c'est un geste de bureau : on ne compare pas
 * quarante lignes sur un téléphone, on en cherche une.
 *
 * L'entête disparaît avec la mise en colonnes, et l'intitulé de chaque colonne revient contre sa
 * valeur. Ranger par colonne s'en va avec lui : c'est un geste qu'on fait devant un tableau.
 */
@media (max-width: 37.5rem) {
    /* Il n'y a plus rien à faire défiler : le cadre rend sa barre et cesse de découper ce qui
       dépasse, sans quoi un menu de rangée s'ouvrirait tranché. */
    .app-table-wrap {
        overflow: visible;
    }

    /*
     * Les rôles de tableau tombent avec la mise en page : un `display` qui n'est plus celui d'une
     * table retire au navigateur les rangées et les cellules qu'il annonçait. Ils sont redits en
     * toutes lettres, et la liste reste une liste pour qui l'écoute.
     */
    .app-table.table-fixed {
        display: block;
        min-width: 0;
    }

    .app-table.table-fixed thead {
        display: none;
    }

    .app-table.table-fixed tbody {
        display: block;
    }

    /*
     * La fiche : l'intitulé de la rangée en tête, ce qu'on en fait à sa droite, et le reste en
     * dessous. Les deux colonnes sont là pour cette première ligne seule — tout le reste les
     * traverse.
     */
    .app-table.table-fixed tbody tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 0 var(--app-space-sm);
        padding: var(--app-space-md);
    }

    .app-table.table-fixed tbody tr:not(:last-child) {
        border-bottom: 1px solid var(--app-line);
    }

    /*
     * Une cellule cesse de se couper : la place manque en largeur, elle ne manque pas en hauteur.
     * Le filet entre colonnes s'en va avec elles, et la hauteur de rangée avec le balayage
     * qu'elle servait.
     */
    .app-table.table-fixed tbody td {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: var(--app-space-md);
        height: auto;
        padding: var(--app-space-2xs) 0;
        border-left: 0;
        overflow: visible;
        text-align: left;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    .app-table.table-fixed tbody td a {
        display: inline;
        overflow: visible;
        white-space: normal;
    }

    /*
     * L'intitulé de la colonne, rendu à sa valeur. Il ne paraît ni sur la première cellule — qui
     * est le nom de la fiche et se passe d'être annoncée — ni sur celle des gestes, qui n'en a
     * pas.
     */
    .app-table.table-fixed tbody td:not(:first-child, .table-tools)::before {
        content: attr(data-label);
        flex: 0 0 auto;
        font-size: var(--app-text-sm);
        color: var(--app-ink-muted);
    }

    /* Le nom de la fiche : seul sur sa ligne, et dans la taille qu'on lit en premier. */
    .app-table.table-fixed tbody td:first-child {
        grid-column: 1;
        padding-top: 0;
        padding-bottom: var(--app-space-xs);
        font-size: var(--app-text-lg);
        font-weight: var(--app-weight-semibold);
    }

    /*
     * C'est ce lien qu'on vise pour ouvrir la fiche, et c'était la plus petite cible de l'écran :
     * une ligne de texte haute de vingt-quatre pixels. Il prend la mesure du doigt, et la prend
     * sur toute la largeur — viser un mot de six lettres n'est pas viser sa rangée.
     */
    .app-table.table-fixed tbody td:first-child a,
    .app-table.table-fixed tbody td:first-child .table-cell-view a {
        display: flex;
        align-items: center;
        min-height: var(--app-touch);
    }

    /* Chaque ligne de la fiche s'atteint aussi : c'est elle qui ouvre la saisie, et le crayon
       n'est que ce qui le dit. */
    .app-table.table-fixed tbody .table-cell {
        min-height: var(--app-touch);
    }

    .app-table.table-fixed tbody td:not(:first-child, .table-tools) {
        grid-column: 1 / -1;
    }

    /*
     * Ce qu'on fait de la fiche, à hauteur de son nom. Sa place est dite et non déduite : la
     * cellule arrive en dernier dans le document, et la grille l'aurait posée tout en bas.
     */
    .app-table.table-fixed tbody td.table-tools {
        grid-column: 2;
        grid-row: 1;
        width: auto;
        padding: 0;
    }

    /*
     * Un nombre garde son cadrage à droite : c'est ce qui le range sous son voisin d'une fiche à
     * l'autre, et la seule comparaison qui survive à l'empilement.
     */
    .app-table.table-fixed tbody td[data-align="number"] {
        text-align: right;
    }

    /* Le filet du bas appartient à la fiche entière ; répété sous chaque ligne, il la découpait
       en autant de cases qu'elle a de colonnes. */
    .app-table.table-fixed tbody :is(th, td) {
        border-bottom: 0;
    }

    /* Une valeur qui se corrige se lit sur deux lignes comme les autres : la couper n'économise
       plus rien, puisque plus rien n'est aligné en dessous. */
    .table-cell-view {
        overflow: visible;
        text-overflow: clip;
        white-space: normal;
    }

    /*
     * Le réglage des colonnes s'en va avec l'entête qu'il surplombait. Il n'y a plus de colonnes
     * à ranger ni à masquer, et son bouton se posait par-dessus la première fiche.
     */
    .table-tools-slot {
        display: none;
    }
}

/* ═══ Le dépôt de documents ════════════════════════════════════════════════════════════ */

/*
 * Un fichier glissé au-dessus de la liste des documents : l'écran entier s'allume, puisque c'est
 * lui qui accepte le dépôt.
 */
.table-screen:has(.document-deposit[data-over]) {
    outline: 2px dashed var(--app-accent);
    outline-offset: -4px;
}

/* Le temps de l'envoi, l'écran le dit au curseur. */
.table-screen:has(.document-deposit[data-busy]) {
    cursor: progress;
}
