/* ==========================================================================
   L'ARBRE `/` — les quelques classes que le contenu réel demande en plus.
   Fichier SÉPARÉ à dessein : `nu.css`, `nu-oeuvres.css` et `nu-film.css` sont
   les feuilles PROUVÉES sur l'appareil (tests 1 → 18 du 23/08). On n'y touche
   pas pour habiller du contenu — sinon on ne saura plus, dans deux jours, ce
   qui a été mesuré et ce qui a été ajouté au jugé.
   Volontairement minimal : ni grille à échelle physique, ni caisse américaine,
   ni cartel. Ce qui manque ici manque EXPRÈS, et se posera calque par calque.
   ========================================================================== */

/* Le nom de la pièce, posé SUR son film. Il vit en BAS de la course : c'est
   là que le film a fini de se dézoomer sur l'œuvre (règle du site).
   ⚠️ Court, obligatoirement : le flux est en `height: 200lvh` PILE dans le
   bloc `@supports` de nu-film.css, parce que la keyframe d'épinglage déplace
   le pin de 100lvh exactement. Un bloc plus haut déborderait. */
.nu-piece {
    margin: auto 0 8vh; padding: 0;
    font: 500 clamp(22px, 6.5vw, 34px)/1.15 var(--f-titre, ui-sans-serif, system-ui, sans-serif);
    letter-spacing: -0.01em;
    text-shadow: 0 2px 24px rgba(0, 0, 0, .5);
}
.nu-piece a { color: #fff; text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, .38); }

/* LE CORPS RÉDACTIONNEL. Il lui faut TOUJOURS un fond À LUI : sur une page à
   film, `html:has(.ft)` est TRANSPARENT (nu-film.css:312) — du texte posé
   dessus se lirait sur le canevas nu de Safari.
   ⚠️ CE FOND ÉTAIT BLANC, IL DEVIENT LE TAUPE DU SOL — conséquence directe du
   chrome posé le 23/08, pas un choix esthétique. Le logo et la boussole du
   site sont encrés en blanc ; en `position: fixed`, ils survolent TOUT ce
   qu'on fait défiler. Un bloc rédactionnel blanc les faisait donc
   littéralement disparaître dès qu'on descendait dans le texte. Le site n'a
   pas ce problème parce qu'il n'a pas de bloc blanc : son rédactionnel est
   posé sur le sol taupe, en encre claire. On s'aligne sur lui.
   Il reste OPAQUE (et pas `transparent`) : c'est ce qui le distingue du
   canevas et lui permet de peindre là où la racine se tait.
   Le couloir latéral est déjà réservé par `.page` (nu-chrome.css) : on ne le
   paie pas deux fois, sinon il reste 318 px de texte sur un écran de 390. */
.nu-corps {
    position: relative; z-index: 1;
    color: var(--fg, #fff);
    /* ⚠️ PLEINE LARGEUR, LE COULOIR EN DEDANS. Première version : le bloc
       restait dans le couloir de 50 px de `.page`, et il portait un fond
       opaque — on voyait donc une COLONNE taupe plate posée sur le décor
       embossé, avec deux bandes claires sur les flancs. Un défaut de boîte
       mal alignée, pas un parti pris. Le bloc sort donc aux deux bords
       physiques (même recette que `.ft` : `100vw` + marge négative calculée
       sur la boîte de contenu) et rentre le couloir DANS son propre padding
       — le texte garde ses 50 px, le fond va d'un bord à l'autre.
       ⚠️ PLUS DE `100vw` (desktop, increment 1) : avec une barre de
       défilement classique, 100vw la compte et le bloc passait 15 px
       dessous, texte décentré. Les deux couloirs de `.page` (50 px) rendus :
       mêmes valeurs calculées au pixel sur téléphone. */
    width: calc(100% + 100px); margin-left: -50px;
    padding: 40px 50px calc(56px + env(safe-area-inset-bottom, 0px));
}
/* ⚠️ ET LE FOND N'EXISTE QUE LÀ OÙ IL EST NÉCESSAIRE. Sur une page ordinaire,
   le sol est déjà porté par la RACINE (nu-chrome.css) et l'embossé doit se
   voir au travers — c'est le contrat du site, où le rédactionnel n'a aucun
   fond à lui. Sur une page à FILM, `html:has(.ft)` fait taire le canevas
   (nu-film.css:312) : là, et là seulement, le bloc doit peindre lui-même,
   sinon le texte se lit sur le canevas nu de Safari. */
html:has(.ft) .nu-corps { background: var(--mobile-grad-top, #58534d); }

/* ⛔ LA BANDE HAUTE DES FICHES À BOUCLE : TROIS PISTES ESSAYÉES, TOUTES
   RETIRÉES LE 07/09. À lire avant d'en proposer une quatrième.
   Le besoin (PO) : « je ne veux pas de bande » au-dessus de la boucle vidéo.
   ① TEINTER LA RACINE, comme un corner à film. ⛔ Sur une fiche, `.nu-corps`
      est transparent (la règle ci-dessus ne vaut que sous `html:has(.ft)`) :
      la racine peint donc TOUTE la page. Verdict PO : « tu m'as changé toutes
      les couleurs de fond, et c'est moche ».
   ② TEINTE + FOND OPAQUE sur le corps, la paire complète. Le fond redevient
      juste, mais ⛔ la zone réservée n'accepte QU'UN APLAT (aucun élément ne
      l'atteint, mesuré le 23/08) : sur une image dont le haut n'est pas uni —
      un ciel, une lampe, du bokeh — l'aplat coupe net. Le corner s'en tire
      parce que ses films ouvrent sur un fond de studio plat. Verdict PO :
      « la bande jure ».
   ③ FONDU DE RACCORD, l'image venant à la rencontre de l'aplat. La jointure
      devient invisible (mesuré : barre `rgb(129,155,175)`, premier pixel de
      la page `rgb(129,156,176)` — 1 niveau d'écart). ⛔ MAIS les transitions
      la cassent : `nuHabille()` (nu-gestes.js) peint la page ENTRANTE avec la
      couleur de la racine COURANTE, c'est-à-dire celle de la page qu'on
      quitte. Dès que deux pages ont des racines différentes, la couleur
      voyage — et sur la page d'arrivée elle apparaît en aplat, sans le fondu.
      Verdict PO : « la couleur du précédent apparaît sur la future ».
   ⇒ CE QUI BLOQUE N'EST PAS LA BANDE, C'EST `nuHabille` : tant qu'il copie la
   racine plutôt que la couleur PROPRE de la page entrante, aucune fiche ne
   peut avoir sa teinte. Le corriger touche les transitions de TOUT l'arbre —
   chantier à froid, avec sa recette, pas un correctif de fin de journée.
   L'amorce de défilement, elle, est réfutée pour de bon : mesuré, le corner
   Sculptures est à `innerHeight` 796 sur un écran de 956 à l'arrivée, barres
   déployées, alors qu'il ouvre défilé de 90 px — la bascule réservé/survol se
   fait AU GESTE SEUL, un `scrollTo` n'en est pas un.
   Les teintes restent calculées par `outils/boucles-affiche.sh` (elles ne
   coûtent rien et resserviront) ; plus personne ne les lit. */

/* La ligne de version : GRÉEMENT DE RECETTE, pas du contenu — elle nomme la
   page et compte ses films, pour qu'un défaut soit désignable. Discrète, et
   à retirer quand l'arbre sortira du labo. */
.v-labo {
    font: 11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: .06em; opacity: .55; margin: 0 0 12px;
}
.nu-corps h1, .nu-corps div:where(.nu-h1) { margin: 0 0 14px; font-size: clamp(28px, 8vw, 40px); line-height: 1.08; letter-spacing: -0.02em; }
.nu-intro { margin: 0 0 26px; font-size: 18px; line-height: 1.45; color: rgba(255, 255, 255, .82); }
.nu-corps :is(h2, h3) { margin: 30px 0 10px; line-height: 1.2; }
.nu-corps p { margin: 0 0 16px; line-height: 1.6; }

.nu-liste { list-style: none; margin: 34px 0 0; padding: 22px 0 0; border-top: 1px solid rgba(255, 255, 255, .22); }
.nu-liste li { padding: 11px 0; border-bottom: 1px solid rgba(255, 255, 255, .12); }
.nu-liste a { color: var(--fg, #fff); text-decoration: none; }
.nu-liste span { color: var(--fg-muted, rgba(255, 255, 255, .55)); font-size: 14px; }

.nu-retour { padding: 22px 0; background: var(--mobile-grad-top, #58534d); }
/* --fg-soft et non --fg-muted (revue Hélène 26/08) : sur le taupe #58534d de
   la fiche — qui n'a PAS le sol sombre du corner — le muted mesure 3,54:1,
   sous le seuil AA (chiffre relevé dans univers-galerie.css). */
/* CTA de NAVIGATION, pas de valeur (PO 27/08) : le `nav a` générique de
   nu.css l'habillait en bouton (bordure #111, padding 12/16 — mesuré 166×49
   au câble, le même poids qu'un « Demander cette pièce »). On lui rend le
   texte nu ; le padding vertical seul garde la cible tactile (~44 px). */
.nu-retour a {
    display: inline-block; padding: 14px 0; border: 0;
    color: var(--fg-soft, rgba(255, 255, 255, .85));
    text-decoration: none; font-size: 15px;
}

/* ── LE RÉGIME PEINTURE DES FICHES (calque du 25/08) ──────────────────────
   Décision PO 25/08 : « les tableaux ISO contenu V2 — fiches avec options ».
   La géométrie vit dans fiche.css (importée par la route) ; ici, uniquement
   ce que l'arbre nu doit fournir pour qu'elle soit JUSTE :
   1. les deux tokens que `.fi-visuel--ouverture.cadre-ca` consomme SANS
      repli (fiche.css:451) — non définis, tout le min() de --cm est invalide
      et la caisse mesure 0×0. Valeurs du site (nav.css:33/54) : 70 px de
      chrome bas, 72 px de pli. Le nu a bien un chrome bas (pictos 48 px +
      garde) — la réserve dit la même chose ici que là-bas ;
   2. le CTA est un <a> (mailto — le formulaire de contact n'est pas un
      calque de l'arbre nu), or .fi-cta est taillé pour un <button> : un
      lien ne centre pas son texte et souligne. On aligne, sans toucher à
      fiche.css.
   Hors condition de largeur (desktop, increment 1) : les pictos et le pli
   existent à toutes les largeurs. */
:root { --bottom-reserve: 70px; --pli: 72px; }
a.fi-cta {
    display: flex; align-items: center; justify-content: center;
    text-decoration: none; text-align: center;
}

/* ── LES LIENS DANS LE TEXTE (29/08, demande PO) ──────────────────────────
   Constat PO : « change-moi la couleur du lien sur laurentbarateau.fr ».
   Mesuré : il s'affichait en `rgb(158, 158, 255)` — le BLEU PAR DÉFAUT du
   navigateur. Aucune règle de l'arbre ne ciblait les liens en ligne du
   corps ; seuls les liens habillés (cartes, retour, pied) avaient un style.
   Un bleu système au milieu d'une charte taupe et vert anis.
   ⚠️ LA COULEUR EST CELLE DE LA MARQUE, PAS UNE INVENTION — mais 5 % plus
   claire, et c'est mesuré : sur le fond taupe (rgb 88,83,77), l'accent pur
   #b4cd00 donne un contraste de 4,23, sous le seuil AA de 4,5 pour du texte
   courant. `#bdd700` est la MÊME teinte (mêmes rapports r:g:b) éclaircie
   d'un vingtième — 4,67, conforme, et l'œil ne distingue pas les deux.
   Revenir à l'accent pur, c'est remplacer une valeur ici.
   Le SOULIGNEMENT reste : un lien ne doit pas se reconnaître à sa seule
   couleur (WCAG 1.4.1). Il est décalé et aminci pour ne pas hacher les
   jambages. */
/* ⚠️ `:not(.carte)` — UNE CARTE DE PIÈCE N'EST PAS UN LIEN DE TEXTE (constat
   PO 29/08 : « les CTA dans tous les items produits doivent être blancs »).
   Le mur d'un corner est une liste : chaque pièce vit dans un <li>, donc
   chaque carte tombait sous `.nu-corps li a` — et repeignait en vert souligné
   le nom ET le prix de toutes les pièces du site. `.carte` (fiche.css)
   demandait pourtant déjà le blanc et l'absence de soulignement, mais avec
   une classe contre deux types elle perdait l'arbitrage de spécificité.
   Le souligné vert reste ce qu'il doit être : la marque d'un lien DANS DU
   TEXTE, où rien d'autre ne le signale. Une carte, elle, s'annonce par son
   image, son cadre et sa cible de 200 px — la règle WCAG 1.4.1 parle des
   liens noyés dans la prose, pas des vignettes d'une grille. */
.nu-corps p a,
.nu-corps li a:not(.carte),
.nu-corps blockquote a,
.nu-corps dd a {
    color: #bdd700;
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    text-decoration-color: rgba(189, 215, 0, 0.5);
    transition: text-decoration-color 0.2s ease;
}
.nu-corps p a:hover,
.nu-corps li a:not(.carte):hover,
.nu-corps blockquote a:hover { text-decoration-color: #bdd700; }
/* Le CTA posé dans le contenu (mailto d'une section qui ne mène à aucune
   fiche) reste un bouton : il ne prend ni la couleur ni le soulignement des
   liens de texte. */
.nu-corps p a.fi-cta { color: inherit; text-decoration: none; }

/* ── LA FICHE NUE ───────────────────────────────────────────────────────── */
/* ⚠️ LA FICHE ROGNE SON DÉBORD HORIZONTAL — mesuré au câble le 25/08 :
   l'image d'un VOLUME dépasse sa boîte PAR CONSTRUCTION (le sujet est calé
   à l'échelle, l'image et ses marges vides débordent — 546 px sur un écran
   de 440, scrollWidth 493). Sur le site, la coquille rogne ; ici personne
   ne le faisait, d'où un défilement horizontal sur toute la fiche.
   `clip` et non `hidden` : il rogne SANS créer de conteneur de défilement —
   la pellicule de la galerie garde son propre défilement interne, et le
   `100vw` du bloc reste le bord de rognage (le débord de -38px des
   ouvertures vit en dedans). */
.nu-corps.fiche { overflow-x: clip; }

/* ── CORNER PEINTURES — SCÈNE BUREAU REPRISE DE DEV (29/09) ───────────── */
@media not all and (max-width: 1023px) {
    html.nu .page--peintures-bureau { padding: 0; }
    html.nu .page--peintures-bureau > .nu-corps { display: none; }
    /* Corner Bijoux : même régime (01/10), scène dans BijouxBureau.astro. */
    html.nu .page--bijoux-bureau { padding: 0; }
    html.nu .page--bijoux-bureau > .nu-corps { display: none; }
}

/* ── FICHE SCULPTURE — SCÈNE BUREAU REPRISE DE DEV (28/09) ───────────────
   Desktop seulement. À 1023 px et moins, `.fb` disparaît et la fiche mobile
   historique reste seule : aucune de ses dimensions, marges ou interactions
   n'est surchargée. */
.fb { display: none; }
@media not all and (max-width: 1023px) {
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)),
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) body { overflow: hidden; }
    .page--fiche-sculpture-bureau > .nu-corps.fiche--volume,
    .page--fiche-bijou-bureau > .nu-corps.fiche { display: none; }

    /* Lightbox photo bureau : image entière à 80 % du viewport, apparition
       et disparition fondues, puis déplacement au pointeur. Le mobile garde
       sa géométrie et ses gestes tactiles historiques. */
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay {
        opacity: 0;
        background: #12100e;
        transition: opacity .22s ease;
    }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay.lb-ouverte { opacity: 1; }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay.lb-fermeture { opacity: 0; }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-image {
        width: 80vw;
        height: 80svh;
        max-width: 80vw;
        max-height: 80svh;
        object-fit: contain;
        user-select: none;
        -webkit-user-drag: none;
    }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay:not(.lb-zoome) .lb-image { cursor: grab; }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay.lb-glisse .lb-image,
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay.lb-zoome.lb-glisse .lb-image { cursor: grabbing; }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)):has(.lb-overlay:not([hidden])) :is(.compass, .qa) {
        display: none;
    }

    @media (prefers-reduced-motion: reduce) {
        html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-overlay,
        html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .lb-piste.lb-anime { transition-duration: .01ms; }
    }

    .fb {
        position: fixed; inset: 0; z-index: 1; display: block;
        width: 100vw; height: 100svh; overflow: hidden; isolation: isolate;
        color: #fff; background: #443f3a;
    }
    /* Mesure au routeur, fiche → fiche : la pane vit à y=-140. Avec 90 px,
       la scène entrante était à -50 puis sautait à 0 lors de sa promotion.
       140 px annule exactement le débord : avant et après = y 0. */
    .pane .fb { top: 140px; }
    .fb-fond {
        position: absolute; inset: 0; z-index: -2;
        background: var(--fb-decor) center / cover no-repeat;
        transform: scale(1.002);
        transition: filter .22s ease, transform .22s ease;
    }
    html.nu.modal-open:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .fb-fond {
        filter: blur(26px) brightness(.62) saturate(.78);
        transform: scale(1.065);
    }
    .fb::after {
        content: ""; position: absolute; inset: 0; z-index: -1;
        /* Voile historique de la fiche dev : 30 % de noir au bord droit,
           fondu jusqu'à zéro au bord gauche. Il détache le texte sans poser
           un nouvel aplat derrière la sculpture. */
        background: linear-gradient(270deg, rgba(0,0,0,.30) 0%, rgba(0,0,0,0) 100%);
        pointer-events: none;
    }
    .fb-cartel {
        position: absolute; top: calc(63px * var(--k, 1)); right: calc(76px * var(--k, 1));
        display: flex; flex-direction: column;
        width: min(calc(788px * var(--k, 1)), 43vw);
        height: min(calc(845px * var(--k, 1)), calc(100svh - 252px * var(--k, 1)));
        padding: calc(50px * var(--k, 1)) calc(64px * var(--k, 1)) calc(46px * var(--k, 1));
        border: 0; border-radius: calc(10px * var(--k, 1));
        background: transparent;
        -webkit-backdrop-filter: blur(8px) brightness(.97); backdrop-filter: blur(8px) brightness(.97);
        box-shadow: 0 4px 30px rgba(0,0,0,.10), inset 1px 1px 1px rgba(255,255,255,.50), inset -1px -1px 1px rgba(0,0,0,.15);
        text-align: right; text-shadow: none;
    }
    .fb-fil { display: flex; justify-content: flex-end; gap: .28em; margin: 0 0 calc(14px * var(--k, 1)); font-size: calc(11px * var(--k, 1)); line-height: 1; }
    /* Sans ligne de format entre eux (fiches bijou), le fil passait sous les
       jambages du titre, « g », « p » (PO 05/10, Safari Mac). */
    .fb :is(h1, .nu-h1) + .fb-fil { margin-top: calc(8px * var(--k, 1)); }
    .fb-fil a { display: inline; padding: 0; border: 0; border-radius: 0; background: none; color: var(--accent, #b4cd00); font: inherit; line-height: inherit; text-decoration: none; }
    .fb-fil span { color: rgba(255,255,255,.58); }
    .fb h1, .fb div:where(.nu-h1) { display: flex; justify-content: flex-end; gap: .25em; margin: 0; font-size: calc(34px * var(--k, 1)); line-height: 1; font-weight: 500; letter-spacing: -.025em; }
    .fb h1 span, .fb div:where(.nu-h1) span { font-weight: 250; }
    .fb-format { align-self: flex-end; width: auto; margin: calc(2px * var(--k, 1)) 0 calc(10px * var(--k, 1)); font-size: calc(12px * var(--k, 1)); line-height: 1; text-align: right; }
    .fb-recit {
        flex: 1 1 auto; min-height: 0; overflow-x: hidden; overflow-y: auto;
        padding: 0 calc(18px * var(--k, 1)) 0 calc(8px * var(--k, 1));
        scrollbar-gutter: auto;
        scrollbar-width: thin;
        scrollbar-color: rgba(225,225,225,.48) transparent;
    }
    .fb-recit::-webkit-scrollbar { width: 3px; }
    .fb-recit::-webkit-scrollbar-track { background: transparent; }
    .fb-recit::-webkit-scrollbar-thumb { border-radius: 0; background: rgba(225,225,225,.48); }
    .fb-recit p, .fb-recit h2 { max-width: none; }
    .fb-recit p { margin: 0 0 calc(10px * var(--k, 1)); font-size: calc(13px * var(--k, 1)); line-height: 1.38; }
    .fb-recit .fb-resume { margin-bottom: calc(15px * var(--k, 1)); font-size: calc(14px * var(--k, 1)); font-weight: 520; }
    .fb-recit h2 { margin: calc(14px * var(--k, 1)) 0 calc(5px * var(--k, 1)); font-size: calc(18px * var(--k, 1)); line-height: 1.1; }
    .fb-recit a {
        color: #fff;
        text-decoration-line: underline;
        text-decoration-color: rgba(180,205,0,.88);
        text-decoration-thickness: 1px;
        text-underline-offset: .18em;
    }
    .fb-recit a:hover { color: var(--accent, #b4cd00); }
    .fb-recit a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
    .fb-statut { margin: calc(11px * var(--k, 1)) 0 0; font-size: calc(11px * var(--k, 1)); line-height: 1.25; font-weight: 520; }
    .fb-partage { display: flex; flex-direction: column; align-items: flex-end; gap: calc(5px * var(--k, 1)); margin-top: calc(12px * var(--k, 1)); font-size: calc(14px * var(--k, 1)); line-height: 1; }
    .fb-partage > div { display: flex; gap: calc(9px * var(--k, 1)); }
    .fb-partage a { display: grid; place-items: center; width: calc(24px * var(--k, 1)); height: calc(24px * var(--k, 1)); padding: 0; border: 0; border-radius: 0; background: transparent; color: var(--accent, #b4cd00); transition: color .2s ease; }
    .fb-partage a:hover { color: #fff; }
    .fb-partage a:focus-visible { outline: 2px solid #fff; outline-offset: 3px; }
    .fb-partage svg { width: calc(18px * var(--k, 1)); height: calc(18px * var(--k, 1)); fill: currentColor; }
    .fb-partage .fb-icone-trait { fill: none; }
    .fb-actions { display: grid; grid-template-columns: 1fr; gap: calc(10px * var(--k, 1)); margin-top: calc(18px * var(--k, 1)); }
    .fb-actions > * { display: grid; place-items: center; min-height: calc(42px * var(--k, 1)); padding: calc(8px * var(--k, 1)) calc(14px * var(--k, 1)); border: 1px solid var(--accent, #b4cd00); border-radius: 2px; background: var(--accent, #b4cd00); color: #fff; font: inherit; font-size: calc(12px * var(--k, 1)); font-weight: 600; text-decoration: none; cursor: pointer; transition: background-color .2s ease, color .2s ease; }
    .fb-actions > *:hover { background: #fff; color: #202218; }
    .fb-actions > *:focus-visible, .fb-vue:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
    .fb-bande {
        position: absolute; left: calc(76px * var(--k, 1)); right: calc(76px * var(--k, 1)); bottom: calc(76px * var(--k, 1));
        display: flex; align-items: center; justify-content: center; gap: calc(12px * var(--k, 1));
        height: calc(94px * var(--k, 1)); padding: calc(2px * var(--k, 1)) calc(28px * var(--k, 1));
        overflow: visible;
        border: 1px solid rgba(255,255,255,.20); border-radius: calc(10px * var(--k, 1));
        background: rgba(0,0,0,.04); -webkit-backdrop-filter: blur(8px) brightness(.97); backdrop-filter: blur(8px) brightness(.97);
        box-shadow: 0 8px 28px rgba(0,0,0,.14), inset 1px 1px 1px rgba(255,255,255,.35);
    }
    html.nu .fb-bande .fb-vue { flex: 0 0 calc(104px * var(--k, 1)); width: calc(104px * var(--k, 1)); height: calc(104px * var(--k, 1)); margin: 0; padding: 0; overflow: hidden; border: 1px solid rgba(255,255,255,.35); border-radius: calc(8px * var(--k, 1)); background: rgba(0,0,0,.28); box-shadow: 0 calc(6px * var(--k, 1)) calc(16px * var(--k, 1)) rgba(0,0,0,.18); cursor: zoom-in; }
    html.nu .fb-bande .fb-vue img { display: block; width: 100%; height: 100%; object-fit: cover; }
    .fb-3d-tile { display: grid; place-items: center; align-content: center; gap: 2px; flex: 0 0 calc(116px * var(--k, 1)); width: calc(116px * var(--k, 1)); height: calc(90px * var(--k, 1)); padding: 4px; border: 0; background: transparent; color: var(--accent, #b4cd00); cursor: pointer; }
    .fb-3d-tile svg { width: calc(58px * var(--k, 1)); height: calc(58px * var(--k, 1)); }
    .fb-3d-tile span { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
    .fb-3d-tile:hover { color: #fff; }

    /* FICHE BIJOU (01/10, reprise de dev) : même scène, le croquis du corner
       en fond et la pièce posée à gauche du cartel. Elle s'efface sous une
       modale : la 3D prend exactement sa place. */
    .fb-piece {
        position: absolute; z-index: 0;
        top: calc(63px * var(--k, 1)); bottom: calc(190px * var(--k, 1)); left: 5vw;
        right: calc(76px * var(--k, 1) + min(calc(788px * var(--k, 1)), 43vw) + 3vw);
        display: grid; place-items: center; margin: 0; padding: 0; border: 0; background: none;
        transition: opacity .22s ease;
    }
    button.fb-piece { cursor: pointer; }
    .fb-piece img { width: 72%; height: 72%; min-height: 0; object-fit: contain; }
    .fb-piece:focus-visible { outline: 3px solid #fff; outline-offset: -3px; }
    html.nu.modal-open .fb-piece { opacity: 0; }
    /* LE PRIX D'UN BIJOU FERRÉ À DROITE, SANS FLEX (PO 05/10, Safari Mac) :
       Chrome le calait au bord du cartel, Safari le posait 87 px plus à
       gauche, pile au bord gauche des pictos de partage. Il est seul sur sa
       ligne : un bloc aligné à droite suffit, et les deux moteurs s'accordent. */
    /* ⚠️ LA VRAIE CAUSE, trouvée au second passage : `p { max-width: 34em }`
       (nu.css). Sur une fenêtre de 1 370 px, 34em du prix font 412 px pour
       une colonne de 499 : le paragraphe plafonnait, calé à gauche, et son
       prix « à droite » tombait 87 px avant le bord. Rien à voir avec Safari :
       dans une fenêtre plus large le plafond ne mordait pas. */
    .fb--bijou .fb-prix { display: block; width: 100%; max-width: none; margin-top: calc(12px * var(--k, 1)); text-align: right; }
    .fb--bijou .fb-prix .fi-montant { display: inline; }
    /* La boucle paysage en fond de scène (01/10), calée à gauche : c'est là
       qu'est la bague, la droite passe sous le cartel. */
    .fb-video {
        position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%;
        object-fit: cover; object-position: left center;
        transition: filter .22s ease, opacity .6s ease;
    }
    /* Une vue choisie dans la bande : la boucle s'efface (02/10). */
    .fb--vue .fb-video { opacity: 0; }
    /* La pièce détourée posée sur la boucle : même flou que sur un décor. */
    .fb--apercu .fb-video { filter: blur(18px) brightness(.72) saturate(.85); }
    html.nu.modal-open .fb-video { filter: blur(26px) brightness(.62) saturate(.78); }
    html.nu .fb .fb-video-mention { right: auto; left: calc(76px * var(--k, 1)); bottom: calc(184px * var(--k, 1)); width: max-content; }

    /* Sur une fiche sculpture bureau, la 3D remplace visuellement la pièce
       dans la moitié gauche. Son fond reprend la référence dev : le décor
       reste présent mais passe dans un voile sombre et flouté derrière le
       modèle seulement. Le cartel à droite demeure net et la bande basse en
       verre masque le pied. Le mobile garde la visionneuse plein écran. */
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-overlay {
        background: transparent;
    }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-stage {
        inset: 0 auto calc(132px * var(--k, 1)) 0;
        z-index: 1;
        width: 55vw;
        background: transparent;
    }
    /* FICHE BIJOU : LA PIÈCE OCCUPE TOUTE LA PAGE ET PASSE SOUS LE VERRE DU
       CARTEL (PO 06/10). La scène s'étend jusqu'au bord droit ; elle déborde
       d'autant à gauche, hors écran, pour que son centre reste à 27,5vw : la
       pièce, la croix et le chargement ne bougent pas. La classe est posée APRÈS
       le cadrage (sinon la pièce grossit, voir cadrer()). visionneuse-3d.js
       glisse la visionneuse dans `.fb`, avant le cartel, qui la recouvre. */
    /* Et jusqu'au bas de la page, sous la bande des vues (PO 06/10) : la scène
       gagne 132 px en bas et autant en haut, hors écran, pour garder son centre. */
    html.nu:has(.page--fiche-bijou-bureau) .v3d-stage.v3d-stage--pleine {
        left: -45vw; width: 145vw;
        top: calc(-132px * var(--k, 1)); bottom: 0;
    }
    .fb--bijou > .v3d-overlay { z-index: 0; }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-stage model-viewer {
        --poster-color: transparent;
        background: transparent;
    }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-fermer {
        top: calc(76px * var(--k, 1));
        right: calc(76px * var(--k, 1) + min(calc(788px * var(--k, 1)), 43vw) + 14px * var(--k, 1));
        left: auto;
        transform: none;
        border: 1px solid rgba(255,255,255,.62);
        background: rgba(20,20,18,.62);
        -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
        box-shadow: 0 4px 18px rgba(0,0,0,.22);
    }
    /* La visionneuse remplace temporairement la navigation spatiale : aucun
       nord/sud/est/ouest ni picto central ne doit concurrencer la rotation. */
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)):has(.v3d-overlay:not([hidden])) :is(.compass, .qa--plan) {
        display: none;
    }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-etat,
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-legende {
        right: auto; width: 55vw;
    }
    /* LA LÉGENDE DE LA 3D PASSE AU-DESSUS DE LA BANDE DES VUES (PO 05/10, Safari
       Mac) : à 140 px elle mordait sur la bande. Remontée de 36 px, l'état de
       chargement d'autant, pour garder leur écart. */
    /* L'état de chargement est au milieu de la scène : la bande des vues
       (132 px) occupe le bas, on remonte donc de sa moitié. */
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-etat { top: calc(50% - 66px * var(--k, 1)); }
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)) .v3d-legende { bottom: calc(176px * var(--k, 1)); }
    /* La mention « mise en situation par IA » parle du décor : le modèle 3D
       ouvert, il n'y a plus de décor à légender, et elle se superposait à la
       légende de la visionneuse. */
    html.nu:has(.v3d-overlay:not([hidden])) .fb-fond-mention { display: none; }
    /* ET L'IMAGE DÉTOURÉE S'EFFACE SOUS LE MODÈLE 3D (PO 05/10, fiche bijou) :
       une vue « pièce entière » reste l'état choisi de la scène, donc le
       script ne la referme pas ; sans cette règle le modèle se posait dessus,
       avec deux croix. `visibility` et non `display` : la scène retrouve son
       image telle quelle quand on referme la 3D. */
    html.nu:has(.v3d-overlay:not([hidden])) :is(.fb-apercu, .fb-apercu-fermer) { visibility: hidden; }
}

/* ── FICHE PEINTURE — SCÈNE BUREAU REPRISE DE DEV (01/10) ────────────────
   Référence PO : dev, Louboutin 2015. Même scène `.fb` que la fiche
   sculpture (verre, typographie, partage, bouton), avec trois écarts :
   le fond est la mise en situation et change au clic sur une vignette,
   le cartel est étroit (29 % de l'écran sur dev), et il porte le prix et
   les finitions de la caisse, fixes sous le récit (PO 01/10).
   Desktop seulement : à 1023 px et moins la fiche mobile reste seule. */
@media not all and (max-width: 1023px) {
    html.nu:has(.page--fiche-peinture-bureau),
    html.nu:has(.page--fiche-peinture-bureau) body { overflow: hidden; }
    .page--fiche-peinture-bureau > .nu-corps.fiche { display: none; }

    /* LE PIED DES DEUX SCÈNES DE FICHE (01/10). La scène est `fixed` : la page
       n'a plus de hauteur, et le pied `sticky` remontait à 142 px du haut, en
       travers du décor (mesuré sur la fiche sculpture comme sur la peinture).
       Ici il se cale au bas de l'écran, sous la bande des vues.
       Le `:not(…accueil)` reprend la règle générale du pied (`sticky`), écrite
       plus bas : on la bat par la spécificité, pas par l'ordre. */
    html.nu:has(:is(.page--fiche-sculpture-bureau, .page--fiche-bijou-bureau)):not(:has(.page--accueil)) body > .nu-pied,
    html.nu:has(.page--fiche-peinture-bureau):not(:has(.page--accueil)) body > .nu-pied { position: fixed; right: 0; bottom: 0; left: 0; }

    /* Deux calques, fondu croisé. */
    :is(.fb--cadre, .fb--volume, .fb--bijou) .fb-fond { opacity: 0; transition: opacity .6s ease, filter .22s ease, transform .22s ease; }
    :is(.fb--cadre, .fb--volume, .fb--bijou) .fb-fond.is-active { opacity: 1; }
    .fb-fond-mention[hidden] { display: none; }
    html.nu.modal-open:has(.page--fiche-peinture-bureau) .fb-fond {
        filter: blur(26px) brightness(.62) saturate(.78);
        transform: scale(1.065);
    }

    .fb--cadre .fb-cartel {
        width: min(calc(440px * var(--k, 1)), 31vw);
        padding: calc(26px * var(--k, 1)) calc(42px * var(--k, 1)) calc(34px * var(--k, 1));
    }
    .fb--cadre h1, .fb--cadre div:where(.nu-h1) { display: block; font-size: calc(28px * var(--k, 1)); }
    .fb--cadre .fb-fil { flex-wrap: wrap; row-gap: .35em; }

    .fb-transaction { display: flex; flex-direction: column; align-items: flex-end; gap: calc(8px * var(--k, 1)); margin: calc(12px * var(--k, 1)) 0 0; }
    .fb-prix { display: flex; align-items: baseline; justify-content: flex-end; gap: .55em; margin: 0; line-height: 1; }
    .fb-prix .fi-montant { font-size: calc(22px * var(--k, 1)); font-weight: 400; }
    .fb-prix-mention { font-size: calc(11px * var(--k, 1)); color: rgba(255,255,255,.72); order: -1; }
    .fb-finitions-note { margin: 0; font-size: calc(11px * var(--k, 1)); line-height: 1.3; color: rgba(255,255,255,.72); text-align: right; }
    /* Le bouton de l'aide à la mesure, au gabarit d'une option cochée. */
    .fb-tour {
        padding: calc(5px * var(--k, 1)) calc(10px * var(--k, 1));
        border: 1px solid rgba(255,255,255,.5); border-radius: calc(6px * var(--k, 1));
        background: rgba(0,0,0,.22); color: #fff; cursor: pointer;
        font: inherit; font-size: calc(11.5px * var(--k, 1)); line-height: 1; font-weight: 600; white-space: nowrap;
    }
    .fb-tour:hover { border-color: var(--accent, #b4cd00); }
    .fb-tour:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
    .fb-finitions { display: flex; flex-direction: column; align-items: flex-end; gap: calc(4px * var(--k, 1)); min-width: 0; margin: 0; padding: 0; border: 0; }
    .fb-finitions legend { margin: 0 0 calc(5px * var(--k, 1)) auto; padding: 0; font-size: calc(10.5px * var(--k, 1)); line-height: 1; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
    .fb-gamme { display: flex; align-items: center; justify-content: flex-end; gap: calc(4px * var(--k, 1)); }
    .fb-gamme-nom { margin-right: calc(4px * var(--k, 1)); font-size: calc(11px * var(--k, 1)); color: rgba(255,255,255,.72); }
    .fb-teinte { position: relative; display: inline-flex; align-items: center; gap: calc(6px * var(--k, 1)); padding: calc(3px * var(--k, 1)); border: 1px solid transparent; border-radius: calc(6px * var(--k, 1)); cursor: pointer; }
    .fb-teinte input { position: absolute; width: 0; height: 0; opacity: 0; }
    .fb-teinte .fi-pastille { width: calc(22px * var(--k, 1)); height: calc(22px * var(--k, 1)); border-width: calc(4px * var(--k, 1)); }
    .fb-teinte-nom { display: none; font-size: calc(11.5px * var(--k, 1)); line-height: 1; font-weight: 600; white-space: nowrap; }
    .fb-teinte-nom small { margin-left: .45em; font-size: inherit; font-weight: 400; color: rgba(255,255,255,.72); }
    .fb-teinte:hover { border-color: rgba(255,255,255,.5); }
    .fb-teinte:has(input:checked) { padding-right: calc(8px * var(--k, 1)); border-color: var(--accent, #b4cd00); background: rgba(0,0,0,.22); }
    .fb-teinte:has(input:checked) .fb-teinte-nom { display: inline; }
    .fb-teinte:has(input:focus-visible) { outline: 2px solid #fff; outline-offset: 2px; }

    /* LE TABLEAU DANS SA CAISSE, sur le décor flouté. Zone libre à gauche du
       cartel ; `--cm` (px par cm) borne l'objet en largeur ET en hauteur.
       LE CREUX EST À LA COTE RÉELLE : 15 mm entre le Dibond et le bord
       intérieur du profil, bois comme alu (cote donnée par le PO le 01/10,
       `creux_cm` de finitions.json). 5 = 2 × (face 1 + creux 1,5), la
       gamme la plus large. Même cote partout depuis le 01/10 (`--ca-creux`,
       fiche.css). */
    .fb-apercu {
        position: absolute; z-index: 0;
        inset: calc(63px * var(--k, 1)) 36vw calc(110px * var(--k, 1)) 7vw;
        display: grid; place-items: center;
        opacity: 0; visibility: hidden;
        transition: opacity .35s ease, visibility 0s linear .35s;
    }
    .fb--apercu .fb-apercu { opacity: 1; visibility: visible; transition: opacity .35s ease; }
    .fb-apercu figure { display: grid; justify-items: center; gap: calc(14px * var(--k, 1)); margin: 0; }
    .fb-apercu .cadre-ca {
        --cm: min(52vw / (var(--l) + 5), (100svh - 250px * var(--k, 1)) / (var(--hv, var(--h)) + 5));
    }
    .fb-apercu .cadre-ca img {
        position: absolute; top: var(--ca-pad); left: var(--ca-pad);
        width: calc(100% - 2 * var(--ca-pad)); height: calc(100% - 2 * var(--ca-pad));
        object-fit: cover; display: block;
    }
    /* La sculpture détourée, posée sur son décor flouté (02/10). */
    /* La bande court sur toute la largeur : l'image s'arrête au-dessus d'elle. */
    :is(.fb--volume, .fb--bijou) .fb-apercu { right: 50vw; bottom: calc(190px * var(--k, 1)); }
    .fb-apercu figure > img { display: block; max-width: 43vw; max-height: calc(100svh - 300px * var(--k, 1)); object-fit: contain; }
    .fb-fond-mention { z-index: 1; }
    .fb-apercu figcaption { font-size: calc(12px * var(--k, 1)); line-height: 1; letter-spacing: .04em; text-shadow: 0 1px 6px rgba(0,0,0,.6); }
    .fb-apercu-fermer {
        position: absolute; top: 0; right: 0;
        display: grid; place-items: center;
        width: calc(40px * var(--k, 1)); height: calc(40px * var(--k, 1)); padding: 0;
        border: 1px solid rgba(255,255,255,.62); border-radius: 50%;
        background: rgba(20,20,18,.62); color: #fff; cursor: pointer;
        -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
        box-shadow: 0 4px 18px rgba(0,0,0,.22);
    }
    .fb-apercu-fermer svg { width: 45%; height: 45%; }
    .fb-apercu-fermer:hover { background: #fff; color: #202218; }
    .fb-apercu-fermer:focus-visible { outline: 3px solid #fff; outline-offset: 3px; }
    /* Le décor passe derrière : flouté et assombri. */
    .fb--apercu .fb-fond.is-active { filter: blur(18px) brightness(.72) saturate(.85); transform: scale(1.06); }
    /* Sans mise en situation, le tableau en caisse est la scène : pas de croix. */
    .fb--cadre:not(:has(.fb-vue[data-fond])) .fb-apercu-fermer { display: none; }

    /* La bande des vues : à droite, sous le cartel, comme sur dev. */
    .fb--cadre .fb-bande { left: auto; width: auto; max-width: 52vw; }
    html.nu :is(.fb--cadre, .fb--volume, .fb--bijou) .fb-bande .fb-vue { cursor: pointer; transition: border-color .2s ease, transform .2s ease; }
    html.nu :is(.fb--cadre, .fb--volume, .fb--bijou) .fb-bande .fb-vue:hover { transform: translateY(-2px); border-color: var(--accent, #b4cd00); }
    html.nu :is(.fb--cadre, .fb--volume, .fb--bijou) .fb-bande .fb-vue[aria-pressed="true"] { border-color: var(--accent, #b4cd00); }
    /* UNE SEULE VIGNETTE ACTIVE À LA FOIS (PO 05/10, Safari Mac : « j'ai deux
       blancs »). Quand la pièce seule est montrée par-dessus, la mise en
       situation qui reste dessous garde `aria-pressed` (c'est elle qui
       reviendra) mais ne se dit plus active à l'œil. */
    /* COULEURS INVERSÉES LE MÊME JOUR (PO) : le vert est l'accent du site,
       donc l'actif et le survol ; le repos est un filet blanc discret. */
    html.nu .fb--apercu .fb-bande .fb-vue:not([data-apercu])[aria-pressed="true"]:not(:hover) { border-color: rgba(255,255,255,.35); }
    html.nu :is(.fb--volume, .fb--bijou) .fb-bande .fb-vue--piece img { object-fit: contain; }

    @media (prefers-reduced-motion: reduce) {
        :is(.fb--cadre, .fb--volume, .fb--bijou) .fb-fond, .fb-apercu, .fb--apercu .fb-apercu, html.nu .fb--cadre .fb-bande .fb-vue { transition-duration: .01ms; }
    }
}

/* Les liens du récit (revue Hélène 26/08) : aucune règle ne les ciblait, ils
   sortaient en bleu UA de Safari (#9E9EFF — 3,18:1 sur le taupe, et la seule
   couleur de /nu/ que personne n'a choisie). Même idiome que .nu-piece a
   (l.22) : blanc, souligné fin. */
.nu-corps.fiche p a { color: var(--fg, #fff); text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, .38); }

/* ── LE TITRE DE PIÈCE SUPERPOSÉ (fiches sculptures, PO 25/08 soir) ───────
   La grille des cartels du corner (.ft-titre) et du héros (.ft-hero-titre),
   portée sur la fiche : les deux voix partagent la même cellule — la série
   très fine dessous, le nom à la recette du H1 par-dessus, chevauchant sa
   base de 58 %. Ferré à gauche (le flux de la fiche). Le format qui suit
   rend l'air que le débord du nom lui prend (~24 px). */
.fi-titre-piece {
    display: grid; justify-items: start;
    margin: 0 0 14px;
}
/* L'ÉCHELLE DU TITRE (piste A « Cartel complet », Hélène 26/08, actée PO) :
   sur SA fiche, le NOM de la pièce est le mot le plus grand de la page — la
   série, répétée huit fois dans la salle, repasse dessous en taille. Avant :
   série 2,4 / nom 2,1 — la graisse seule sauvait la hiérarchie. */
.fi-piece-serie {
    grid-area: 1 / 1;
    font-size: 2rem; font-weight: 200;
    letter-spacing: 0.05em; line-height: 1;
    color: var(--fg, #fff);
}
.fi-piece-nom {
    grid-area: 1 / 1; align-self: end; justify-self: start;
    transform: translate(-2px, 58%);
    font-size: 2.6rem; font-weight: 600; line-height: 1.05;
    color: var(--fg, #fff);
    text-shadow: var(--shadow-text-strong, 0 1px 4px rgba(0, 0, 0, .45));
}
/* Collées sous le nom (PO 26/08, resserré deux fois) : à 2,6 rem le débord
   du nom superposé fait ~26 px — 32 (la marche « groupe » de la gamme) le
   rend et rien de plus : les dimensions le touchent presque. */
.fi-titre-piece + .fi-format { margin-top: 32px; }

/* ── LA PISTE A « CARTEL COMPLET » (Hélène 26/08, actée PO après sonde) ────
   La fiche sculpture EST un cartel de galerie : complet (cotes légendées,
   édition laconique, prix en ligne de cartel dès le premier écran), un récit
   ouvert par la provenance, et UN SEUL moment de transaction, après les
   vues. L'ordre des blocs vit dans le gabarit ; ici, la voix et la gamme. */

/* Le prix en ligne de cartel : la boîte de verre tombe, la voix étiquette
   reste — la question est répondue, elle ne s'achète pas ici. */
.fi-prix--cartel {
    margin-top: 4px; padding: 0;
    border: 0; border-radius: 0; background: none;
}
.fi-prix--cartel .fi-montant {
    font-size: 0.88rem; font-weight: 400;
    color: var(--fg-soft, rgba(255, 255, 255, .85));
    text-shadow: var(--shadow-text);
}

/* L'exergue de provenance, en tête de récit — voix légende, barre d'accent. */
.fi-exergue {
    padding-left: 10px;
    border-left: 2px solid var(--accent, #b4cd00);
    font-size: 0.82rem; font-weight: 400;
    letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--fg-soft, rgba(255, 255, 255, .85));
    text-shadow: var(--shadow-text);
}

/* La rubrique redevient rubrique : 28 px, SOUS le nom de la pièce (41,6) —
   « La pièce en situation » était le plus gros mot de la page (35,2). Vaut
   pour toute fiche /nu/ : aucun h1 de fiche ne descend sous 28. */
.nu-corps.fiche .fi-suggest-titre { font-size: 1.75rem; }

/* LA GAMME D'ESPACEMENT — trois marches (16 paragraphe / 32 groupe /
   64 section) au lieu des dix valeurs relevées au câble le 26/08. Le 64 est
   cohérent avec la respiration de la salle (72-128, univers-galerie.css :
   « le vide est la moitié du travail ») un cran dessous. Scopé volume : les
   peintures gardent leur loi du 15/08. */
.nu-corps.fiche--volume .fi-ouverture { margin-top: 32px; }
.nu-corps.fiche--volume section.v3d { margin-top: 32px; }
.nu-corps.fiche--volume .fi-exergue { margin: 64px 0 16px; }
.nu-corps.fiche--volume .nu-intro { margin-top: 64px; }
.nu-corps.fiche--volume .fi-exergue + .nu-intro { margin-top: 0; }
.nu-corps.fiche--volume > h2 { margin: 32px 0 16px; }
.nu-corps.fiche--volume .fi-galerie-bloc { margin-top: 64px; }

/* ESSAI (PO 05/10) : LE FILM DE LA PIÈCE EN FOND DE FICHE, téléphone seulement.
   Fenêtre `clip-path` + pin `fixed` (le patron de `.qsj-fenetre`) : l'image ne
   défile jamais, quelle que soit la hauteur de la fiche. Le voile est un fond
   peint dans le pin, pas une opacité animée. Réglage : `--fi-voile`. */
.fi-film { position: absolute; inset: 0; z-index: -1; pointer-events: none;
           -webkit-clip-path: inset(0); clip-path: inset(0); }
.fi-film .ft-pin { position: fixed; top: 0; left: 0; right: auto; width: 100%;
                   height: 100vh; height: 100lvh; }
.fi-film .ft-pin::before { content: ""; position: absolute; z-index: 1; left: 0; width: 100%; top: -80px;
    height: calc(100% + 80px + 100lvh - 100svh + 100px + env(safe-area-inset-bottom, 0px));
    background: rgba(0, 0, 0, var(--fi-voile, .35)); }
/* La première image du film est dans la page (`src` posé au build) : elle se
   voit avant que le lecteur ait peint, donc dès l'entrée par glissement. */
.fi-film .sq-img { opacity: 1; }
/* VERDICT iPhone du PO (05/10) : en `fixed`, le film est rogné aux bandes d'iOS
   (bande taupe en haut et en bas), alors que le corner les traverse. C'est la
   loi du 21/08 : seul `animation-timeline` laisse les barres traversantes. Le
   pin repasse donc dans la couche de défilement, tenu par une animation liée
   au défilement comme au corner ; sa course est la hauteur de la boîte moins
   l'écran, lue en `cqh` (la boîte est son propre conteneur de taille). Le
   montage `fixed` ci-dessus reste le repli des moteurs sans la propriété. */
@supports (animation-timeline: view()) {
    /* La boîte déborde de `.nu-corps` jusqu'aux bords de `.page` (ses marges :
       nu-chrome.css:395-398, nu.css:42), sinon le film commence sous l'en-tête
       et s'arrête dans les marges latérales. Elle s'arrête au pied de page. */
    .fi-film { container-type: size; view-timeline: --fi-boite block;
               -webkit-clip-path: none; clip-path: none;
               /* Le débord du film sous le pin allongeait le document de 100 px
                  tout en bas : la boîte, qui couvre déjà tout le document, le rogne. */
               overflow: clip;
               top: calc(0px - var(--brand-h) - env(safe-area-inset-top)); bottom: -80px; left: -50px; right: -50px; }
    .fi-film .ft-pin {
        position: absolute;
        animation-name: fi-epingle;
        animation-timing-function: linear;
        animation-fill-mode: both;
        animation-timeline: --fi-boite;
        animation-range: contain 0% contain 100%;
    }
}
/* Le film passe sous le pied de page, qui reste lisible devant lui.
   ⛔ PAS DE TEINTE DE RACINE ICI pour la bande d'arrivée : c'est la piste ① à ③
   du 07/09 (plus haut dans ce fichier), bloquée par `nuHabille`. */
@supports (animation-timeline: view()) {
    .page:has(.fi-film) ~ .nu-pied { position: relative; z-index: 2; }
}
/* ESSAI : L'AMORCE DU CORNER SUR LA FICHE (PO 05/10). La page s'ouvre défilée
   de `--ft-amorce` (nu-film.js, `poseLAmorce`) ; ces 90 px au-dessus d'elle
   logent le débord haut du film, qui sans eux tombe hors du document. La boîte
   remonte d'autant pour ne pas rogner ce débord. */
@supports (animation-timeline: view()) {
    @media (max-width: 1023px) {
        .page:has(.fi-film) { margin-top: var(--ft-amorce, 90px); }
        .fi-film { top: calc(0px - var(--brand-h) - env(safe-area-inset-top) - var(--ft-amorce, 90px)); }
    }
}
/* PENDANT UN GLISSEMENT (enregistrement d'écran du PO, 06/10 17:29) :
   ① dans le calque `.pane`, l'animation liée au défilement plaçait le film de
      la fiche entrante environ 175 px sous le haut de l'écran : on la coupe et
      on pose le pin à la main, à l'amorce près (le calque est remonté d'autant
      par `nuCale`). ponytail: vaut pour une entrée par le haut de fiche ; une
      entrée par le bas (geste nord) demanderait la hauteur de la boîte.
   ② le décor embossé passe au-dessus du calque (`html:has(.pane) body::after`,
      nu-chrome.css) : sur un film il se lit en surimpression. Il se tait comme
      sur un corner à film. */
@supports (animation-timeline: view()) {
    @media (max-width: 1023px) {
        /* ③ (second enregistrement, 18:44) : le même décalage frappe TOUTE page
           transformée, pas seulement le calque : la page qu'on quitte, et la
           page promue tant qu'elle garde la translation de `nuCale` (une
           bande sombre en haut, qui « remonte » après l'arrivée). La règle
           suit donc la transformation en ligne de `.page` ; `--fi-y` est posé
           par `nuHabille` sur la page qui part (son défilement), et vaut
           l'amorce pour une page qui entre. */
        .page[style*="transform"] .fi-film .ft-pin { animation: none; transform: translateY(var(--fi-y, var(--ft-amorce, 90px))); }
        html:has(.fi-film) body::after { opacity: 0; }
        /* ④ LA BANDE SOMBRE DU TRANSPORT (mesure en mouvement du 06/10 : la
           géométrie est juste à chaque image, c'est donc la peinture) : sous
           une page transformée, WebKit applique le `overflow-x: clip` de
           `.nu-corps.fiche` AUSSI en vertical à ce qu'il compose à part. Le
           film, qui déborde de la boîte vers le haut (marge de `.page`) et sur
           les côtés, était rogné à son bord : bande jusque sous le logo. La
           page (nu.css:40) rogne déjà l'horizontal, cette boîte n'en a pas
           besoin ici. */
        .nu-corps.fiche:has(> .fi-film) { overflow-x: visible; }
        /* Le bloc « Retour au corner » porte le taupe du sol, invisible sur une
           fiche ordinaire : sur le film il fait un pavé (vu sur l'iPhone du PO). */
        .nu-corps.fiche:has(> .fi-film) .nu-retour { background: none; }
    }
}
@keyframes fi-epingle {
    from { transform: translateY(0); }
    to   { transform: translateY(calc(100cqh - 100lvh)); }
}
.nu-corps.fiche--volume .fi-galerie-bloc + .fi-prix { margin-top: 64px; }
.nu-corps.fiche--volume .fi-cta { margin-top: 16px; }
.nu-corps.fiche--volume .fi-cta-note { margin-top: 16px; }
.nu-corps.fiche--volume .nu-retour { margin-top: 64px; }
/* ── L'ACCUEIL AU BUREAU (PO 26/09, 10:20) : LA HOME DE DEV, SURCHARGÉE ────
   Même HTML que le téléphone ; tout ce qui suit ne vaut qu'au-delà de 1023 px.
   · Retirés au bureau : les deux portes et `.hm-ame` (« ça n'a rien à faire
     sur la page d'accueil », PO). Ils restent au téléphone.
   · Le bloc de nom de dev (#titresFlow : bas gauche, nom 4rem, sous-titre
     3rem), repris sur le DOM mobile : `.hm-name` (le h1, masqué au téléphone
     où la signature porte le nom) redevient visible, `.hm-role` passe dessous.
   · Nouveaux et propres au bureau : la baseline et les réseaux (masqués au
     téléphone juste ici).
   · Le HALO de dev (hello-child-ai/style.css:136-142, « Organic Blur Ball ») :
     une loupe floue de 8rem, masque radial, qui dérive sur le nom (20 s) et sur
     le sous-titre (30 s). Recopié à l'identique, tailles en `--k`, flou
     préfixé AVANT le standard (règle du minifieur, verifie-flou).
   Tailles en calc(base * var(--k)) À PLAT (fluid-scale, nu-chrome.css). */
.page--accueil .hm-baseline, .page--accueil .hm-suivre { display: none; }
@media not all and (max-width: 1023px) {
    html.nu .page--accueil .hm-doors, html.nu .page--accueil .hm-ame { display: none; }
    /* Pleine hauteur au bureau (la colonne de 100svh n'est posée qu'au
       téléphone) : le bloc de nom tombe en bas à gauche comme sur dev, le
       pied se range sous lui, à gauche, à sa largeur de texte (sa boîte
       pleine largeur passait sous l'index et les flèches). */
    html.nu .page--accueil { display: flex; flex-direction: column; min-height: 100svh; }
    html.nu .page--accueil .hm-body { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; padding-bottom: calc(36px * var(--k)); }
    html.nu .page--accueil .nu-pied {
        width: fit-content; margin: 0 auto 0 0; text-align: left;
        padding: 0 0 calc(8px * var(--k)) calc(96px * var(--k));
    }
    /* PO 06/10 (croquis sur capture) : le bloc de nom quitte le bas de page et
       se centre sur la médiane de l'écran, à la hauteur de « Accueil » dans
       l'index. Le pied reste en bas à gauche. */
    html.nu .page--accueil .hm-identity {
        text-align: left; padding: 0 0 0 calc(96px * var(--k));
        max-width: calc(760px * var(--k));
        position: absolute; top: 50svh; transform: translateY(-50%);
    }
    html.nu .page--accueil .hm-name {
        position: relative; width: auto; height: auto; overflow: visible; clip-path: none;
        font-size: calc(64px * var(--k)); font-weight: 700; line-height: 1; letter-spacing: -0.01em;
        color: var(--fg); margin: 0;
    }
    html.nu .page--accueil .hm-role {
        position: relative; margin-top: calc(10px * var(--k));
        font-size: calc(44px * var(--k)); line-height: 1.05; white-space: nowrap;
    }
    html.nu .page--accueil .hm-baseline {
        display: block; margin-top: calc(22px * var(--k));
        font-size: calc(21px * var(--k)); line-height: 1.4; font-weight: 400;
        color: var(--fg); max-width: 32em;
    }
    html.nu .page--accueil .hm-suivre { display: block; margin-top: calc(26px * var(--k)); }
    html.nu .page--accueil .hm-suivre__t { font-size: calc(15px * var(--k)); color: var(--fg); margin: 0; }
    html.nu .page--accueil .hm-reseaux {
        display: flex; gap: calc(6px * var(--k)); margin: calc(6px * var(--k)) 0 0 calc(-10px * var(--k));
        padding: 0; list-style: none;
    }
    html.nu .page--accueil .hm-reseaux a {
        display: flex; align-items: center; justify-content: center;
        width: calc(44px * var(--k)); height: calc(44px * var(--k));
        color: var(--fg); transition: color 0.25s ease;
        /* nu.css habille `nav a` et `a` en capsule : on rétablit. */
        border: 0; border-radius: 0; background: none; padding: 0;
    }
    html.nu .page--accueil .hm-reseaux a:hover { color: var(--accent); }
    html.nu .page--accueil .hm-reseaux a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
    html.nu .page--accueil .hm-reseaux svg { width: calc(22px * var(--k)); height: calc(22px * var(--k)); }
    /* LE HALO (dev, à l'identique) */
    html.nu .page--accueil :is(.hm-name, .hm-role)::after {
        content: ''; position: absolute; top: -100%; left: -50%; width: 160%; height: 300%;
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
        -webkit-mask-image: radial-gradient(closest-side, black 0%, transparent 80%);
        mask-image: radial-gradient(closest-side, black 0%, transparent 80%);
        -webkit-mask-size: calc(128px * var(--k)) calc(128px * var(--k));
        mask-size: calc(128px * var(--k)) calc(128px * var(--k));
        -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
        pointer-events: none; z-index: 2;
        animation: nu-halo-1 20s infinite linear;
    }
    html.nu .page--accueil .hm-role::after { animation: nu-halo-2 30s infinite linear; }
}
/* ── LA BOUTIQUE AU BUREAU (PO 27/09) : LA BOUTIQUE DE DEV ──────────────────
   Mise en page relevée sur dev.crealab.shop/boutique/ (Playwright, 1440) :
   une section par scène, fond `cover` FIXE sous un dégradé
   rgb(23,20,3) → transparent à 65 % ; carte de verre (padding 48, rayon 24,
   flou 8 px + luminosité 0,97, ombre et double liseré intérieur) ; titres en
   46,08 px graisse 400 ; compte 21,6 ; texte 19,2 (20,8 dans l'entrée) ;
   bouton vert #B4CD00, texte blanc 14,4 graisse 600, rayon 3 ; fil d'Ariane
   16 px, lien vert ; « Mes Collections » 78,4 px en bas de l'entrée.
   Deux écarts VOULUS, dictés par le cadrage (livrables/cadrage_desktop-nu_v1.md) :
   · pas de zoom global : les valeurs de dev × `--k` (comme l'accueil), ce qui
     rend le texte à ~17 px au lieu des 11,9 de dev ;
   · la carte bornée à 760k (celle de dev mesurait 1 084 px avant zoom, soit
     ~100 caractères par ligne à cette taille) : 60 à 75 caractères.
   Scènes à 100vh (PO 27/09 ; dev les faisait à 78 % de l'écran). Le pied du
   corps devient une BANDE collée en bas (sticky), sur toute la largeur (PO
   27/09) : signature à gauche, mentions à droite, le centre et les coins
   laissés libres pour le chevron sud, le plan et le contact. Sur les photos,
   un voile sombre flouté le garde lisible. Sous 1024 px, rien : le bloc est
   masqué et le pied reste celui de toutes les pages. */
.bq-bureau { display: none; }
@media not all and (max-width: 1023px) {
    html.nu .page--boutique { padding: 0; }
    html.nu .page--boutique .nu-corps { display: none; }
    html.nu .page--boutique .bq-bureau { display: block; }
    html.nu .bq-scene {
        position: relative; display: flex; flex-direction: column; justify-content: center; align-items: flex-start;
        min-height: 100vh; padding: calc(80px * var(--k));
        background-image: linear-gradient(90deg, rgb(23, 20, 3) 0%, rgba(0, 0, 0, 0) 65%), var(--bq-fond);
        background-size: auto, cover; background-position: center, center;
        background-attachment: scroll, fixed; background-repeat: no-repeat;
        color: #fff;
    }
    /* L'entrée laisse la place de la marque au-dessus de sa carte, comme dev
       (padding 80 en tête, la carte centrée dans ce qui reste). */
    /* Le bas de l'entrée réserve la place du grand titre (posé en absolu
       au-dessus de la bande du pied) : la carte se centre dans ce qui reste. */
    html.nu .bq-scene--entree { padding-top: calc(var(--brand-h) + 24px); padding-bottom: calc(210px * var(--k)); }
    html.nu .bq-verre {
        position: relative; z-index: 2;
        width: calc(760px * var(--k)); max-width: 100%;
        padding: calc(48px * var(--k)); border-radius: 24px;
        box-shadow: rgba(0, 0, 0, 0.1) 0 4px 30px 0, rgba(255, 255, 255, 0.5) 1px 1px 1px 0 inset, rgba(0, 0, 0, 0.15) -1px -1px 1px 0 inset;
        -webkit-backdrop-filter: blur(8px) brightness(0.97);
        backdrop-filter: blur(8px) brightness(0.97);
    }
    html.nu .bq-ariane { font-size: calc(16px * var(--k)); line-height: 1.5; margin: 0 0 calc(4px * var(--k)); }
    html.nu .bq-ariane a {
        color: #b4cd00; text-decoration: none;
        /* nu.css habille `nav a` en capsule : on rétablit. */
        border: 0; border-radius: 0; background: none; padding: 0;
    }
    html.nu .bq-ariane a:focus-visible { outline: 2px solid #b4cd00; outline-offset: 2px; }
    html.nu .bq-titre {
        margin: 0; font-size: calc(46.08px * var(--k)); font-weight: 400; line-height: 1;
        letter-spacing: -0.432px; color: #fff;
    }
    html.nu .bq-compte { margin: calc(8px * var(--k)) 0 calc(14.4px * var(--k)); font-size: calc(21.6px * var(--k)); line-height: 1.1; }
    html.nu .bq-texte p { margin: 0 0 calc(14.4px * var(--k)); font-size: calc(19.2px * var(--k)); line-height: 1.45; color: #fff; }
    html.nu .bq-scene--entree .bq-titre { margin-bottom: calc(18px * var(--k)); }
    html.nu .bq-scene--entree .bq-texte p { font-size: calc(20.8px * var(--k)); }
    html.nu .bq-texte .bq-intro { font-weight: 700; }
    html.nu .bq-texte strong { font-weight: 700; }
    html.nu .bq-bouton {
        display: inline-flex; align-items: center; gap: calc(14.4px * var(--k));
        align-self: flex-end; float: right; margin-top: calc(6px * var(--k));
        padding: calc(7.2px * var(--k)) calc(14.4px * var(--k)); border-radius: 3px; border: 0;
        background: #b4cd00; color: #fff; text-decoration: none;
        font-size: calc(14.4px * var(--k)); font-weight: 600; line-height: 1;
    }
    html.nu .bq-bouton svg { width: calc(9px * var(--k)); height: calc(9px * var(--k)); }
    html.nu .bq-bouton:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
    html.nu .bq-verre::after { content: ''; display: block; clear: both; }
    html.nu .bq-h2 {
        position: absolute; left: calc(80px * var(--k)); bottom: calc(96px * var(--k)); z-index: 5; margin: 0;
        font-size: calc(78.4px * var(--k)); font-weight: 400; line-height: 1; letter-spacing: -1.44px; color: #fff;
    }
    /* LE DÉTAIL, MIS EN VALEUR (PO 27/09 : « plus gros, une meilleure mise en
       page », puis « à droite des blocs, en conservant le léger
       chevauchement ») : la pièce tirée sort à DROITE de la carte, dans sa
       bloc de verre, et mord de 25k sur le bord de la carte (réglage PO ;
       moins que ses 48k de marge : jamais sur le texte) ; son nom dessous,
       en lien vers sa fiche. La carte garde sa colonne unique de 760k.
       Échelle : la pièce tient dans sa boîte (contain), sculpture et tableau
       posés en bas ; le bijou garde son écrin cadré sur l'objet
       (--ox/--oy/--kb, reflet gardé). */
    html.nu .bq-tete .bq-compte { margin-bottom: calc(14.4px * var(--k)); }
    /* Posée nue sur la photo, la pièce se mêlait au sujet de la scène (une
       sculpture sur une sculpture) et son nom ne se lisait pas : elle a donc
       SON bloc de verre, du même verre que la carte, qui chevauche la carte. */
    html.nu .bq-bloc { position: relative; max-width: 100%; }
    html.nu .bq-vitrine {
        position: absolute; z-index: 3;
        left: calc(100% - 25px * var(--k)); top: 50%; transform: translateY(-64%);   /* chevauchement 25k (réglage PO 27/09), jamais sur le texte ; remonté (PO 27/09) */
    }
    html.nu .bq-vitrine-carte {
        position: relative; z-index: 1;
        display: flex; flex-direction: column; align-items: center;
        padding: calc(24px * var(--k)) calc(24px * var(--k)) calc(20px * var(--k));
        border-radius: 24px;
        box-shadow: rgba(0, 0, 0, 0.1) 0 4px 30px 0, rgba(255, 255, 255, 0.5) 1px 1px 1px 0 inset, rgba(0, 0, 0, 0.15) -1px -1px 1px 0 inset;
        /* Teintée, flou léger : réglage du PO (27/09, blur(2px) brightness(1)). */
        background: rgba(23, 20, 16, 0.3);
        -webkit-backdrop-filter: blur(2px) brightness(1);
        backdrop-filter: blur(2px) brightness(1);
    }
    html.nu .bq-legende { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); }
    /* « PAS QUE CET EXEMPLE » (PO 27/09) : la ligne « Au hasard parmi N »
       au-dessus de la pièce, et deux cartes décalées DERRIÈRE le bloc, qui en
       font le dessus d'une pile. Floutées elles aussi (PO 27/09 : « passe un
       flou en fond de carte ») : ce sont donc des éléments SŒURS de la carte,
       pas ses pseudo-éléments (un flou posé dans un élément qui floute déjà
       ne voit rien derrière lui). */
    html.nu .bq-hasard {
        margin: 0 0 calc(10px * var(--k)); align-self: stretch; text-align: center;
        font-size: calc(13px * var(--k)); letter-spacing: 0.06em; text-transform: uppercase;
        color: rgba(255, 255, 255, 0.82); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
    }
    html.nu .bq-pile {
        position: absolute; inset: 0; z-index: 0; border-radius: 24px;
        /* Réglage du PO dans ses DevTools (27/09) : sans fond, flou de 3 px. */
        border: 1px solid rgba(255, 255, 255, 0.28);
        -webkit-backdrop-filter: blur(3px);
        backdrop-filter: blur(3px);
        pointer-events: none;
    }
    html.nu .bq-pile--1 { transform: translate(calc(10px * var(--k)), calc(-10px * var(--k))) rotate(3deg); }
    html.nu .bq-pile--2 { transform: translate(calc(20px * var(--k)), calc(-18px * var(--k))) rotate(6deg); border-color: rgba(255, 255, 255, 0.18); }
    html.nu .bq-detail {
        position: relative; inset: auto;
        width: calc(260px * var(--k)); height: calc(290px * var(--k));
    }
    html.nu .bq-detail .bd-item {
        left: 50%; bottom: 0; top: auto;
        width: auto; height: auto; max-width: 100%; max-height: 100%;
        transform: translateX(-50%);
    }
    html.nu .bq-detail--sculptures .bd-item { height: 100%; }
    html.nu .bq-detail--peintures .bd-item { max-width: 96%; max-height: 92%; bottom: 4%; transform: translateX(-50%) rotate(1.6deg); }
    html.nu .bq-detail--bijoux .bd-item {
        left: 50%; top: 50%; bottom: auto;
        height: 100%; width: auto; max-width: none; max-height: none;
        transform-origin: var(--ox, 50%) var(--oy, 50%);
        transform: translate(calc(var(--ox, 50%) * -1), calc(var(--oy, 50%) * -1)) scale(var(--kb, 1));
    }
    html.nu .bq-legende {
        margin-top: calc(10px * var(--k));
        font-size: calc(16px * var(--k)); line-height: 1.2; color: #fff; text-align: center;
        text-decoration: none; border: 0; border-bottom: 1px solid rgba(255, 255, 255, 0.45);
        background: none; border-radius: 0; padding: 0 0 2px;
    }
    html.nu .bq-legende:hover { border-bottom-color: #b4cd00; }
    html.nu .bq-legende:focus-visible { outline: 2px solid #b4cd00; outline-offset: 3px; }
    /* LE PIED CANONIQUE DU BUREAU. La bande née sur le hub puis validée sur
       le corner Sculptures est celle de TOUTES les pages intérieures. La
       home reste la seule exception : son pied vit dans sa composition et
       garde son calage propre. Ne jamais ajouter ici une liste de pages. */
    html.nu:not(:has(.page--accueil)) body > .nu-pied {
        position: sticky; bottom: 0; z-index: 8;   /* sous le chrome (boussole 9, pictos 10) */
        display: flex; justify-content: space-between; align-items: center; gap: calc(24px * var(--k));
        /* UN SEUL AXE pour tout le bas (PO 27/09 : « tout aligné ») : les pictos
           plan et enveloppe sont centrés à 10k + 24k du bord (boîte de 48k à
           10k) ; la bande fait 68k, son contenu se centre donc sur le même axe.
           ET PAS DE PLACE EN FIN DE PAGE (PO : « la marge sous la dernière
           section sert à rien ») : la marge négative rend sa hauteur, la bande
           se pose sur le bas de la dernière scène au lieu de l'allonger.
           Colonnes : 80k à gauche et à droite, celles des cartes, du grand
           titre et des mentions IA. */
        height: calc(68px * var(--k)); margin-top: calc(-68px * var(--k));
        padding: 0 calc(80px * var(--k));
        text-align: left; font-size: calc(12px * var(--k));
        background: rgba(30, 27, 24, 0.55);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
    }
    html.nu:not(:has(.page--accueil)) body > .nu-pied p { margin: 0; }
    html.nu:not(:has(.page--accueil)) body > .nu-pied .nu-pied-legal { text-align: right; }
    /* Le long corner Peintures garde le pied canonique, mais dans le flux :
       collant, il rayait les premières œuvres et masquait le premier cartel
       sur les portables 1280 × 800. La marge négative conserve son calage sur
       la respiration finale sans lui redonner une seconde hauteur. */
    html.nu:has(.page--peintures-bureau) body > .nu-pied,
    html.nu:has(.page--bijoux-bureau) body > .nu-pied {
        position: static;
        bottom: auto;
    }
    /* Le chevron sud (libellé + flèche, 62k de haut) centré sur le même axe :
       34k − 31k = 3k du bord, au lieu de 8k. */
    html.nu:not(:has(.page--accueil)) .cp--s { bottom: calc(3px * var(--k) + env(safe-area-inset-bottom)); }
    /* La flèche d'indice (boîte fixe de 48 px, nu-chrome.css) sur le même axe :
       centre à 34k du bord, donc 34k − 24 px (PO 27/09). */
    html.nu:has(.page--boutique) .hint-defiler { bottom: calc(34px * var(--k) - 24px + env(safe-area-inset-bottom)); }
    html.nu .bq-mention {
        position: absolute; right: calc(80px * var(--k)); bottom: calc(82px * var(--k)); margin: 0;   /* colonne droite commune, au-dessus de la bande */
        font-size: calc(12px * var(--k)); color: rgba(255, 255, 255, 0.8);
    }
}

/* `not` nierait toute la requête : le halo n'existe qu'au bureau (son
   `content` n'est posé que là), la garde de mouvement peut donc rester seule. */
@media (prefers-reduced-motion: reduce) {
    html.nu .page--accueil :is(.hm-name, .hm-role)::after { animation: none; opacity: 0; }
}
@keyframes nu-halo-1 {
    0% { -webkit-mask-position: -20% 50%; mask-position: -20% 50%; opacity: 0; }
    33% { filter: contrast(1); -webkit-mask-position: 30% 20%; mask-position: 30% 20%; opacity: 1; }
    66% { filter: contrast(2); -webkit-mask-position: 60% 80%; mask-position: 60% 80%; opacity: 1; }
    100% { filter: contrast(1); -webkit-mask-position: 120% 40%; mask-position: 120% 40%; opacity: 0; }
}
@keyframes nu-halo-2 {
    0% { -webkit-mask-position: -20% 80%; mask-position: -20% 80%; opacity: 0; }
    50% { filter: contrast(1); -webkit-mask-position: 50% 10%; mask-position: 50% 10%; opacity: 1; }
    70% { filter: contrast(2); opacity: 1; }
    100% { -webkit-mask-position: 120% 70%; mask-position: 120% 70%; opacity: 0; }
}

/* La table de dev (accueil au bureau) : voir nu-accueil.css. */
.ab-pile { display: none; }
/* L'hôte de l'accueil n'existe qu'au bureau, une fois placé (nu-accueil.css) :
   jamais rendu ici, donc jamais monté ni préchauffé. */
.pa-perso { display: none; }

/* ── L'ACCUEIL ISO (PO 27/08, 2e tour) : un seul écran, portes PLEINES ────
   Verdict PO sur le 1er tour (portes réduites à 190 centrées sur l'axe) :
   « c'est moche, tu as transformé les portes en carré — on avait des marges
   à réduire ». Leçon : la variable libre, ce sont les MARGES, jamais les
   portes. Ici : hauteur 100svh (le seul viewport constant de cet iOS, mémo
   23/08 ; l'accueil s'atteint par vrai chargement) + resserrage — identité
   (padding 26→8, interlignes), gap du corps 26→14, pied dégraissé et rendu
   à la réserve du bas. Les portes gardent leur min(42svh, 320) d'origine ;
   le centrage exact sur l'axe (50svh) reste géométriquement incompatible
   avec des portes de 320 (l'identité seule descend à ~300) — le flux les
   pose au plus près. */
.page--accueil { height: 100svh; overflow: clip; display: flex; flex-direction: column; }
/* ⚠️ PADDING LATÉRAL RETIRÉ (28/08) — le titre en avait besoin, pas le bloc.
   « digital » est devenu « numérique » (anglicisme + incohérence interne) et
   la ligne est passée à TROIS rangs, décalant toute la page : mesuré au
   câble, « Créateur numérique » réclame 314 px et les 24 px de padling de
   chaque côté n'en laissaient que 292. Deux issues : rapetisser le titre, ou
   lui rendre la largeur. On rend la largeur — le PO a demandé ce titre À LA
   TAILLE DES H1 DE CORNER, ce n'est pas au wording de faire plier la
   typographie. Reste 340 px, soit 26 px de marge. `.hm-ame` garde sa propre
   laisse (`max-width: 34ch`), elle ne s'élargit donc pas.
   12 en haut : la signature grossie descend plus bas. */
.page--accueil .hm-identity { padding: 12px 0 0; }
/* « Jocelyn Bouget » est dit DEUX FOIS sur l'accueil (PO 27/08) : la
   signature manuscrite verte de la marque le dit déjà, en mieux. Le nom
   RESTE dans le DOM — lecteurs d'écran et crawlers le lisent, le title et
   la description le portent aussi, le référencement ne perd rien — mais
   l'écran ne le répète plus : patron sr-only, pas un display:none (qui le
   retirerait de l'accessibilité avec). */
.page--accueil .hm-name {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
/* Centré et resserré (PO 27/08) — la signature grossie porte le nom,
   les deux lignes de texte se rangent sous elle, au centre. */
.page--accueil .hm-identity { text-align: center; }
/* ⛔ LES TROIS LIENS DU PIED : ESSAI D'ÉLARGISSEMENT AU DOIGT, RÉFUTÉ PAR LA
   MESURE (28/08). Ils font 15 px de haut — exemptés par WCAG 2.2 (liens EN
   LIGNE dans une phrase), mais pénibles au doigt. Le padding d'un élément en
   ligne agrandit la zone de tap sans pousser la ligne : `padding: 8px 3px`
   posé, puis mesuré sur l'appareil — et c'est là que ça casse. Je tablais sur
   17 px entre les zones des deux lignes ; il y en a **2** (interligne 17 px
   pour un texte de 15 px). Les zones se chevauchaient donc de 14 px, et le
   test de survol l'a montré : « Conditions de commande » VOLAIT les taps de
   « Confidentialité » (le dernier dans le DOM gagne). Cible obtenue 31 px,
   mais un lien sur deux devenu intouchable — pire que le défaut.
   CE QU'IL FAUDRAIT VRAIMENT : aérer l'interligne du pied. À 28 px on tient
   des cibles de 27 px sans chevauchement, au prix de +22 px de hauteur (la
   garde du bas passerait de 57 à 35 px). Pour atteindre les 44 px de l'AAA il
   faudrait ~44 px d'interligne, soit +54 px : la garde tomberait à 3 px et
   l'écran unique sauterait. C'est donc un arbitrage de MISE EN PAGE sur une
   page validée, pas un réglage — il attend le PO. Ne pas reposer le padding
   sans toucher à l'interligne d'abord. */
/* « Créateur digital & Artiste » DEVIENT LE TITRE DE LA PAGE (PO 28/08 :
   « passe-le en titre blanc, comme le "La Boutique d'Art" »). Le h1 réel
   est le nom, sr-only juste au-dessus — c'est la signature verte qui le
   porte à l'écran ; cette ligne est donc le titre VU de la home, et elle
   prend exactement le costume des H1 de corner (`.nu-corps h1`, l.67) :
   mêmes clamp, interligne, approche, et le blanc plein au lieu du muted. */
.page--accueil .hm-role {
    margin-top: 0;
    font-size: clamp(28px, 8vw, 40px);
    font-weight: 700;
    /* Interlignage RESSERRÉ à 0,95 (PO 28/08) — sous le 1.08 des H1 de
       corner, qui sont eux sur UNE ligne : ici le titre en fait deux, et
       deux lignes de titre se tiennent plus près qu'un rang isolé. */
    line-height: 0.95;
    letter-spacing: -0.02em;
    color: var(--fg);
}
.page--accueil .hm-ame { margin-top: 6px; margin-inline: auto; }
/* flex-start et non center (PO : « les portes peuvent remonter ») : le
   justify-center rendait la moitié du vide gagné AU-DESSUS de l'identité —
   collé en haut, tout le gain descend sous les portes et elles remontent
   vers l'axe des boutons. */
.page--accueil .hm-body { gap: 14px; justify-content: flex-start; }
/* Le costume générique de l'arbre (nu.css : `nav` = 28px de marge, `nav a`
   = bordure #111) habillait les portes en boutons de labo — même piège que
   le retour de la fiche. Le gap du corps suffit, le liseret du verre est le
   seul cadre légitime. */
.page--accueil .hm-doors { margin: 0; }
/* Rangs alignés en miroir (PO 27/08 : cap / titre / 2 lignes de sous-titre) :
   « La Boutique d'Art » passait sur 2 lignes à 136 px utiles (mesuré 42 px
   contre 21 côté Studio) — les DEUX titres descendent d'un cran et tiennent
   la ligne. */
.page--accueil .hm-door__t { font-size: 1.02rem; white-space: nowrap; }
/* FERRÉES SUR LEURS FLÈCHES (essai PO 27/08) : l'arbre réserve DÉJÀ 50 px
   de couloirs de boussole — le padding 46 de home.css (fait pour un écran
   sans rails) s'y AJOUTAIT : des portes de 118 px flottant loin des
   flèches. À zéro, chaque porte s'appuie contre le rail de la sienne. */
.page--accueil .hm-doors { padding: 0; }
.page--accueil .hm-door { border: 0; }
/* La marge portes→copyright (PO : « passe une marge ») se prend DANS le
   pied : la colonne est PLEINE (mesuré : corps étiré + pied remplissent les
   796 px exactement, un margin-top:auto n'a rien à absorber) — on bascule
   18 px du padding bas (la réserve avait du gras) vers le haut : même
   hauteur totale, le © descend de 18, les mentions restent au-dessus de la
   porte basse (fin ~738 pour un chrome à 744). */
.page--accueil .nu-pied { padding: 28px 46px calc(var(--bottom-reserve, 70px) - 12px); }

/* ── LE PIED DE L'ARBRE ────────────────────────────────────────────────────
   Porté de `home.css` (.hm-footer) le 28/08, aux mêmes valeurs : cette
   feuille-là n'est importée que par l'accueil, or le pied vit maintenant sur
   TOUTES les pages (composant NuPied — les trois liens légaux n'existaient
   que sur la home). La règle `.page--accueil` juste au-dessus garde à
   l'accueil son calage validé ; ce bloc-ci sert partout ailleurs.
   La garde du bas reprend `--bottom-reserve` : les deux pictogrammes
   flottants du chrome vivent là, le pied ne doit pas passer dessous. */
.nu-pied {
    padding: 34px 46px calc(var(--bottom-reserve, 70px) + 6px);
    text-align: center;
    font-size: 0.72rem; line-height: 1.5;
    color: var(--fg-muted, rgba(255, 255, 255, .62));
    text-shadow: var(--shadow-text, 0 1px 3px rgba(0, 0, 0, .35));
}
.nu-pied-legal { margin-top: 3px; }
/* ── LE PIED COMPACTÉ SUR LES PAGES À FILM (29/08, demande PO) ────────────
   Constat PO à l'écran, sur le bas de Mon Amour : « une bande grise ». C'est
   ce pied — posé la veille pour que les liens légaux existent ailleurs que
   sur l'accueil — qui ajoute sa hauteur APRÈS la dernière image plein écran.
   Mesuré sur l'appareil : 193 px, soit 34 de padding haut + 54 de texte +
   76 de garde basse.
   On ne récupère QUE le haut, et c'est délibéré :
   · LA GARDE BASSE EST INCOMPRESSIBLE — les deux pictogrammes flottants du
     chrome vivent là (48 px de haut, à 10 px du bord) ; sous 58 px le texte
     passerait derrière eux ;
   · L'INTERLIGNE DES LIENS LÉGAUX NE BOUGE PAS — leurs cibles tactiles sont
     déjà en dette à 15 px, et le correctif reconnu est de les AÉRER. Les
     resserrer pour gagner des pixels irait contre.
   ⛔ ET ON NE TOUCHE PAS AU PIN. `overflow: clip` sur `.ft-pin` a été essayé
   en direct sur l'iPhone du PO le 29/08 : il supprimait bien les 180 px de
   débord fantôme, mes mesures disaient « plus de gris » — et la page a
   TRIPLÉ de hauteur à l'écran. Le scrub mesure sa propre géométrie ; lui
   retirer son débord fausse la réserve. Réfuté par l'œil, pas par le calcul.
   Sur une page à film il n'y a pas de rédactionnel au-dessus du pied : c'est
   une image qui finit. Le haut n'a donc rien à séparer. */
html:has(.page--film) .nu-pied {
    padding-top: 12px;
    padding-bottom: var(--bottom-reserve, 70px);
}
.nu-pied a { color: var(--fg-muted, rgba(255, 255, 255, .62)); text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, 0.2); }

/* ── LE HUB BOUTIQUE : TROIS PORTES-VITRINES (PO 27/08) ───────────────────
   Le vocabulaire des portes de l'accueil (verre --lg-glass, liseret --lg-rim,
   scrim, squircle), décliné en pleine largeur : un carrefour se lit en liste.
   La VITRINE : une vraie pièce, excentrée à droite et un peu trop grande
   pour la boîte — le teasing, c'est ce qui déborde (rogné par le squircle).
   ⚠️ Le fond photo recule à .32 (l'accueil l'affiche à .55) : ici il porte
   une pièce PAR-DESSUS — deux images qui se disputent l'œil, c'est zéro
   image (« attention aux visuels de fond », PO). Réglage d'œil à affiner. */
/* ⚠️ PAS de gap ici : LES MARGES ENTRE PORTES SONT PILOTÉES PAR L'ITEM TIRÉ
   (PO 27/08) — vitrine.js mesure le débord réel de la pièce élue et donne à
   chaque porte l'air exact qu'elle réclame (un Louboutin vertical en
   demande beaucoup, une bague presque rien). Formule : AIR uniforme (20)
   + débord — voir vitrine.js. Les margin-top ci-dessous ne sont que le
   REPLI sans JS, calibré large sur les premières pièces SSR. */
/* ⚠️ `gap: 0` EXPLICITE, ET C'EST UN CORRECTIF (PO 28/08). `.bd-portes` est
   un <nav>, et le `nav { display: flex; gap: 12px }` générique de nu.css:48
   s'appliquait — alors que le commentaire ci-dessus jure « PAS de gap ici ».
   Mesuré au câble : l'AIR annoncé à 20 px en valait 32 à chaque frontière,
   et la formule des marges pilotées mentait donc de 12 px partout. Le
   costume générique `nav a` avait bien été neutralisé sur `.bd-porte`
   (bordure, padding) — le `gap` du conteneur, lui, avait été oublié. */
.bd-portes { display: flex; flex-direction: column; gap: 0; margin: 10px 0 6px; padding: 0; }
.bd-porte { margin-top: 48px; }
.bd-porte--bijoux { margin-top: 26px; }
.bd-porte {
    position: relative;
    display: block; height: 150px;
    border-radius: var(--r-card, 28px);
    /* ⚠️ PAS d'overflow:hidden ici (PO : « les items doivent SORTIR,
       déborder au-dessus des portes ») : le fond et le scrim se rognent
       eux-mêmes (border-radius:inherit), la vitrine, elle, est libre. */
    background: var(--lg-glass, rgba(255, 255, 255, .04));
    box-shadow: var(--shadow-card), inset 0 0 18px rgba(255, 255, 255, 0.07);
    color: var(--fg); text-decoration: none;
    border: 0; padding: 0; /* le costume `nav a` générique (bordure #111, padding) ne s'applique pas ici */
    transition: transform 0.18s ease;
}
.bd-porte:active { transform: scale(0.985); }
.bd-fond {
    position: absolute; inset: 0;
    border-radius: inherit;
    background-size: cover; background-position: center;
    opacity: 0.32;
}
.bd-porte::after {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    background: linear-gradient(90deg, rgba(40, 37, 33, 0.72), rgba(40, 37, 33, 0.12) 62%);
    pointer-events: none;
}
.bd-porte::before {
    content: '';
    position: absolute; inset: 0;
    border-radius: inherit;
    padding: var(--lg-rim-w, 1px);
    background: var(--lg-rim, rgba(255, 255, 255, .3));
    -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
    mask-composite: exclude;
    pointer-events: none;
    z-index: 3;
}
/* La vitrine, À L'ÉCHELLE PHYSIQUE (PO 27/08, 2e tour : « respecter les
   ratios = une 150 cm plus haute qu'une 90 ») : hauteur rendue = hauteur
   RÉELLE en cm × un px/cm UNIQUE (--kv) — le principe du mur `--cm`,
   décliné en vitrine. Chaque pièce a SA taille : Dentelle (83) domine
   Entrelas (62), la Louboutin (150) écrase une 90. Jamais rognée : c'est la
   marge pilotée (vitrine.js) qui absorbe. Le bijou reste hors échelle
   (à 2 px/cm une bague ferait 6 px) : écrin fixe, macro assumée — mais
   CADRÉ, voir plus bas.
   La SCULPTURE est POSÉE (ancrée au sol de sa porte, elle sort par le
   haut) ; le TABLEAU est ACCROCHÉ (centré sur la porte, le débord se
   répartit haut ET bas — demande PO) ; le BIJOU est CENTRÉ dans son
   écrin, sur son objet et non sur son reflet (PO 28/08). */
.bd-portes { --kv: 2.3; }
.bd-vitrine {
    position: absolute; bottom: 6px; right: 14px;
    width: 180px; height: 210px;
    z-index: 4;
}
.bd-porte--sculptures .bd-item,
.bd-porte--peintures .bd-item {
    height: calc(var(--hcm, 80) * var(--kv, 2.3) * 1px);
    max-height: none; max-width: none; width: auto;
}
.bd-porte--peintures .bd-vitrine { top: 50%; bottom: auto; height: 0; overflow: visible; }
/* La LÉGÈRE ROTATION du tableau (PO 27/08, réglée à l'œil : « un peu moins
   et dans l'autre sens ») : un cadre jamais tout à fait droit, c'est la
   main qui vient de l'accrocher. Le rect tourné est mesuré tel quel par le
   pilote de marges (getBoundingClientRect), le débord reste juste. */
.bd-porte--peintures .bd-item { bottom: auto; top: 0; transform: translate(-50%, -50%) rotate(1.6deg); }
/* L’ÉCRIN DESCENDU DE 20 px EN DEUX TOURS (PO 28/08 : « tu peux le redescendre
   également », puis « descends-le encore »). C’est l’ÉCRIN qu’on baisse, pas
   la pièce : le bijou reste centré dedans, donc un seul nombre déplace tout
   le monde et l'invariant « centré dans son écrin » tient. */
.bd-porte--bijoux .bd-vitrine { width: 128px; height: 128px; bottom: 14px; right: 26px; }
/* LE BIJOU CENTRÉ SUR SON OBJET, PAS SUR SON REFLET (PO 28/08 : « on va
   juste grossir un peu l'item, et on va le centrer — attention, l'image a
   un reflet, et on doit centrer l'objet »).
   Le render est un canevas de 2500 px où la pièce est posée sur un sol
   réfléchissant : le reflet pèse 258 à 655 px, soit 15 à 28 % de la boîte
   englobante. Un `contain` nu centrait donc le couple objet+reflet — la
   pièce montait — et donnait des tailles apparentes allant de 80 à 121 px
   selon la marge transparente du fichier, pas selon le bijou.
   ⚠️ ON NE RECADRE PAS (décision PO 08/08 : les reflets sont le travail de
   Jocelyn, ils restent affichés). On ne fait que DÉPLACER et AGRANDIR :
     --ox/--oy  centre de l'OBJET SEUL, en % du canevas (mesuré par
                outils/cadre-bijoux.py, seuil d'opacité 97 % — l'objet a un
                cœur opaque, le reflet est semi-transparent partout) ;
     --kb       l’échelle qui met toutes les pièces au même poids (plus
                grande dimension = 84 % de l’écrin, soit 108 px).
   LA MÉCANIQUE, en une phrase : `transform-origin` EST le centre de
   l'objet, donc le `scale` ne le déplace pas ; et `translate(-ox, -oy)`
   pose ce centre sur le centre de l'écrin. Les deux sont indépendants —
   changer la taille ne décentre rien. Sans entrée mesurée : 50 %/50 % et
   k=1, c'est-à-dire le comportement d'avant. */
.bd-porte--bijoux .bd-item {
    left: 50%; top: 50%; bottom: auto;
    height: 100%; width: auto; max-width: none; max-height: none;
    transform-origin: var(--ox, 50%) var(--oy, 50%);
    transform: translate(calc(var(--ox, 50%) * -1), calc(var(--oy, 50%) * -1)) scale(var(--kb, 1));
}
/* Le zigzag : la vitrine des peintures passe à GAUCHE, le texte à droite,
   le scrim se retourne — trois compositions, pas trois rangées. */
.bd-porte--g .bd-vitrine { right: auto; left: 14px; }
.bd-porte--g::after { background: linear-gradient(270deg, rgba(40, 37, 33, 0.72), rgba(40, 37, 33, 0.12) 62%); }
.bd-porte--g .bd-corps { left: auto; right: 20px; text-align: right; }
/* Taille NATURELLE bornée, plus un carré étiré : le cadre d'une caisse doit
   épouser l'œuvre (ratio réel), pas la boîte de la vitrine. Ancré en bas :
   l'objet est POSÉ, il ne flotte pas. */
.bd-item {
    position: absolute; bottom: 0; left: 50%;
    transform: translateX(-50%);
    max-width: 100%; max-height: 100%; width: auto; height: auto;
    opacity: 0;
    filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.35));
}
.bd-item--vu { opacity: 1; }
/* LA CAISSE AMÉRICAINE de la vitrine peintures (« on vend l'objet tableau,
   pas l'image » — PO 27/08) : face sombre, creux d'ombre, l'œuvre dedans —
   l'évocation du vrai cadre de la fiche, à l'échelle d'un teaser. */
.bd-item--caisse {
    border: 6px solid #26211d;
    padding: 3px;
    background: #26211d;
    box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6), 0 8px 18px rgba(0, 0, 0, 0.4);
    filter: none;
}
/* ⚠️ LE TEXTE PASSE DEVANT LA VITRINE — correctif du 28/08, et c'était
   structurel, pas un accident de tirage : `.bd-vitrine` est en z-index 4,
   `.bd-corps` était en 2. La pièce couvrait donc le nom de la collection et
   son compteur — mesuré en 375 comme en 320 px : le buste barrait
   « Sculptures », le tableau mangeait « Peintures » ET « 108 œuvres ».
   Le débord reste la loi (« les items doivent SORTIR ») ; ce qui change,
   c'est l'ordre : le teasing passe DERRIÈRE l'information qu'il teasait.
   L'ombre portée monte d'un cran — sur une pièce blanche mate, du blanc sur
   blanc sans ombre ne se lit pas. */
.bd-corps {
    position: absolute; left: 20px; top: 50%;
    transform: translateY(-50%);
    z-index: 5;
    text-shadow: 0 1px 3px rgba(20, 17, 14, .75), 0 2px 12px rgba(20, 17, 14, .55);
}
.bd-titre { display: block; font-size: 1.3rem; font-weight: 700; line-height: 1.15; }
.bd-compte { display: block; margin-top: 4px; font-size: 0.85rem; color: var(--fg-soft, rgba(255, 255, 255, .85)); }
.bd-porte:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ── LE CTA PHOTOS, SUR LE VISUEL (PO 26/08) ──────────────────────────────
   La pastille de verre du corner (flou + liseret blanc), en petit, ancrée au
   bas du visuel — elle ouvre la lightbox sur les vues de la bande
   (délégation lightbox.js sur `.fi-galerie-cta`).
   Le VOILE sous le flou (revue Hélène 26/08, GO PO — remonté de .35 à .5 au
   second tour : sur le buste BLANC, le blanc du texte tombait à ~2,3:1, le
   text-shadow ne rattrapait pas tout) : .5 reste un cran sous la mention IA
   (.fi-vue-mention, .55) — lisible sur toute image, la charte verre+liseret
   inchangée. */
.fi-galerie-cta {
    position: absolute; z-index: 2;
    right: 6px; bottom: 6px;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 12px; border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.45);
    background: rgba(20, 18, 16, 0.5);
    -webkit-backdrop-filter: blur(16px);
    backdrop-filter: blur(16px);
    color: #fff;
    font-family: inherit; font-size: 0.8rem; font-weight: 600; line-height: 1;
    letter-spacing: 0.02em;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
    cursor: pointer;
}
.fi-galerie-cta svg { width: 15px; height: 15px; }
/* LA CIBLE TACTILE, PAS LE RENDU (revue Hélène 26/08) : la pastille mesure
   ~27 px de haut — un doigt vise 44. Le débord invisible étend le tap sans
   toucher au dessin ; il reste DANS la pastille (z-index 2), donc il gagne
   sur le calque 3D (z-index 1) autour de son coin. */
.fi-galerie-cta::after { content: ""; position: absolute; inset: -10px; }
.fi-galerie-cta:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ── LE VISUEL OUVRE LA 3D (revue Hélène 26/08, GO PO) ────────────────────
   Un calque-bouton transparent couvre la pièce réduite : sur une fiche
   produit, tout le monde tape l'image — elle répond désormais par le geste
   le plus fort du site (délégation `[data-ouvre-3d]`, visionneuse-3d.js).
   Sous la pastille Photos (1 < 2) : les deux gestes cohabitent. */
.fi-visuel-3d {
    position: absolute; inset: 0; z-index: 1;
    background: transparent; border: 0; padding: 0;
    cursor: pointer;
}
.fi-visuel-3d:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ── L'ACCENT DE LA 3D (revue Hélène 26/08, GO PO) ────────────────────────
   Les deux barres de la fiche (3D, devis) avaient exactement le même poids
   de verre : l'œil ne distinguait pas l'expérience de la transaction. Le
   liseret lime marque le geste-wahou d'un cran ; le CTA devis garde son
   filet assourdi (univers-galerie.css). Scopé fiche nu : seules les fiches
   volume rendent un lanceur ici. */
.nu-corps.fiche .v3d-bouton { border-color: rgba(180, 205, 0, 0.65); }

/* ── LE VISUEL DE VOLUME, RÉDUIT SOUS SON CARTEL — ET À L'ÉCHELLE ─────────
   (PO 26/08, deux temps). Le cartel ouvre la fiche, la pièce suit, plus
   petite. ⚠️ MAIS L'ÉCHELLE PHYSIQUE RESTE UNE INFORMATION (rappel PO :
   « on s'est pris la tête pour que les visuels soient à l'échelle ») —
   la borne fixe du premier essai rendait Entrelas (62 cm) aussi large
   qu'un buste de 83. La largeur vient donc du SUJET : --lv (sa largeur
   apparente mesurée, en cm) × un px/cm UNIQUE pour toutes les fiches
   sculptures — 4,2 px/cm plafonné, 0,9vw sur les petits écrans. Le ratio
   et le calage mesurés ne bougent pas ; fiche.css garde ses gardes. */
.nu-corps.fiche .fi-visuel--ouverture.fi-volume {
    width: calc(var(--lv) * min(0.9vw, 4.2px));
    max-width: 100%;
    margin-block: 10px 6px;
}
/* ⚠️ PLUS DE FOND CLAIR (constat PO 29/08 : « les singles bijoux, le visuel
   est KO »). Ce `background: #f4f2f0` datait de la reconstruction de l'arbre,
   quand ce visuel était supposé être une photo. Or les dix bijoux sont des
   rendus DÉTOURÉS, à canal alpha : le fond posait un carré blanc de la
   largeur de la page derrière une bague qui n'en demandait pas — la bague
   avait l'air collée sur un timbre.
   C'est le même défaut que le corner avait déjà nommé ET neutralisé :
   « .media-wait pose un fond clair le temps du chargement : sur une pièce
   détourée il reste visible AUTOUR d'elle, et fabrique le fond qui ne sert à
   rien » (fiche.css, .carte-visuel, 10/08). La règle n'avait pas été portée
   jusqu'ici. Le jour où une pièce NON détourée passerait par ce visuel, c'est
   à elle de porter son fond — pas au gabarit de le supposer. */
.nu-visuel { display: block; width: 100%; height: auto; margin: 22px 0; }
/* Le bouton qui porte la vignette d'une fiche nue (PO 05/09 : elle ouvre la
   lightbox) — un bouton nu, aux dimensions exactes de l'image, qui hérite la
   marge de la vignette pour que rien ne bouge dans la page. */
.nu-visuel-cadre { display: block; width: 100%; margin: 22px 0; padding: 0; border: 0; background: none; cursor: zoom-in; -webkit-tap-highlight-color: transparent; }
.nu-visuel-cadre .nu-visuel { margin: 0; }
/* LA BOUCLE VIDÉO D'OUVERTURE (PO 05/09) : bord à bord et collée au haut de
   l'écran. `.nu-corps` fait déjà 100vw avec le couloir de 50 px en padding
   et 40 px en tête ; `.page` réserve `--brand-h` + la barre d'état. On
   rend tout ça en marges négatives : la vidéo commence sous les infos iOS,
   la marque fixe (z 8) se pose par-dessus, comme sur un film de corner. */
.nu-visuel-cadre--video {
    position: relative; overflow: hidden;
    /* Les deux couloirs de `.nu-corps` rendus, et pas `100vw` : la barre de
       défilement classique n'est pas comptée (desktop, increment 1). */
    width: calc(100% + 100px);
    margin: calc(-40px - var(--brand-h) - env(safe-area-inset-top, 0px)) -50px 22px;
    cursor: zoom-in;
}
.nu-video-ouverture { display: block; width: 100%; height: auto; }
/* ── L'AFFICHE EN FOND DU CADRE : plus jamais d'aplat à la place de l'image.
   Le cadre porte la PREMIÈRE IMAGE de sa boucle en fond, la vidéo se pose
   par-dessus quand elle est prête. Pendant un glissement, la fiche qui arrive
   montre donc son image et non un rectangle de couleur (constat PO 07/09 :
   un aplat saumon en haut de la page entrante, capture à l'appui).
   Le `poster` du <video> ne suffit pas : dans un document importé par le
   routeur, la vidéo repart de zéro et ne peint rien avant d'avoir chargé.
   L'image est déjà en cache — `nu-gestes.js` précharge l'affiche des voisines.
   ⚠️ PLACÉE ICI, ET PAS PLUS HAUT : `.nu-visuel-cadre` pose `background: none`
   quelques lignes plus bas ; à spécificité égale c'est l'ORDRE qui tranche, et
   la règle mise en tête de feuille était écrasée en silence (mesuré :
   `backgroundImage: none` alors que `--affiche` était bien résolue). */
.nu-visuel-cadre--video { background: var(--affiche) center / cover no-repeat; }
/* ⚠️ ET LA HAUTEUR SE RÉSERVE, SINON RIEN DE TOUT ÇA NE SERT. Un `<video>`
   sans métadonnées chargées n'a pas de hauteur intrinsèque : dans le calque de
   transition, le cadre s'écrasait sur la hauteur par défaut et le texte
   remontait par-dessus l'image (constat PO 07/09, deux captures). Le ratio est
   posé au build (`--ratio`, depuis les dimensions réelles du fichier), donc la
   boîte a sa taille définitive AVANT le premier octet de vidéo. */
.nu-visuel-cadre--video { aspect-ratio: var(--ratio); }
.nu-visuel-cadre--video .nu-video-ouverture { height: 100%; object-fit: cover; }

/* La mention se CENTRE en bas : à droite elle chevauchait le libellé vertical
   de la boussole (mesuré au navigateur, 05/09). */
/* ⚠️ Pas de `left: 50%` + translate : une boîte absolue calée à 50 % n'a
   droit qu'à la MOITIÉ de la largeur pour se dimensionner, le texte débordait
   de la pastille (capture PO 05/09 22:35). Centrage par les deux bords. */
.nu-video-mention { left: 0; right: 0; bottom: 12px; width: max-content; max-width: calc(100% - 24px); margin: 0 auto; text-align: center; }
.nu-cotes { list-style: none; margin: 0 0 10px; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 10px; }
.nu-cotes li { font-size: 14px; color: var(--fg-muted, rgba(255, 255, 255, .55)); }
.nu-cotes li + li::before { content: '· '; color: rgba(255, 255, 255, .3); }
.nu-prix { margin: 0 0 24px; font-size: 20px; font-weight: 600; }
.nu-galerie { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin: 26px 0 0; }
.nu-galerie img { width: 100%; height: auto; display: block; background: #f4f2f0; }

/* ── LE COMPTEUR EN ÉTIQUETTE, AU BUREAU (PO 02/10) ────────────────────────
   Un verre collé au bord droit de l'écran, sous la boussole : on n'en voit que
   le flanc gauche arrondi, le reste sort de l'écran. Fixe, donc toujours là
   quand on défile. Posée par la page : `<aside class="cpt-etiquette">` autour
   d'un `<Compteurs>` (Mes services ; prévue pour d'autres pages, le nombre de
   tableaux par exemple). Le verre est celui de `.bq-verre`. Masquée sous
   1024 px : le téléphone garde son compteur dans le fil de la page. */
.cpt-etiquette { display: none; }
@media not all and (max-width: 1023px) {
    html.nu .cpt-etiquette {
        display: block; position: fixed; z-index: 4;
        top: calc(118px * var(--k)); right: 0;
        padding: calc(16px * var(--k)) calc(26px * var(--k)) calc(16px * var(--k)) calc(24px * var(--k));
        border-radius: 24px 0 0 24px; color: #fff; text-align: center;
        box-shadow: rgba(0, 0, 0, 0.1) 0 4px 30px 0, rgba(255, 255, 255, 0.5) 1px 1px 1px 0 inset, rgba(0, 0, 0, 0.15) 0 -1px 1px 0 inset;
        -webkit-backdrop-filter: blur(8px) brightness(0.97);
        backdrop-filter: blur(8px) brightness(0.97);
    }
    /* Pendant un glissement la page voyage dans `.pane`, qui déborde de 140 px
       en haut : même recalage que `.fb`. */
    html.nu .pane .cpt-etiquette { top: calc(140px + 118px * var(--k)); }
    html.nu .cpt-etiquette .cpt-service { margin: 0; }
    html.nu .cpt-etiquette .cpt-chiffres { margin: 0; }
    html.nu .cpt-etiquette .cpt-chiffres > div { padding: 0; }
    html.nu .cpt-etiquette .cpt-chiffres > div + div { margin-top: calc(14px * var(--k)); padding-top: calc(14px * var(--k)); }
    html.nu .cpt-etiquette .cpt-chiffres dt { font-size: calc(60px * var(--k)); }
    html.nu .cpt-etiquette .cpt-chiffres dd { margin-top: calc(6px * var(--k)); font-size: calc(11px * var(--k)); }
}

/* ── LES PAGES DE PIED AU BUREAU (04/10) : mentions légales, confidentialité,
   conditions de commande (`horsCarte`, classe `page--legale`). Patron des
   pôles : la table embossée de l'accueil, voile à droite, le texte dans le
   verre de `.bq-verre`, à gauche. Ici le fond est sur `.page` et le verre
   est `.nu-corps` lui-même : la route générique n'a pas d'enveloppe de tête.
   Le lien « Accueil » du bas est remplacé par le fil d'Ariane. */
.lg-ariane { display: none; }
@media not all and (max-width: 1023px) {
    html.nu .page--legale {
        box-sizing: border-box; min-height: 100vh;
        padding: calc(var(--brand-h) + 24px) calc(80px * var(--k)) calc(120px * var(--k));
        background-image: linear-gradient(270deg, rgb(23, 20, 3) 0%, rgba(0, 0, 0, 0) 65%), url(/assets/accueil-bureau/fond-embosse.webp);
        background-size: auto, cover; background-position: center, 50% 50%;
        background-attachment: scroll, fixed; background-repeat: no-repeat;
    }
    html.nu .page--legale > .nu-corps {
        box-sizing: border-box; width: calc(760px * var(--k)); max-width: 100%; min-height: 0; margin: 0;
        padding: calc(48px * var(--k)); border-radius: 24px; background: none; color: #fff;
        box-shadow: rgba(0, 0, 0, 0.1) 0 4px 30px 0, rgba(255, 255, 255, 0.5) 1px 1px 1px 0 inset, rgba(0, 0, 0, 0.15) -1px -1px 1px 0 inset;
        -webkit-backdrop-filter: blur(8px) brightness(0.97);
        backdrop-filter: blur(8px) brightness(0.97);
    }
    html.nu .page--legale .lg-ariane { display: block; }
    html.nu .page--legale > .nu-corps h1 { margin: 0 0 calc(18px * var(--k)); font-size: calc(46.08px * var(--k)); font-weight: 400; line-height: 1; letter-spacing: -0.432px; }
    html.nu .page--legale > .nu-corps h2 { margin: calc(36px * var(--k)) 0 calc(12px * var(--k)); font-size: calc(32px * var(--k)); font-weight: 400; line-height: 1.1; }
    html.nu .page--legale > .nu-corps :is(p, li) { margin: 0 0 calc(14.4px * var(--k)); font-size: calc(19.2px * var(--k)); line-height: 1.45; max-width: none; text-wrap: pretty; }
    html.nu .page--legale > .nu-corps .nu-intro { font-weight: 700; }
    html.nu .page--legale > .nu-corps > :last-child { margin-bottom: 0; }
    html.nu .page--legale > .nu-retour { display: none; }
}
