/* Patchbay Studio Planner — la feuille d'impression.

   POURQUOI UNE FEUILLE À PART, ET POURQUOI ELLE EST AUTONOME
   Les exports sont le livrable qui justifie tout le reste : un ingénieur du son
   qui essaie l'appli sans pouvoir rien imprimer repart les mains vides. Cette
   feuille est la moitié « papier » du lot 6a ; l'autre moitié est
   `coeur/exports.js`, qui rend les données. Elle n'est encore liée à aucune
   page — un lot ultérieur s'en chargera — et elle est donc écrite pour ne rien
   supposer de l'interface : elle ne cible que ses propres classes, et un seul
   crochet est demandé à la page hôte (voir LE CONTRAT, plus bas).

   POURQUOI TOUT EST EN MILLIMÈTRES
   Une étiquette de baie n'est pas une boîte qui s'adapte : elle doit tomber
   pile sur une façade de 19 pouces, sinon les colonnes se décalent d'une
   demi-case au bout de dix paires et le panneau devient illisible. D'où des
   cotes ABSOLUES, jamais un pourcentage, jamais un `fr` de grille.

     · 19 pouces hors tout            482,6 mm
     · deux oreilles de rack          2 × 16,15 mm
     · bande de désignation utile     450,3 mm
     · sur 24 paires, une colonne     18,76 mm

   POURQUOI L'ÉTIQUETTE SE COUPE EN DEUX
   450 mm n'entrent sur aucune feuille A4, dans aucun sens : le A4 paysage fait
   297 mm, marges comprises. Une bande de façade s'imprime donc en DEUX MOITIÉS
   de 225,15 mm, qu'on aboute au montage — c'est la seule façon d'obtenir la
   cote juste sur une imprimante de bureau. Les repères de coupe des bords
   intérieurs sont ce qui permet l'about ; c'est pour cela qu'ils vont jusqu'au
   filet et ne s'arrêtent pas avant.
   `--etq-colonnes` dit combien de colonnes porte la moitié imprimée : le rendu
   la pose, la feuille ne la devine pas.

   POURQUOI IL N'Y A PAS UNE SEULE COULEUR
   Une étiquette imprimée sur la laser d'un studio n'a pas de couleur, et une
   teinte de groupe qui ne survit pas au noir et blanc ne sépare plus rien —
   or SÉPARER est sa seule raison d'être (elle ne code rien, le code couleur du
   projet reste celui de l'appareil). Les six teintes nommées de la liste fermée
   deviennent donc six TRAMES, qui se distinguent à l'œil sans aucune encre de
   couleur, et qui se doublent d'un filet inférieur de graisse et de style
   différents : deux signaux valent mieux qu'un sur une photocopie de photocopie.
   L'ordre des trames suit celui de `COULEURS_GROUPE`, jamais un autre : le rang
   est ce qui attribue la teinte à l'écran, et deux ordres divergents feraient
   d'un même groupe l'ardoise à l'écran et le quadrillage sur le papier.

   POURQUOI `print-color-adjust: exact`
   Sans lui, les navigateurs suppriment fonds et trames à l'impression « pour
   économiser l'encre » — et les six groupes redeviennent identiques, c'est-à-dire
   que la seule chose que la teinte devait faire cesse d'être faite.

   PAS DE FOND PERDU, PAS D'EN-TÊTE QUI MANGE UNE ÉTIQUETTE
   Aucun fond ne court jusqu'au bord de la page : les trames sont bornées à leur
   case, et la page reste blanche sous les marges. Une imprimante de bureau ne
   sait pas imprimer à fond perdu, et un aplat coupé au massicot se voit.
   L'en-tête et le pied que le navigateur ajoute, eux, ne se retirent pas en CSS
   — c'est un réglage de la boîte d'impression. La parade est donc géométrique :
   `@page` réserve 14 mm en haut et en bas, et AUCUNE étiquette ne commence à
   moins de cette distance du bord. Si l'utilisateur laisse les en-têtes cochés,
   ils tombent dans la marge et ne mangent rien.

   LE CONTRAT AVEC LE RENDU (c'est ce qu'un lot d'intégration doit produire)
   La feuille ne cible QUE ces classes ; elle n'en invente aucune autre.

     body.impression-seule        seul crochet demandé à la page hôte : à
                                  l'impression, tout ce qui n'est pas `.impression`
                                  est masqué. SANS cette classe (un ⌘P tapé sur
                                  l'application), la feuille masque tout et
                                  imprime une phrase qui renvoie aux trois
                                  exports du menu `⋯` — voir F4, plus bas.
     .impression                  la racine des planches. Masquée à l'écran.
       .planche                   une page. `--etq-colonnes` y est posée.
         .planche-titre           nom de la baie, moitié imprimée, date
         .etiquette-baie          UNE bande de façade, cotée en millimètres
           .etq-groupes           la rangée des bandeaux de groupe
             .etq-groupe          `data-teinte="ardoise|prune|mousse|sable|ocean|brique"`,
                                  `style="--de:3; --span:5"` (colonne de début 1-based
                                  DANS LA MOITIÉ imprimée, et largeur en colonnes)
           .etq-rangee.rangee-a   la rangée A — les sorties
           .etq-numeros           les numéros de colonne, entre les deux rangées
           .etq-rangee.rangee-b   la rangée B — les entrées
             .etq-case            une colonne ; `.vide` si le point est libre
               .etq-texte         la forme COURTE de `coeur/exports.js`
         .fiche-facade            LA FAÇADE LISIBLE — l'autre document de la
                                  même baie. Voir « DEUX DOCUMENTS », plus bas
           .fiche-meta            la ligne de rappel : paires, points, groupes
           .fc-bande              UNE bande — un `<table>`, quatre rangées ;
                                  toutes les bandes d'une fiche ont le même
                                  nombre de colonnes, la dernière complète
                                  avec des `.fc-nul`
             .fc-gout             la gouttière « A / sorties », hors cadre
             .fc-groupe           un bandeau de groupe, `colspan` et
                                  `data-teinte` — MÊMES trames que l'étiquette
             .fc-case             un point ; `.vide` si libre
               .fc-app            l'appareil, .fc-port son port, .fc-meta le
                                  signal et la connectique
             .fc-n                le numéro de colonne et son MODE
           .fiche-legende         ce que veut dire chaque mode employé
           .fiche-cordons         les cordons du jour, datés et à part
         .feuille-cablage         la feuille de route
         .liste-cables            la liste de câbles — TROIS inventaires
           .inventaire            un inventaire = UNE façon d'acheter ;
                                  `data-inventaire="fond-de-baie|cordon|direct"`.
                                  Les trois sortent toujours, même vides
             .recapitulatif       les lignes de courses de CET inventaire,
                                  et d'aucun autre
           .a-placer              déclaré, pas encore câblé — à ne pas acheter

   POURQUOI TROIS RÉCAPITULATIFS ET PAS UN
   Le fond de baie se mesure au mur et se tire une fois, le cordon de façade
   s'achète à la douzaine, le câble direct ne touche aucune baie : trois
   commandes, chez trois rayons. Un agrégat commun — « 27 × XLR/XLR » — ne se
   transforme en aucun bon de commande, et c'est ce que le découpage évite. La
   feuille ne les sépare donc pas seulement par un titre : chaque
   `.recapitulatif` vit DANS son `.inventaire`, et il n'existe aucune règle qui
   en peigne un hors de ce parent.

   DEUX DOCUMENTS POUR LA MÊME FAÇADE, ET CE QUI LES SÉPARE
   L'ÉTIQUETTE est une pièce de menuiserie : elle se colle sur un panneau de
   19 pouces, donc elle est cotée en millimètres réels, donc sa colonne fait
   18,76 mm. Aucune mise en page n'élargira jamais une paire de jacks.
   La FICHE répond à la même question en changeant le seul terme qui pouvait
   l'être — le support. Elle se punaise au mur ; sa largeur est celle du papier.
   Une colonne y fait 22 mm sur trois lignes, et elle porte ce que l'étiquette ne
   portera jamais : le nom entier de l'appareil, le signal et la connectique, et
   le MODE de chaque colonne — qui ne se voit sur aucune façade et commande
   pourtant tout le brassage. Devant la baie, l'étiquette dit OÙ, la fiche dit
   QUOI.

   CE QUE LES CASES PORTENT, ET CE QU'ELLES NE PORTENT PLUS
   L'étiquette n'a longtemps porté qu'une ligne : la forme COURTE du nom de
   port, coupée à dix caractères par `LONGUEUR_COURTE`. La première étiquette
   réellement imprimée a rendu « Input 6 », « Monitor O… », « Control R… » — un
   panneau où rien ne désignait rien. Les deux documents portent désormais
   L'APPAREIL PUIS SON PORT, en forme longue, et c'est la feuille qui coupe ce
   qui dépasse, ligne par ligne et à la largeur réelle de la colonne : une baie
   de 12 paires, dont les colonnes font 37,5 mm, n'est plus tronquée pour rien.
   Le module rend toujours les deux formes ; la courte ne sert simplement plus
   ici. La forme longue va aussi dans la feuille de route, qui a le A4 entier. */

/* ------------------------------------------------------------------ écran --- */
/* La seule règle hors `@media print`, et elle est là pour une raison : la
   planche est du balisage ordinaire dans la page. Sans ce masquage, la lier à
   l'interface ferait apparaître trois mètres d'étiquettes sous les baies. */
.impression { display: none; }

/* ------------------------------------------------------------- impression --- */
@media print {

  /* 14 mm en haut et en bas : c'est là que tombent l'en-tête et le pied que le
     navigateur ajoute quand l'utilisateur ne les décoche pas. 10 mm sur les
     côtés, ce que toutes les laser de bureau savent atteindre.
     Paysage : 297 mm de large, dont 277 utiles — la demi-façade en fait 225,15. */
  @page {
    size: A4 landscape;
    margin: 14mm 10mm;
  }

  .impression { display: block; }

  /* le thème sombre de l'appli n'a rien à faire sur du papier : du noir sur du
     blanc, et aucun aplat qui court jusqu'au bord */
  html, body {
    background: #fff !important;
    color: #000 !important;
    height: auto !important;
    overflow: visible !important;
  }

  /* Le crochet demandé à la page hôte. IL N'EST PLUS OPTIONNEL depuis F4 : il
     était censé laisser, sans lui, « la planche en forme sans masquer l'appli,
     utilisable pour un aperçu », mais personne n'a jamais imprimé dans cet
     état-là — ce qui en sortait était l'interface entière repeinte en blanc.
     Les deux cas sont donc traités, et chacun sort quelque chose de lisible :
     avec le crochet, la planche seule ; sans, la phrase qui dit où sont les
     documents (juste en dessous). */
  body.impression-seule > *:not(.impression) { display: none !important; }
  body.impression-seule { display: block !important; }

  /* ------------------------------------------------- F4 — LE ⌘P DIRECT ---

     LE DÉFAUT : le repeint en blanc ci-dessus s'applique INCONDITIONNELLEMENT,
     le masquage de l'appli seulement sous `body.impression-seule` — que seuls
     les quatre exports posent. Un ⌘P tapé sur l'application sortait donc
     l'interface entière, en noir sur blanc, dans une mise en page conçue pour
     un écran de 1440 px : des pages blanches et des morceaux illisibles. Et
     rien ne disait où étaient les vrais documents, alors qu'ils sont « le
     livrable qui justifie tout le reste » (§7 pt 1). L'utilisateur en tirait
     que l'appli n'imprime pas.

     LE REMÈDE EST GÉOMÉTRIQUE, SANS UNE LIGNE DE JS ET SANS UN NŒUD DE DOM.
     Hors du crochet, on masque tout et on imprime une seule phrase, portée par
     un `::after` de `body` : elle survit au masquage des ENFANTS, puisqu'elle
     n'en est pas un. Zéro coût à l'écran — tout ceci vit sous `@media print`.

     Écarté : laisser l'appli s'imprimer « au cas où ». Une page qu'on ne peut
     pas lire ne renseigne sur rien, et le papier gâché est le seul retour que
     l'utilisateur en obtient. Un refus qui DIT où aller vaut mieux qu'une
     sortie qui ne dit rien — c'est la règle du §3 sur les commandes qui ne
     feraient rien : elles le disent au lieu de mentir. */
  body:not(.impression-seule) > * { display: none !important; }
  body:not(.impression-seule) {
    display: block !important;
    font: 11pt/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
  }
  body:not(.impression-seule)::after {
    content: "Patchbay Studio Planner — cette page n’est pas faite pour être imprimée telle quelle. "
             "Les quatre documents à imprimer s’ouvrent depuis le menu « ⋯ » de la barre du haut : "
             "étiquettes de baie, fiche de façade, liste de câbles, feuille de câblage. Chacun montre "
             "un aperçu, puis lance l’impression avec les bonnes cotes.";
    display: block;
    max-width: 150mm;
    margin: 20mm auto 0;
  }

  /* la feuille est autonome : elle ne peut pas compter sur le `box-sizing` que
     `style.css` pose globalement, or toutes les cotes d'étiquette sont données
     filet compris */
  .impression, .impression *, .impression *::before, .impression *::after {
    box-sizing: border-box;
  }

  .impression {
    font: 9pt/1.35 "Helvetica Neue", Helvetica, Arial, sans-serif;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }

  /* P5 — `break-inside: avoid` A ÉTÉ RETIRÉ D'ICI, ET LE COMMENTAIRE DISAIT
     DÉJÀ POURQUOI. « Rien ne se coupe au milieu d'une étiquette » est vrai, et
     c'est `.etiquette-baie` qui le porte, avec sa propre règle, plus bas. Une
     `.planche` n'est pas une étiquette : c'est aussi la feuille de câblage et
     la liste de câbles, dont les règles voisines raisonnent explicitement sur
     du contenu qui COULE sur plusieurs pages — « son titre ne se retrouve
     jamais seul en bas d'une page », « trois pages dont deux presque vides ».
     Interdire la coupure de la planche contredisait ces deux raisonnements, et
     demandait au navigateur de tenir sur un A4 une liste de soixante câbles.
     Reste ce qui est vrai de toute planche : elle commence sur une page neuve. */
  .planche {
    break-after: page;
    page-break-after: always;
  }
  .planche:last-child { break-after: auto; page-break-after: auto; }

  .planche-titre {
    font: 8pt/1.3 "SF Mono", Menlo, Consolas, monospace;
    letter-spacing: .06em;
    text-transform: uppercase;
    margin: 0 0 6mm;
    padding-bottom: 1.5mm;
    border-bottom: .3mm solid #000;
  }
  .planche-titre .moitie { float: right; font-weight: 400; letter-spacing: 0; text-transform: none; }

  /* ---------------------------------------------- l'étiquette de façade --- */

  /* Les cotes réelles d'une façade 19". Elles vivent sur `.etiquette-baie` et
     non sur `:root` : deux baies de largeurs de colonne différentes peuvent
     coexister sur la même planche, chacune avec sa cote. */
  .etiquette-baie {
    --largeur-19-pouces: 482.6mm;
    --oreille-rack: 16.15mm;
    --largeur-utile: 450.3mm;          /* 482,6 − 2 × 16,15 */
    --etq-colonnes: 12;                /* la MOITIÉ d'une baie de 24 ; le rendu la pose */
    --largeur-colonne: 18.7625mm;      /* 450,3 / 24 */
    --hauteur-rangee: 7mm;             /* la bande de désignation réelle */
    --hauteur-groupes: 5mm;
    --hauteur-numeros: 4mm;
    --filet: .25mm;

    width: calc(var(--largeur-colonne) * var(--etq-colonnes));
    margin: 0 0 16mm;
    border: var(--filet) solid #000;
    position: relative;
    break-inside: avoid;
    background: #fff;
  }

  /* Les repères de coupe : quatre équerres posées ENTIÈREMENT À L'EXTÉRIEUR du
     filet. C'est la condition pour qu'ils servent à quelque chose — un repère
     imprimé dans l'étiquette resterait sur la bande une fois coupée, et on aurait
     collé un trait de montage sur la façade.
     Chaque équerre prolonge les deux bords qui se croisent à son coin : c'est ce
     prolongement qui permet d'ABOUTER les deux moitiés d'une même façade, un
     repère isolé ne disant que « coupez par ici » et pas « alignez ici ». */
  .etq-reperes { position: absolute; inset: 0; pointer-events: none; }
  .etq-reperes span {
    position: absolute;
    width: 4mm;
    height: 4mm;
  }
  .etq-reperes span.hg { left: -4mm;  top: -4mm;    border-right: .2mm solid #000; border-bottom: .2mm solid #000; }
  .etq-reperes span.hd { right: -4mm; top: -4mm;    border-left:  .2mm solid #000; border-bottom: .2mm solid #000; }
  .etq-reperes span.bg { left: -4mm;  bottom: -4mm; border-right: .2mm solid #000; border-top:    .2mm solid #000; }
  .etq-reperes span.bd { right: -4mm; bottom: -4mm; border-left:  .2mm solid #000; border-top:    .2mm solid #000; }

  /* les trois rangées partagent la MÊME grille : c'est ce qui garantit qu'un
     bandeau de groupe couvre exactement les colonnes qu'il annonce */
  .etq-groupes,
  .etq-rangee,
  .etq-numeros {
    display: grid;
    grid-template-columns: repeat(var(--etq-colonnes), var(--largeur-colonne));
  }

  .etq-groupes { height: var(--hauteur-groupes); border-bottom: var(--filet) solid #000; }
  .etq-rangee  { height: var(--hauteur-rangee); }
  .rangee-a    { border-bottom: var(--filet) solid #000; }
  .etq-numeros {
    height: var(--hauteur-numeros);
    border-bottom: var(--filet) solid #000;
    background: #f2f2f2;
  }

  .etq-groupe {
    grid-column: var(--de) / span var(--span);
    display: flex;
    align-items: center;
    padding: 0 1mm;
    overflow: hidden;
    font: 6pt/1 "SF Mono", Menlo, Consolas, monospace;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    /* le nom reste ALIGNÉ À GAUCHE, à une colonne comme à vingt-quatre : sur
       l'étiquette comme à l'écran, l'œil cherche où le groupe COMMENCE */
    border-right: var(--filet) solid #000;
  }
  /* P5 — `.etq-groupe:last-child { border-right: 0 }` A ÉTÉ RETIRÉ. Il visait
     le dernier élément DU DOM, alors que les bandeaux sont placés par
     `grid-column: var(--de) / span var(--span)` : le dernier du balisage n'est
     pas forcément celui qui touche le bord droit de l'étiquette, et la règle
     effaçait donc un séparateur AU MILIEU de la bande — exactement l'inverse de
     ce qu'elle cherchait. Rien ne le remplace, et c'est le bon choix : les
     `.etq-case` des deux rangées du dessous gardent toutes leur filet de droite,
     y compris la dernière. Les trois rangées se coupent désormais de la même
     façon, et le filet du bord est celui de `.etiquette-baie`. */

  /* DEUX LIGNES, ET UNE POLICE ÉTROITE — ce qu'a appris la première étiquette
     réellement imprimée (1er septembre 2026).

     Elle portait UNE ligne, en chasse fixe, coupée à dix caractères. Ce qui en
     est sorti : « Input 6 », « Monitor O… », « Control R… », « Line 11/1… ».
     Deux défauts distincts, et le second est celui qui rend le panneau inutile.
       · la coupure à dix mangeait le mot qui SÉPARE — « Monitor Out L » et
         « Monitor Out R » sortaient identiques, à un caractère près jamais
         imprimé ;
       · rien ne disait l'APPAREIL. Le nom d'appareil n'était pas tronqué, il
         n'était pas là : « Input 6 » sur un panneau où trois machines ont un
         « Input 6 » ne désigne aucun point.

     D'où la case en colonne : l'appareil au-dessus, le port en dessous. La
     bande de désignation fait 7 mm ; deux lignes de 5 et 6,8 pt en occupent
     4,5, marges comprises. Rien n'est perdu.

     ET LA CHASSE FIXE PART, pour ces deux lignes seulement. Mesuré dans les
     17,2 mm utiles d'une colonne de baie 24 : la mono y place 12 caractères, une
     condensée 19. C'est très exactement ce que la plainte demandait — « plus de
     texte, quitte à plus petit » —, et c'est 60 % de plus sans descendre d'un
     point. Les NUMÉROS gardent la mono : eux s'alignent en colonne, et c'est le
     seul endroit où la chasse fixe sert à quelque chose. Sans condensée
     installée, la pile retombe sur l'Helvetica du reste de la feuille : on perd
     les 60 %, jamais la lisibilité.

     Aucune troncature n'est faite dans le balisage : `text-overflow` coupe ce
     qui dépasse, LIGNE PAR LIGNE et à la largeur réelle. Une baie de 12 paires
     a des colonnes de 37,5 mm — elle affiche tout, et `court()` la tronquait
     quand même. */
  .etq-case {
    border-right: var(--filet) solid #000;
    padding: .4mm .8mm;
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
    font-family: "Arial Narrow", "Helvetica Neue", Helvetica, Arial, sans-serif;
    white-space: nowrap;
  }
  .etq-case:last-child { border-right: 0; }
  /* une case vide reste une case : sur la façade réelle il y a bien un jack là,
     et une bande interrompue ferait compter les colonnes de travers */
  .etq-case.vide { color: #999; }

  .etq-app, .etq-texte { display: block; overflow: hidden; text-overflow: ellipsis; }
  /* l'appareil DÉSIGNE, le port se LIT en brassant : le second est le plus gros
     des deux, et c'est bien le petit qui porte le nom de la machine */
  .etq-app   { font-size: 5pt; line-height: 1.05; color: #333; }
  .etq-texte { font-size: 6.8pt; line-height: 1.1; }

  .etq-numeros .etq-case {
    align-items: center;                 /* la case est en colonne : c'est lui qui centre en largeur */
    justify-content: center;
    font: 5.5pt/1 "SF Mono", Menlo, Consolas, monospace;
    padding: 0;
  }

  /* ------------------------------------------- les six trames de groupe --- */
  /* PARTAGÉES PAR LES DEUX DOCUMENTS DE FAÇADE — l'étiquette et la fiche. Un
     groupe doit se reconnaître de l'une à l'autre : deux jeux de trames
     feraient de « Guitare » l'ardoise sur le panneau et le quadrillage sur la
     feuille punaisée à côté, c'est-à-dire deux groupes pour l'œil. C'est le
     même raisonnement que celui qui fait venir la teinte du RANG et jamais
     d'un réglage — voir juste en dessous.

     Six trames dans l'ORDRE de `COULEURS_GROUPE` : ardoise, prune, mousse,
     sable, ocean, brique. Elles se lisent par leur MOTIF, jamais par leur
     densité — six gris différents deviennent trois gris sur une photocopie —,
     et chacune double son motif d'un filet inférieur de style distinct, pour
     que la séparation survive même à un aplat mal fixé. */

  .etq-groupe[data-teinte="ardoise"],
  .fc-groupe[data-teinte="ardoise"] {
    background: #fff;
    border-bottom: .5mm solid #000;
  }
  .etq-groupe[data-teinte="prune"],
  .fc-groupe[data-teinte="prune"] {
    background: repeating-linear-gradient(45deg, #000 0 .2mm, #fff .2mm 1.4mm);
    border-bottom: .5mm dashed #000;
  }
  .etq-groupe[data-teinte="mousse"],
  .fc-groupe[data-teinte="mousse"] {
    background: repeating-linear-gradient(-45deg, #000 0 .2mm, #fff .2mm 1.4mm);
    border-bottom: .5mm dotted #000;
  }
  .etq-groupe[data-teinte="sable"],
  .fc-groupe[data-teinte="sable"] {
    background: radial-gradient(#000 .18mm, #fff .18mm) 0 0 / 1.4mm 1.4mm;
    border-bottom: .5mm double #000;
  }
  .etq-groupe[data-teinte="ocean"],
  .fc-groupe[data-teinte="ocean"] {
    background: repeating-linear-gradient(90deg, #000 0 .2mm, #fff .2mm 1.2mm);
    border-bottom: .8mm solid #000;
  }
  .etq-groupe[data-teinte="brique"],
  .fc-groupe[data-teinte="brique"] {
    background:
      repeating-linear-gradient(0deg, #000 0 .15mm, transparent .15mm 1.4mm),
      repeating-linear-gradient(90deg, #000 0 .15mm, #fff .15mm 1.4mm);
    border-bottom: .5mm solid #000;
  }

  /* le nom du groupe doit rester lisible PAR-DESSUS sa propre trame : un cartouche
     blanc autour du texte, et non une trame allégée — alléger la trame reviendrait
     à confondre deux groupes voisins, ce que la trame existe pour éviter */
  .etq-groupe > span,
  .fc-groupe > span {
    background: #fff;
    padding: 0 .6mm;
    box-shadow: 0 0 0 .2mm #fff;
  }


  /* -------------------------------------------- la fiche de façade --- */

  /* CE QUI LA SÉPARE DE L'ÉTIQUETTE, EN UNE LIGNE : elle ne se colle sur rien.
     L'étiquette est cotée en millimètres RÉELS parce qu'elle tombe sur une
     façade 19" ; la fiche a pour seule contrainte le papier, donc ses colonnes
     valent `1fr` — ou plutôt, puisque c'est un tableau, la part égale que
     `table-layout: fixed` leur donne. Aucune cote n'est donc écrite ici, sauf
     la gouttière : elle porte deux mots, sa largeur est celle des mots.

     POURQUOI UN TABLEAU. Un bandeau de groupe couvre N colonnes : c'est un
     `colspan`, et une cellule ne peut PAS se tromper de colonne. L'étiquette,
     elle, place ses bandeaux avec `--de`/`--span` en indices de grille 1-based
     relatifs à la moitié imprimée — le morceau qui « casse en silence », dit le
     commentaire de `bandeauxDeMoitie`. La fiche n'a pas la contrainte
     millimétrique qui obligeait à la grille ; elle prend donc l'outil sûr.

     POURQUOI LES BANDES SONT TOUTES À `--fc-colonnes` COLONNES, même la
     dernière, qui laisse ses cases en trop vides (`.fc-nul`) : empilées, leurs
     colonnes tombent l'une sous l'autre, et l'œil qui descend ne change pas de
     pas. Une dernière bande élargie se lirait comme une autre baie. */

  .fiche-facade {
    --fc-gouttiere: 13mm;   /* « col. / mode », le plus long des trois mots de la gouttière */
    --fc-filet: .2mm;
  }

  .fiche-meta {
    font: 7.5pt/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif;
    color: #333;
    margin: 0 0 4mm;
  }

  .fc-bande {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    margin: 0 0 7mm;
    break-inside: avoid;   /* une bande coupée en deux pages ne se lit plus */
  }
  .fc-bande .fc-c-gout { width: var(--fc-gouttiere); }

  .fc-bande td, .fc-bande th {
    border: var(--fc-filet) solid #000;
    padding: .7mm .8mm;
    vertical-align: top;
    overflow: hidden;
  }

  /* la gouttière — hors du cadre, comme à l'écran : elle nomme les rangées, elle
     n'est pas une colonne de la façade */
  .fc-bande .fc-gout {
    border: 0;
    padding: .7mm 1.6mm .7mm 0;
    text-align: right;
    vertical-align: middle;
    font: 5.5pt/1.2 "SF Mono", Menlo, Consolas, monospace;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: #444;
  }
  .fc-bande .fc-gout b { display: block; font-size: 10pt; letter-spacing: 0; color: #000; }

  /* la rangée des groupes : pas de cadre à elle, le filet inférieur de la trame
     lui suffit — et c'est ce filet qui double le motif (voir les six trames) */
  .fc-r-groupes td { border: 0; height: 5mm; }
  .fc-groupe {
    font: 6.5pt/1 "SF Mono", Menlo, Consolas, monospace;
    letter-spacing: .04em;
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    vertical-align: bottom !important;
    border-right: var(--fc-filet) solid #000 !important;
  }
  .fc-groupe.vide { border-right: 0 !important; }

  /* une case : l'appareil, le port, ce qui passe dedans. Trois lignes qui
     s'enroulent — la fiche a de la hauteur, c'est tout son intérêt */
  /* 18 mm de HAUTEUR MINIMALE, et c'est une mesure : deux bandes de douze
     colonnes et leur légende occupent 146 mm sur les 182 mm utiles d'un A4
     paysage. La place restante n'a aucune valeur — on la donne aux caractères,
     qui sont la seule raison d'être de ce document. Une case dont le contenu
     dépasse pousse sa rangée : rien n'est jamais coupé ici, contrairement à
     l'étiquette, qui n'a pas le choix. */
  .fc-case {
    height: 18mm;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    overflow-wrap: anywhere;
  }
  .fc-case span { display: block; }
  /* `balance` répartit les lignes du nom d'appareil plutôt que de laisser un
     « E » seul sous « Soundcraft Spirit ». Sans effet là où le navigateur ne
     le connaît pas — le nom reste entier dans les deux cas. */
  .fc-app  { font-size: 7pt; line-height: 1.15; font-weight: 700; text-wrap: balance; }
  .fc-port { font-size: 9.5pt; line-height: 1.2; margin-top: .5mm; }
  .fc-meta { font-size: 6pt; line-height: 1.15; color: #444; margin-top: .8mm; }
  /* un point libre reste une case, et le dit : sur la façade réelle il y a bien
     un jack là, et une colonne sautée ferait recompter tout le reste */
  .fc-case.vide { color: #999; text-align: center; }

  /* le numéro de colonne et son mode, entre les deux rangées — c'est la place
     qu'ils occupent sur un vrai panneau, et le mode n'est écrit nulle part
     ailleurs sur du papier */
  .fc-n {
    background: #f1f1f1;
    text-align: center;
    vertical-align: middle !important;
    padding: .5mm .3mm !important;
  }
  .fc-n b { display: block; font: 10pt/1.1 "SF Mono", Menlo, Consolas, monospace; }
  .fc-n i {
    display: block;
    font: 6pt/1.2 "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-style: normal;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: #333;
  }

  /* les cases en trop de la dernière bande : elles existent pour tenir la
     largeur, elles ne doivent rien montrer */
  .fc-nul { border: 0 !important; }

  .fiche-legende, .fiche-cordons {
    break-inside: avoid;
    margin-top: 4mm;
    font: 7pt/1.35 "Helvetica Neue", Helvetica, Arial, sans-serif;
  }
  .fl-titre {
    font: 7pt/1.3 "SF Mono", Menlo, Consolas, monospace;
    text-transform: uppercase;
    letter-spacing: .05em;
    border-bottom: .3mm solid #000;
    padding-bottom: 1mm;
    margin-bottom: 1.5mm;
  }
  .fl-ligne { margin-bottom: .8mm; }
  .fl-ligne b { display: inline-block; min-width: 22mm; text-transform: uppercase; font-size: 6.5pt; }
  .fiche-cordons p { margin: 0 0 1.5mm; font-style: italic; color: #444; }
  .fiche-cordons ul { margin: 0; padding-left: 5mm; }
  .fiche-cordons li { font-family: "SF Mono", Menlo, Consolas, monospace; font-size: 7pt; }

  /* -------------------------------------------- la feuille de route --- */
  /* Elle a toute la largeur du A4 : c'est ici que va la forme LONGUE. */

  .feuille-cablage { font-size: 8.5pt; }
  .feuille-cablage h2,
  .liste-cables h2 {
    font: 9pt/1.3 "SF Mono", Menlo, Consolas, monospace;
    text-transform: uppercase;
    letter-spacing: .06em;
    margin: 6mm 0 2mm;
    border-bottom: .3mm solid #000;
    padding-bottom: 1mm;
    break-after: avoid;
  }
  .feuille-cablage .etape {
    break-inside: avoid;
    padding: 1mm 0;
    border-bottom: .1mm solid #bbb;
  }
  .feuille-cablage .etape-titre {
    font: 7pt/1.3 "SF Mono", Menlo, Consolas, monospace;
    text-transform: uppercase;
    letter-spacing: .05em;
  }
  /* une case à cocher, parce qu'on suit cette feuille en cochant : elle est
     dessinée par la feuille et non par le balisage, pour qu'un export texte
     n'en garde aucune trace */
  .feuille-cablage .geste { padding-left: 6mm; position: relative; }
  .feuille-cablage .geste::before {
    content: "";
    position: absolute;
    left: 0; top: .9mm;
    width: 3mm; height: 3mm;
    border: .25mm solid #000;
  }

  /* --------------------------------------------- la liste de câbles --- */

  .liste-cables table { width: 100%; border-collapse: collapse; font-size: 8pt; }
  .liste-cables th, .liste-cables td {
    text-align: left;
    padding: 1mm 1.5mm;
    border-bottom: .1mm solid #bbb;
    vertical-align: top;
  }
  .liste-cables th {
    font: 7pt/1.3 "SF Mono", Menlo, Consolas, monospace;
    text-transform: uppercase;
    letter-spacing: .05em;
    border-bottom: .3mm solid #000;
  }
  .liste-cables tr { break-inside: avoid; }

  /* un inventaire est une COMMANDE : il commence franchement, et son titre ne
     se retrouve jamais seul en bas d'une page (le `break-after: avoid` des h2
     s'en charge déjà). Pas de `break-before: page` en revanche — trois pages
     dont deux presque vides pour trois rubriques dont deux tiennent en une
     ligne coûterait plus de papier que ça n'apporte de clarté. */
  .liste-cables .inventaire + .inventaire { margin-top: 9mm; }

  /* le récapitulatif est ce qu'on emporte chez le revendeur : il se lit de loin,
     donc plus gros que le détail qu'il résume. Il est SOUS son inventaire et
     n'existe pas ailleurs : trois commandes, trois listes de courses. */
  .liste-cables .inventaire > .recapitulatif { margin-top: 6mm; break-inside: avoid; }
  .liste-cables .recapitulatif li {
    font: 11pt/1.6 "SF Mono", Menlo, Consolas, monospace;
    list-style: none;
  }

  /* « déclaré, pas encore câblé » n'est PAS une ligne de courses : elle vit dans
     sa propre rubrique, en retrait et en italique, pour qu'on ne l'achète pas
     par mégarde */
  .liste-cables .a-placer { margin-top: 6mm; font-style: italic; color: #444; }
  .liste-cables .a-placer h2 { font-style: normal; }
}
