/*
|--------------------------------------------------------------------------
| RIWAQ SHOP — Boutique
|--------------------------------------------------------------------------
|
| Feuille autonome, sans rapport avec admin.css : le back-office parle à un
| opérateur qui traite des dizaines de commandes, la boutique parle à
| quelqu'un qui arrive d'une publicité sur son téléphone et se demande s'il
| peut faire confiance.
|
| C'est de là que vient le parti pris : au Maroc, le paiement à la
| livraison EST l'argument. Il n'est donc pas relégué dans un bandeau de
| réassurance en pied de page — il accompagne chaque prix, partout.
|
| Le vert profond du thé à la menthe sert d'unique accent. Le reste est
| volontairement neutre et chaud : ce sont les photos de cuir qui doivent
| porter la couleur, pas l'habillage.
*/

:root {
    /*
     * « Ivoire & Bordeaux », arrêtée le 20 août 2026.
     *
     * Répartition 60/30/10 : l'ivoire porte la page, le blanc et les
     * gris chauds portent les cartes, l'en-tête et les formulaires, le
     * bordeaux ne sert qu'aux gestes — bouton d'action, prix de la
     * fiche, lien actif, panier. Au-delà d'un dixième de la page il
     * cesse d'appeler, et c'est tout ce qu'on lui demande.
     *
     * Le reste est volontairement neutre : la couleur doit venir des
     * produits. Un fond blanc pur écrasait les photos, un rose
     * d'interface les aurait concurrencées.
     */
    --shop-ink: #0B1E3A;
    --shop-muted: #6B7280;
    --shop-paper: #F8F5ED;
    --shop-surface: #FFFFFF;
    --shop-line: #E7DECF;
    /*
     * Neutre chaud intermédiaire, entre le fond et la bordure : fonds
     * d'image en attente, survols discrets, blocs de réassurance. Il
     * est dérivé de la palette, qui ne nomme que les deux extrémités.
     */
    --shop-sand: #F2EBDD;

    /*
     * L'accent, et lui seul. `--shop-onbrand` existe pour que le texte
     * posé dessus ne soit jamais écrit en dur dans une règle.
     */
    --shop-brand: #D4AF37;
    --shop-brand-blue: #14335E;
    --shop-brand-hover: #B78E1E;
    --shop-brand-soft: #FFF4D1;
    --shop-brand-veil: #F6E4AE;
    --shop-brand-line: rgba(212, 175, 55, 0.42);
    --shop-onbrand: #0B1E3A;

    /*
     * Signaux à usage strictement limité. Chacun dit une seule chose,
     * et s'en servir ailleurs la lui retire :
     *
     *   --shop-sale       la remise, jamais une erreur de formulaire ;
     *   --shop-gold       le badge « meilleure vente », toujours en
     *                     fond avec du texte foncé — posé en texte sur
     *                     blanc il tombe sous le seuil de lisibilité ;
     *   --shop-ok         la commande confirmée ;
     *   --shop-whatsapp   le vert de WhatsApp, qui n'est pas le nôtre :
     *                     le bouton doit se reconnaître comme WhatsApp,
     *                     pas comme la boutique.
     */
    --shop-sale: #C0392B;
    /*
     * Le prix. Il partage la valeur de la remise : demandé en rouge
     * franc plutôt qu'en bordeaux, parce que le bordeaux se lisait
     * comme une couleur d'habillage et que le montant se cherchait du
     * regard sur une grille de douze cartes. Le jeton reste distinct
     * pour que l'un puisse bouger sans l'autre.
     */
    --shop-price: #0B1E3A;
    --shop-gold: #D4AF37;
    --shop-ok: #2E7D5B;
    --shop-whatsapp: #25D366;

    --shop-focus: rgba(212, 175, 55, 0.26);
    --shop-shadow: rgba(11, 30, 58, 0.07);
    --shop-shadow-soft: rgba(11, 30, 58, 0.12);
    --shop-shadow-strong: rgba(11, 30, 58, 0.22);
    --shop-shadow-deep: rgba(11, 30, 58, 0.28);
    /*
     * L'en-tête et la barre du panier laissent voir la page derrière
     * eux. Le voile reprend l'ivoire du fond : posé sur l'ancien
     * papier, il tirait sur le gris d'un ton que rien n'expliquait.
     */
    --shop-veil: rgba(248, 245, 237, 0.94);
    --shop-veil-strong: rgba(248, 245, 237, 0.98);
    /* Le pied de page renverse l'encre : ces deux jetons sont les
       seuls tons de texte posés sur le fond sombre. */
    --shop-onink: rgba(248, 245, 237, 0.78);
    --shop-line-onink: rgba(248, 245, 237, 0.18);
    /* Voile de la carte de confirmation, posé par-dessus la page. */
    --shop-scrim: rgba(11, 30, 58, 0.58);

    --shop-space: 1rem;
    --shop-radius: 10px;
    --shop-max: 78rem;

    /*
     * Cible tactile minimale, 44 px : la taille d'un pouce. Les liens du menu,
     * les pastilles et les commandes de l'en-tête ne descendent pas dessous.
     */
    --shop-tap: 2.75rem;
    /* La barre collée de l'en-tête sur téléphone : une seule ligne. */
    --shop-bar: 3.75rem;
    /*
     * Pour les masques de défilement (`mask-image`) : seule l'opacité compte,
     * la teinte n'est jamais vue. Un jeton plutôt qu'une valeur en dur dans
     * la règle.
     */
    --shop-opaque: #000;

    --shop-serif: Georgia, "Times New Roman", serif;
    --shop-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    /*
     * Réservée aux références et aux montants du bon de commande : des
     * chiffres de largeur fixe s'alignent en colonne et se recopient sans
     * erreur au téléphone, un « 0 » ne se confond plus avec un « O ».
     */
    --shop-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

*,
*::before,
*::after {
    box-sizing: border-box;
}

body {
    margin: 0;
    background: var(--shop-paper);
    color: var(--shop-ink);
    font-family: var(--shop-sans);
    font-size: 1rem;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

img {
    max-width: 100%;
    display: block;
}

a {
    color: inherit;
}

:where(a, button, input, select, summary):focus-visible {
    outline: 2px solid var(--shop-brand);
    outline-offset: 2px;
}

/*
 * Lu par les lecteurs d'écran, invisible à l'œil : les libellés du panier
 * et du sélecteur de langue, que le pictogramme remplace à l'écran.
 *
 * La classe était employée dans le panier depuis le début sans avoir
 * jamais été déclarée — le mot « Quantité » s'affichait donc en clair au
 * milieu des contrôles.
 */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    border: 0;
    clip-path: inset(50%);
    white-space: nowrap;
}

.shop-wrap {
    width: min(100% - 2rem, var(--shop-max));
    margin-inline: auto;
}

/* ==========================================================
   Typographie
   ========================================================== */

/*
 * Le serif porte la personnalité, en très grand et très resserré. Il ne
 * sert que pour les titres : en continu il fatiguerait sur mobile, où se
 * fait l'essentiel du trafic.
 */
.shop-display {
    margin: 0;
    font-family: var(--shop-serif);
    font-weight: 400;
    letter-spacing: -0.03em;
    line-height: 1.02;
}

/*
 * Le titre plafonnait à 84 pixels : sur trois lignes, il poussait à lui
 * seul la colonne de texte au-delà de l'écran.
 */
.shop-display--hero {
    font-size: clamp(2.5rem, 6vw, 4rem);
}

.shop-display--section {
    font-size: clamp(1.75rem, 4vw, 2.5rem);
}

.shop-lede {
    margin: 1.25rem 0 0;
    max-width: 34rem;
    color: var(--shop-muted);
    font-size: 1.0625rem;
}

.shop-lede--tight {
    margin-top: 0.75rem;
}

/* ==========================================================
   En-tête
   ========================================================== */

.shop-header {
    position: sticky;
    top: 0;
    z-index: 20;
    background: var(--shop-veil);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--shop-line);
}

.shop-header__inner {
    display: flex;
    align-items: center;
    gap: clamp(1rem, 3vw, 2rem);
    min-height: 4.5rem;
}

.shop-brand {
    display: inline-flex;
    align-items: center;
    flex: 0 0 auto;
    text-decoration: none;
}

.shop-brand {
    gap: 0.625rem;
}

.shop-brand__logo {
    width: 2.75rem;
    height: 2.75rem;
    flex: 0 0 auto;
    object-fit: cover;
    border-radius: 0.375rem;
}

/*
 * Le nom est composé, pas image : il reste net à toutes les tailles, se
 * copie, se lit à voix haute par un lecteur d'écran, et suit la couleur
 * du texte plutôt qu'un aplat figé.
 */
.shop-brand__name {
    display: grid;
    font-family: var(--shop-serif);
    font-size: 1.0625rem;
    letter-spacing: 0.16em;
    line-height: 1.05;
}

.shop-brand__name span {
    color: var(--shop-muted);
    font-size: 0.625rem;
    letter-spacing: 0.34em;
}

/*
 * margin-inline-start plutôt que margin-left : la marge bascule seule du
 * bon côté en arabe. C'est ce qui garde le menu contre les langues, à
 * droite en RTL et à gauche en LTR, sans règle dirigée.
 */
/*
 * La navigation se colle à la marque — à gauche en français et en
 * anglais, à droite en arabe — et ce sont les commandes qui sont
 * poussées à l'autre bout. La propriété logique suffit : aucune règle
 * dirigée n'est nécessaire pour retourner l'en-tête en arabe.
 */
.shop-nav {
    display: flex;
    /*
     * Chaque lien porte 0,375 rem de garde de chaque côté : une cible de
     * 44 px de large même pour « Sacs ». L'écart est réduit d'autant, de
     * sorte que la rangée garde la largeur qu'elle avait (1,5 rem entre les
     * mots) — sur tablette, quelques pixels de plus suffisent à renvoyer
     * le panier et la langue sur une seconde ligne.
     */
    gap: 0.5625rem;
    min-width: 0;
    font-size: 0.9375rem;
}

.shop-nav a {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: var(--shop-tap);
    min-inline-size: var(--shop-tap);
    padding-inline: 0.375rem;
    text-decoration: none;
    white-space: nowrap;
}

/*
 * Le soulignement est un trait posé sous le mot, pas une bordure : la cible
 * tactile fait 44 px de haut, et une bordure de bas de boîte se serait
 * retrouvée à quatorze pixels du texte. La page courante porte aussi un
 * poids plus fort — l'or seul sur blanc ne suffirait pas à la distinguer.
 */
.shop-nav a::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0.5rem;
    block-size: 2px;
    background: transparent;
    transition: background-color 0.15s ease;
}

.shop-nav a:hover::after,
.shop-nav a[aria-current="page"]::after {
    background: var(--shop-brand);
}

.shop-nav a[aria-current="page"] {
    font-weight: 600;
}

/*
 * Panier et langues : les deux commandes qui ne défilent jamais avec la
 * liste des catégories.
 */
.shop-header__actions {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    gap: 0.75rem;
    margin-inline-start: auto;
}

/*
 * Le lien du panier est déclaré ici, avec le reste de l'en-tête, et non
 * dans la section « Panier » : les règles du téléphone qui l'échangent
 * contre un pictogramme viennent après, et une règle déclarée plus bas
 * dans la feuille l'emporterait sur elles à spécificité égale.
 */
.shop-cart-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-block-size: var(--shop-tap);
    min-inline-size: var(--shop-tap);
    padding-inline: 0.25rem;
    text-decoration: none;
}

/*
 * Le chariot sur tous les écrans : il se lit dans les trois langues,
 * là où le mot « Panier » changeait de longueur à chacune et décalait
 * l'en-tête. Le libellé reste dans le HTML pour les lecteurs d'écran.
 */
.shop-cart-link__icon {
    width: 1.5rem;
    height: 1.5rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.shop-cart-count {
    display: grid;
    place-items: center;
    min-width: 1.375rem;
    height: 1.375rem;
    padding-inline: 0.375rem;
    border-radius: 999px;
    background: var(--shop-brand);
    color: var(--shop-surface);
    font-size: 0.75rem;
    font-weight: 600;
}

/*
 * display:grid l'emportait sur le display:none que le navigateur applique
 * à l'attribut hidden : la pastille affichait « 0 » sur un panier vide.
 */
.shop-cart-count[hidden] {
    display: none;
}

/*
|--------------------------------------------------------------------------
| Réseaux et téléphone
|--------------------------------------------------------------------------
|
| Les mêmes liens en haut et en bas de page. En haut ils sont réduits à
| leurs pictogrammes : le client qui hésite cherche une preuve que la
| boutique existe ailleurs qu'ici, et il la cherche tout de suite, pas
| après avoir fait défiler quatre écrans.
|
| Le numéro s'écrit en toutes lettres sur grand écran et se réduit au
| combiné sur téléphone, là où il suffit d'appuyer.
*/

.shop-social {
    display: flex;
    align-items: center;
    gap: 0.125rem;
}

.shop-social__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    min-inline-size: 2.25rem;
    min-block-size: 2.25rem;
    padding-inline: 0.25rem;
    border-radius: 999px;
    color: inherit;
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.shop-social__link:hover {
    background: var(--shop-brand-soft);
    color: var(--shop-brand);
}

/*
 * Dans l'en-tête, les pictogrammes seuls font 44 px : à 36, Instagram et
 * Facebook étaient les deux seules cibles de la barre sous le minimum
 * tactile, sur les écrans tactiles de bureau comme sur les tablettes
 * posées à l'horizontale.
 */
.shop-header .shop-social__link {
    min-inline-size: var(--shop-tap);
    min-block-size: var(--shop-tap);
}

.shop-social__icon {
    flex: none;
    inline-size: 1.125rem;
    block-size: 1.125rem;
    fill: currentColor;
}

/* Le combiné est tracé, pas plein : il vient du même jeu que la loupe. */
.shop-social__icon--stroke {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* ==========================================================
   Bandeau d'accueil
   ========================================================== */

/*
 * Le bandeau d'accueil occupait 932 pixels — 117 % de la hauteur d'écran.
 * Le visiteur arrivait donc sur une boutique sans y voir un seul produit :
 * il fallait faire défiler pour découvrir qu'il y avait quelque chose à
 * acheter. Sur une vitrine alimentée par la publicité, c'est la première
 * seconde qui décide.
 *
 * Il tient désormais dans l'écran, en laissant apparaître le haut des
 * produits — l'amorce qui donne envie de continuer.
 */
.shop-hero {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: center;
    gap: clamp(1.5rem, 4vw, 3rem);
    padding-block: clamp(1.25rem, 2.5vw, 2rem);
}

/*
 * La hauteur est bornée au lieu de découler de la largeur : en ratio 4/5,
 * une colonne de 592 pixels imposait 740 pixels de haut, et c'est elle qui
 * étirait tout le bandeau. La photo est recadrée par object-fit, jamais
 * déformée.
 */
.shop-hero__media {
    position: relative;
    block-size: clamp(20rem, 46vh, 28rem);
    overflow: hidden;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
}

.shop-hero__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shop-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

/*
 * Sous-titre du bandeau d'accroche. Gris plutôt que noir : il porte la
 * précision, pas l'annonce, et doit céder le pas au titre.
 */
.shop-hero__lede {
    margin-block-start: 0.875rem;
    max-inline-size: 32ch;
    color: var(--shop-muted);
    font-size: clamp(1rem, 1.4vw, 1.125rem);
    line-height: 1.5;
}

/*
 * Le paiement à la livraison, marqué d'un filet d'or. La ligne n'est pas
 * écrite en doré : l'or sur crème tombe sous 2:1 et ne se lirait plus. Le
 * filet porte la couleur, le texte garde le bleu nuit.
 *
 * `border-inline-start` et non `border-left` : en arabe le filet passe de
 * lui-même à droite.
 */
.shop-hero__cod {
    margin-block-start: 1rem;
    border-inline-start: 2px solid var(--shop-brand);
    padding-inline-start: 0.75rem;
    color: var(--shop-ink);
    font-size: 0.9375rem;
    font-weight: 600;
}

/* ==========================================================
   Boutons
   ========================================================== */

.shop-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 3rem;
    padding-inline: 1.5rem;
    border: 1px solid transparent;
    border-radius: var(--shop-radius);
    font: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.shop-btn--primary {
    background: var(--shop-brand);
    color: var(--shop-onbrand);
}

.shop-btn--primary:hover {
    background: var(--shop-brand-hover);
}

/*
 * Contour bordeaux. Un seul bouton plein par écran : sur la fiche
 * produit, le plein va à la commande au paiement à la livraison, et le
 * panier passe ici. Les deux se disputaient l'attention, et la cliente
 * hésitait sur lequel cliquer.
 */
.shop-btn--secondary {
    border-color: var(--shop-brand);
    background: var(--shop-surface);
    color: var(--shop-brand);
}

.shop-btn--secondary:hover {
    background: var(--shop-brand-soft);
}

/*
 * Contour encre : le bouton des cartes produit. Lisible sur le blanc
 * comme sur l'ivoire (l'or en texte tombe sous 3:1), et assez discret
 * pour qu'une grille de douze cartes ne devienne pas un mur doré.
 */
.shop-btn--outline {
    border: 1.5px solid var(--shop-ink);
    background: transparent;
    color: var(--shop-ink);
}

.shop-btn--outline:hover {
    background: var(--shop-sand);
}

/* Neutre : « voir plus », « continuer mes achats ». Aucun appel. */
.shop-btn--ghost {
    border-color: var(--shop-line);
    background: transparent;
}

.shop-btn--ghost:hover {
    background: var(--shop-sand);
}

.shop-btn--block {
    width: 100%;
}

/*
 * Pictogramme posé dans un bouton. `flex: none` l'empêche de se tasser
 * quand le libellé arabe, plus long, remplit la ligne.
 */
.shop-btn__icon {
    flex: none;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/*
 * Éteint : il faut d'abord choisir une taille. Le fond neutre dit que
 * le bouton existe mais n'attend rien ; le bordeaux serait un appel
 * qu'on ne peut pas suivre.
 */
.shop-btn[disabled],
.shop-btn[aria-disabled="true"] {
    background: var(--shop-sand);
    border-color: transparent;
    color: var(--shop-muted);
    cursor: not-allowed;
}

/* ==========================================================
   Grille de produits
   ========================================================== */

.shop-section {
    padding-block: clamp(1.75rem, 3.5vw, 2.75rem);
}

/* Les rayons suivent le visuel d'accroche : pas de double souffle. */
.shop-section--tight {
    padding-block-end: 0;
}

/*
 * Les trois rayons, en pastilles rondes. Chaque rubrique avait un bloc de
 * quatre produits plus bas dans la page ; ici elle tient en une ligne, et
 * la photo dit ce qu'on y trouve mieux que son nom seul.
 */
.shop-rayons {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
    margin: 1rem 0 0;
    padding: 0;
    list-style: none;
}

.shop-rayon {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    align-items: center;
    min-block-size: var(--shop-tap);
    color: var(--shop-ink);
    text-align: center;
    text-decoration: none;
}

.shop-rayon__media {
    display: block;
    inline-size: 100%;
    aspect-ratio: 1;
    overflow: hidden;
    border: 1px solid var(--shop-line);
    border-radius: 50%;
    background: var(--shop-sand);
}

.shop-rayon__media img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

.shop-rayon__name {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.25;
}

.shop-rayon:hover .shop-rayon__media {
    border-color: var(--shop-brand);
}

/*
 * Les trois promesses, au milieu de la page. Le bandeau du haut les dit
 * déjà, mais on le dépasse en deux secondes : au paiement à la livraison,
 * c'est à hauteur de produit qu'elles lèvent l'hésitation.
 */
.shop-promises {
    margin-block-start: 1.5rem;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem;
    padding: 1rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    list-style: none;
    text-align: center;
}

.shop-promises li {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    min-inline-size: 0;
}

.shop-promises strong {
    font-size: 0.875rem;
}

.shop-promises span {
    color: var(--shop-muted);
    font-size: 0.75rem;
    line-height: 1.35;
}

/* Le seul bouton doré de l'accueil, sous la grille. */
.shop-section__more {
    margin: 1.5rem 0 0;
}

@media (min-width: 621px) {
    .shop-section__more .shop-btn {
        display: inline-flex;
        inline-size: auto;
        min-inline-size: 18rem;
        margin-inline: auto;
    }

    .shop-section__more {
        text-align: center;
    }
}

@media (max-width: 420px) {
    .shop-promises {
        padding: 0.875rem 0.625rem;
        gap: 0.5rem;
    }

    .shop-promises strong {
        font-size: 0.8125rem;
    }
}

/*
 * La grille du catalogue suit immédiatement les filtres : elle n'a pas
 * besoin du grand souffle vertical des sections de la page d'accueil.
 */
.shop-section--products {
    padding-top: 2rem;
}

.shop-section__head {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.shop-section__head--catalog {
    padding-top: 1.5rem;
}

/*
 * Colonnes plus larges et gouttières franches. L'écart vertical dépasse
 * l'horizontal : les cartes ayant maintenant un bouton, un espacement
 * égal ferait remonter le titre de la rangée suivante contre lui.
 */
.shop-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16.5rem, 1fr));
    column-gap: clamp(1rem, 2vw, 1.75rem);
    row-gap: clamp(1.25rem, 2.5vw, 2rem);
}

.shop-card {
    display: flex;
    flex-direction: column;
}

.shop-card a {
    text-decoration: none;
}

.shop-card__media {
    position: relative;
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
}

.shop-card__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.4s ease;
}

.shop-card:hover .shop-card__media img {
    transform: scale(1.04);
}

.shop-card__tag {
    position: absolute;
    inset-block-start: 0.75rem;
    inset-inline-start: 0.75rem;
    padding: 0.25rem 0.625rem;
    border-radius: 999px;
    background: var(--shop-ink);
    color: var(--shop-paper);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.shop-card__tag--sale {
    background: var(--shop-sale);
}

.shop-card__tag--out {
    background: var(--shop-muted);
}

/*
 * Le corps pousse le bouton en bas : dans une rangée, les boutons
 * s'alignent quelle que soit la longueur des noms.
 */
.shop-card__body {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding-top: 1rem;
}

.shop-card__price {
    margin: 0.375rem 0 1rem;
}

.shop-card__amount {
    font-size: 1.0625rem;
    font-weight: 600;
}

/*
 * Le prix en cours reste à l'encre, même en promotion : c'est la
 * pastille de remise qui porte le rouge. Deux rouges côte à côte —
 * le montant et le pourcentage — se volaient l'attention, et le
 * montant est ce qui doit rester lisible.
 */
.shop-card__amount--sale {
    color: var(--shop-ink);
}

.shop-card__was {
    margin-inline-start: 0.5rem;
    color: var(--shop-muted);
    font-size: 0.875rem;
    text-decoration: line-through;
}

.shop-card__body > form,
.shop-card__body > .shop-btn {
    margin-top: auto;
}

.shop-card__body .shop-btn[aria-disabled="true"] {
    color: var(--shop-muted);
    cursor: not-allowed;
}

.shop-card__category {
    color: var(--shop-muted);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.shop-card__name {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: 1.1875rem;
    font-weight: 400;
    letter-spacing: -0.01em;
    line-height: 1.25;
}

/*
 * Le nom est un lien : sa cible fait 44 px de haut, comme celle du
 * panier, sans changer la taille du texte.
 */
.shop-card__name a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--shop-tap);
}

/* ==========================================================
   Prix
   ========================================================== */

/*
 * Le prix ne va jamais seul : la mention du paiement à la livraison lui
 * est attachée partout. C'est la promesse qui décide de l'achat sur ce
 * marché, elle ne peut pas vivre uniquement en pied de page.
 */
.shop-price {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.5rem;
}

/*
 * Nom et prix sur une seule ligne, alignés sur la même ligne de base :
 * l'un dit ce que c'est, l'autre ce que ça coûte, et l'œil les prend
 * ensemble. Le nom prend la place restante et passe à la ligne s'il est
 * long ; le prix garde la sienne.
 *
 * Pas de `flex-wrap` ici : une rangée qui peut aller à la ligne préfère
 * y renvoyer le prix entier plutôt que de le comprimer. Sans elle, le
 * bloc se replie par l'intérieur — le montant reste à côté du nom,
 * l'ancien prix barré et la remise passent dessous.
 */
.shop-product__identity {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.75rem 1rem;
    margin-block-start: 0.25rem;
}

/*
 * Base à huit rem et non douze : à 320 pixels, douze rem plus le prix
 * dépassaient la largeur utile et le montant basculait sous le nom —
 * exactement ce qu'on cherchait à éviter. Le nom passe à la ligne autant
 * de fois qu'il le faut, le prix reste à côté.
 */
.shop-product__identity > .shop-display {
    flex: 1 1 8rem;
    min-inline-size: 0;
    margin-block: 0;
}

/*
 * En promotion, le bloc porte trois choses : le prix, l'ancien barré et
 * la remise. À trois, il dépasse la largeur d'un téléphone et emportait
 * tout sous le nom. Il peut donc se replier — mais par l'intérieur : le
 * montant reste sur la ligne du nom, l'ancien prix et la remise passent
 * dessous.
 */
.shop-product__identity > .shop-price {
    flex: 0 1 auto;
    justify-content: flex-end;
    margin-block: 0;
}

/*
 * Le montant lui-même ne se comprime ni ne se coupe : c'est la seule
 * information de la page qui doit rester entière, « 1 29… » ne veut
 * rien dire.
 */
.shop-product__identity .shop-price__amount {
    flex: 0 0 auto;
    white-space: nowrap;
}

.shop-price--product {
    margin-top: 1rem;
}

/*
 * Le prix, partout où il paraît — carte, fiche, panier, récapitulatif.
 * Rouge et gras : c'est le seul texte de la page qui prenne cette
 * couleur, et c'est ce qui le rend trouvable d'un coup d'œil.
 *
 * Les chiffres sont en chasse fixe (`tabular-nums`) : sur une grille,
 * « 99 DH » et « 199 DH » s'alignent alors sous la même colonne au lieu
 * de danser d'une carte à l'autre.
 */
.shop-price__amount {
    color: var(--shop-price);
    font-size: 1.125rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

/*
 * Le prix de la fiche produit : celui sur lequel se prend la décision,
 * et le seul de l'écran — il porte donc la couleur de la marque. Sur
 * une grille de douze cartes, la même règle aurait noyé la page de
 * bordeaux et lui aurait retiré sa force d'appel.
 */
.shop-price__amount--lg {
    font-size: 1.625rem;
    line-height: 1.15;
}

.shop-price__was {
    color: var(--shop-muted);
    font-size: 0.875rem;
    text-decoration: line-through;
}

/* ==========================================================
   Fiche produit
   ========================================================== */

.shop-product {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
    gap: clamp(1.5rem, 3.5vw, 2.75rem);
    padding-block: clamp(1.25rem, 3vw, 2.25rem);
}

/*
 * `align-content: start` : la colonne de gauche est étirée sur la
 * hauteur de la colonne de droite, et ses deux rangées se partageaient
 * l'excédent — cent pixels de vide s'ouvraient entre la photo et ses
 * vignettes sur les fiches au formulaire long.
 */
.shop-product__gallery {
    display: grid;
    align-content: start;
    gap: 0.625rem;
}

.shop-product__main {
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
}

.shop-product__main img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/*
 * Vignettes portées de 5 à 7 rem : à la taille précédente, une boucle
 * ou une couture ne se distinguait pas d'une vignette à l'autre, et il
 * fallait ouvrir chaque photo pour voir ce qui changeait.
 */
.shop-product__thumbs {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
    gap: 0.625rem;
}

.shop-thumb {
    aspect-ratio: 1;
    overflow: hidden;
    padding: 0;
    border: 1px solid var(--shop-line);
    border-radius: calc(var(--shop-radius) - 2px);
    background: var(--shop-sand);
    cursor: pointer;
}

.shop-thumb[aria-pressed="true"] {
    border-color: var(--shop-ink);
    border-width: 2px;
}

.shop-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shop-field {
    margin-top: 1.25rem;
}

.shop-field__label {
    display: block;
    margin-bottom: 0.625rem;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.shop-field__value {
    color: var(--shop-muted);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}

.shop-choices {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.shop-swatch {
    display: grid;
    place-items: center;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    border: 1px solid var(--shop-line);
    border-radius: 999px;
    background: none;
    cursor: pointer;
}

.shop-swatch span {
    width: 1.75rem;
    height: 1.75rem;
    border: 1px solid var(--shop-line);
    border-radius: 999px;
}

.shop-swatch[aria-pressed="true"] {
    border-color: var(--shop-ink);
    border-width: 2px;
}

.shop-size {
    min-width: 3rem;
    min-height: 2.75rem;
    padding-inline: 0.75rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: transparent;
    font: inherit;
    font-size: 0.9375rem;
    cursor: pointer;
}

.shop-size[aria-pressed="true"] {
    border-color: var(--shop-ink);
    background: var(--shop-ink);
    color: var(--shop-paper);
}

/*
 * Réassurance placée juste au-dessus de l'appel à l'action, là où se
 * prend la décision.
 */
.shop-reassure {
    margin-top: 1.25rem;
    padding: 1rem 1.25rem;
    border-radius: var(--shop-radius);
    background: var(--shop-brand-soft);
    color: var(--shop-brand);
    font-size: 0.9375rem;
}

/* Rupture de stock : le même encart, mais sans la promesse en vert. */
.shop-reassure--muted {
    background: var(--shop-sand);
    color: var(--shop-ink);
}

.shop-reassure strong {
    display: block;
    font-size: 1rem;
}

.shop-product__add {
    margin-top: 1.25rem;
}

/*
 * Taille et quantité partagent une rangée : ce sont les deux seules
 * décisions qui restent avant le bouton, et empilées elles repoussaient
 * l'appel à l'action d'une centaine de pixels.
 *
 * `align-items: end` cale les commandes sur la même ligne de base quand
 * les deux libellés n'ont pas la même hauteur.
 */
.shop-product__pick {
    display: flex;
    flex-wrap: wrap;
    align-items: end;
    gap: 0.75rem 1.5rem;
    margin-block: 1.25rem 0.75rem;
}

.shop-product__pick > .shop-field {
    flex: 1 1 12rem;
    margin-top: 0;
}

.shop-product__pick > .shop-stepper {
    flex: 0 0 auto;
    flex-wrap: wrap;
    margin-block-end: 0;
}

/*
 * Dans la rangée partagée, le libellé de la quantité passe au-dessus
 * des trois commandes et prend la graphie de celui des tailles : les
 * deux groupes se lisent alors de la même façon.
 */
.shop-product__pick .shop-stepper__label {
    flex-basis: 100%;
    margin-inline-end: 0;
    margin-block-end: 0.25rem;
    color: var(--shop-ink);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/*
 * Sur téléphone, les pointures prennent la rangée entière et la
 * quantité passe dessous.
 *
 * Elles défilaient auparavant dans un couloir, côte à côte avec le
 * pas-à-pas, pour ne pas repousser le bouton de commande plus bas. Le
 * couloir tombait à quatre-vingt-deux pixels sur un écran de 390 : deux
 * pointures et demie visibles, la troisième coupée en son milieu, ce qui
 * se lit comme un défaut d'affichage et non comme quelque chose à faire
 * glisser. Personne ne balaie ce qu'il prend pour cassé.
 *
 * La raison de ce couloir a disparu : la barre de commande collée en bas
 * garde « Commander » sous le pouce quoi qu'il arrive, et une rangée de
 * plus ne coûte donc plus l'accès au bouton.
 */
@media (max-width: 620px) {
    /*
     * Une grille et non plus deux rangées empilées : les pointures
     * prennent la colonne souple, la quantité reste sur sa largeur
     * propre à côté. La page gagne une rangée entière, et les deux
     * dernières décisions avant le bouton se lisent d'un seul regard.
     *
     * `minmax(0, 1fr)` et non `1fr` : sans le minimum à zéro, une
     * colonne de grille refuse de descendre sous la largeur de son
     * contenu, et les pointures repoussaient la quantité hors de
     * l'écran au lieu de passer à la ligne.
     *
     * La quantité prend dix rem et non `auto` : son libellé porte
     * `flex-basis: 100%`, ce qui gonflait la piste automatique à 241
     * pixels — les trois commandes n'en occupent que 160. Il ne restait
     * que quatre-vingt-quatre pixels aux pointures, soit une seule par
     * rangée, empilées sur six lignes.
     */
    .shop-product__pick {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 10rem;
        gap: 0.625rem;
        align-items: end;
    }

    /*
     * Les pointures vont à la ligne dans leur propre colonne. Aucune
     * n'est jamais rognée ni réduite : quarante-quatre pixels restent
     * quarante-quatre, une rangée de plus coûte moins cher qu'une
     * pointure qu'on ne peut pas toucher.
     */
    .shop-product__pick > .shop-field {
        min-inline-size: 0;
    }

    .shop-product__pick .shop-choices {
        flex-wrap: wrap;
    }

    .shop-product__pick .shop-size {
        flex: 0 0 auto;
    }

    .shop-product__pick > .shop-stepper {
        flex: 0 0 auto;
    }

    /*
     * Sous 390 pixels, la quantité repasse sous les pointures : à cette
     * largeur les deux côte à côte ne tiennent qu'en rognant l'un ou
     * l'autre, et le brief l'interdit.
     */
    @media (max-width: 389px) {
        .shop-product__pick {
            grid-template-columns: minmax(0, 1fr);
        }
    }
}

.shop-prose {
    margin-block-start: 0.75rem;
    color: var(--shop-muted);
}

/* ==========================================================
   Filtres du catalogue
   ========================================================== */

.shop-filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    padding-block: 1.5rem;
    border-bottom: 1px solid var(--shop-line);
}

/*
 * Le bouton qui rallonge la grille, à la place des numéros de page, et le
 * compte qui dit où l'on en est.
 */
.shop-more {
    display: flex;
    flex-direction: column;
    gap: 0.625rem;
    align-items: center;
    margin: 1.5rem 0 0;
}

.shop-more__count {
    color: var(--shop-muted);
    font-size: 0.875rem;
}

@media (min-width: 621px) {
    .shop-more .shop-btn {
        inline-size: auto;
        min-inline-size: 16rem;
    }
}

.shop-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    align-items: center;
    min-width: 0;
}

.shop-pagination {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

/*
 * Famille or, jamais bleu nuit plein : une pastille remplie de navy
 * pesait autant qu'un bouton « Commander » et détournait le clic vers
 * un simple filtre. Le rayon reste un rayon.
 */
/*
 * Les pastilles de catégorie sont des cibles tactiles : 44 px de haut
 * comme le reste de la boutique, sans grossir le texte.
 */
.shop-chip {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--shop-tap);
    padding: 0.5rem 1rem;
    border: 1px solid var(--shop-brand-line);
    border-radius: 999px;
    background: var(--shop-brand-soft);
    color: var(--shop-ink);
    font-size: 0.875rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.shop-chip:hover {
    border-color: var(--shop-brand);
    background: var(--shop-brand-veil);
}

/*
 * L'état actif se marque par l'or affirmé et l'anneau bleu nuit, pas
 * par un renversement de couleur : l'œil suit une intensité, il n'a
 * pas à réapprendre une seconde grammaire.
 */
.shop-chip[aria-current="page"] {
    border-color: var(--shop-ink);
    background: var(--shop-brand);
    color: var(--shop-ink);
    font-weight: 600;
}

.shop-chip[aria-current="page"]:hover {
    background: var(--shop-brand-hover);
}

.shop-search,
.shop-catalog-sort {
    display: flex;
    gap: 0.5rem;
    margin-inline-start: auto;
}

.shop-input {
    min-height: 2.75rem;
    padding-inline: 0.875rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    font: inherit;
    font-size: 0.9375rem;
}

.shop-empty {
    padding: clamp(3rem, 8vw, 5rem) 1rem;
    text-align: center;
    color: var(--shop-muted);
}

.shop-empty__text {
    margin-top: 1rem;
}

.shop-empty__cta {
    margin-top: 1.5rem;
}

/*
 * Titre de page du panier et de la commande : l'air au-dessus qui les
 * décolle de l'en-tête.
 */
.shop-pagehead {
    padding-block-start: 2.5rem;
}

/* ==========================================================
   Pied de page
   ========================================================== */

/* ==========================================================
   Adaptation
   ========================================================== */

@media (max-width: 900px) {
    .shop-hero,
    .shop-product {
        grid-template-columns: 1fr;
    }

    .shop-hero__media {
        order: -1;
        /*
         * En colonne unique la photo doit rester large et courte. La
         * proportion 3/2 seule la laissait remonter à 510 pixels sur une
         * tablette, repoussant le titre et les boutons hors de l'écran :
         * on la plafonne.
         */
        block-size: auto;
        aspect-ratio: 3 / 2;
        max-block-size: 16rem;
    }

    .shop-hero {
        padding-block: clamp(1.5rem, 3vw, 2.25rem);
        gap: 1.5rem;
    }
}

/* ==========================================================
   Téléphone
   ==========================================================

   Le visiteur type arrive d'une publicité, sur un écran de 390 px, une
   main sur l'appareil. Tout ce qui suit part de là.
   ========================================================== */

@media (max-width: 620px) {
    /* ---- En-tête sur deux rangées ---------------------------------- */

    /*
     * Marque et commandes sur la première rangée, catégories sur la
     * seconde. Tout tenir sur une seule ligne débordait dès la troisième
     * catégorie et poussait la page à défiler latéralement.
     */
    .shop-header__inner {
        flex-wrap: wrap;
        gap: 0.5rem 0.75rem;
        min-height: 0;
        padding-block: 0.625rem;
    }

    .shop-brand__logo {
        height: 1.875rem;
    }

    .shop-header__actions {
        gap: 0.5rem;
    }

    /*
     * La liste des catégories occupe toute la rangée et défile
     * horizontalement. En arabe le défilement part de la droite : c'est
     * la direction du document qui le décide, aucune règle dirigée n'est
     * nécessaire.
     */
    .shop-nav {
        order: 3;
        width: 100%;
        gap: 1.125rem;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        padding-block-end: 0.125rem;
        font-size: 0.875rem;
        scrollbar-width: none;
    }

    .shop-nav::-webkit-scrollbar {
        display: none;
    }

    /* ---- Filtres du catalogue -------------------------------------- */

    .shop-filters {
        gap: 0.625rem;
        padding-block: 1rem;
    }

    .shop-chips {
        width: 100%;
        flex-wrap: nowrap;
        gap: 0.5rem;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        padding-block-end: 0.25rem;
        scrollbar-width: none;
    }

    .shop-chips::-webkit-scrollbar {
        display: none;
    }

    .shop-chip {
        padding: 0.4375rem 0.875rem;
        font-size: 0.8125rem;
    }

    .shop-search,
    .shop-catalog-sort {
        margin-inline-start: 0;
        width: 100%;
    }

    .shop-input {
        flex: 1;
        min-width: 0;
    }

    .shop-section--products {
        padding-block: 1.25rem 2rem;
    }

    /* ---- Catalogue en deux colonnes -------------------------------- */

    /*
     * Deux produits par rangée : c'est ce que le client attend d'une
     * boutique sur téléphone, et il en voit quatre sans faire défiler.
     * minmax(0, 1fr) et non une largeur minimale — sans quoi une seule
     * colonne subsiste à 390 px.
     */
    .shop-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 0.75rem;
        row-gap: 1.75rem;
    }

    .shop-card__body {
        padding-top: 0.625rem;
    }

    .shop-card__name {
        font-size: 0.9375rem;
        /* Deux lignes au plus : les boutons d'une rangée restent alignés. */
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
        overflow: hidden;
    }

    .shop-card__price {
        margin-block: 0.25rem 0.75rem;
    }

    .shop-card__amount {
        font-size: 0.9375rem;
    }

    .shop-card__was {
        font-size: 0.8125rem;
    }

    .shop-card__tag {
        inset-block-start: 0.5rem;
        inset-inline-start: 0.5rem;
        padding: 0.1875rem 0.5rem;
        font-size: 0.625rem;
    }

    /*
     * Quarante-quatre pixels, pas quarante : c'est le bouton d'achat
     * de la grille, touché au pouce sur un écran tenu d'une main. La
     * hauteur ne change rien au nombre de colonnes.
     */
    .shop-card__body .shop-btn {
        min-height: 2.75rem;
        padding-inline: 0.5rem;
        font-size: 0.8125rem;
    }


    /* ---- Fiche produit --------------------------------------------- */

    .shop-product {
        gap: 1.5rem;
        padding-block: 1.25rem 2rem;
    }

    /*
     * La photo entière plutôt qu'un cadrage. `cover` remplissait le carré
     * en coupant la chaussure : le talon ou la pointe sortaient du cadre,
     * et c'est justement ce qu'on regarde avant d'acheter. `contain` la
     * montre en entier ; le fond sable comble ce qui reste.
     */
    .shop-product__main {
        aspect-ratio: 1;
        background: var(--shop-sand);
    }

    .shop-product__main img {
        object-fit: contain;
    }

    /*
     * Les vignettes défilent au lieu d'empiler trois rangées entre la
     * photo et le prix. Le magnétisme les arrête sur un bord : sans lui,
     * le rail s'immobilise au milieu d'une vignette et l'on croit que
     * l'affichage est coupé.
     */
    .shop-product__thumbs {
        display: flex;
        gap: 0.5rem;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        padding-block-end: 0.25rem;
        scrollbar-width: none;
        scroll-snap-type: inline mandatory;
        scroll-padding-inline-start: 0;
    }

    .shop-product__thumbs::-webkit-scrollbar {
        display: none;
    }

    .shop-thumb {
        flex: 0 0 4.5rem;
        scroll-snap-align: start;
    }

    .shop-thumb img {
        object-fit: contain;
    }

    /* Cibles tactiles : 44 px, la taille d'un pouce. */
    .shop-swatch {
        width: 2.75rem;
        height: 2.75rem;
    }

    .shop-price__amount--lg {
        font-size: 1.375rem;
    }

    .shop-reassure {
        padding: 0.875rem 1rem;
        font-size: 0.875rem;
    }

    .shop-prose {
        margin-top: 1.5rem;
        padding-top: 1.5rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .shop-card__media img,
    .shop-btn,
    .shop-nav a::after {
        transition: none;
    }

    /*
     * Couper la transition ne suffisait pas : le zoom de la photo au
     * survol s'appliquait quand même, d'un coup. C'est le mouvement
     * lui-même qu'on retire ; les transitions de couleur, elles, ne
     * déplacent rien et restent.
     */
    .shop-card:hover .shop-card__media img {
        transform: none;
    }
}

/* ==========================================================
   Panier
   ========================================================== */

.shop-cart {
    display: grid;
    grid-template-columns: 1fr 20rem;
    align-items: start;
    gap: clamp(1.5rem, 3.5vw, 2.25rem);
    padding-block: 1.75rem;
}

.shop-line {
    display: grid;
    grid-template-columns: 5.5rem 1fr auto;
    gap: 1rem;
    align-items: center;
    padding: 1.25rem 0;
    border-bottom: 1px solid var(--shop-line);
}

.shop-line__media {
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
}

.shop-line__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shop-line__name {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: 1.0625rem;
    font-weight: 400;
}

/*
 * Le nom du produit est un lien : sa cible fait 44 px de haut comme les
 * autres, sans changer la taille du texte.
 */
.shop-line__name a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--shop-tap);
    text-decoration: none;
}

/* Retour au catalogue, sous le titre du panier. */
.shop-pagehead__back {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--shop-tap);
    color: var(--shop-ink);
    font-size: 0.9375rem;
    text-decoration: underline;
    text-underline-offset: 3px;
}

/*
 * Barre de commande du panier : téléphone seulement. Au-delà de
 * 620 pixels, le récapitulatif est à côté des articles et porte déjà le
 * bouton.
 */
.shop-cartbar--order {
    display: none;
}

@media (max-width: 620px) {
    .shop-cartbar--order:not([hidden]) {
        display: block;
    }
}

@media (min-width: 621px) {
    body:has(.shop-cartbar--order:not([hidden])) .shop-footer {
        margin-bottom: 0;
    }
}

.shop-line__meta {
    margin: 0.25rem 0 0;
    color: var(--shop-muted);
    font-size: 0.875rem;
}

.shop-line__controls {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

/*
 * La quantité du panier reprend le sélecteur de la fiche produit — mêmes
 * touches, mêmes dimensions : le geste appris sur le produit se rejoue
 * ici sans réapprentissage.
 */
.shop-line__qty {
    display: flex;
    align-items: center;
    gap: 0.375rem;
}

/*
 * Retirer une ligne. Discret — gris, sans fond, sans rouge : ce n'est
 * pas une action qu'on met en avant. Mais la zone touchée fait ses
 * quarante-quatre pixels : le lien souligné n'en offrait que
 * vingt-trois, et sur téléphone il jouxte le bouton « moins ». Un pouce
 * qui vise l'un et touche l'autre vide la ligne au lieu d'en retirer un.
 *
 * Le soulignement part au profit de l'icône : souligné *et* accompagné
 * d'une corbeille, le libellé faisait doublon de signal.
 */
.shop-line__remove {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-block-size: 2.75rem;
    padding-inline: 0.5rem;
    margin-inline-start: -0.5rem;
    border: 0;
    border-radius: var(--shop-radius);
    background: none;
    color: var(--shop-muted);
    font: inherit;
    font-size: 0.8125rem;
    cursor: pointer;
}

.shop-line__remove:hover {
    color: var(--shop-ink);
}

.shop-line__remove-icon {
    flex: none;
    inline-size: 1rem;
    block-size: 1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.shop-cart__update {
    padding-block-start: 1.25rem;
}

/*
 * Confirmation d'enregistrement d'une quantité : discrète, elle passe et
 * s'efface. Le vert dit que c'est fait sans réclamer un regard.
 */
.shop-cart__status {
    margin-block: 1rem 0;
    color: var(--shop-brand);
    font-size: 0.875rem;
    font-weight: 600;
}

.shop-cart__status[hidden] {
    display: none;
}

/*
 * Récapitulatif rendu collant : sur une longue liste, le total et le
 * bouton de commande doivent rester sous les yeux.
 */
.shop-summary {
    position: sticky;
    top: 6rem;
    padding: 1.5rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
}

.shop-summary__row {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.5rem;
}

/*
 * Le trait qui sépare le détail des articles de ce qu'il faut payer.
 * Porté par le total, et par la ligne de sous-total du récapitulatif de
 * commande, qui ouvre le même décompte.
 */
.shop-summary__row--sep,
.shop-summary__row--total {
    margin-top: 0.5rem;
    padding-block-start: 1rem;
    border-block-start: 1px solid var(--shop-line);
}

.shop-summary__row--total {
    font-size: 1.125rem;
    font-weight: 600;
}

.shop-summary__muted {
    color: var(--shop-muted);
}

.shop-summary__note {
    margin: 1rem 0 1.25rem;
    color: var(--shop-muted);
    font-size: 0.875rem;
}

/*
 * Le paiement à la livraison accompagne le total. À l'encre : l'or sur blanc
 * ne fait que 2,1:1, et c'est la ligne qui dit ce que le livreur encaissera.
 */
.shop-summary__cod {
    margin-top: 1rem;
    color: var(--shop-ink);
    font-size: 0.875rem;
    font-weight: 500;
}

.shop-whatsapp {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: 100%;
    min-height: 3rem;
    margin-top: 0.75rem;
    border-radius: var(--shop-radius);
    background: var(--shop-whatsapp);
    color: var(--shop-ink);
    font-weight: 600;
    text-decoration: none;
}

.shop-whatsapp:hover {
    background: var(--shop-whatsapp);
    filter: brightness(0.94);
}

.shop-whatsapp svg {
    width: 1.25rem;
    height: 1.25rem;
    fill: currentColor;
}

.shop-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
}

.shop-form-grid > .shop-form-field--wide {
    grid-column: 1 / -1;
}

/*
 * Même disposition qu'au formulaire rapide : le libellé occupe la
 * première colonne, le champ la seconde. La consigne, troisième
 * élément de la grille, est renvoyée sous le champ et non sous le
 * libellé.
 */
.shop-form-field {
    display: grid;
    grid-template-columns: minmax(4.5rem, 7.5rem) 1fr;
    align-items: center;
    gap: 0.625rem;
}

.shop-form-field label {
    margin-bottom: 0;
    font-size: 0.8125rem;
    font-weight: 600;
}

.shop-form-field__hint {
    grid-column: 2;
}

.shop-form-field:has(textarea) {
    align-items: start;
}

.shop-form-field:has(textarea) label {
    padding-block-start: 0.625rem;
}

.shop-form-field .shop-input,
.shop-form-field select,
.shop-form-field textarea {
    width: 100%;
    min-height: 2.75rem;
    padding: 0.625rem 0.875rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    font: inherit;
    font-size: 0.9375rem;
}

/*
 * Consigne sous un champ : elle explique le format attendu avant que le
 * client ne se trompe, plutôt que de le corriger après coup.
 */
.shop-form-field__hint {
    margin: 0.375rem 0 0;
    color: var(--shop-muted);
    font-size: 0.8125rem;
}

/*
 * Le champ fautif ne rougit plus : le rouge ne dit qu'une chose sur ce
 * site, la remise. Un cadre à l'encre se voit tout autant sur un fond
 * ivoire, et il ne se confond avec aucune promotion.
 */
.shop-form-field .shop-input:invalid:not(:placeholder-shown) {
    border-color: var(--shop-ink);
}

/*
 * L'erreur d'un champ, dite sous lui dans la langue de la page (shop.js).
 * Même habit que l'alerte du formulaire : encre sur sable, filet au début
 * de la ligne, qui bascule seul en arabe.
 */
.shop-field__error {
    margin: 0.375rem 0 0;
    padding-block: 0.375rem;
    padding-inline: 0.625rem;
    border-inline-start: 3px solid var(--shop-ink);
    border-radius: calc(var(--shop-radius) / 2);
    background: var(--shop-sand);
    color: var(--shop-ink);
    font-size: 0.8125rem;
    font-weight: 600;
}

/* Sur grand écran, sous le champ et non sous le libellé. */
@media (min-width: 621px) {
    .shop-form-field .shop-field__error {
        grid-column: 2;
    }
}

[aria-invalid="true"],
.shop-form-field [aria-invalid="true"] {
    border-color: var(--shop-ink);
    border-width: 2px;
}

/*
 * La note au livreur, repliée. Le « + » se lit dans les deux sens
 * d'écriture et dit qu'il y a quelque chose à ouvrir.
 */
.shop-note {
    display: block;
}

.shop-note__toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    min-block-size: var(--shop-tap);
    color: var(--shop-ink);
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 3px;
    list-style: none;
    cursor: pointer;
}

.shop-note__toggle::-webkit-details-marker {
    display: none;
}

.shop-note__toggle::before {
    content: "+";
    font-size: 1.125rem;
    line-height: 1;
    text-decoration: none;
}

.shop-note[open] .shop-note__toggle::before {
    content: "−";
}

.shop-note textarea {
    margin-block-start: 0.25rem;
}

/*
 * Vignettes du récapitulatif de commande : deux noms français se
 * ressemblent, deux photos non.
 */
/*
 * Deux classes : la règle « un montant ne se coupe jamais », plus bas
 * dans la feuille, remet le retour à la ligne sur toutes les rangées.
 * Ici la vignette garde le nom et le montant sur sa ligne ; c'est le nom
 * qui se replie.
 */
.shop-summary .shop-summary__row--item {
    flex-wrap: nowrap;
    align-items: center;
}

.shop-summary__thumb {
    flex: none;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    border-radius: calc(var(--shop-radius) - 2px);
    background: var(--shop-sand);
    object-fit: cover;
}

.shop-summary__item {
    flex: 1 1 auto;
    min-inline-size: 0;
}

.shop-alert {
    margin-bottom: 1.5rem;
    padding: 1rem 1.25rem;
    border: 1px solid var(--shop-ink);
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
    color: var(--shop-ink);
}

@media (max-width: 900px) {
    .shop-cart,
    .shop-form-grid {
        grid-template-columns: 1fr;
    }

    .shop-summary {
        position: static;
    }
}

@media (max-width: 620px) {
    .shop-line {
        grid-template-columns: 4rem 1fr;
    }

    /*
     * La rangée peut aller à la ligne. La zone de suppression fait
     * désormais ses quarante-quatre pixels, icône comprise : en anglais
     * — « Remove » — les trois commandes ne tenaient plus sur 320
     * pixels et poussaient la page à défiler latéralement.
     *
     * `margin-inline-start: 0` sur le bouton : le retrait optique qui
     * alignait son libellé n'a plus lieu d'être une fois qu'il se
     * retrouve seul sur sa ligne.
     */
    .shop-line__controls {
        grid-column: 1 / -1;
        flex-wrap: wrap;
        justify-content: space-between;
        row-gap: 0.25rem;
    }

    .shop-line__remove {
        margin-inline-start: 0;
    }
}

/* ==========================================================
   Confirmation d'ajout au panier
   ========================================================== */

/*
 * Une carte au centre de l'écran sur fond assombri. Le centre est le seul
 * endroit qui se voie aussi bien sur un téléphone tenu à une main que sur
 * un écran large — un bandeau d'angle passe inaperçu sur les deux.
 *
 * Elle se referme seule au bout de deux secondes : c'est une
 * confirmation, pas une étape.
 */
.shop-added {
    position: fixed;
    inset: 0;
    z-index: 80;
    display: grid;
    place-items: center;
    padding: 1rem;
}

.shop-added[hidden] {
    display: none;
}

.shop-added__backdrop {
    position: absolute;
    inset: 0;
    background: var(--shop-scrim);
    opacity: 0;
    transition: opacity 0.2s ease;
}

.shop-added.is-visible .shop-added__backdrop {
    opacity: 1;
}

.shop-added__card {
    position: relative;
    width: min(20rem, 100%);
    padding: 1.5rem 1.25rem 1.25rem;
    border-radius: calc(var(--shop-radius) * 2);
    background: var(--shop-surface);
    box-shadow: 0 24px 60px var(--shop-shadow-deep);
    text-align: center;
    opacity: 0;
    transform: scale(0.94) translateY(0.5rem);
    transition: opacity 0.2s ease, transform 0.2s ease;
}

.shop-added.is-visible .shop-added__card {
    opacity: 1;
    transform: none;
}

/*
 * La croix se place au coin de fin : à droite en français, à gauche en
 * arabe, sans règle supplémentaire.
 */
.shop-added__close {
    position: absolute;
    inset-block-start: 0.25rem;
    inset-inline-end: 0.5rem;
    width: 2.25rem;
    height: 2.25rem;
    border: 0;
    background: none;
    color: var(--shop-muted);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
}

.shop-added__media {
    width: 6.5rem;
    height: 6.5rem;
    margin-inline: auto;
    margin-block-end: 0.875rem;
    object-fit: cover;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
}

.shop-added__media[hidden] {
    display: none;
}

.shop-added__title {
    margin: 0;
    color: var(--shop-brand);
    font-size: 1.0625rem;
    font-weight: 600;
}

.shop-added__name {
    margin: 0.375rem 0 0;
    font-family: var(--shop-serif);
    font-size: 1.0625rem;
    line-height: 1.3;
}

.shop-added__variant,
.shop-added__price {
    margin: 0.25rem 0 0;
    color: var(--shop-muted);
    font-size: 0.875rem;
    /*
     * Chaque ligne est isolée du reste : le nom latin d'une couleur et le
     * montant gardent leur propre sens de lecture au milieu d'une page en
     * arabe.
     */
    unicode-bidi: isolate;
}

.shop-added__price {
    font-weight: 600;
    color: var(--shop-ink);
}

.shop-added__variant[hidden],
.shop-added__price[hidden] {
    display: none;
}

.shop-added .shop-btn {
    margin-top: 1.125rem;
}

/* Pulsation du compteur : le changement doit se remarquer. */
.shop-cart-count.is-bumped {
    animation: shop-bump 0.35s ease;
}

@keyframes shop-bump {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.35); }
    100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .shop-added__card,
    .shop-added__backdrop {
        transition: none;
    }

    .shop-cart-count.is-bumped {
        animation: none;
    }
}

/* ==========================================================
   Sélecteur de langue
   ========================================================== */

/*
 * Replié derrière un globe : les trois langues alignées prenaient le
 * tiers de l'en-tête, sur un écran de téléphone où chaque pixel sert à
 * montrer des produits.
 */
.shop-langs {
    position: relative;
    flex: 0 0 auto;
}

.shop-langs__toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    min-height: 2.75rem;
    padding-inline: 0.375rem;
    border-radius: var(--shop-radius);
    color: var(--shop-muted);
    cursor: pointer;
    list-style: none;
}

/* Le triangle par défaut de Safari, qui ne ressemble à rien d'autre. */
.shop-langs__toggle::-webkit-details-marker {
    display: none;
}

.shop-langs__toggle:hover,
.shop-langs[open] .shop-langs__toggle {
    color: var(--shop-ink);
}

.shop-langs__icon {
    width: 1.375rem;
    height: 1.375rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
}

.shop-langs__current {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
}

/*
 * Le panneau s'ouvre sous le globe, aligné sur le bord de fin : c'est
 * celui dont il est le plus proche, à droite en français comme à gauche
 * en arabe.
 */
.shop-langs__menu {
    position: absolute;
    inset-block-start: calc(100% + 0.25rem);
    inset-inline-end: 0;
    z-index: 30;
    display: grid;
    gap: 0.125rem;
    min-width: 8.5rem;
    padding: 0.25rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    box-shadow: 0 8px 24px var(--shop-shadow-soft);
}

.shop-lang {
    display: flex;
    align-items: center;
    min-block-size: var(--shop-tap);
    padding: 0.4rem 0.55rem;
    border-radius: calc(var(--shop-radius) - 2px);
    color: var(--shop-muted);
    font-size: 0.875rem;
    text-decoration: none;
    white-space: nowrap;
}

.shop-lang:hover {
    background: var(--shop-sand);
    color: var(--shop-ink);
}

.shop-lang.is-active {
    background: var(--shop-ink);
    color: var(--shop-paper);
    font-weight: 600;
}

/* ==========================================================
   Récapitulatif de commande
   ==========================================================

   Cette page est partagée sur WhatsApp : c'est elle que le vendeur
   ouvrira, et souvent la seule que le client rouvrira. Elle montre donc
   les articles en photo, pas seulement leurs noms.
   ========================================================== */

/*
 * La section garde la largeur de page commune — c'est elle qui pose le
 * bord sur lequel s'alignent le logo et la navigation. C'est son contenu
 * qui est borné : un bon de commande ne se lit pas sur 1 250 pixels.
 *
 * Auparavant la section elle-même était réduite à 44 rem et recentrée :
 * le reçu flottait à 187 pixels du bord suivi depuis l'accueil, sans
 * rien pour le rattacher à la page.
 */
.shop-recap {
    padding-block: clamp(1.5rem, 3vw, 2.5rem);
}

.shop-recap > * {
    max-inline-size: 44rem;
}

.shop-ticket__logo {
    display: block;
    /* 132 sur 44 : exactement le 3:1 du fichier, aucune bande vide. */
    inline-size: 8.25rem;
    block-size: auto;
    max-block-size: 2.75rem;
    object-fit: contain;
}/*
 * L'envoi sur WhatsApp est la seule chose qu'il reste à faire : cet
 * encart passe donc avant le récapitulatif et porte l'accent vert de la
 * boutique. Placé après la liste des articles{
    margin-top: 1.5rem;
    padding: 1.25rem;
    border: 2px solid var(--shop-brand);
    border-radius: var(--shop-radius);
    background: var(--shop-brand-soft);
}

.shop-recap__step {
    margin: 0;
    color: var(--shop-brand);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* Le bouton de l'étape obligatoire : plus haut que partout ailleurs. */
.shop-whatsapp--lg {
    min-height: 3.5rem;
    margin-top: 1rem;
    font-size: 1.0625rem;
}

/*
 * Le verrou anti-robot, entre le dernier champ et le bouton.
 *
 * Le widget est un cadre d'environ 300 x 65 px dont nous ne maîtrisons pas
 * le contenu : on ne lui impose ni largeur ni couleur, on se contente de
 * le poser et de le centrer. Le contraindre casserait son affichage sur
 * les écrans étroits, où il se replie de lui-même.
 *
 * `margin-inline: auto` et non `margin-left/right` : c'est ce qui rend le
 * centrage juste en arabe comme en français, sans règle [dir] séparée.
 */
.shop-turnstile {
    display: flex;
    justify-content: center;
    margin-block-start: 1.25rem;
    margin-inline: auto;
}

/*
 * Rien ne s'affiche tant que le script de Cloudflare n'a pas répondu. Sans
 * cette réserve de hauteur, le bouton d'envoi sauterait vers le bas au
 * moment où le widget apparaît — et le client cliquerait à côté.
 */
.shop-turnstile:not(:empty) {
    min-block-size: 65px;
}

.shop-checkout__submit {
    margin-top: 1.5rem;
}

.shop-recap__hint {
    margin-top: 1.25rem;
    color: var(--shop-muted);
    font-size: 0.875rem;
}

/*
 * L'aide, après le reçu. Un filet la sépare de la commande : ce qui est
 * au-dessus est acquis, ce qui est ici est facultatif. WhatsApp garde son
 * vert — c'est un canal de contact, pas une action d'achat.
 */
.shop-recap__help {
    margin-block-start: 2rem;
    padding-block-start: 1.5rem;
    border-block-start: 1px solid var(--shop-line);
}

.shop-recap__help-title {
    margin-block: 0 0.75rem;
    color: var(--shop-muted);
    font-size: 0.9375rem;
}

/*
 * Le bouton s'arrête à son libellé. Étalé sur les 44 rem de la colonne,
 * il pesait autant que le reçu au-dessus — or il ne sert qu'à poser une
 * question. `align-items: start` suit la direction : à droite en arabe.
 */
.shop-recap__help {
    display: flex;
    flex-direction: column;
    align-items: start;
}

/*
 * `.shop-whatsapp` est pleine largeur partout ailleurs — c'est un bouton
 * d'appel. Ici il n'appelle rien : on le ramène à son libellé, sans
 * toucher à la classe partagée.
 */
.shop-recap__help .shop-whatsapp {
    inline-size: auto;
    margin-block-start: 0;
    padding-inline: 1.25rem;
}

.shop-recap__back {
    margin-top: 2rem;
}

/* ----------------------------------------------------------
   Le bon de commande

   Dessiné comme le bordereau papier que le livreur pose sur le
   carton : un en-tête, les coordonnées, les articles, une
   perforation, et dessous le seul chiffre qui compte à la porte.
   Le client le lit sur son téléphone, le photographie, le montre.
   ---------------------------------------------------------- */

.shop-ticket {
    --ticket-pad: clamp(1.125rem, 4vw, 1.75rem);

    position: relative;
    margin-top: 1.75rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
}

.shop-ticket__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.375rem 0.75rem;
    padding: var(--ticket-pad);
    border-bottom: 1px solid var(--shop-line);
}

.shop-ticket__brand {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: 1.125rem;
    letter-spacing: 0.12em;
}

.shop-ticket__doc {
    margin: 0;
    color: var(--shop-muted);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/*
 * Le paiement à la livraison est l'argument de la boutique : il est
 * rappelé jusque sur le bon, à côté du nom, et non enfoui dans les
 * totaux.
 */
.shop-ticket__cod {
    margin: 0;
    margin-inline-start: auto;
    padding: 0.25rem 0.625rem;
    border-radius: 999px;
    background: var(--shop-brand-soft);
    color: var(--shop-brand);
    font-size: 0.75rem;
    font-weight: 600;
}

.shop-ticket__ids {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.875rem;
    margin: 0;
    padding: var(--ticket-pad);
    border-bottom: 1px solid var(--shop-line);
    background: var(--shop-paper);
}

.shop-ticket__id dt {
    color: var(--shop-muted);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.shop-ticket__ref {
    margin-block: 0.25rem 0;
    margin-inline: 0;
    font-family: var(--shop-mono);
    font-size: 0.9375rem;
    font-variant-numeric: tabular-nums;
    /* Référence et date restent lisibles de gauche à droite en arabe. */
    unicode-bidi: isolate;
}

.shop-ticket__to,
.shop-ticket__lines {
    padding: var(--ticket-pad);
}

.shop-ticket__lines {
    padding-block-start: 0;
}

.shop-ticket__label {
    margin: 0 0 0.625rem;
    color: var(--shop-muted);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/*
 * Nom, adresse, ville et note sont écrits par le client ou repris du
 * transporteur : ils arrivent en arabe comme en caractères latins, et
 * commencent souvent par un chiffre. `plaintext` fait déduire le sens de
 * lecture du texte lui-même, sans quoi « 18 rue Ibn Sina » s'affiche
 * « rue Ibn Sina 18 » sur une page en arabe — et le livreur cherche.
 *
 * Posé sur une boîte en ligne et non sur le paragraphe : le bloc garde
 * ainsi l'alignement de la page, à droite en arabe, pendant que le texte
 * s'ordonne selon sa propre langue.
 */
.shop-ticket__bidi {
    unicode-bidi: plaintext;
}

.shop-ticket__who {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: 1.0625rem;
}

.shop-ticket__phone {
    margin: 0.125rem 0 0;
    font-family: var(--shop-mono);
    font-size: 0.9375rem;
    font-variant-numeric: tabular-nums;
    unicode-bidi: isolate;
}

.shop-ticket__where {
    margin: 0.375rem 0 0;
    color: var(--shop-muted);
    font-size: 0.9375rem;
}

.shop-ticket__city {
    margin: 0.125rem 0 0;
    font-size: 0.9375rem;
    font-weight: 600;
}

.shop-ticket__note {
    margin: 0.75rem 0 0;
    padding-inline-start: 0.75rem;
    border-inline-start: 2px solid var(--shop-sand);
    color: var(--shop-muted);
    font-size: 0.875rem;
}

.shop-ticket__note-label {
    display: block;
    color: var(--shop-ink);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.shop-ticket__items {
    margin: 0;
    padding: 0;
    list-style: none;
}

.shop-ticket__item {
    display: grid;
    grid-template-columns: 3.5rem 1fr auto;
    align-items: center;
    gap: 0.875rem;
    padding-block: 0.75rem;
    border-block-start: 1px solid var(--shop-line);
}

.shop-ticket__item:first-child {
    border-block-start: 0;
    padding-block-start: 0;
}

.shop-ticket__media {
    aspect-ratio: 1;
    overflow: hidden;
    border-radius: calc(var(--shop-radius) - 2px);
    background: var(--shop-sand);
}

.shop-ticket__media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.shop-ticket__body {
    min-width: 0;
}

.shop-ticket__name {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: 1rem;
    line-height: 1.3;
}

.shop-ticket__meta {
    margin: 0.1875rem 0 0;
    color: var(--shop-muted);
    font-size: 0.8125rem;
}

/*
 * Le calcul de la ligne se lit toujours « 2 × 99 DH », même en arabe.
 *
 * Les montants restent dans la fonte du texte, contrairement aux
 * références : ils portent le nom de la devise, et « درهم » composé en
 * chasse fixe s'étire lettre à lettre jusqu'à devenir illisible. Seuls
 * les chiffres sont alignés, par les chiffres tabulaires.
 */
.shop-ticket__calc {
    font-variant-numeric: tabular-nums;
    unicode-bidi: isolate;
}

.shop-ticket__amount {
    font-size: 0.9375rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    /* Le montant garde l'ordre occidental, même en arabe. */
    unicode-bidi: isolate;
}

/*
 * La perforation : au-dessus ce que le client a choisi, en dessous ce
 * qu'il sortira de sa poche. Les deux entailles sont remplies de la
 * couleur du papier, comme des trous découpés dans le bordereau.
 */
.shop-ticket__perf {
    position: relative;
    height: 1.25rem;
    border-block-start: 1px dashed var(--shop-line);
}

.shop-ticket__perf::before,
.shop-ticket__perf::after {
    content: "";
    position: absolute;
    inset-block-start: -0.6875rem;
    width: 1.25rem;
    height: 1.25rem;
    border: 1px solid var(--shop-line);
    border-radius: 50%;
    background: var(--shop-paper);
}

.shop-ticket__perf::before {
    inset-inline-start: -0.6875rem;
}

.shop-ticket__perf::after {
    inset-inline-end: -0.6875rem;
}

.shop-ticket__totals {
    padding: var(--ticket-pad);
    padding-block-start: 0;
}

.shop-ticket__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.25rem;
    color: var(--shop-muted);
    font-size: 0.9375rem;
}

/*
 * Le montant dû est le seul chiffre que le client cherchera sur cette
 * page : il porte donc le vert de la boutique et la plus grande taille
 * de la carte, tout le reste étant tenu au calme.
 */
.shop-ticket__due {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 0.375rem 1rem;
    margin: 0.875rem 0 0;
    padding: 0.875rem 1rem;
    border-radius: calc(var(--shop-radius) - 2px);
    background: var(--shop-brand);
    color: var(--shop-surface);
}

.shop-ticket__due-label {
    font-size: 0.9375rem;
    font-weight: 600;
}

.shop-ticket__due-amount {
    font-size: clamp(1.375rem, 5vw, 1.75rem);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
    unicode-bidi: isolate;
}

@media (max-width: 620px) {
    .shop-recap {
        padding-block: 1.5rem 2rem;
    }

    .shop-ticket__ids {
        grid-template-columns: minmax(0, 1fr);
        gap: 0.625rem;
    }

    .shop-ticket__item {
        grid-template-columns: 3rem 1fr auto;
        gap: 0.75rem;
    }

    .shop-ticket__name {
        font-size: 0.9375rem;
    }
}

/*
 * À l'impression — ou à l'enregistrement en PDF depuis le téléphone — il
 * ne doit rester que le bon : l'en-tête de boutique, la barre de panier
 * et les boutons ne servent à personne sur une feuille.
 */
@media print {
    .shop-header,
    .shop-footer,
    .shop-cartbar,
    .shop-recap__help,
    .shop-recap__back,
    .shop-recap__head {
        display: none;
    }

    .shop-recap {
        padding-block: 0;
    }

    .shop-ticket {
        margin-top: 0;
        break-inside: avoid;
    }

    .shop-ticket__due {
        /* Les aplats ne s'impriment pas : le cadre prend le relais. */
        border: 2px solid var(--shop-ink);
        background: none;
        color: var(--shop-ink);
    }
}

/*
 * Barre de commande collée en bas, sur téléphone seulement. Le prix y
 * reste lisible pendant qu'on fait défiler les photos et la
 * description : c'est la seule chose qu'on cherche des yeux avant de
 * décider, et la remonter coûtait un aller-retour.
 *
 * `display: none` par défaut plutôt qu'un affichage masqué : hors
 * téléphone elle ne prend aucune place et ne déplace rien.
 */
.shop-buybar {
    display: none;
}

/*
 * Les règles de la barre restent groupées ici, après sa déclaration de
 * base. Placées plus haut dans le fichier, elles se faisaient écraser
 * par le `display: none` ci-dessus : une requête média n'ajoute pas de
 * spécificité, c'est la dernière règle écrite qui l'emporte, et la
 * barre ne s'allumait sur aucun téléphone.
 */
@media (max-width: 620px) {
    /*
     * `padding-block-end` reprend `safe-area-inset-bottom` : sur les
     * iPhone à encoche, la barre d'accueil recouvrait le bas du bouton,
     * et le pouce tombait à côté.
     *
     * La hauteur est réservée par `padding-block-end` sur le corps de la
     * page (voir `.shop-product`) : la barre étant fixe, elle ne pousse
     * rien et ne provoque aucun déplacement au chargement.
     */
    .shop-buybar {
        position: fixed;
        inset-inline: 0;
        inset-block-end: 0;
        z-index: 60;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.75rem;
        border-block-start: 1px solid var(--shop-line);
        padding: 0.625rem 1rem;
        padding-block-end: calc(0.625rem + env(safe-area-inset-bottom, 0px));
        background: var(--shop-veil-strong);
        backdrop-filter: blur(10px);
        -webkit-backdrop-filter: blur(10px);
        box-shadow: 0 -6px 24px var(--shop-shadow-soft);
    }

    /*
     * Masquée quand le formulaire de commande est à l'écran : proposer
     * « Commander » juste au-dessus du formulaire de commande ouvert ne
     * fait que recouvrir le premier champ.
     */
    .shop-buybar[hidden] {
        display: none;
    }

    /*
     * Le bandeau global du panier et celui-ci occupent le même bas
     * d'écran. Sur une fiche produit, c'est la commande de cet article
     * qui prime : le bandeau du panier s'efface, l'icône de l'en-tête
     * continuant d'y donner accès.
     *
     * Uniquement ici : au-dessus de 620 pixels la barre de commande
     * n'existe pas, et masquer le bandeau du panier ferait disparaître
     * le panier de la fiche sans rien mettre à la place.
     */
    main:has(.shop-buybar) ~ .shop-cartbar {
        display: none;
    }

    .shop-buybar__price {
        /* La marge par défaut du paragraphe ajoutait trente-six pixels
           de haut à une barre qui doit rester une lisière. */
        margin-block: 0;
        min-inline-size: 0;
        color: var(--shop-ink);
        font-size: 1.125rem;
        font-weight: 700;
        white-space: nowrap;
    }

    .shop-buybar__was {
        margin-inline-start: 0.4rem;
        color: var(--shop-muted);
        font-size: 0.875rem;
        font-weight: 500;
        text-decoration: line-through;
    }

    .shop-buybar .shop-btn {
        flex: 1 1 auto;
        max-inline-size: 60%;
        min-height: 2.75rem;
    }

    /*
     * La place de la barre est rendue au bas de la fiche, sans quoi elle
     * recouvre les derniers produits suggérés.
     */
    .shop-product {
        padding-block-end: calc(4.5rem + env(safe-area-inset-bottom, 0px));
    }
}

.shop-cartbar {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 50;
    border-block-start: 1px solid var(--shop-line);
    background: var(--shop-veil-strong);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 -6px 24px var(--shop-shadow-soft);
}

.shop-cartbar[hidden] {
    display: none;
}

.shop-cartbar__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.75rem;
}

.shop-cartbar__info {
    display: flex;
    flex-direction: column;
    line-height: 1.25;
}

.shop-cartbar__count {
    color: var(--shop-muted);
    font-size: 0.8125rem;
}

.shop-cartbar__total {
    font-size: 1.125rem;
}

/*
 * La barre recouvre le bas de page : on rend la hauteur au document pour
 * que le pied de page et le dernier produit restent atteignables.
 */
body:has(.shop-cartbar:not([hidden])) .shop-footer {
    margin-bottom: 4.5rem;
}

/*
 * L'arabe a besoin d'un peu plus d'interligne : ses signes diacritiques
 * dépassent au-dessus et en dessous de la ligne.
 */
[lang="ar"] body,
[dir="rtl"] {
    line-height: 1.75;
}

/*
 * Le serif Georgia n'a pas de glyphes arabes : le rendu retomberait sur
 * une police système au hasard. On demande explicitement les polices
 * arabes présentes sur les appareils courants.
 */
[dir="rtl"] .shop-display,
[dir="rtl"] .shop-brand,
[dir="rtl"] .shop-card__name,
[dir="rtl"] .shop-line__name {
    font-family: "Geeza Pro", "Noto Naskh Arabic", "Segoe UI",
        system-ui, sans-serif;
    letter-spacing: 0;
}

@media (max-width: 620px) {
    .shop-cartbar__inner {
        gap: 0.75rem;
        /* La barre de gestes de l'iPhone ne doit pas couvrir le bouton. */
        padding-block-end: calc(0.75rem + env(safe-area-inset-bottom, 0px));
    }

    .shop-cartbar__total {
        font-size: 1.0625rem;
    }

    .shop-cartbar .shop-btn {
        flex: 0 0 auto;
        min-height: 2.75rem;
        padding-inline: 1rem;
        font-size: 0.875rem;
    }

}

/* ==========================================================
   Quantité — pas-à-pas
   ==========================================================

   Deux touches encadrent le nombre. Elles sont dimensionnées
   pour le pouce : sur un téléphone tenu d'une main, une cible
   plus petite oblige à viser, et viser fait abandonner.

   Le nombre reste un champ ordinaire — c'est lui qui porte la
   valeur, les touches ne sont qu'un raccourci.
   ========================================================== */

.shop-stepper {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-block-end: 0.75rem;
}

/*
 * Le libellé pousse le groupe de commande vers la fin de la ligne : les
 * trois éléments qui se manipulent restent côte à côte, le pouce n'a pas
 * à traverser le texte pour passer du moins au plus.
 */
.shop-stepper__label {
    margin-inline-end: auto;
    color: var(--shop-muted);
    font-size: 0.875rem;
}

.shop-stepper__step {
    display: grid;
    place-items: center;
    inline-size: 2.75rem;
    block-size: 2.75rem;
    flex: 0 0 auto;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    color: var(--shop-ink);
    font: inherit;
    font-size: 1.25rem;
    line-height: 1;
    cursor: pointer;
    transition: border-color 150ms ease, background-color 150ms ease;
}

.shop-stepper__step:hover {
    border-color: var(--shop-brand);
    background: var(--shop-brand-soft);
}

.shop-stepper__step:focus-visible {
    outline: 2px solid var(--shop-brand);
    outline-offset: 2px;
}

.shop-stepper__value {
    inline-size: 3.5rem;
    block-size: 2.75rem;
    flex: 0 0 auto;
    padding-inline: 0.25rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    color: var(--shop-ink);
    font: inherit;
    font-size: 1rem;
    font-weight: 600;
    text-align: center;
}

/*
 * Les flèches natives du champ nombre feraient doublon avec les deux
 * touches, et se chevauchent avec elles sur les petites largeurs.
 */
.shop-stepper__value::-webkit-outer-spin-button,
.shop-stepper__value::-webkit-inner-spin-button {
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
}

.shop-stepper__value {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* ==========================================================
   Choix de la ville — champ unique
   ==========================================================

   Un seul contrôle : on tape, la liste se réduit sous le
   champ, on choisit. Le panneau se superpose au reste du
   formulaire plutôt que de le pousser vers le bas — huit
   cents villes déplaceraient tout l'écran à chaque frappe.

   Le <select> du serveur reste dans le formulaire, sorti du
   flux : il porte la valeur et sert de repli sans script.
   ========================================================== */

.shop-cities {
    display: grid;
    gap: 0.5rem;
}

.shop-combo {
    position: relative;
}

.shop-combo__field {
    inline-size: 100%;
}

/*
 * Le select natif quitte l'écran sans quitter le formulaire : `hidden`
 * ou `display: none` le retireraient de la validation, et sur certains
 * navigateurs du POST lui-même.
 *
 * Le sélecteur est qualifié par les deux classes de champ parce que
 * leurs règles de mise en forme — `.shop-form-field select` au panier,
 * `.shop-field select` sur la fiche produit — sont plus spécifiques
 * qu'une simple classe et l'emportaient : le select restait affiché en
 * pleine largeur sous le composant.
 */
.shop-combo__native,
.shop-form-field .shop-combo__native,
.shop-field .shop-combo__native {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    /*
     * Les minimums de la règle de champ survivraient à block-size seul :
     * le select gardait ses 44 pixels de haut sous le composant.
     */
    min-inline-size: 0;
    min-block-size: 0;
    max-block-size: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    clip-path: inset(50%);
    overflow: hidden;
    appearance: none;
}

.shop-combo__list {
    position: absolute;
    z-index: 20;
    inset-inline: 0;
    inset-block-start: calc(100% + 0.25rem);
    max-block-size: 17rem;
    margin: 0;
    padding: 0.25rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    box-shadow: 0 0.75rem 2rem var(--shop-shadow-soft);
    list-style: none;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.shop-combo__list[hidden] {
    display: none;
}

/*
 * L'en-tête de tarif reste visible pendant le défilement : c'est le
 * critère qui fait choisir entre deux communes voisines.
 */
.shop-combo__group {
    position: sticky;
    inset-block-start: -0.25rem;
    padding-block: 0.375rem;
    padding-inline: 0.625rem;
    background: var(--shop-sand);
    color: var(--shop-muted);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}

.shop-combo__option {
    padding-block: 0.625rem;
    padding-inline: 0.625rem;
    border-radius: calc(var(--shop-radius) - 0.125rem);
    color: var(--shop-ink);
    font-size: 0.9375rem;
    cursor: pointer;
}

.shop-combo__option:hover,
.shop-combo__option.is-active {
    background: var(--shop-brand-soft);
    color: var(--shop-brand);
}

.shop-combo__option[aria-selected="true"] {
    font-weight: 600;
}

.shop-combo__empty {
    padding-block: 1rem;
    padding-inline: 0.625rem;
    color: var(--shop-muted);
    font-size: 0.875rem;
    text-align: center;
}

/* Envoi tenté sans ville : le champ le dit. */
/* Même règle que les autres champs fautifs : à l'encre, pas en rouge. */
.shop-combo.is-missing .shop-combo__field {
    border-color: var(--shop-ink);
}

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

/* ==========================================================
   Commander depuis la fiche produit
   ==========================================================

   Le bloc le plus important de la boutique. Il répond aux quatre
   questions qu'un visiteur se pose en quelques secondes — quel produit,
   combien, combien la livraison, comment commander — sans le faire
   changer de page.

   Il est encadré et légèrement surélevé, seul élément de la fiche à
   l'être : c'est là qu'on veut que l'œil tombe après la photo et le
   prix.
   ========================================================== */

.shop-order {
    margin-block-start: 18px;
    padding-block: 18px;
    padding-inline: 20px;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    box-shadow: 0 10px 30px var(--shop-shadow);
}

/*
 * L'erreur du formulaire de commande, à l'encre : le rouge est réservé
 * à la remise. Le trait épais du côté du début de ligne suffit à la
 * distinguer d'un simple paragraphe, et il bascule seul en arabe.
 */
.shop-order__error {
    margin: 0 0 16px;
    padding-block: 10px;
    padding-inline: 14px;
    border: 1px solid var(--shop-ink);
    border-inline-start-width: 3px;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
    color: var(--shop-ink);
    font-size: 14px;
}

.shop-order__form {
    display: grid;
    gap: 14px;
}

.shop-field {
    display: grid;
    gap: 6px;
}

.shop-field label {
    color: var(--shop-ink);
    font-size: 13.5px;
    font-weight: 600;
}

.shop-field input,
.shop-field select,
.shop-field textarea {
    inline-size: 100%;
    padding-block: 12px;
    padding-inline: 14px;
    border: 1px solid var(--shop-line);
    border-radius: 10px;
    background: var(--shop-surface);
    color: var(--shop-ink);
    font: inherit;
    font-size: 15.5px;
}

/*
 * 16 px au minimum sur les champs : en dessous, Safari sur iPhone
 * agrandit la page au premier appui et le client se retrouve à faire
 * défiler un formulaire zoomé.
 */
@media (max-width: 620px) {
    .shop-field input,
    .shop-field select,
    .shop-field textarea {
        font-size: 16px;
    }
}

.shop-field input:focus-visible,
.shop-field select:focus-visible,
.shop-field textarea:focus-visible {
    outline: none;
    border-color: var(--shop-brand);
    box-shadow: 0 0 0 3px var(--shop-focus);
}

.shop-field textarea {
    resize: vertical;
    min-block-size: 4.5rem;
}

/*
 * Libellé et champ sur une seule ligne : le formulaire de commande
 * tombait sur six rangées de deux lignes, et le bouton d'envoi passait
 * sous la ligne de flottaison avant même que le client ait commencé.
 *
 * La colonne du libellé est bornée par minmax() plutôt que fixée : les
 * trois langues n'écrivent pas « Ville » de la même longueur.
 */
.shop-order__form .shop-field {
    grid-template-columns: minmax(5rem, 8.5rem) 1fr;
    align-items: center;
    gap: 0.75rem;
    margin-top: 0;
}

/*
 * Consigne sous un champ : elle occupe la seconde colonne, sous le
 * champ, et non la première sous le libellé.
 */
.shop-field__hint {
    grid-column: 2;
    margin: 0;
    color: var(--shop-muted);
    font-size: 0.8125rem;
    line-height: 1.45;
}

/* L'adresse tient sur deux lignes : son libellé se cale en haut. */
.shop-order__form .shop-field:has(textarea) {
    align-items: start;
}

.shop-order__form .shop-field:has(textarea) label {
    padding-block-start: 0.75rem;
}

/*
 * Sous 620 px la colonne du libellé prendrait le tiers de l'écran et
 * laisserait au champ de quoi montrer six caractères. Les deux
 * repassent donc l'un au-dessus de l'autre.
 */
@media (max-width: 620px) {
    .shop-order__form .shop-field,
    .shop-form-field {
        grid-template-columns: 1fr;
        align-items: stretch;
        gap: 0.375rem;
    }

    .shop-order__form .shop-field:has(textarea) label,
    .shop-form-field:has(textarea) label,
    .shop-form-field__hint,
    .shop-field__hint {
        padding-block-start: 0;
        grid-column: auto;
    }
}

/* ---- Le récapitulatif ---- */

.shop-order__totals {
    display: grid;
    gap: 8px;
    margin: 4px 0 0;
    padding-block: 14px;
    padding-inline: 16px;
    border-radius: 12px;
    background: var(--shop-sand);
}

.shop-order__totals > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
}

.shop-order__totals dt {
    /* À l'encre : le gris du site sur ce fond sable ne fait que 4,1:1. */
    color: var(--shop-ink);
    font-size: 14px;
}

.shop-order__totals dd {
    margin: 0;
    color: var(--shop-ink);
    font-size: 14.5px;
    font-weight: 600;
}

/*
 * Le total est le seul nombre qu'on lit sans chercher : c'est celui que
 * le livreur réclamera à la porte.
 */
.shop-order__grand {
    margin-block-start: 4px;
    padding-block-start: 10px;
    border-block-start: 1px solid var(--shop-line);
}

.shop-order__grand dt {
    color: var(--shop-ink) !important;
    font-weight: 700;
}

.shop-order__grand dd {
    font-size: 20px;
    font-weight: 800;
}

/* ---- Les trois promesses ---- */

.shop-order__promises {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin: 2px 0 0;
    padding: 0;
    list-style: none;
    color: var(--shop-muted);
    font-size: 12.5px;
}

.shop-order__promises li {
    display: flex;
    align-items: center;
    gap: 6px;
}

.shop-order__promises li::before {
    content: "";
    inline-size: 5px;
    block-size: 5px;
    border-radius: 999px;
    background: var(--shop-brand);
}

/* ==========================================================
   Bouton WhatsApp flottant
   ==========================================================

   Ancré au coin bas de l'écran, du côté de la lecture : à droite en
   français, à gauche en arabe. `inset-inline-end` s'en charge sans
   qu'on écrive deux règles.

   Il s'efface derrière la barre de panier sur mobile — celle-ci est un
   geste d'achat en cours, et rien ne doit passer devant.
   ========================================================== */

.shop-wa {
    position: fixed;
    inset-block-end: 1rem;
    inset-inline-end: 1rem;
    z-index: 60;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 10px;
}

[dir="rtl"] .shop-wa {
    align-items: flex-start;
}

/*
 * Le vert de WhatsApp porte du texte foncé, pas du blanc : blanc sur
 * ce vert donne moins de deux pour un, et le libellé se devinait
 * plutôt qu'il ne se lisait. Le vert, lui, ne bouge pas — c'est à lui
 * que le bouton se reconnaît.
 */
.shop-wa__button {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding-block: 12px;
    padding-inline: 16px;
    border-radius: 999px;
    background: var(--shop-whatsapp);
    color: var(--shop-ink);
    font-size: 15px;
    font-weight: 600;
    text-decoration: none;
    box-shadow: 0 8px 24px var(--shop-shadow-strong);
    transition: transform var(--shop-fast, 150ms ease);
}

.shop-wa__button:hover {
    transform: translateY(-2px);
}

.shop-wa__button:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--shop-focus), 0 8px 24px var(--shop-shadow-strong);
}

.shop-wa__icon svg,
.shop-wa__choice-icon svg {
    display: block;
    inline-size: 22px;
    block-size: 22px;
    fill: currentColor;
}

/*
 * Sur téléphone le libellé disparaît : la pastille verte au logo est
 * reconnue sans un mot, et la place gagnée revient au contenu.
 */
@media (max-width: 620px) {
    .shop-wa__text {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .shop-wa__button {
        padding: 14px;
    }

    .shop-wa {
        inset-block-end: 0.75rem;
        inset-inline-end: 0.75rem;
    }
}

/* ---- Le choix entre les deux numéros ---- */

.shop-wa__panel {
    inline-size: min(18rem, calc(100vw - 2rem));
    padding-block: 16px;
    padding-inline: 16px;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    background: var(--shop-surface);
    box-shadow: 0 16px 40px var(--shop-shadow-strong);
}

.shop-wa__title {
    margin: 0;
    color: var(--shop-ink);
    font-size: 16px;
    font-weight: 700;
}

.shop-wa__lede {
    margin: 4px 0 12px;
    color: var(--shop-muted);
    font-size: 13px;
    line-height: 1.5;
}

.shop-wa__choice {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-block: 10px;
    padding-inline: 12px;
    border-radius: 10px;
    color: var(--shop-ink);
    text-decoration: none;
}

.shop-wa__choice:hover {
    background: var(--shop-brand-soft);
}

.shop-wa__choice-icon {
    display: grid;
    place-items: center;
    inline-size: 36px;
    block-size: 36px;
    flex: 0 0 auto;
    border-radius: 999px;
    background: var(--shop-whatsapp);
    color: var(--shop-surface);
}

.shop-wa__choice-role {
    display: block;
    font-size: 13.5px;
    font-weight: 600;
}

.shop-wa__choice-num {
    display: block;
    color: var(--shop-muted);
    font-family: var(--shop-mono);
    font-size: 12.5px;
}

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

    .shop-wa__button:hover {
        transform: none;
    }
}

/* ==========================================================
   Pied de page
   ==========================================================

   Il ne portait qu'un copyright. Le visiteur qui se demandait qui vend,
   où se trouve le magasin et ce qui se passe s'il veut échanger n'avait
   aucune réponse — et au paiement à la livraison, où il faut faire
   crédit d'avance à un inconnu, cette absence coûte des commandes.

   Trois étages : les coordonnées en quatre colonnes, les pages d'aide
   sur une ligne, puis l'identité légale. Sur téléphone les colonnes se
   rangent en une seule, mais les réseaux et les pages d'aide se
   partagent la ligne pour ne pas faire défiler un mètre de fond bleu.
   ========================================================== */

.shop-footer {
    margin-block-start: 2rem;
    padding-block: 2.25rem 1rem;
    background: var(--shop-ink);
    color: var(--shop-onink);
    font-size: 0.9rem;
}

/* Sur fond sombre le survol ne peut pas prendre le rose pâle. */
.shop-footer .shop-social__link:hover {
    background: var(--shop-line-onink);
    color: var(--shop-surface);
}

/*
 * Les coordonnées prennent la largeur de leur contenu : un numéro ou une
 * adresse e-mail coupés en deux ne se recopient plus. La marque et
 * l'adresse du magasin se partagent le reste.
 */
.shop-footer__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) max-content max-content;
    gap: 1.5rem 2.5rem;
}

.shop-footer__logo {
    display: block;
    inline-size: 6.5rem;
    block-size: auto;
    margin-block-end: 0.5rem;
}

.shop-footer__tagline {
    margin: 0;
    max-inline-size: 17rem;
    color: var(--shop-paper);
    font-family: var(--shop-serif);
    font-size: 1.05rem;
    line-height: 1.5;
}

/* L'or de la marque, en capitales normales : un titre, pas une étiquette. */
.shop-footer__head {
    margin: 0 0 0.75rem;
    color: var(--shop-gold);
    font-family: var(--shop-serif);
    font-size: 1rem;
    font-weight: 700;
}

.shop-footer__address {
    display: grid;
    gap: 0.15rem;
    margin: 0 0 0.6rem;
    font-style: normal;
    line-height: 1.55;
}

.shop-footer__link {
    color: var(--shop-onink);
    text-decoration: none;
}

.shop-footer__link:hover {
    color: var(--shop-paper);
    text-decoration: underline;
    text-decoration-color: var(--shop-gold);
    text-underline-offset: 3px;
}

.shop-footer__link:focus-visible {
    outline: 2px solid var(--shop-gold);
    outline-offset: 3px;
    border-radius: 2px;
}

.shop-footer__link--map {
    display: inline-block;
    color: var(--shop-paper);
    text-decoration: underline;
    text-decoration-color: var(--shop-gold);
    text-underline-offset: 3px;
}

/*
 * Pictogramme, nom du canal en retrait, puis la valeur en clair : l'œil
 * lit la colonne des numéros sans relire « WhatsApp », « Téléphone »…
 */
.shop-footer__contact {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-block-size: 2rem;
}

.shop-footer__contact .shop-social__icon {
    color: var(--shop-gold);
}

.shop-footer__label {
    flex: none;
}

.shop-footer__value {
    min-inline-size: 0;
    overflow-wrap: anywhere;
    color: var(--shop-paper);
    font-weight: 600;
}

.shop-footer__social {
    display: grid;
}

/* Les pages d'aide : titre et liens sur une seule ligne qui se replie. */
.shop-footer__help {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem 1.75rem;
    margin-block-start: 1.75rem;
    padding-block: 1rem;
    border-block-start: 1px solid var(--shop-line-onink);
}

.shop-footer__help .shop-footer__head {
    margin: 0;
}

.shop-footer__pages {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.shop-footer__legal {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.5rem;
    padding-block-start: 0.875rem;
    /* Le bouton WhatsApp flotte dans ce coin : le texte ne passe pas dessous. */
    padding-inline-end: 15rem;
    border-block-start: 1px solid var(--shop-line-onink);
    font-size: 0.8rem;
}

.shop-footer__legal p {
    margin: 0;
}

@media (max-width: 900px) {
    .shop-footer__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/*
 * Téléphone : une colonne, le contact d'abord, les deux réseaux sur une
 * même ligne. Les pages d'aide passent sur deux colonnes, à portée de
 * pouce.
 */
@media (max-width: 620px) {
    .shop-footer {
        padding-block-start: 1.75rem;
    }

    .shop-footer__grid {
        gap: 1.5rem 1rem;
    }

    .shop-footer__brand {
        display: flex;
        align-items: center;
        gap: 1rem;
        grid-column: 1 / -1;
    }

    .shop-footer__logo {
        inline-size: 4.5rem;
        margin: 0;
    }

    .shop-footer__col {
        grid-column: 1 / -1;
    }

    /* On appelle avant de venir : le contact passe devant l'adresse. */
    .shop-footer__col:nth-child(3) {
        order: -1;
    }

    .shop-footer__brand {
        order: -2;
    }

    .shop-footer__social {
        display: flex;
        flex-wrap: wrap;
        column-gap: 1.5rem;
    }

    .shop-footer__help {
        display: block;
        margin-block-start: 1.5rem;
    }

    .shop-footer__help .shop-footer__head {
        margin-block-end: 0.5rem;
    }

    .shop-footer__pages {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.15rem 1rem;
    }

    .shop-footer__pages .shop-footer__link {
        display: block;
        padding-block: 0.3rem;
    }

    .shop-footer__legal {
        flex-direction: column;
        padding-inline-end: 4rem;
    }
}

/* ==========================================================
   Pages d'information
   ==========================================================

   Une seule colonne, mesure de lecture courte. Ces pages se lisent
   vraiment — ce sont les seules du site dans ce cas — et une ligne de
   quatre-vingt-dix caractères se perd d'une ligne à l'autre.
   ========================================================== */

.shop-page {
    padding-block: 1.75rem 2rem;
}

.shop-page__title {
    margin: 0 0 1.5rem;
    max-inline-size: 24ch;
    color: var(--shop-ink);
    font-family: var(--shop-serif);
    font-size: clamp(1.8rem, 5vw, 2.6rem);
    font-weight: 700;
    line-height: 1.15;
}

.shop-page__body {
    max-inline-size: 62ch;
}

.shop-page__body h2 {
    margin: 2rem 0 0.6rem;
    color: var(--shop-ink);
    font-size: 1.15rem;
    font-weight: 700;
}

.shop-page__body p {
    margin: 0 0 1rem;
    color: var(--shop-muted);
    font-size: 1rem;
    line-height: 1.75;
}

.shop-page__body ul {
    margin: 0 0 1rem;
    padding-inline-start: 1.1rem;
    color: var(--shop-muted);
    font-size: 1rem;
    line-height: 1.75;
}

.shop-page__body li {
    margin-block-end: 0.35rem;
}

.shop-page__supplement {
    margin-block-start: 2rem;
    padding-block-start: 1.25rem;
    border-block-start: 1px solid var(--shop-line);
}

.shop-page__supplement h2 {
    margin-block-start: 0;
}

/*
 * Une référence officielle (récépissé CNDP) ne se coupe pas : ses tirets
 * offraient au navigateur un point de coupure, et « D- » restait seul en
 * fin de ligne sur téléphone.
 */
.shop-ref {
    white-space: nowrap;
}

.shop-page__email {
    color: var(--shop-ink);
    text-underline-offset: 3px;
}

.shop-page__map {
    margin-block-start: 2rem;
}

/* ==========================================================
   Recherche
   ==========================================================

   Toujours visible, jamais repliée derrière une loupe : un champ qu'il
   faut ouvrir avant de taper n'est pas une recherche visible.

   Sur grand écran elle prend la place libre entre la navigation et le
   panier. Sur téléphone elle passe à la ligne, pleine largeur, sous les
   catégories.
   ========================================================== */

/*
 * Bouton loupe. Il n'a de rôle qu'en dessous de 900 pixels, où le champ
 * est replié ; au-dessus, le champ est toujours là et le bouton n'aurait
 * rien à ouvrir.
 */
.shop-search-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    min-inline-size: 2.75rem;
    min-block-size: 2.75rem;
    border: 0;
    border-radius: var(--shop-radius);
    background: transparent;
    color: var(--shop-ink);
    cursor: pointer;
}

.shop-search-toggle svg {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
}

.shop-search-toggle[aria-expanded="true"] {
    color: var(--shop-brand-hover);
}

.shop-search {
    position: relative;
    display: flex;
    align-items: center;
    flex: 1 1 12rem;
    max-inline-size: 22rem;
    min-inline-size: 0;
}

.shop-search__label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.shop-search__icon {
    position: absolute;
    inset-inline-start: 0.7rem;
    inline-size: 1.05rem;
    block-size: 1.05rem;
    fill: none;
    stroke: var(--shop-muted);
    stroke-width: 1.8;
    stroke-linecap: round;
    pointer-events: none;
}

.shop-search__input {
    inline-size: 100%;
    padding-block: 0.55rem;
    padding-inline: 2.3rem 0.75rem;
    border: 1px solid var(--shop-line);
    border-radius: 999px;
    background: var(--shop-surface);
    color: var(--shop-ink);
    font: inherit;
    font-size: 0.92rem;
}

.shop-search__input:focus-visible {
    outline: none;
    border-color: var(--shop-brand);
    box-shadow: 0 0 0 3px var(--shop-focus);
}

/*
 * Le bouton n'est là que pour le clavier et les lecteurs d'écran : la
 * touche Entrée soumet déjà. Le masquer visuellement évite d'ajouter du
 * bruit à côté d'un champ qui se comprend seul.
 */
.shop-search__go {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.shop-search__go:focus-visible {
    position: static;
    inline-size: auto;
    block-size: auto;
    margin: 0;
    margin-inline-start: 0.5rem;
    padding-block: 0.45rem;
    padding-inline: 0.9rem;
    overflow: visible;
    clip-path: none;
    border-radius: 999px;
    background: var(--shop-brand);
    color: var(--shop-surface);
    font-size: 0.85rem;
}

@media (max-width: 900px) {
    /*
     * Le retour à la ligne s'ouvre ici et non à 620 px seulement.
     * `.shop-search` réclame `flex: 1 0 100%` dès cette largeur : sans
     * `wrap`, elle exigeait toute la largeur sans pouvoir descendre, et
     * poussait l'en-tête — donc chaque page — à défiler latéralement
     * entre 621 et 900 pixels, la bande des tablettes.
     */
    .shop-header__inner {
        flex-wrap: wrap;
    }

    /*
     * La recherche passe sous la navigation et prend toute la largeur :
     * c'est la commande qu'on cherche du pouce, elle mérite la ligne.
     */
    .shop-search-toggle {
        display: inline-flex;
    }

    /*
     * Repliée par défaut. Elle occupait une rangée entière de l'en-tête à
     * chaque page, pour un champ dont on ne se sert pas à chaque visite —
     * autant de hauteur prise sur les produits.
     */
    .shop-search {
        display: none;
        order: 3;
        flex: 1 0 100%;
        max-inline-size: none;
        margin-block-start: 0.6rem;
    }

    .shop-search.is-open {
        display: flex;
    }

    .shop-search__input {
        font-size: 16px;
    }
}

/* ==========================================================
   Badges de la carte produit
   ==========================================================

   Deux au maximum, et chacun repose sur un fait vérifiable : promotion
   réelle, stock réellement bas, ventes réellement livrées, mise en ligne
   récente. Un badge qui ment use la confiance qu'il cherche à gagner.

   Les couleurs suivent le sens : le rouge de la marque pour la remise,
   l'ambre pour la rareté, le vert pour la preuve sociale, l'encre pour
   la nouveauté. Aucun ne crie plus fort que le prix.
   ========================================================== */

/*
 * Les badges étaient posés un par un en absolu, chacun au même endroit :
 * deux badges se superposaient exactement. Ils vivent maintenant dans un
 * conteneur, seul absolu, et redeviennent des éléments de flux.
 */
.shop-card__tags .shop-card__tag {
    position: static;
    inset: auto;
}

.shop-card__tags {
    position: absolute;
    inset-block-start: 0.6rem;
    inset-inline-start: 0.6rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    max-inline-size: calc(100% - 1.2rem);
}

.shop-card__tag--sale {
    background: var(--shop-sale);
    color: var(--shop-surface);
}

/*
 * La rareté n'a pas de couleur propre dans la palette : ni or, réservé
 * à la meilleure vente, ni rouge, réservé à la remise. Elle prend le
 * fond pâle de la marque — « il n'en reste que deux » pousse à agir,
 * donc du côté du geste.
 */
.shop-card__tag--scarce {
    background: var(--shop-brand-soft);
    color: var(--shop-brand);
}

/*
 * L'or, toujours en fond et avec du texte foncé : posé en texte sur
 * blanc il tombe sous le seuil de lisibilité.
 */
.shop-card__tag--best {
    background: var(--shop-gold);
    color: var(--shop-ink);
}

.shop-card__tag--new {
    background: var(--shop-ink);
    color: var(--shop-paper);
}

/*
 * « 99 DH au lieu de 149 DH ». Le barré seul se devine ; avec ces trois
 * mots il se lit, et c'est la seule façon d'être sûr que l'ancien prix
 * ne passe pas pour le nouveau.
 */
.shop-card__was-label {
    color: var(--shop-muted);
    font-size: 0.78em;
    font-weight: 400;
}

/*
|--------------------------------------------------------------------------
| Avis clients
|--------------------------------------------------------------------------
|
| Des messages reçus, pas un tableau de bord de notation. La note
| moyenne se lit en gros parce que c'est ce qu'on cherche d'abord ;
| l'effectif se lit juste dessous parce qu'une moyenne sans effectif ne
| vaut rien.
|
| Les étoiles reprennent le vert de la marque. L'ambre de cette feuille
| appartient à la rareté (« il n'en reste que deux ») : deux ambres sur
| la même fiche auraient dit deux choses avec la même couleur.
|
*/

.shop-reviews {
    margin-block: 2.25rem;
    padding-block-start: 1.75rem;
    border-block-start: 1px solid var(--shop-line);
}

.shop-reviews__head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 2rem;
    margin-block-end: 1.75rem;
}

.shop-reviews__title {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2rem);
    font-weight: 400;
    line-height: 1.15;
}

/*
 * La moyenne, son « sur 5 » et l'effectif tiennent sur une ligne de
 * base commune : le grand chiffre poserait sinon les deux petits en
 * haut de sa propre hauteur.
 */
.shop-reviews__score {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    margin: 0;
}

.shop-reviews__average {
    font-family: var(--shop-serif);
    font-size: 2.5rem;
    line-height: 1;
    color: var(--shop-brand);
}

.shop-reviews__outof,
.shop-reviews__count {
    color: var(--shop-muted);
    font-size: 0.875rem;
}

.shop-reviews__count::before {
    content: "·";
    margin-inline-end: 0.4rem;
}

.shop-reviews__list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.shop-review {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 1.25rem;
    background: var(--shop-surface);
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
}

.shop-review__stars,
.shop-review__title,
.shop-review__by,
.shop-review__verified {
    margin: 0;
}

.shop-stars {
    display: inline-flex;
    gap: 0.1rem;
}

.shop-stars__item {
    fill: var(--shop-line);
}

.shop-stars__item.is-filled {
    fill: var(--shop-brand);
}

.shop-review__title {
    font-weight: 600;
    font-size: 0.9375rem;
}

/*
 * La citation est en romain, pas en italique : l'arabe n'a pas
 * d'italique, et le navigateur en fabrique une penchée mécaniquement,
 * illisible.
 */
.shop-review__text {
    margin: 0;
    font-family: var(--shop-serif);
    font-size: 1.0625rem;
    line-height: 1.55;
    white-space: pre-line;
}

.shop-review__by {
    margin-block-start: auto;
    padding-block-start: 0.6rem;
    border-block-start: 1px solid var(--shop-line);
    font-size: 0.875rem;
}

.shop-review__name {
    font-weight: 600;
}

.shop-review__city::before {
    content: "·";
    margin-inline: 0.4rem;
}

.shop-review__city {
    color: var(--shop-muted);
}

.shop-review__verified {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--shop-brand);
    font-size: 0.8125rem;
    font-weight: 600;
}

.shop-review__verified svg {
    fill: none;
    stroke: currentColor;
    stroke-width: 2.2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/*
 * Sur l'accueil, l'avis parle de la boutique et non d'un produit
 * précis : le nom du produit devient donc un lien, seul moyen d'aller
 * voir ce dont il est question.
 */
.shop-review__product {
    margin: 0;
    font-size: 0.8125rem;
}

.shop-review__product a {
    color: var(--shop-muted);
    text-decoration-color: var(--shop-line);
    text-underline-offset: 0.2em;
}

.shop-review__product a:hover {
    color: var(--shop-brand);
}

@media (max-width: 620px) {
    .shop-reviews {
        margin-block: 2.5rem;
        padding-block-start: 2rem;
    }

    .shop-reviews__head {
        align-items: flex-start;
    }

    .shop-reviews__average {
        font-size: 2rem;
    }
}

/*
|--------------------------------------------------------------------------
| Pastille de remise
|--------------------------------------------------------------------------
|
| « -34 % ». Le seul rouge de la boutique, et il ne dit que cela : ni
| une erreur de saisie, ni une alerte. C'est ce qui lui garde sa force.
|
| Elle s'aligne sur la ligne de base des montants et non sur leur
| hauteur : posée en exposant, elle flottait au-dessus du prix.
|
*/

.shop-off {
    display: inline-block;
    padding-block: 0.15rem;
    padding-inline: 0.45rem;
    border-radius: 999px;
    background: var(--shop-sale);
    color: var(--shop-paper);
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.4;
    white-space: nowrap;
}

/*
|--------------------------------------------------------------------------
| Le bouton WhatsApp cède la place à la barre du panier
|--------------------------------------------------------------------------
|
| Les deux sont fixés au bas de l'écran. Mesuré en 390 px dans les
| trois langues : la bulle verte se posait sur la fin du bouton « voir
| le panier » et en masquait le libellé — « Voir mon pa… » en français,
| et en arabe, où tout est inversé, elle couvrait le bouton entier.
|
| Le sélecteur s'appuie sur l'ordre du gabarit : la barre est écrite
| avant le bouton flottant. Il suit l'attribut `hidden`, que le script
| du panier pose et retire à chaque changement de quantité — la bulle
| redescend donc d'elle-même quand le panier se vide.
|
*/

.shop-cartbar:not([hidden]) ~ .shop-wa {
    inset-block-end: calc(4.5rem + 1rem);
}

/*
 * Même dégagement au-dessus de la barre de commande de la fiche. Il ne
 * tenait jusqu'ici qu'à un effet de bord : le bandeau du panier reste
 * dans le document avec `display: none`, donc sans `[hidden]`, et la
 * règle ci-dessus continuait de relever la bulle. Panier vide, elle
 * retombait sur le bouton « Commander ».
 */
/*
 * Et au-dessus de la barre de commande du panier, écrite dans la page
 * (donc dans <main>) et non à côté de la bulle.
 */
@media (max-width: 620px) {
    main:has(.shop-cartbar--order:not([hidden])) ~ .shop-wa {
        inset-block-end: calc(4.5rem + 1rem + env(safe-area-inset-bottom, 0px));
    }
}

/*
 * Sur le reçu de commande, la page porte son propre bouton WhatsApp, sous
 * le reçu : la bulle flottante, posée sur la colonne des montants, en
 * cachait un à chaque défilement. Sans ce bouton (lien ouvert par un
 * tiers, WhatsApp non configuré), la bulle reste.
 */
main:has(.shop-recap__help) ~ .shop-wa {
    display: none;
}

main:has(.shop-buybar) ~ .shop-wa {
    inset-block-end: calc(4.5rem + 1rem + env(safe-area-inset-bottom, 0px));
}

/*
 * Effacée tant que la zone d'achat est à l'écran. Une bulle flottante
 * finit toujours par croiser un bouton pleine largeur en défilant, et
 * ici ces boutons sont « Commander », « Ajouter au panier » et
 * « Confirmer ma commande » — ceux qu'elle ne doit jamais recouvrir.
 * Elle revient sur les photos, la description et les suggestions.
 *
 * La classe est posée par product.js ; sans JavaScript la bulle reste
 * visible, comme avant.
 */
.shop-wa.is-yielding {
    opacity: 0;
    visibility: hidden;
    transform: translateY(0.5rem);
}

.shop-wa {
    transition: opacity 0.18s ease, visibility 0.18s ease, transform 0.18s ease;
}

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


/* ==========================================================
   Identité RIWAQ SHOP — Bleu nuit, or et crème
   ==========================================================

   Cette couche suit docs/RIWAQSHOP_UI_BRANDING_SPEC.md. Elle reste
   volontairement concentrée sur la marque, l'en-tête, les boutons et
   le pied : la logique catalogue/COD ne change pas.
   ========================================================== */

.shop-header {
    background: var(--shop-surface);
    border-block-end-color: var(--shop-line);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: 0 8px 24px var(--shop-shadow);
}

.shop-header__trust {
    background: var(--shop-ink);
    color: var(--shop-paper);
}

.shop-header__trust-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    min-block-size: var(--shop-tap);
    padding-block: 0;
}

.shop-trust {
    display: flex;
    align-items: center;
    min-inline-size: 0;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scrollbar-width: none;
    color: var(--shop-paper);
    font-size: 0.75rem;
    font-weight: 600;
    white-space: nowrap;
}

.shop-trust::-webkit-scrollbar {
    display: none;
}

.shop-trust span {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding-inline: 0.9rem;
}

/*
 * Or sur bleu nuit, dix-sept pixels : assez pour se lire, trop peu
 * pour prendre le pas sur le mot qu'elle accompagne.
 */
.shop-trust__icon {
    flex: none;
    inline-size: 1.0625rem;
    block-size: 1.0625rem;
    color: var(--shop-brand);
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.shop-trust span:first-child {
    padding-inline-start: 0;
}

.shop-trust span + span {
    border-inline-start: 1px solid var(--shop-line-onink);
}

/*
 * Le numéro est un lien d'appel : sa cible fait 44 px de haut comme les
 * autres. La barre gagne huit pixels pour la contenir, au lieu d'une
 * cible qui déborderait sur l'en-tête et y volerait les clics.
 */
.shop-header__phone {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    flex: none;
    min-block-size: var(--shop-tap);
    color: var(--shop-paper);
    font-size: 0.75rem;
    text-decoration: none;
    white-space: nowrap;
}

.shop-header__phone strong {
    color: var(--shop-brand);
    font-weight: 700;
}

.shop-header__inner {
    min-block-size: 5rem;
    padding-block: 0.6rem;
}

.shop-brand {
    gap: 0;
}

.shop-brand__logo {
    inline-size: clamp(9.5rem, 13vw, 11.5rem);
    block-size: auto;
    max-block-size: 3.75rem;
    object-fit: contain;
    border-radius: 0;
}

.shop-nav a:hover,
.shop-nav a[aria-current="page"] {
    color: var(--shop-ink);
}

.shop-search__input {
    background: var(--shop-paper);
}

.shop-search__input:focus-visible {
    border-color: var(--shop-brand);
}

.shop-cart-count {
    background: var(--shop-brand);
    color: var(--shop-onbrand);
}

.shop-btn--primary {
    border-color: var(--shop-brand);
    background: var(--shop-brand);
    color: var(--shop-onbrand);
    box-shadow: 0 8px 18px var(--shop-shadow);
}

.shop-btn--primary:hover {
    border-color: var(--shop-brand-hover);
    background: var(--shop-brand-hover);
}

.shop-btn--secondary {
    border-color: var(--shop-ink);
    background: var(--shop-ink);
    color: var(--shop-surface);
}

.shop-btn--secondary:hover {
    border-color: var(--shop-brand-blue);
    background: var(--shop-brand-blue);
}

.shop-btn--ghost {
    border-color: var(--shop-line);
    background: var(--shop-surface);
    color: var(--shop-ink);
}

/*
 * Or en retrait. Sur la fiche produit, « Commander » et « Ajouter au
 * panier » ne peuvent pas être deux pleins identiques : côte à côte,
 * ils ne disent plus lequel des deux fait avancer l'achat. Celui-ci
 * garde la famille or — c'est bien une action commerciale — mais rend
 * le plein à la commande.
 */
.shop-btn--soft {
    border-color: var(--shop-brand-line);
    background: var(--shop-brand-soft);
    color: var(--shop-ink);
}

.shop-btn--soft:hover {
    border-color: var(--shop-brand);
    background: var(--shop-brand-veil);
}

.shop-btn--ghost:hover {
    border-color: var(--shop-brand);
    background: var(--shop-brand-soft);
}

@media (max-width: 900px) {
    .shop-header__inner {
        gap: 0.75rem 1rem;
    }

    .shop-header .shop-social {
        display: none;
    }

    .shop-brand__logo {
        inline-size: 9.25rem;
        max-block-size: 3.25rem;
    }
}

@media (max-width: 620px) {
    .shop-header__trust-inner {
        min-block-size: 2rem;
        padding-block: 0.25rem;
    }

    .shop-trust {
        inline-size: 100%;
        font-size: 0.6875rem;
    }

    .shop-trust span {
        gap: 0.3rem;
        padding-inline: 0.6rem;
    }

    .shop-trust__icon {
        inline-size: 1rem;
        block-size: 1rem;
    }

    .shop-header__phone {
        display: none;
    }

    .shop-header__inner {
        padding-block: 0.55rem;
    }

    .shop-brand__logo {
        inline-size: 8.25rem;
        max-block-size: 2.75rem;
    }

    .shop-nav {
        padding-block-start: 0.25rem;
    }
}


/* ==========================================================
   Lot 1 — en-tête compact, commande focalisée, pages d'erreur
   ==========================================================

   Tout ce bloc est écrit pour le téléphone d'abord : le visiteur type
   arrive d'une publicité, sur 390 px, une main sur l'appareil. Aucune
   valeur de couleur ici — les jetons de `:root` — et uniquement des
   propriétés logiques : l'arabe se retourne sans règle dirigée.
   ========================================================== */

/* ---- Pastilles --------------------------------------------------

   Les liens de navigation du téléphone, les langues du menu et les
   catégories de la page 404. Même famille que les filtres du catalogue
   (`.shop-chip`), qui fournit les couleurs ; seule la taille change : une
   pastille de filtre fait 33 px, une cible tactile en fait 44.
*/

.shop-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.shop-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-block-size: var(--shop-tap);
    padding-inline: 1rem;
    font-size: 0.9375rem;
    line-height: 1.2;
}

/* La langue courante du menu : même grammaire que la page courante. */
.shop-chip[aria-current="true"] {
    border-color: var(--shop-ink);
    background: var(--shop-brand);
    color: var(--shop-ink);
    font-weight: 600;
}

/* ---- Barre de l'en-tête -----------------------------------------

   L'enveloppe pleine largeur de la rangée marque/recherche/panier. Sur
   grand écran elle ne change rien — même fond que l'en-tête. Sur
   téléphone c'est elle, et elle seule, qui reste collée.
*/

.shop-header__bar {
    background: var(--shop-surface);
}

/* Menu et pastilles : propres au téléphone, absents ailleurs. */
.shop-menu,
.shop-pillbar {
    display: none;
}

@media (max-width: 620px) {

    /*
     * L'en-tête perd sa boîte : la barre de réassurance, la barre et les
     * pastilles deviennent trois frères dans <body>. C'est ce qui permet de
     * ne coller que la barre — une cellule collante reste bornée par son
     * parent, et l'en-tête entier ne fait que 144 px de haut. Le fond, le
     * filet et l'ombre de l'en-tête passent donc à la barre.
     */
    .shop-header {
        display: contents;
    }

    html {
        /* Une ancre (`#commander`) ne se glisse pas sous la barre collée. */
        scroll-padding-block-start: calc(var(--shop-bar) + 0.5rem);
    }

    .shop-header__bar {
        position: sticky;
        inset-block-start: 0;
        z-index: 20;
        border-block-end: 1px solid var(--shop-line);
        box-shadow: 0 4px 14px var(--shop-shadow);
    }

    /*
     * Une seule ligne de 60 px : menu, logo, loupe, panier. La recherche
     * dépliée passe dessous, sur sa propre ligne, et la barre grandit le
     * temps qu'elle est ouverte.
     */
    .shop-header__inner {
        gap: 0 0.25rem;
        min-block-size: var(--shop-bar);
        padding-block: 0.25rem;
    }

    /*
     * Le lien du logo fait 44 px de haut quelle que soit la taille de l'image :
     * à 108 px de large, le logo n'en a que 36, et la cible aurait suivi.
     */
    .shop-brand {
        flex: 0 1 auto;
        min-block-size: var(--shop-tap);
        min-inline-size: 0;
    }

    .shop-brand__logo {
        inline-size: 8.25rem;
        max-inline-size: 100%;
        max-block-size: 2.75rem;
    }

    /*
     * Un écran de 320 px n'a que 288 px utiles : menu, logo, loupe et
     * panier avec sa pastille n'y tiennent pas avec un logo de 132 px, et la
     * barre passait sur deux lignes. Le logo reste lisible à 108 px.
     */
    @media (max-width: 340px) {
        .shop-brand__logo {
            inline-size: 6.75rem;
        }
    }

    /* Ce que la barre ne porte plus : les catégories, les langues, les réseaux. */
    .shop-nav,
    .shop-langs,
    .shop-header .shop-social {
        display: none;
    }

    .shop-search-toggle {
        margin-inline-start: auto;
    }

    .shop-header__actions {
        margin-inline-start: 0;
        gap: 0;
    }

    /* ---- Le menu ---- */

    .shop-menu {
        display: block;
        flex: none;
    }

    .shop-menu__toggle {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        inline-size: var(--shop-tap);
        block-size: var(--shop-tap);
        border-radius: var(--shop-radius);
        color: var(--shop-ink);
        cursor: pointer;
        list-style: none;
    }

    /* Le triangle par défaut de Safari, qui ne ressemble à rien d'autre. */
    .shop-menu__toggle::-webkit-details-marker {
        display: none;
    }

    .shop-menu[open] .shop-menu__toggle {
        background: var(--shop-sand);
    }

    .shop-menu__icon {
        inline-size: 1.5rem;
        block-size: 1.5rem;
        fill: none;
        stroke: currentColor;
        stroke-width: 1.6;
        stroke-linecap: round;
        stroke-linejoin: round;
    }

    /*
     * La feuille s'ouvre sous la barre, sur toute sa largeur. La barre est
     * collée, donc positionnée : c'est elle qui sert de repère. Plafonnée à
     * la hauteur de l'écran moins la barre, elle défile si les pages d'aide
     * sont nombreuses.
     */
    .shop-menu__panel {
        position: absolute;
        inset-inline: 0;
        inset-block-start: 100%;
        max-block-size: calc(100dvh - var(--shop-bar));
        overflow-y: auto;
        border-block-end: 1px solid var(--shop-line);
        background: var(--shop-surface);
        box-shadow: 0 14px 28px var(--shop-shadow-soft);
    }

    .shop-menu__inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        gap: 0.75rem;
        padding-block: 1rem 0.5rem;
    }

    .shop-menu__langs {
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    .shop-menu__links {
        border-block-start: 1px solid var(--shop-line);
    }

    .shop-menu__links ul {
        margin: 0;
        padding: 0;
        list-style: none;
    }

    .shop-menu__links a {
        display: flex;
        align-items: center;
        min-block-size: var(--shop-tap);
        font-size: 0.9375rem;
        text-decoration: none;
    }

    .shop-menu__links a:hover {
        text-decoration: underline;
    }

    /* ---- Les catégories, en pastilles ---- */

    .shop-pillbar {
        display: block;
        border-block-end: 1px solid var(--shop-line);
        background: var(--shop-surface);
    }

    /*
     * La rangée défile latéralement. Les marges de 1,25 rem sont aussi la
     * zone de fondu : au repos, la première pastille est entière ; en
     * défilant, les suivantes s'effacent sous le bord au lieu d'être
     * tranchées en plein mot. Le dégradé est symétrique, donc le même en
     * arabe. L'aimant ramène une pastille contre le bord plutôt que de
     * laisser la rangée s'arrêter à cheval sur deux.
     */
    .shop-pillbar .shop-pills {
        flex-wrap: nowrap;
        padding-block: 0.25rem;
        padding-inline: 1.25rem;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        scroll-snap-type: inline proximity;
        scroll-padding-inline: 1.25rem;
        scrollbar-width: none;
        -webkit-mask-image: linear-gradient(
            to right,
            transparent,
            var(--shop-opaque) 1.25rem,
            var(--shop-opaque) calc(100% - 1.25rem),
            transparent
        );
        mask-image: linear-gradient(
            to right,
            transparent,
            var(--shop-opaque) 1.25rem,
            var(--shop-opaque) calc(100% - 1.25rem),
            transparent
        );
    }

    .shop-pillbar .shop-pills::-webkit-scrollbar {
        display: none;
    }

    .shop-pillbar .shop-pills li {
        flex: none;
        scroll-snap-align: start;
    }

    /* ---- La barre de réassurance : deux messages, jamais coupés ---- */

    .shop-header__trust-inner {
        justify-content: center;
    }

    .shop-trust {
        flex-wrap: wrap;
        justify-content: center;
        overflow: visible;
        white-space: normal;
    }

    /* Le troisième message (l'échange) n'a pas la place : la fiche le redit. */
    .shop-trust span:nth-child(n + 3) {
        display: none;
    }
}

/*
 * Bande 621–900 px : deux rangées voulues plutôt qu'un retour à la ligne
 * subi.
 *
 * Logo, catégories, loupe, langue et panier réclament 780 px en arabe ;
 * une tablette en portrait n'en a que 736. Le dernier élément tombait donc
 * seul sur une seconde ligne — la langue et le panier collés au bord, sous
 * un grand vide. Ici la première rangée garde le logo et les commandes, et
 * les catégories prennent toute la seconde, dans les trois langues et sur
 * toute la bande.
 */
@media (min-width: 621px) and (max-width: 900px) {
    .shop-header__inner {
        column-gap: 0.75rem;
        row-gap: 0;
    }

    .shop-nav {
        order: 2;
        flex: 1 0 100%;
    }

    .shop-search-toggle {
        margin-inline-start: auto;
    }

    .shop-header__actions {
        margin-inline-start: 0;
    }

    /*
     * Trois messages et le numéro ne tiennent pas sur une tablette en
     * portrait : le troisième était tranché en plein mot (« Échange et
     * ret »). Comme sur téléphone, l'échange cède sa place ; la fiche
     * produit et le pied de page le redisent.
     */
    .shop-trust span:nth-child(n + 3) {
        display: none;
    }

    /* À 621 px en français, il manquait huit pixels : l'écart se resserre. */
    .shop-trust span {
        padding-inline: 0.6rem;
    }
}

/* ---- Commande : en-tête réduit ----------------------------------

   Retour au panier, logo, rappel du paiement à la livraison. Il ne colle
   pas : il n'a rien à garder sous les yeux, et la hauteur est prise aux
   champs du formulaire.
*/

.shop-header--focus {
    position: static;
    box-shadow: none;
}

@media (max-width: 620px) {
    /* Redonne sa boîte à l'en-tête réduit : `display: contents` ne vaut que pour l'en-tête complet. */
    .shop-header--focus {
        display: block;
        border-block-end: 1px solid var(--shop-line);
        background: var(--shop-surface);
    }
}

.shop-focus {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-block-size: var(--shop-bar);
    padding-block: 0.25rem;
}

.shop-focus__back {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    min-block-size: var(--shop-tap);
    min-inline-size: var(--shop-tap);
    color: var(--shop-ink);
    font-size: 0.9375rem;
    font-weight: 500;
    text-decoration: none;
}

.shop-focus__back:hover {
    text-decoration: underline;
}

.shop-focus__icon {
    flex: none;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* Le chevron regarde vers le début de la ligne : à droite en arabe. */
[dir="rtl"] .shop-focus__icon--back {
    transform: scaleX(-1);
}

.shop-focus__note {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    margin: 0;
    margin-inline-start: auto;
    color: var(--shop-ink);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.3;
}

/* L'or foncé, pas l'or plein : sur blanc, le plein ne tient pas 2:1. */
.shop-focus__note .shop-focus__icon {
    color: var(--shop-brand-hover);
}

@media (max-width: 620px) {
    /*
     * Le mot « Retour au panier » n'a pas la place à côté du logo et de la
     * mention : la flèche reste, le mot passe aux lecteurs d'écran.
     */
    .shop-focus__label {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
}

/*
 * Le pied de la page de commande : l'identité légale seule, sur le fond de
 * la page. Ni colonnes ni liens — voir le gabarit.
 */
.shop-focus-legal {
    margin-block-start: 2.5rem;
    padding-block: 1.25rem 1.5rem;
    border-block-start: 1px solid var(--shop-line);
    color: var(--shop-ink);
    font-size: 0.8125rem;
}

.shop-focus-legal__inner {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.5rem;
}

.shop-focus-legal p {
    margin: 0;
}

/* ---- Commande : le récapitulatif avant le bouton -----------------

   Le formulaire est lui-même la grille : les champs d'un côté, de l'autre
   la colonne de validation — récapitulatif, verrou, bouton. Sous 900 px
   la grille s'empile dans le même ordre, et le récapitulatif passe donc
   avant le bouton sur téléphone aussi.
*/

.shop-checkout {
    padding-block: 1.75rem;
}

.shop-checkout__form {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 20rem;
    align-items: start;
    gap: clamp(1.5rem, 3.5vw, 2.25rem);
}

.shop-checkout__form > .shop-alert {
    grid-column: 1 / -1;
    margin-block-end: 0;
}

/*
 * Sur grand écran la colonne de validation reste en vue pendant qu'on
 * remplit : le bouton, et le total qu'il porte, ne sortent pas du cadre. Pas
 * d'en-tête collé sur cette page, donc un simple décalage du bord.
 */
.shop-checkout__side {
    position: sticky;
    inset-block-start: 1.5rem;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.25rem;
}

.shop-checkout__side .shop-summary {
    position: static;
}

.shop-checkout__side .shop-turnstile,
.shop-checkout__side .shop-checkout__submit {
    margin-block-start: 0;
}

/* Un montant ne se coupe jamais : c'est le libellé qui passe à la ligne. */
.shop-summary__row {
    flex-wrap: wrap;
}

.shop-summary__amount {
    flex: none;
    white-space: nowrap;
}

@media (max-width: 900px) {
    .shop-checkout__form {
        grid-template-columns: minmax(0, 1fr);
    }

    .shop-checkout__side {
        position: static;
    }
}

/* ---- Formulaire rapide de la fiche : titre, montants entiers ---- */

.shop-order__title {
    margin: 0 0 0.875rem;
    font-size: 1.125rem;
    line-height: 1.2;
}

/*
 * Les deux étapes de la fiche — choisir l'article, dire où le livrer —
 * portent un numéro dans une pastille d'or. Le numéro se lit avant le
 * texte : la cliente sait qu'il n'y a que deux choses à faire.
 */
.shop-step {
    display: flex;
    gap: 0.625rem;
    align-items: center;
    margin-block: 1.25rem 0.75rem;
    color: var(--shop-ink);
    font-family: var(--shop-serif);
    font-size: 1.125rem;
    font-weight: 600;
    line-height: 1.25;
}

.shop-step__num {
    display: inline-grid;
    flex: none;
    place-items: center;
    inline-size: 1.75rem;
    block-size: 1.75rem;
    border-radius: 50%;
    background: var(--shop-brand);
    color: var(--shop-onbrand);
    font-family: var(--shop-sans);
    font-size: 0.9375rem;
}

.shop-order .shop-step {
    margin-block-start: 0;
}

/*
 * Panier et WhatsApp sous la commande, côte à côte et à parts égales :
 * aucun des deux ne passe devant l'autre, et tous deux cèdent le pas au
 * bouton plein du dessus.
 */
.shop-order__alt {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.5rem;
    margin-block-start: 0.875rem;
}

.shop-order__alt .shop-btn {
    min-inline-size: 0;
    padding-inline: 0.75rem;
    white-space: normal;
    line-height: 1.15;
    text-align: center;
}

/*
 * Accordéons du détail produit. `<details>` fait tout le travail ; le
 * CSS remplace seulement le triangle du navigateur par un « + » qui
 * tourne en « × », lisible dans les deux sens d'écriture.
 */
.shop-acc-group {
    margin-block-start: 1.5rem;
    border-block-start: 1px solid var(--shop-line);
}

.shop-acc {
    border-block-end: 1px solid var(--shop-line);
}

.shop-acc__head {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    justify-content: space-between;
    min-block-size: var(--shop-tap);
    padding-block: 0.625rem;
    color: var(--shop-ink);
    font-weight: 600;
    list-style: none;
    cursor: pointer;
}

.shop-acc__head::-webkit-details-marker {
    display: none;
}

.shop-acc__head::after {
    content: "+";
    flex: none;
    font-size: 1.375rem;
    font-weight: 400;
    line-height: 1;
    transition: transform 0.2s ease;
}

.shop-acc[open] > .shop-acc__head::after {
    transform: rotate(45deg);
}

.shop-acc__head:focus-visible {
    outline: 2px solid var(--shop-brand);
    outline-offset: 2px;
}

.shop-acc__body {
    margin-block: 0 1rem;
}

.shop-acc__body p + p {
    margin-block-start: 0.75rem;
}

.shop-acc__links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1.25rem;
    margin: 0.75rem 0 0;
    padding: 0;
    list-style: none;
}

.shop-acc__links a {
    display: inline-flex;
    align-items: center;
    min-block-size: var(--shop-tap);
    color: var(--shop-ink);
    text-decoration: underline;
    text-underline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
    .shop-acc__head::after {
        transition: none;
    }
}

/*
 * Le total sur une ligne : « 199.00 / درهم » se coupait en deux, le
 * nombre d'un côté, la devise de l'autre. C'est le libellé, plus long, qui
 * se replie.
 */
.shop-order__totals dd {
    flex: none;
    white-space: nowrap;
}

/*
 * À 320 px le total — « 199 DH + livraison » — ne tient plus à côté de son
 * libellé : le montant passe à la ligne, calé sur la fin, au lieu de
 * pousser la page de côté.
 */
@media (max-width: 360px) {
    .shop-order__totals > div {
        flex-wrap: wrap;
    }

    .shop-order__totals dd {
        margin-inline-start: auto;
    }
}

.shop-summary__amount {
    margin-inline-start: auto;
}

/* ---- Pages d'erreur ---------------------------------------------

   La 404 vit dans le gabarit de la boutique, la 500 dans un gabarit
   autonome ; toutes deux partagent ce bloc. Le texte est à l'encre et non
   au gris : sur l'ivoire, le gris du site tombe à 4,4:1.
*/

.shop-notfound {
    display: grid;
    /*
     * Une colonne bornée à la largeur disponible : sans cela, la colonne
     * implicite prend la largeur de ce qui s'y lit le plus large — le
     * champ de recherche et son bouton — et la page débordait de 25 px à
     * 320 px.
     */
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 1.25rem;
    padding-block: clamp(2.5rem, 8vw, 5rem);
    text-align: center;
}

.shop-notfound__text {
    max-inline-size: 34rem;
    margin: 0;
    color: var(--shop-ink);
    font-size: 1.0625rem;
}

.shop-notfound__search {
    display: flex;
    gap: 0.5rem;
    inline-size: min(100%, 30rem);
}

.shop-notfound__search .shop-input {
    flex: 1;
    min-inline-size: 0;
    font-size: 1rem;
}

.shop-notfound__pills {
    justify-content: center;
}

.shop-notfound__actions {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 0.5rem;
    margin-block-start: 0.5rem;
}

.shop-notfound__wa {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-block-size: var(--shop-tap);
    color: var(--shop-ink);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.25em;
}

.shop-notfound__icon {
    flex: none;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    color: var(--shop-whatsapp);
}

/* La 500 n'a pas d'en-tête : le logo ouvre la page, centré. */
.shop-notfound--error .shop-brand {
    margin-block-end: 1rem;
}

.shop-errorpage main {
    display: grid;
    align-content: center;
    min-block-size: 100dvh;
}

/*
|--------------------------------------------------------------------------
| Fil d'Ariane (fiche produit)
|--------------------------------------------------------------------------
|
| Encre sur ivoire plutôt que le gris secondaire : `--shop-muted` sur le
| fond tombe sous 4,5:1. Chaque lien garde une cible de 44 px de haut ; le
| nom du produit, dernier maillon, se coupe d'une ellipse plutôt que de
| repousser la page sur deux lignes.
*/
.shop-breadcrumb {
    padding-block-start: 0.5rem;
}

.shop-breadcrumb__list {
    display: flex;
    align-items: center;
    flex-wrap: nowrap;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.875rem;
    color: var(--shop-ink);
    min-inline-size: 0;
}

.shop-breadcrumb__list li {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.shop-breadcrumb__list li + li::before {
    content: "/";
    opacity: 0.6;
}

.shop-breadcrumb__link {
    display: inline-flex;
    align-items: center;
    min-block-size: 2.75rem;
    color: var(--shop-ink);
    text-underline-offset: 0.25em;
}

.shop-breadcrumb__list .shop-breadcrumb__current {
    flex-shrink: 1;
    min-inline-size: 0;
    font-weight: 600;
}

.shop-breadcrumb__current span {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.shop-breadcrumb + .shop-product {
    padding-block-start: 0.5rem;
}

/*
 * Les deux colonnes de la fiche peuvent rétrécir sous la largeur de leur
 * contenu le plus long. Sans cela, une ligne du formulaire (tailles,
 * quantité) élargissait la colonne au-delà de l'écran : 1 à 2 px de
 * défilement horizontal à 390 px en français et en anglais.
 */
.shop-product > * {
    min-inline-size: 0;
}

/* ==========================================================
   Fiche produit : commande resserrée et fenêtre du téléphone
   ==========================================================
 *
 * La commande occupait près de mille pixels sur un téléphone : deux
 * titres d'étape, un encadré, des libellés espacés, un récapitulatif
 * en trois lignes et les promesses sous le bouton. Tout ce qui suit
 * resserre cet ensemble partout, puis, sous 620 pixels, le range dans
 * une fenêtre qui monte du bas de l'écran (voir product.js).
 */

/* Les promesses, sous le prix, sur une ligne. */
.shop-product__promises {
    margin-block: 0.5rem 0;
}

.shop-product .shop-step {
    margin-block: 1rem 0.5rem;
}

.shop-product .shop-order .shop-step {
    margin-block-start: 0;
}

.shop-product .shop-product__add {
    margin-block-start: 0.5rem;
}

/*
 * Article sans couleur ni pointure à choisir : l'étape s'intitule déjà
 * « Quantité », le même mot au-dessus du compteur faisait doublon. Il
 * reste pour les lecteurs d'écran, qui en ont besoin pour nommer le champ.
 */
.shop-product__pick:not(:has([data-size-field])) .shop-stepper__label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.shop-product .shop-product__pick {
    margin-block: 0.5rem 0;
}

.shop-product .shop-order {
    margin-block-start: 1rem;
    padding-block: 14px;
    padding-inline: 16px;
}

.shop-product .shop-order__title {
    margin-block-end: 0.625rem;
}

.shop-product .shop-order__form {
    gap: 10px;
}

.shop-product .shop-order__totals {
    gap: 4px;
    padding-block: 10px;
    padding-inline: 14px;
}

.shop-product .shop-order__grand {
    margin-block-start: 2px;
    padding-block-start: 6px;
}

.shop-product .shop-order__alt {
    margin-block-start: 0.625rem;
}

.shop-product .shop-acc-group {
    margin-block-start: 1rem;
}

.shop-order__foot {
    display: grid;
    gap: 10px;
}

/* En-tête et fond n'existent qu'en fenêtre. */
.shop-sheet__head,
.shop-sheet__backdrop {
    display: none;
}

@media (max-width: 620px) {
    .shop-sheet.is-modal {
        position: fixed;
        inset: 0;
        z-index: 70;
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
    }

    .shop-sheet.is-modal[hidden] {
        display: none;
    }

    .shop-sheet.is-modal .shop-sheet__backdrop {
        display: block;
        position: absolute;
        inset: 0;
        background: var(--shop-scrim);
    }

    /*
     * La fenêtre laisse voir une bande de la fiche au-dessus d'elle : on
     * sait qu'on n'a pas quitté la page, et qu'un appui dessus referme.
     * `dvh` suit la barre d'adresse du navigateur qui se replie ; `vh`
     * reste pour les navigateurs qui l'ignorent.
     */
    .shop-sheet.is-modal .shop-sheet__panel {
        position: relative;
        max-block-size: calc(100vh - 2.5rem);
        max-block-size: calc(100dvh - 2.5rem);
        overflow-y: auto;
        overscroll-behavior: contain;
        padding-inline: 1rem;
        border-start-start-radius: 18px;
        border-start-end-radius: 18px;
        background: var(--shop-surface);
        box-shadow: 0 -10px 30px var(--shop-shadow-strong);
        animation: shop-sheet-in 0.22s ease-out;
    }

    .shop-sheet.is-modal .shop-sheet__panel:focus {
        outline: none;
    }

    .shop-sheet.is-modal .shop-sheet__head {
        position: sticky;
        inset-block-start: 0;
        z-index: 2;
        display: flex;
        align-items: center;
        gap: 0.75rem;
        margin-inline: -1rem;
        padding-block: 0.625rem;
        padding-inline: 1rem 0.5rem;
        border-block-end: 1px solid var(--shop-line);
        background: var(--shop-surface);
    }

    .shop-sheet__thumb {
        flex: none;
        inline-size: 3rem;
        block-size: 3rem;
        border-radius: 8px;
        object-fit: cover;
        background: var(--shop-sand);
    }

    .shop-sheet__name {
        display: grid;
        flex: 1 1 auto;
        min-inline-size: 0;
        margin: 0;
        line-height: 1.3;
    }

    .shop-sheet__name span {
        overflow: hidden;
        font-size: 0.875rem;
        white-space: nowrap;
        text-overflow: ellipsis;
    }

    .shop-sheet__name strong {
        color: var(--shop-price);
        font-size: 1rem;
    }

    .shop-sheet__close {
        flex: none;
        inline-size: var(--shop-tap);
        block-size: var(--shop-tap);
        border: 0;
        background: none;
        color: var(--shop-ink);
        font-size: 1.625rem;
        line-height: 1;
        cursor: pointer;
    }

    .shop-sheet.is-modal .shop-step {
        margin-block: 0.75rem 0.375rem;
        font-size: 1rem;
    }

    .shop-sheet.is-modal .shop-step__num {
        inline-size: 1.5rem;
        block-size: 1.5rem;
        font-size: 0.8125rem;
    }

    .shop-sheet.is-modal .shop-product__add {
        margin-block-start: 0;
    }

    .shop-sheet.is-modal .shop-field {
        gap: 4px;
    }

    /* Le second encadré disparaît : la fenêtre est déjà le cadre. */
    .shop-sheet.is-modal .shop-order {
        margin-block-start: 0.25rem;
        padding: 0;
        border: 0;
        background: none;
        box-shadow: none;
    }

    .shop-sheet.is-modal .shop-order__title {
        margin-block-end: 0.5rem;
    }

    .shop-sheet.is-modal .shop-order__form {
        gap: 0.625rem;
    }

    .shop-sheet.is-modal .shop-field label {
        font-size: 13px;
    }

    .shop-sheet.is-modal .shop-field input,
    .shop-sheet.is-modal .shop-field select,
    .shop-sheet.is-modal .shop-field textarea {
        padding-block: 10px;
    }

    .shop-sheet.is-modal .shop-field textarea {
        min-block-size: 3rem;
    }

    /*
     * La consigne du téléphone reste dans l'exemple du champ
     * (« 06XXXXXXXX ») et revient en message d'erreur si la saisie est
     * refusée : sous le champ, elle ne faisait qu'allonger la fenêtre.
     */
    .shop-sheet.is-modal .shop-field__hint {
        display: none;
    }

    /*
     * Le total et le bouton restent collés au bas de la fenêtre pendant
     * qu'on remplit. Le prix de l'article est déjà dans l'en-tête : il
     * ne reste ici que la livraison et le total à payer à la porte.
     */
    .shop-sheet.is-modal .shop-order__foot {
        position: sticky;
        inset-block-end: 0;
        z-index: 1;
        gap: 0.5rem;
        margin-inline: -1rem;
        padding-block: 0.5rem;
        padding-block-end: calc(0.5rem + env(safe-area-inset-bottom, 0px));
        padding-inline: 1rem;
        border-block-start: 1px solid var(--shop-line);
        background: var(--shop-surface);
    }

    .shop-sheet.is-modal .shop-order__totals {
        gap: 2px;
        margin: 0;
        padding: 0;
        background: none;
    }

    .shop-sheet.is-modal .shop-order__totals > div:first-child {
        display: none;
    }

    .shop-sheet.is-modal .shop-order__grand {
        margin: 0;
        padding: 0;
        border: 0;
    }

    .shop-sheet.is-modal .shop-order__grand dd {
        font-size: 1.0625rem;
    }

    .shop-sheet.is-modal .shop-order__alt {
        margin-block: 0.5rem 0.75rem;
    }

    .shop-sheet.is-modal .shop-order__alt .shop-btn {
        min-block-size: var(--shop-tap);
        font-size: 0.875rem;
    }

    .shop-sheet.is-modal .shop-order__error {
        margin-block: 0.5rem;
    }

    /*
     * La couleur tient sur une ligne : son libellé, puis les pastilles.
     * Le libellé « Pointure » s'efface à l'œil — le titre de l'étape le
     * dit déjà — mais reste lu par les lecteurs d'écran.
     */
    .shop-sheet.is-modal .shop-field:has(> [data-colors]) {
        grid-template-columns: auto 1fr;
        align-items: center;
        gap: 0.75rem;
    }

    .shop-sheet.is-modal [data-size-field] > .shop-field__label {
        position: absolute;
        inline-size: 1px;
        block-size: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .shop-sheet.is-modal .shop-order__totals dt {
        font-size: 0.8125rem;
    }

    .shop-sheet.is-modal .shop-order__totals dd {
        font-size: 0.875rem;
    }

    /* La page derrière ne défile plus, et la bulle WhatsApp se retire. */
    .has-sheet,
    .has-sheet body {
        overflow: hidden;
    }

    .has-sheet .shop-wa {
        visibility: hidden;
    }
}

@keyframes shop-sheet-in {
    from {
        transform: translateY(100%);
    }

    to {
        transform: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .shop-sheet.is-modal .shop-sheet__panel {
        animation: none;
    }
}
