/*
|--------------------------------------------------------------------------
| 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: #1B1815;
    --shop-muted: #6C6459;
    --shop-paper: #FBF8F4;
    --shop-surface: #FFFFFF;
    --shop-line: #E8E1D8;
    /*
     * 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: #F2ECE4;

    /*
     * 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: #7B2D42;
    --shop-brand-hover: #632334;
    --shop-brand-soft: #F4E4E7;
    --shop-onbrand: #FFFFFF;

    /*
     * 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: #C0392B;
    --shop-gold: #C39A4B;
    --shop-ok: #2E7D5B;
    --shop-whatsapp: #25D366;

    --shop-focus: rgba(123, 45, 66, 0.18);
    --shop-shadow: rgba(27, 24, 21, 0.07);
    --shop-shadow-soft: rgba(27, 24, 21, 0.12);
    --shop-shadow-strong: rgba(27, 24, 21, 0.22);
    --shop-shadow-deep: rgba(27, 24, 21, 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(251, 248, 244, 0.92);
    --shop-veil-strong: rgba(251, 248, 244, 0.97);
    /* 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(251, 248, 244, 0.72);
    --shop-line-onink: rgba(251, 248, 244, 0.16);
    /* Voile de la carte de confirmation, posé par-dessus la page. */
    --shop-scrim: rgba(27, 24, 21, 0.55);

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

    --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-eyebrow {
    margin: 0 0 0.75rem;
    color: var(--shop-brand);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.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;
}

/*
 * La description passe sous le formulaire : en haut de fiche elle
 * séparait le prix du choix de la taille, alors qu'elle ne se lit
 * qu'après avoir décidé d'acheter. Le filet la détache du bon de
 * commande.
 */
.shop-lede--after-form {
    max-width: none;
    margin-block-start: 1.5rem;
    padding-block-start: 1.5rem;
    border-block-start: 1px solid var(--shop-line);
}

/* Deux filets se suivraient si la description longue existe aussi. */
.shop-lede--after-form + .shop-prose {
    margin-block-start: 0.75rem;
    padding-block-start: 0;
    border-block-start: 0;
}

/* ==========================================================
   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;
    gap: 1.5rem;
    min-width: 0;
    font-size: 0.9375rem;
}

.shop-nav a {
    padding: 0.25rem 0;
    border-bottom: 1px solid transparent;
    text-decoration: none;
    white-space: nowrap;
    transition: border-color 0.15s ease;
}

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

/*
 * 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;
    gap: 0.5rem;
    min-height: 2.75rem;
    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);
}

.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;
}

.shop-social__number {
    white-space: nowrap;
}

/*
 * Sous 900 px l'en-tête range déjà la recherche sur sa propre ligne :
 * le numéro se réduit à son combiné, qu'il suffit d'effleurer.
 */
@media (max-width: 900px) {
    .shop-header .shop-social__number {
        display: none;
    }
}

/* Le pictogramme des liens du pied de page se pose avant le libellé. */
.shop-footer__link:has(.shop-social__icon) {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

/* ==========================================================
   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;
}

/*
 * Les trois promesses. Écrites en toutes lettres plutôt qu'en icônes :
 * une icône de camion ne dit pas « dans 798 villes ».
 */
.shop-promises {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1px;
    margin-top: 1.75rem;
    border: 1px solid var(--shop-line);
    border-radius: var(--shop-radius);
    overflow: hidden;
    background: var(--shop-line);
}

.shop-promise {
    padding: 1.25rem;
    background: var(--shop-paper);
}

.shop-promise__value {
    display: block;
    font-family: var(--shop-serif);
    font-size: 1.5rem;
    line-height: 1.1;
}

.shop-promise__label {
    display: block;
    margin-top: 0.25rem;
    color: var(--shop-muted);
    font-size: 0.8125rem;
}

/* ==========================================================
   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);
}

/* 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);
}

/*
 * 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;
}

/* ==========================================================
   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;
}

.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-onbrand);
}

/*
 * 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, quatre pointures et le pas-à-pas ne tiennent pas côte
 * à côte. Plutôt que de laisser la quantité passer à la ligne — ce qui
 * repousse à nouveau le bouton —, ce sont les pointures qui défilent
 * dans leur propre couloir. Les cibles gardent leurs 44 pixels.
 */
@media (max-width: 620px) {
    .shop-product__pick {
        flex-wrap: nowrap;
        gap: 0.75rem;
    }

    .shop-product__pick > .shop-field {
        flex: 1 1 0;
        min-inline-size: 0;
    }

    .shop-product__pick .shop-choices {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        padding-block-end: 0.25rem;
        scrollbar-width: none;
    }

    .shop-product__pick .shop-choices::-webkit-scrollbar {
        display: none;
    }

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

.shop-prose {
    margin-top: 1.5rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--shop-line);
    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);
}

.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;
}

.shop-chip {
    padding: 0.5rem 1rem;
    border: 1px solid var(--shop-line);
    border-radius: 999px;
    font-size: 0.875rem;
    text-decoration: none;
    white-space: nowrap;
}

.shop-chip[aria-current="page"] {
    border-color: var(--shop-ink);
    background: var(--shop-ink);
    color: var(--shop-onbrand);
}

.shop-search {
    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) {
    /*
     * Les trois arguments restent en ligne au lieu de s'empiler : empilés
     * ils ajoutaient 180 pixels au bandeau et repoussaient les produits
     * hors de l'écran. Ce sont trois chiffres courts — « 798 », « 0 DH »,
     * « 20 – 45 DH » —, ils tiennent côte à côte.
     */
    .shop-promises {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 0.5rem;
    }

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

    .shop-promise__label {
        font-size: 0.6875rem;
        line-height: 1.3;
    }

    /* ---- 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 {
        margin-inline-start: 0;
        width: 100%;
    }

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

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

    .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;
    }

    .shop-card__body .shop-btn {
        min-height: 2.5rem;
        padding-inline: 0.5rem;
        font-size: 0.8125rem;
    }

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

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

    /*
     * Les vignettes défilent au lieu d'empiler trois rangées entre la
     * photo et le prix.
     */
    .shop-product__thumbs {
        display: flex;
        gap: 0.5rem;
        overflow-x: auto;
        overscroll-behavior-inline: contain;
        padding-block-end: 0.25rem;
        scrollbar-width: none;
    }

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

    .shop-thumb {
        flex: 0 0 5.5rem;
    }

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

    /* 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 {
        transition: 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;
}

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

.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;
}

.shop-line__remove {
    border: 0;
    background: none;
    color: var(--shop-muted);
    font: inherit;
    font-size: 0.8125rem;
    text-decoration: underline;
    cursor: pointer;
}

.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, en vert de la boutique. */
.shop-summary__cod {
    margin-top: 1rem;
    color: var(--shop-brand);
    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);
}

.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;
    }

    .shop-line__controls {
        grid-column: 1 / -1;
        justify-content: space-between;
    }
}

/* ==========================================================
   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 {
    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.
   ========================================================== */

.shop-recap {
    max-width: 44rem;
    padding-block: clamp(1.5rem, 3vw, 2.5rem);
}

/*
 * 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, il se faisait oublier et
 * la commande arrivait sans que le vendeur en sache rien.
 */
.shop-recap__action {
    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;
}

.shop-recap__action-title {
    margin: 0.375rem 0 0;
    font-family: var(--shop-serif);
    font-size: 1.25rem;
    line-height: 1.25;
}

.shop-recap__action-text {
    margin: 0.5rem 0 0;
    color: var(--shop-muted);
    font-size: 0.9375rem;
}

/* 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;
}

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

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

.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__action,
    .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 panier ancrée en bas
   ========================================================== */

/*
 * Toujours visible dès qu'un article est choisi. Sur mobile c'est le
 * chemin le plus court vers le panier : le pouce l'atteint sans avoir à
 * remonter jusqu'à l'en-tête.
 */
.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;
}

/* ==========================================================
   Écriture de droite à gauche
   ========================================================== */

/*
 * La mise en page n'utilise que des propriétés logiques — margin-inline,
 * inset-inline, padding-block — qui s'inversent d'elles-mêmes selon
 * l'attribut dir. Les surcharges [dir="rtl"] qui dupliquaient chaque
 * règle ont disparu : elles finissaient toujours par diverger de la règle
 * de base et laissaient le menu du mauvais côté après un changement de
 * langue.
 *
 * Ne restent ici que les cas qui ne relèvent pas de la direction :
 * l'ordre des chiffres et le choix des polices.
 */

/*
 * L'arabe se lit de droite à gauche mais ses chiffres restent en ordre
 * occidental : isoler les montants évite qu'un prix suivi d'une devise ne
 * s'affiche à l'envers.
 */
[dir="rtl"] .shop-card__amount,
[dir="rtl"] .shop-price__amount,
[dir="rtl"] .shop-cartbar__total,
[dir="rtl"] .shop-summary__row span,
[dir="rtl"] .shop-promise__value {
    unicode-bidi: isolate;
}

/*
 * 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;
    }

}

/* ==========================================================
   Rayons de la page d'accueil
   ==========================================================

   Les catégories étaient reléguées en bas de page sous forme
   de pastilles de texte, après le catalogue entier. Un
   visiteur qui arrive d'une publicité ne sait pas encore ce
   qu'il cherche : c'est par le rayon qu'il entre, pas par une
   liste de quarante-huit articles.

   Elles passent donc devant, illustrées, et de taille à être
   cliquées du pouce.
   ========================================================== */

.shop-section--rooms {
    padding-block: clamp(1.5rem, 4vw, 2.75rem);
}

.shop-rooms {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: clamp(0.75rem, 2vw, 1.25rem);
}

.shop-room {
    position: relative;
    display: block;
    overflow: hidden;
    border-radius: var(--shop-radius);
    background: var(--shop-sand);
    text-decoration: none;
}

.shop-room__media {
    display: block;
    aspect-ratio: 16 / 9;
}

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

.shop-room:hover .shop-room__media img {
    transform: scale(1.04);
}

/*
 * Le nom est posé sur la photo, sur un voile sombre : un bandeau blanc
 * sous l'image aurait doublé la hauteur de la carte pour deux lignes.
 */
.shop-room__body {
    position: absolute;
    inset-inline: 0;
    inset-block-end: 0;
    display: grid;
    gap: 0.125rem;
    padding: 1.25rem 1rem 0.875rem;
    background: linear-gradient(
        to top,
        rgba(28, 25, 23, 0.78) 0%,
        rgba(28, 25, 23, 0.45) 55%,
        rgba(28, 25, 23, 0) 100%
    );
    color: var(--shop-onbrand);
}

.shop-room__name {
    font-family: var(--shop-serif);
    font-size: 1.25rem;
    line-height: 1.15;
}

.shop-room__count {
    color: var(--shop-onink);
    font-size: 0.8125rem;
    unicode-bidi: isolate;
}

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

/* ==========================================================
   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 {
    color: var(--shop-muted);
    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.

   Quatre colonnes qui se replient en une seule sur téléphone. Le fond
   sombre le sépare du catalogue : on sait qu'on est arrivé au bas.
   ========================================================== */

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

/* 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);
}

.shop-footer__social {
    margin-block-start: 0.25rem;
    margin-inline-start: -0.25rem;
}

.shop-footer__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
    column-gap: 2rem;
    row-gap: 1.5rem;
}

.shop-footer__name {
    margin: 0;
    color: var(--shop-paper);
    font-family: var(--shop-serif);
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

.shop-footer__tagline {
    margin: 0.375rem 0 0;
    max-inline-size: 22rem;
    font-size: 0.9rem;
    line-height: 1.6;
}

.shop-footer__head {
    margin: 0 0 0.5rem;
    color: var(--shop-paper);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
}

.shop-footer__head--spaced {
    margin-block-start: 0.875rem;
}

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

.shop-footer__link {
    display: block;
    margin-block-end: 0.3rem;
    color: var(--shop-onink);
    font-size: 0.9rem;
    text-decoration: none;
}

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

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

.shop-footer__legal {
    margin-block-start: 1.25rem;
    padding-block-start: 0.875rem;
    border-block-start: 1px solid var(--shop-line-onink);
    font-size: 0.8rem;
}

/* ==========================================================
   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__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.
   ========================================================== */

.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) {
    /*
     * 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 {
        order: 3;
        flex: 1 0 100%;
        max-inline-size: none;
        margin-block-start: 0.6rem;
    }

    .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-onbrand);
    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);
}
