/* ════════════════════════════════════════════════════════════════════
   BOUTIQUE

   Volontairement court. La page produit charge par-dessus les feuilles
   du configurateur, qui pèsent déjà 66 Ko : tout ce qui est ajouté ici
   se paie sur le temps d'affichage.
   ════════════════════════════════════════════════════════════════════ */

.entete {
    border-bottom: 1px solid var(--bordure);
    padding: var(--r4) 0;
    margin-bottom: var(--r5);
}

.entete__marque { text-decoration: none; }

.entete__nav {
    display: flex;
    align-items: center;
    gap: var(--r5);
}

.entete__panier { position: relative; }

.pastille {
    display: inline-block;
    min-width: 1.4rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: var(--or);
    color: #fff;
    font-size: .75rem;
    line-height: 1.4rem;
    text-align: center;
}

.pied {
    margin-top: var(--r6);
    padding: var(--r5) 0;
    border-top: 1px solid var(--bordure);
}

/* ── Catalogue ─────────────────────────────────────────────────────── */

.filtres {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--r4);
    margin-bottom: var(--r5);
}

.filtres > .champ { flex: 1 1 10rem; margin-bottom: 0; }

.catalogue {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: var(--r4);
}

.produit-carte { text-decoration: none; display: block; }

.produit-carte__image {
    width: 100%;
    aspect-ratio: 1;
    object-fit: cover;
    border-radius: var(--arrondi);
    margin-bottom: var(--r3);
}

.produit-carte__nom { font-size: 1.05rem; margin-bottom: var(--r2); }
.produit-carte__prix { margin-top: var(--r3); }

/* ── Page produit ──────────────────────────────────────────────────── */

.produit {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--r5);
}

/* Deux colonnes seulement à partir du bureau : sur téléphone, le
   configurateur a besoin de toute la largeur. */
@media (min-width: 60rem) {
    .produit { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
    .produit__visuel { position: sticky; top: var(--r4); align-self: start; }
}

.produit__image {
    width: 100%;
    border-radius: var(--arrondi);
}

.produit__vignettes {
    display: flex;
    gap: var(--r3);
    margin-top: var(--r3);
    flex-wrap: wrap;
}

.produit__vignette {
    width: 4.5rem;
    height: 4.5rem;
    object-fit: cover;
    border: 2px solid transparent;
    border-radius: var(--arrondi);
    cursor: pointer;
}

.produit__vignette.active { border-color: var(--or); }

.produit__prix strong { font-size: 1.5rem; }
.produit__prix s { margin-right: var(--r3); }

.produit__accroche { color: var(--texte-doux); margin-bottom: var(--r4); }

.produit__achat {
    display: flex;
    gap: var(--r3);
    align-items: stretch;
    margin-top: var(--r5);
}

.produit__quantite { width: 5rem; }

/* Le bouton d'ajout occupe le reste : c'est l'action de la page. */
.produit__achat .bouton { flex: 1; }

.produit__description { margin-top: var(--r5); }

/* ── Panier ────────────────────────────────────────────────────────── */

.panier-ligne {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--r4);
    align-items: start;
}

@media (min-width: 45rem) {
    .panier-ligne { grid-template-columns: 8rem 1fr auto; }
}

.panier-ligne__apercu img {
    width: 100%;
    max-width: 8rem;
    aspect-ratio: 1;
    object-fit: contain;
    border: 1px solid var(--bordure);
    border-radius: var(--arrondi);
}

.panier-ligne__actions {
    flex-wrap: wrap;
    margin-top: var(--r4);
}

.panier-ligne__quantite { width: 4.5rem; }

.panier-ligne__prix { text-align: right; }
.panier-ligne__prix strong { font-size: 1.15rem; }

.panier-total { margin-top: var(--r5); }
.panier-total .rang--fin { margin-top: var(--r4); flex-wrap: wrap; }

/* ── Tunnel de commande ────────────────────────────────────────────── */

.commande__colonnes { display: grid; grid-template-columns: 1fr; gap: var(--r5); }

@media (min-width: 55rem) {
    .commande__colonnes { grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); }
    .commande__recap { position: sticky; top: var(--r4); align-self: start; }
}

/*
 * ── DEUX NIVEAUX, COMME DANS LE PANIER ───────────────────────────────
 *
 * Le nom et le prix se partageaient une rangée en « space-between ». Le
 * détail de gravure, ajouté dessous, y aurait été comprimé dans la
 * largeur restante après le prix.
 *
 * C'est le même défaut que celui corrigé dans le panier en 0.43.1 : il
 * suffisait de reprendre la structure plutôt que de la refaire.
 */
.commande__ligne {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--r2) var(--r3);
    align-items: start;
    padding: var(--r3) 0;
    border-bottom: 1px solid var(--bordure);
}

.commande__total {
    padding-top: var(--r3);
    margin-top: var(--r3);
    border-top: 1px solid var(--bordure);
}

/*
 * ── SEUL LE BOUTON DE VALIDATION PREND TOUTE LA LARGEUR ──────────────
 *
 * Cette règle visait « tout bouton du récapitulatif », ce qui allait
 * tant qu'il n'y en avait qu'un. Le bouton « Appliquer » du code promo
 * l'a hérité : il s'étalait sur toute la ligne et écrasait le champ, qui
 * se réduisait à trente pixels.
 *
 * Écrire ce qu'on vise plutôt que ce qui se trouve là aujourd'hui : le
 * bouton de validation est celui qui porte « bouton--principal ».
 */
.commande__recap .bouton--principal { width: 100%; margin-top: var(--r4); }

.livraison-mode label { align-items: flex-start; }
.livraison-mode .faible { display: block; }

.champ__erreur {
    margin-top: var(--r2);
    font-size: .875rem;
    color: var(--danger, #c0392b);
}

.commande-confirmee { margin-bottom: var(--r5); }

/* ── Zone de dessin du configurateur ────────────────────────────────

   RIEN N'EST DÉCLARÉ ICI, ET C'EST VOULU.

   Une version précédente posait sur « #sp-canvas-overlay » :

       position: absolute;
       inset: 0;

   Le configurateur calcule pourtant lui-même la position et les
   dimensions de cette zone, au pixel près, à partir de l'image qu'il
   mesure. « inset: 0 » l'étirait à toute la figure et décalait la
   gravure par rapport à la médaille.

   Ces règles accompagnaient un conteneur « .produit__scene » retiré en
   0.25.1, quand le configurateur a repris la main sur sa zone. Le
   balisage est parti, le style est resté : c'est le genre de résidu qui
   ne casse rien tant que personne ne regarde le résultat.

   Si un jour quelque chose doit être ajouté ici, vérifier d'abord que le
   configurateur ne le fait pas déjà.
   ─────────────────────────────────────────────────────────────────── */

/*
 * ── UNE SEULE VIGNETTE EST DORÉE À LA FOIS ───────────────────────────
 *
 * Une règle donnait un anneau doré permanent à la vignette porteuse du
 * canvas, EN PLUS de celui de la vignette sélectionnée. Les deux
 * paraissaient donc actives en même temps, et l'on ne savait plus
 * laquelle on regardait.
 *
 * La porteuse se distingue autrement : par une pastille discrète, qui
 * dit « c'est ici qu'on grave » sans se confondre avec « c'est ici qu'on
 * est ».
 */
.produit__vignette { position: relative; }

.produit__vignette[data-porteuse="1"]::after {
    content: "";
    position: absolute;
    right: 3px;
    bottom: 3px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--or);

    /* Un liseré sombre : sur une photo claire, un point doré seul se
       perd. */
    box-shadow: 0 0 0 1.5px var(--fond-carte);
}

/* ── Galerie produit ────────────────────────────────────────────────
   La structure porte les noms de classes de WooCommerce : le
   configurateur les cherche, et lui en donner d'autres obligerait à
   modifier un fichier de 5107 lignes repris tel quel. */

.sp-galerie { position: relative; }

.sp-galerie__contenu { position: relative; line-height: 0; }

.sp-galerie__image { margin: 0; }

/* Une figure masquée garde sa place dans le document : le configurateur
   mesure les dimensions de son image, et une figure retirée mesurerait
   zéro. On la cache donc sans la sortir du flux. */
.sp-galerie__image[hidden] { display: none; }

.sp-galerie__image img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--arrondi);
}

.produit__vignettes { display: flex; gap: var(--r2); margin-top: var(--r3); }

.produit__vignette {
    padding: 0;
    border: 1px solid var(--bordure);
    border-radius: var(--arrondi);
    background: none;
    cursor: pointer;
    line-height: 0;
    overflow: hidden;
    transition: box-shadow .18s var(--sortie), border-color .18s var(--sortie);
}

.produit__vignette img { display: block; width: 64px; height: 64px; object-fit: cover; }

.produit__vignette:hover {
    border-color: rgba(var(--or-rvb), .5);
    box-shadow: var(--anneau);
}

.produit__vignette:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--fond), 0 0 0 4px var(--or);
}

.produit__vignette.active { border-color: var(--or); box-shadow: var(--anneau-large); }

/* ── Retour d'ajout au panier ───────────────────────────────────────
   La zone est créée par le script : sans lui elle n'existe pas, et
   n'occupe donc aucune place. */

.panier-retour:empty { display: none; }

/* Une ligne, sous le bouton. Le détail est dans le volet du panier :
   le répéter ici pousserait la page vers le bas au moment où le client
   vient d agir. */
.panier-retour__ok {
    margin: var(--r3) 0 0;
    padding: var(--r3) var(--r4);
    background: rgba(var(--or-rvb), .08);
    border-left: 2px solid var(--or);
    border-radius: var(--arrondi);
    font-size: .9375rem;
}

.panier-retour__ok a { margin-left: var(--r2); }

.panier-resume {
    margin-top: var(--r4);
    padding: var(--r4);
    background: var(--fond-carte);
    border: 1px solid var(--bordure);
    border-left: 3px solid var(--or);
    border-radius: var(--arrondi);
}

.panier-resume__confirmation { margin: 0 0 var(--r3); font-weight: 600; }

.panier-resume__lignes {
    list-style: none;
    margin: 0 0 var(--r3);
    padding: 0;
    font-size: .9375rem;
}

/*
 * ── DEUX NIVEAUX, PAS UNE SEULE LIGNE ────────────────────────────────
 *
 * Le nom, la croix et le prix se partageaient une ligne unique en
 * « space-between ». Le nom d'un produit fait souvent soixante
 * caractères : il se retrouvait comprimé dans le tiers restant, et le
 * détail de gravure dessous héritait de la même étroitesse.
 *
 * En grille, l'en-tête occupe la première rangée et le détail la
 * seconde, sur TOUTE la largeur. Le détail cesse d'être coincé sous le
 * nom.
 */
.panier-resume__lignes li {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: var(--r2) var(--r3);
    align-items: start;
    padding: var(--r3) 0;
    border-bottom: 1px solid var(--bordure);
}

/* Le détail traverse les deux colonnes. */
.panier-resume__lignes .detail-gravure { grid-column: 1 / -1; }

.panier-resume__lignes li:last-child { border-bottom: none; }

.panier-resume__total { margin: 0 0 var(--r3); color: var(--texte-doux); }

/* Une erreur garde le filet rouge, pas le doré : elle ne doit pas
   ressembler à une confirmation. */
.panier-resume:has(.message--erreur) { border-left-color: var(--perdu); }

/* ════════════════════════════════════════════════════════════════════
   SURVOL DES ÉLÉMENTS

   ── UN MOUVEMENT DOIT DIRE QUELQUE CHOSE ─────────────────────────────

   Le geste est le même que sur les boutons : légère levée, anneau doré,
   ombre de la même teinte. Répéter un seul mouvement plutôt que d'en
   inventer un par élément fait que le client apprend une fois : ce qui
   se soulève est cliquable.

   Il n'est mis QUE sur ce qui mène quelque part. Une carte qui bouge
   sans être cliquable est une promesse non tenue, et on finit par
   cliquer partout pour voir.
   ════════════════════════════════════════════════════════════════════ */

.produit-carte {
    display: block;
    text-decoration: none;
    color: inherit;
    transition: box-shadow .2s var(--sortie), transform .2s var(--sortie),
                border-color .2s var(--sortie);
}

.produit-carte:hover {
    text-decoration: none;
    border-color: rgba(var(--or-rvb), .5);
    box-shadow: var(--anneau), 0 8px 24px rgba(var(--or-rvb), .14);
    transform: translateY(-3px);
}

.produit-carte:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--fond), 0 0 0 4px var(--or);
}

.produit-carte:active { transform: translateY(-1px); }

/* L'image respire légèrement, sans déborder de son cadre : c'est ce
   qui donne l'impression que la carte est un objet et pas un
   rectangle. */
.produit-carte__image {
    overflow: hidden;
    border-radius: var(--arrondi);
}

.produit-carte__image img {
    display: block;
    width: 100%;
    height: auto;
    transition: transform .35s var(--sortie);
}

.produit-carte:hover .produit-carte__image img { transform: scale(1.03); }

/* Les liens de navigation : un filet doré qui se déploie depuis la
   gauche. Discret, et il indique la direction de lecture. */
.entete__nav a {
    position: relative;
    padding-bottom: 2px;
}

.entete__nav a::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    height: 1px;
    width: 100%;
    background: var(--or);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform .22s var(--sortie);
}

.entete__nav a:hover::after,
.entete__nav a:focus-visible::after { transform: scaleX(1); }

@media (prefers-reduced-motion: reduce) {
    .produit-carte,
    .produit-carte__image img,
    .entete__nav a::after { transition: none; }

    .produit-carte:hover { transform: none; }
    .produit-carte:hover .produit-carte__image img { transform: none; }
    .entete__nav a:hover::after { transform: scaleX(1); }
}

/* ── L'aperçu du panier est cliquable ───────────────────────────────
   La règle de taille vise « img ». Enveloppée dans un lien, l'image la
   garde, mais le lien doit prendre la même largeur : sinon il se réduit
   au contenu et la loupe se pose de travers. */

.panier-ligne__apercu .detail-gravure__lien {
    display: block;
    width: 100%;
    max-width: 8rem;
}

.panier-ligne__apercu .detail-gravure__lien img { max-width: 100%; }

/* ── Actions du panier ──────────────────────────────────────────────
   Le bouton de validation est seul de son côté : mis dans la même
   rangée que « vider » et « continuer », il aurait leur poids visuel, et
   trois boutons alignés ne disent pas lequel termine l'achat. */

.panier__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--r4);
    margin-top: var(--r4);
}

.bouton--large {
    min-height: 52px;
    padding: 0 var(--r6);
    font-size: 1rem;
}

/* Sur un écran étroit, le bouton passe en premier et prend toute la
   largeur : c'est ce qu'on cherche, et le pouce l'atteint sans viser. */
@media (max-width: 40rem) {
    .panier__actions { flex-direction: column-reverse; align-items: stretch; }

    .panier__actions .bouton--large { width: 100%; }

    .panier__actions .rang { justify-content: center; }
}

/* Le détail de gravure traverse les deux colonnes de la ligne de
   récapitulatif : sinon il reste dans la première, comprimée par le
   prix. */

.commande__ligne .detail-gravure { grid-column: 1 / -1; }

.commande__ligne-entete { min-width: 0; overflow-wrap: anywhere; }

/* Le prix ne se coupe pas : « 19,90 » sur une ligne et « € » sur la
   suivante se lit mal, et c'est le chiffre qu'on vérifie. */
.commande__ligne-prix { white-space: nowrap; }

/* ── Code promo ─────────────────────────────────────────────────────
   Placé avant les totaux : après, le client verrait son total puis
   découvrirait qu'il pouvait le réduire. */

.promo-champ {
    padding-bottom: var(--r3);
    margin-bottom: var(--r3);
    border-bottom: 1px solid var(--bordure);
}

/*
 * ── LE CHAMP PREND LA PLACE, LE BOUTON PREND LA SIENNE ───────────────
 *
 * Le champ portait « flex: 1 1 8rem » et le bouton rien : ce dernier
 * gardait donc la largeur de son texte plus ses marges intérieures, qui
 * sont généreuses, pendant que le champ se contentait de ce qui restait.
 *
 * Résultat inverse de ce qu'on veut : un bouton de trois cents pixels
 * pour deux mots, et une zone de saisie où l'on ne voit pas le code
 * qu'on tape.
 *
 * Le champ grandit sans limite haute, le bouton ne grandit ni ne
 * rétrécit.
 */
.promo-champ .rang { align-items: flex-end; gap: var(--r3); }

.promo-champ .champ {
    /*
     * Une largeur de base de 7rem, pas « auto ».
     *
     * Avec « auto », la base est la largeur du contenu : un libellé qui
     * se replie sur deux lignes donne un champ étroit, et le champ ne
     * retrouve sa place que si le reste de la ligne le permet.
     *
     * 7rem tient un code de dix caractères. « min-width: 0 » reste
     * nécessaire pour qu'il puisse descendre en dessous sur un écran
     * étroit plutôt que de déborder.
     */
    flex: 1 1 7rem;
    min-width: 0;
    margin-bottom: 0;
}

.promo-champ .bouton {
    flex: 0 0 auto;

    /*
     * Les marges intérieures d'un bouton ordinaire sont dimensionnées
     * pour un appel à l'action. Celui-ci accompagne un champ : il doit
     * se voir sans dominer la ligne.
     */
    padding: 0 var(--r4);
}

/*
 * Le libellé ne se replie pas.
 *
 * « Code promo » sur deux lignes décalait le champ vers le bas et
 * réduisait sa largeur de base. Deux mots courts n'ont aucune raison de
 * se couper.
 */
.promo-champ .champ label { display: block; white-space: nowrap; }

.promo-actif {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--r3);
    flex-wrap: wrap;
}

.promo-actif__code {
    display: inline-block;
    padding: 2px var(--r2);
    margin-right: var(--r2);
    background: rgba(var(--or-rvb), .15);
    border-radius: var(--r1);
    color: var(--or);
}

/* La remise en doré : c'est la bonne nouvelle de la page. */
.commande__remise {
    padding: var(--r2) 0;
    color: var(--or);
    font-size: .9375rem;
}

/* Le refus d'un code s'affiche là où le client vient de cliquer : en
   haut de page, il passerait inaperçu. */
.promo-erreur {
    margin: var(--r2) 0 0;
    color: var(--erreur);
    font-size: .8125rem;
}

/* ── Lignes de total du récapitulatif ───────────────────────────────
   Le port et le total final se distinguent du sous-total : c'est le
   dernier chiffre que le client lit avant de décider. */

.commande__ligne-total {
    padding: var(--r2) 0;
    font-size: .9375rem;
}

.commande__total-final {
    padding-top: var(--r3);
    margin-top: var(--r2);
    border-top: 1px solid var(--bordure);
    font-size: 1.125rem;
}

.commande__total-final strong { color: var(--or); }

.commande__offert { color: var(--or); }

/* ── Caractéristiques sous la description ───────────────────────────── */

.produit__caracteristiques { margin-top: var(--r6); }

.carac-groupe { margin-bottom: var(--r5); }

.carac-groupe h3 {
    margin: 0 0 var(--r3);
    color: var(--or);
    font-size: 1rem;
}

.carac-liste { margin: 0; }

/* Nom à gauche, valeur à droite, séparés par un filet : c'est la forme
   qu'on lit sans effort dans un tableau technique. */
.carac-ligne {
    display: flex;
    justify-content: space-between;
    gap: var(--r4);
    padding: var(--r3) 0;
    border-bottom: 1px solid var(--bordure);
}

.carac-ligne:last-child { border-bottom: none; }

.carac-ligne dt {
    color: var(--texte-doux);
    font-size: .9375rem;
}

.carac-ligne dd {
    margin: 0;
    font-weight: 600;
    text-align: right;
}
