/* V33 — POLICE : retour a UNE seule face, comme le template. La note V32 ci-dessous supposait que
   le proprietaire, ayant « Centra No. 2 » installee, voyait ses titres en gras et qu'il fallait
   declarer medium(500)+bold(700) pour reproduire ce rendu. MESURE contradictoire, faite dans le
   navigateur du proprietaire sur le template lui-meme (canvas measureText + sonde DOM, meme chaine,
   meme corps 13px) :
     template  400/500/700/800/850 -> 345.36 px  (largeur IDENTIQUE a toutes les graisses)
     staging   400 -> 345.36 | 500 -> 349.48 | 700/800/850 -> 354.20 px
   Le template declare UNE face (400) ET pose font-synthesis:none : la selection CSS retombe donc
   toujours sur book, et aucun faux-gras n'est synthetise — personne, proprietaire inclus, ne voit
   de gras. Les `font-weight:700/800/850` du template sont inertes. En declarant de vraies faces
   500/700, V32 a rendu le staging plus gras que sa reference (+2,6 % de chasse) : c'est le defaut
   « polices trop grasses » signale. Les fichiers medium/bold restent sur le disque, simplement plus
   references. Les `font-weight` du CSS sont conserves tels quels (inertes ici, comme le template) :
   les reecrire un a un n'aurait rien change au rendu et aurait touche des fichiers non possedes. */
/* V34 — LISSAGE : le « plus gras que le template » qui restait apres V33 n'etait PAS une graisse.
   Mesure des deux cotes sur le sous-titre du hero (Range.getClientRects, meme chaine, 15px) :
     template 438.68 / 346.16 px   |   staging 438.68 / 346.16 px   -> metriques IDENTIQUES,
     et la chasse canvas vaut 421.38 px a 400/500/700/800/850 des deux cotes (graisses inertes).
   La seule difference etait la RASTERISATION : le template pose `-webkit-font-smoothing:antialiased`
   + `text-rendering:optimizeLegibility` sur `body`, le theme restait en `auto` — donc en
   subpixel-antialiasing sur macOS, qui epaissit les fûts sans changer une seule metrique.
   Verifie avant edition : ajouter les deux proprietes laisse paragraphe ET h1 au pixel pres. */
/* V35 — DECLARATION DE FACE alignee sur celle du template, a l'identique :
   nom de famille "Centra No2", sources `local()` AVANT l'url, `font-style:normal`, et repli
   "Helvetica Neue" avant Arial. Le woff2 est deja LE MEME fichier des deux cotes (sha1
   1f44a47caab457794b386d3c5330d346802b12eb), seule la declaration divergeait.
   Ce que ca change : (a) sur un poste ou « Centra No. 2 » est INSTALLEE, le navigateur prend
   la fonte locale comme le fait le template — mesure sur le poste du proprietaire :
   `"Centra No. 2 Book", monospace` rend 541.85 px, soit exactement `monospace`, donc elle n'y
   est PAS installee et les deux cotes tombent sur le woff2 (c'est ce qui rendait la comparaison
   valide) ; (b) pendant le swap et si le woff2 echoue, le repli devient Helvetica Neue (412.81 px)
   au lieu d'Arial (409.37 px) — Centra vaut 421.38 px, aucun des deux ne la remplace exactement.
   PAS de `-moz-osx-font-smoothing:grayscale` : le template ne le declare pas, l'ajouter ferait
   diverger le staging du template sous Firefox/macOS. */
@font-face{font-family:"Centra No2";src:local("Centra No. 2 Book"),local("CentraNo2-Book"),url(../fonts/centra-no2-book.woff2) format("woff2");font-style:normal;font-weight:400;font-display:swap}
/* `--focus` n'est PAS un doublon de `--gold` : c'est l'or de marque assombri pour rester
   perceptible en anneau de focus. Mesuré sur les fonds réels du site (relevés au
   getComputedStyle, pas supposés), l'or #b59a5b plafonnait à 2,15-2,69:1 contre les crèmes
   (stone #ece4d5, section #f5f0e7, body #fbf8f2, paper #fffefa) — sous les 3:1 qu'exige
   WCAG 2.2 (1.4.11 / 2.4.13) pour un indicateur non textuel. #937b42 garde exactement la
   même teinte (42°) et la même saturation (38 %), seule la luminosité descend de 53 % à
   42 %, et remonte le pire cas à 3,23:1 (jusqu'à 4,04:1 sur paper).
   `--gold` reste intact pour les badges, les pastilles et les icônes : seul l'`outline` des
   règles `:focus-visible` bascule sur `--focus`. */
:root{--ink:#171713;--ink-soft:#2d2d28;--muted:#686860;--green:#215e4b;--green-dark:#174536;--deep:#171713;--ivory:#f6f2e9;--stone:#ece4d5;--paper:#fffefa;--line:rgba(23,23,19,.13);--line-strong:rgba(23,23,19,.23);--gold:#b59a5b;--gold-soft:#e9ddbf;--focus:#937b42;--danger:#8b3f35;--white:#fff;--radius:26px;--green-soft:#e4eee9}
/* `.screen-reader-text` : masquage declare PAR LE THEME, et c'est indispensable.
   Le porteur decisif echappe au theme : WooCommerce emet un `<label class="screen-reader-text">`
   dans le champ quantite, donc a l'INTERIEUR de la pilule `.gbs-buy .quantity`, qui est en
   `overflow:hidden` — on ne peut ni le retirer ni lui donner une autre classe. Deux autres
   porteurs viennent du theme lui-meme et comptaient sur une declaration qu'ils n'ecrivaient pas :
   le `<caption>` de `regaine-landing.php` et la live region `#gbs-storefront-live` batie par
   `storefront.js`. Or cette classe n'etait declaree que par `wp-block-library`
   et `wc-blocks-style`, et `mu-plugins-prod-only/gbs-css-optim.php` dequeue PRECISEMENT ces
   deux feuilles sur les pages WooCommerce, EN PRODUCTION et pour les visiteurs deconnectes
   uniquement. Sans la regle ci-dessous, ces textes sont invisibles sur le staging et sur un
   compte connecte, mais s'affichent en clair pour un client en prod — et le label de quantite,
   large de ~390 px, expulse le bouton `+` hors de la pilule. Aucune sonde sur staging ne peut
   voir cette divergence. Mesure du 2026-08-17 : `.quantity` passe de 132 px a 522 px de
   `scrollWidth` des que le masquage disparait.
   (`.gbs-countdown-sr` dans product.css reste : elle precede cette declaration et fonctionne.) */
.screen-reader-text{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;white-space:nowrap}
.screen-reader-text:focus{position:static;width:auto;height:auto;margin:0;clip:auto;clip-path:none;overflow:visible;white-space:normal}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--paper);color:var(--ink);font-family:"Centra No2","Helvetica Neue",Arial,sans-serif;font-synthesis:none;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;font-size:16px;line-height:1.5}body.gbs-lock{overflow:hidden}a{color:inherit;text-decoration:none}button,input,select,textarea{font:inherit}button{color:inherit}img{max-width:100%;height:auto}svg{width:1.35em;height:1.35em}.gbs-shell{width:min(1320px,calc(100% - 48px));margin-inline:auto}.gbs-main{min-height:60vh}.gbs-proofbar{height:36px;display:grid;grid-template-columns:repeat(3,1fr);background:#0c3427;color:#fff;padding-inline:max(24px,calc((100% - 1320px)/2));font-size:12px;font-weight:700;line-height:normal}.gbs-proofbar span{display:flex;align-items:center;justify-content:center;gap:8px;padding:7px 12px;white-space:nowrap}.gbs-proofbar span+span{border-inline-start:1px solid rgba(255,255,255,.18)}.gbs-proofbar svg{width:15px;height:15px;flex:0 0 auto;color:var(--gold-soft)}.gbs-proofbar span.gbs-proofbar__ship--short{display:none}.gbs-header{position:sticky;top:0;z-index:200;display:grid;grid-template-columns:270px 1fr auto;align-items:center;height:84px;padding:10px max(24px,calc((100% - 1320px)/2));background:rgba(251,248,242,.96);border-bottom:1px solid var(--line);backdrop-filter:blur(14px)}.gbs-logo img{display:block;width:205px;max-height:62px;object-fit:contain}.gbs-nav{display:flex;justify-content:center;align-items:center;gap:28px}.gbs-nav a,.gbs-nav button{min-height:44px;border:0;background:transparent;display:flex;align-items:center;gap:5px;font-size:13px;font-weight:700;color:var(--ink-soft);cursor:pointer}.gbs-header-actions{display:flex;gap:8px}.gbs-round,.gbs-icon-button{width:48px;height:48px;border:1px solid var(--line);border-radius:50%;background:transparent;display:grid;place-items:center;cursor:pointer}.gbs-cart-count{position:absolute;transform:translate(18px,-20px);min-width:22px;height:22px;padding:0 5px;background:var(--green);color:white;border-radius:999px;display:grid;place-items:center;font-size:12px}.gbs-mobile-menu-trigger{display:none}.gbs-button{min-height:48px;padding:14px 23px;border:1px solid var(--green);border-radius:999px;background:var(--green);color:white;display:inline-flex;align-items:center;justify-content:center;gap:9px;font-size:13px;font-weight:800;line-height:1.2;cursor:pointer}.gbs-button--outline{background:var(--ivory);color:var(--green)}.gbs-eyebrow{margin:0 0 8px;color:var(--green);font-size:12px;font-weight:800;letter-spacing:.15em;text-transform:uppercase}.gbs-section{padding-block:86px}.gbs-section--stone{background:var(--stone)}.gbs-section--dark{background:var(--deep);color:white}.gbs-section-head{display:flex;justify-content:space-between;gap:36px;align-items:end;margin-bottom:34px}.gbs-section-head h2{font-size:clamp(38px,5vw,72px);line-height:.98;letter-spacing:-.055em;margin:0;font-weight:800;max-width:900px}.home .gbs-hero__copy h1{font-weight:800}.gbs-section-head>p{max-width:520px;color:#686860;font-size:14px}.gbs-layer{position:fixed;inset:0;z-index:500;display:none}.gbs-layer.is-open{display:block}.gbs-layer__scrim{position:absolute;inset:0;border:0;background:rgba(4,17,14,.58);backdrop-filter:blur(4px)}.gbs-cart{position:absolute;inset-block:0;inset-inline-end:0;width:min(720px,100%);display:grid;grid-template-columns:240px minmax(0,480px);background:var(--paper);box-shadow:-20px 0 70px rgba(0,0,0,.2);overflow:hidden}.gbs-reco-rail{padding:24px 16px;background:linear-gradient(180deg,#eee8db,#e5eadf);overflow:auto}.gbs-reco-rail h2{font-size:24px;line-height:1.08;margin:0 0 22px}.gbs-reco-list{display:grid;gap:10px}.gbs-reco-card{display:grid;grid-template-columns:80px 1fr;gap:10px;min-height:112px;padding:8px;background:var(--white);border:1px solid var(--line);border-radius:18px}.gbs-reco-card__link{display:contents}.gbs-reco-card__media{grid-row:1/3;width:80px;height:96px;border-radius:12px;background:#e5eadf;display:grid;place-items:center;overflow:hidden}.gbs-reco-card__media img{width:85%;height:85%;object-fit:contain}.gbs-reco-card strong{font-size:13px;font-weight:700;line-height:1.25;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.gbs-reco-card__action{display:flex;align-items:end;justify-content:space-between;gap:5px}.gbs-reco-card__action>span{font-size:15px}.gbs-icon-button{width:44px;height:44px;background:var(--green);color:white;border:0;font-size:24px}.gbs-cart-panel{min-width:0;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr) auto;height:100dvh}.gbs-cart-head{padding:22px 26px;display:flex;justify-content:space-between;align-items:start;border-bottom:1px solid var(--line)}.gbs-cart-head h2{margin:0;font-size:31px;font-weight:800;letter-spacing:-.045em}.gbs-shipping-progress{padding:18px 26px;background:#f2ede3;display:grid;gap:4px;color:var(--green)}.gbs-shipping-progress strong{font-size:13px;letter-spacing:.12em;text-transform:uppercase}.gbs-shipping-progress i{display:block;height:7px;margin-top:8px;background:#d5dbd2;border-radius:999px}.gbs-shipping-progress i b{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--green),#3f8971)}.gbs-shipping-progress.is-pending:after{content:"";position:absolute;right:22px;width:18px;height:18px;border:2px solid var(--gold);border-radius:50%;animation:gbsPulse 1.8s ease-in-out infinite}.gbs-cart-lines{overflow:auto;padding:8px 26px}.gbs-cart-line{position:relative;display:grid;grid-template-columns:126px 1fr;gap:12px;padding:18px 0;border-bottom:1px solid var(--line)}.gbs-cart-line>a{display:contents}.gbs-cart-line__media{grid-row:1/4;width:126px;height:126px;border-radius:18px;background:#e6e2d7;display:grid;place-items:center;overflow:hidden}.gbs-cart-line__media img{width:84%;height:84%;object-fit:contain}.gbs-cart-line strong{font-size:16px;font-weight:400;line-height:1.32}.gbs-cart-line__price{font-size:18px;font-weight:800;letter-spacing:-.025em}.gbs-quantity{display:flex;width:150px;align-items:center;justify-content:space-between;border:1px solid var(--line);border-radius:999px}.gbs-quantity button{width:44px;height:44px;border:0;background:transparent;cursor:pointer}.gbs-remove{position:absolute;top:14px;right:0;border:0;background:transparent;font-size:25px;cursor:pointer}.gbs-cart-footer{padding:16px 26px max(18px,env(safe-area-inset-bottom));border-top:1px solid var(--line);background:var(--paper);display:grid;gap:10px}.gbs-cart-footer>div{display:flex;justify-content:space-between;align-items:end}.gbs-cart-footer strong{font-size:24px}.gbs-cart-empty{padding:40px}.gbs-search-dialog{position:absolute;top:8vh;left:50%;transform:translateX(-50%);width:min(900px,calc(100% - 32px));background:var(--ivory);border-radius:28px;padding:26px}.gbs-search-dialog header{display:flex;justify-content:space-between}.gbs-search-dialog h2{font-size:42px;margin:0}.gbs-search-dialog form{display:flex;margin-top:28px}.gbs-search-dialog input[type=search]{width:100%;min-height:58px;border:1px solid var(--line);border-radius:999px;padding:0 24px;font-size:20px}.gbs-search-dialog button[type=submit]{width:58px;height:58px;margin-inline-start:-58px;border:0;border-radius:50%;background:var(--green);color:white;cursor:pointer}.gbs-mega{position:absolute;z-index:70;top:100%;left:0;right:0;background:rgba(255,254,250,.99);border-top:1px solid var(--line);border-bottom:1px solid var(--line);box-shadow:0 30px 70px rgba(16,37,28,.16);backdrop-filter:blur(20px);padding:30px max(24px,calc((100% - 1320px)/2)) 34px}.gbs-mega-grid{display:grid;grid-template-columns:repeat(3,1fr) 1.2fr;gap:28px}.gbs-mega a{display:block;padding:8px}.gbs-mega-card{background:var(--deep);color:white;border-radius:22px;padding:24px}.site-footer,.site-info,.footer-widgets-container{display:none!important}@keyframes gbsPulse{0%,100%{transform:scale(1);box-shadow:0 0 0 0 rgba(190,160,93,.4)}50%{transform:scale(1.08);box-shadow:0 0 0 8px rgba(190,160,93,0)}}
@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}
@media(max-width:900px){.gbs-header{height:72px;grid-template-columns:48px 1fr auto;padding:8px 14px}.gbs-mobile-menu-trigger{display:grid}.gbs-nav{display:none}.gbs-header .gbs-logo{justify-self:center}.gbs-logo img{width:168px}.gbs-header-actions .gbs-round{width:44px;height:44px}.gbs-shell{width:min(100% - 30px,760px)}.gbs-section{padding-block:54px}.gbs-section-head{display:block}.gbs-cart{width:min(600px,100vw)}.gbs-cart>.gbs-cart-panel-v29{min-width:0}.gbs-reco-rail{overflow:visible;padding:18px}.gbs-reco-list{display:flex;overflow:auto;scroll-snap-type:x mandatory;gap:12px}.gbs-reco-card{flex:0 0 min(250px,78vw);scroll-snap-align:start}.gbs-cart-panel{height:auto;min-height:0;grid-template-rows:auto auto auto auto}.gbs-mega{inset:106px 0 0;overflow:auto}.gbs-mega-grid{grid-template-columns:1fr}.gbs-cart-line{grid-template-columns:92px 1fr}.gbs-cart-line__media{width:92px;height:92px}}
/* Proofbar : les 3 arguments ne tiennent pas sous 680 px (594 px requis en repli Arial).
   Sous 680 px on garde les deux qui portent la conversion COD, paiement en premier ;
   sous 350 px le paiement seul. Selecteurs en `span.classe` a dessein : `.gbs-proofbar span`
   vaut (0,1,1) et battrait une classe nue. */
@media(max-width:679px){.gbs-proofbar{grid-template-columns:repeat(2,1fr)}.gbs-proofbar span{padding:7px 8px}.gbs-proofbar span.gbs-proofbar__auth,.gbs-proofbar span.gbs-proofbar__ship{display:none}.gbs-proofbar span.gbs-proofbar__cod{order:1}.gbs-proofbar span.gbs-proofbar__ship--short{display:flex;order:2}.gbs-proofbar span+span{border-inline-start:0}.gbs-proofbar span.gbs-proofbar__ship--short{border-inline-start:1px solid rgba(255,255,255,.18)}}
@media(max-width:349px){.gbs-proofbar{grid-template-columns:1fr}.gbs-proofbar span.gbs-proofbar__ship--short{display:none}}

/* Locale-scoped fragment hosts prevent WooCommerce's session cache from
   replacing a French V2 cart with stale Arabic or legacy markup. */
.gbs-reco-list-v29{display:grid;gap:10px}
/* La colonne est DECLAREE `minmax(0,1fr)` au lieu d'etre laissee implicite : une piste implicite
   `auto` prend pour taille MINIMALE le plus grand min-content de ses items, et `.cart-undo`
   contient un libelle `white-space:nowrap` — `min-width:0` sur ce libelle l'autorise a retrecir
   mais ne reduit PAS sa contribution min-content. Mesure a 375 apres une suppression : piste a
   399,25 px, donc en-tete, bloc vide et bande d'annulation rendus a 399,3 px et rognes a droite
   par `.gbs-cart{overflow:hidden}` (croix de fermeture et bouton « Annuler » coupes).
   Les deux moities sont necessaires : la piste borne la colonne, `min-width:0` autorise les
   enfants a descendre sous leur min-content — sans lui un item deborde encore sa piste. */
.gbs-cart-panel-v29{min-width:0;display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr) auto;height:100dvh}
.gbs-cart-panel-v29>*,.gbs-cart-panel>*{min-width:0}
@media(max-width:900px){.gbs-reco-list-v29{display:flex;overflow:auto;scroll-snap-type:x mandatory;gap:12px}}
@media(max-width:480px){.gbs-shell{width:calc(100% - 24px)}.gbs-logo img{width:145px}.gbs-header-actions{gap:3px}.gbs-header-actions .gbs-round{width:42px;height:42px}.gbs-section-head h2{font-size:38px}.gbs-cart-head{padding:16px}.gbs-shipping-progress,.gbs-cart-lines,.gbs-cart-footer{padding-inline:16px}.gbs-search-dialog{top:2vh;padding:18px}.gbs-search-dialog h2{font-size:30px}}

/* V29 storefront shell: keep the GeneratePress parent from introducing a
   second layout and provide the progressive mobile navigation. */
.gbs-shipping-progress{position:relative}

/* Le libelle et le message sont deux elements INLINE dans le meme <p> emis par
   gbs_storefront_shipping_progress_html() : sans regle, ils se collent en une seule phrase
   (« Objectif livraisonPlus que 422 DH pour obtenir la livraison offerte. »). Le recapitulatif
   du tunnel avait deja sa propre regle (checkout.css, `.gbs-checkout-order-panel … strong`),
   le tiroir n'en avait aucune : le rendu est partage entre les deux surfaces, la regle vit
   donc dans la feuille globale, une seule fois, au lieu d'etre recopiee par surface. */
.gbs-shipping-progress__copy p>strong{display:block;margin-bottom:4px}

/* The free-shipping goal uses a real local SVG instead of a decorative empty
   ring, so the state remains immediately recognisable without Unicode icons. */
.gbs-shipping-progress__truck{position:absolute;inset-inline-end:20px;inset-block-end:12px;width:38px;height:38px;border:2px solid var(--gold);border-radius:50%;background:#f8f1dc;color:var(--green);display:grid;place-items:center;box-shadow:0 5px 16px rgba(75,57,17,.14);z-index:1}
.gbs-shipping-progress__truck svg{width:21px;height:21px}
.gbs-shipping-progress.is-pending:after{display:none}
.gbs-shipping-progress.is-pending .gbs-shipping-progress__truck{animation:gbsPulse 1.8s ease-in-out infinite}
.gbs-shipping-progress.is-unlocked .gbs-shipping-progress__truck{background:#f0e2b7}
@media(prefers-reduced-motion:reduce){.gbs-shipping-progress.is-pending .gbs-shipping-progress__truck{animation:none}}
.gbs-mega-feature{background:linear-gradient(135deg,var(--green-dark),#10231b);color:#fff;border-radius:22px;padding:28px;display:flex!important;flex-direction:column;justify-content:space-between;min-height:220px}
.gbs-mega>.gbs-mega-utils{display:flex;justify-content:flex-end;gap:22px;padding-top:20px;margin-top:20px;border-top:1px solid var(--line)}
.gbs-mobile-nav-content{display:none}
.gbs-checkout-header{position:sticky;top:0;z-index:100;display:grid;grid-template-columns:48px 1fr 48px;align-items:center;min-height:76px;padding:10px max(20px,calc((100% - 1280px)/2));background:rgba(255,255,255,.96);border-bottom:1px solid var(--line);backdrop-filter:blur(14px)}
.gbs-checkout-header .gbs-logo{justify-self:center}.gbs-checkout-header .gbs-logo img{width:180px;max-height:54px;object-fit:contain}
.gbs-filter-trigger{display:none}
@media(max-width:900px){
  .gbs-header{grid-template-columns:44px minmax(0,1fr) auto}
  .gbs-nav{position:fixed;z-index:240;inset:var(--gbs-drawer-top,108px) 0 0;width:min(360px,92vw);padding:24px;background:var(--ivory);box-shadow:18px 0 45px rgba(0,0,0,.18);display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start;gap:5px;transform:translateX(-110%);visibility:hidden;transition:transform .22s ease,visibility .22s}
  [dir=rtl] .gbs-nav{right:0;left:auto;transform:translateX(110%)}
  [dir=rtl] .gbs-mobile-menu-open .gbs-nav{transform:translateX(0)}
  .gbs-mobile-menu-open .gbs-nav{transform:translateX(0);visibility:visible}
  .gbs-nav a,.gbs-nav button{width:100%;justify-content:space-between;padding-inline:12px;border-bottom:1px solid var(--line)}
  .gbs-nav>.gbs-nav-primary-item{display:none}
  /* Pas d'`overflow` ici : le tiroir defile sur `.gbs-nav` (voir plus bas). La
     declaration `overflow:auto` qui vivait sur cette ligne etait morte depuis la
     bascule du scroll, et elle a deja fait diagnostiquer a tort un debordement. */
  .gbs-mobile-nav-content{display:block;padding-bottom:max(28px,env(safe-area-inset-bottom))}
  .gbs-mobile-nav-head{position:sticky;top:-24px;z-index:2;display:flex;align-items:center;justify-content:space-between;min-height:66px;margin:-24px -24px 12px;padding:12px 18px;background:rgba(251,248,242,.98);border-bottom:1px solid var(--line)}
  .gbs-mobile-nav-head strong{font-size:25px;font-weight:500}
  .gbs-mobile-nav-head .gbs-round{width:44px;height:44px;padding:0;border:1px solid var(--line)}
  .gbs-mobile-nav-content .gbs-mega-grid{display:grid;grid-template-columns:1fr;gap:20px}
  .gbs-mobile-nav-content .gbs-mega-grid section{padding-bottom:14px;border-bottom:1px solid var(--line)}
  .gbs-mobile-nav-content .gbs-mega-grid section a{min-height:44px;padding:10px 4px;border:0}
  .gbs-mobile-nav-content .gbs-mega-feature{min-height:164px;padding:20px;border:0}
  .gbs-nav .gbs-mega-feature{background:linear-gradient(135deg,var(--green-dark),#10231b);color:#fff}
  .gbs-mobile-nav-content .gbs-mega-utils{display:flex;justify-content:flex-start;gap:8px;padding-top:16px;margin-top:8px;border-top:1px solid var(--line)}
  .gbs-mobile-nav-content .gbs-mega-utils a{min-height:44px;padding:10px 12px;border:1px solid var(--line);border-radius:999px}
  .gbs-mobile-menu-open:after{content:"";position:fixed;z-index:210;inset:var(--gbs-drawer-top,108px) 0 0;background:rgba(4,17,14,.5)}
  .gbs-mega{z-index:250;top:106px;left:min(360px,92vw);padding:22px}
  [dir=rtl] .gbs-mega{left:0;right:min(360px,92vw)}
  .gbs-filter-trigger{display:inline-flex}
}

/* V29: keep the search action legible with the local icon system. */
.gbs-search-dialog button[type=submit]{position:relative;color:transparent;font-size:0}
.gbs-search-dialog button[type=submit]::before{content:"→";position:absolute;inset:0;display:grid;place-items:center;color:var(--ivory);font-size:25px;line-height:1}
.gbs-search-dialog button[type=submit]:focus-visible{outline:3px solid var(--focus);outline-offset:4px}
@media(max-width:480px){
  .gbs-header{padding-inline:7px;grid-template-columns:44px minmax(0,1fr) auto}.gbs-logo img{width:128px}.gbs-mobile-menu-trigger,.gbs-header-actions .gbs-round{width:44px;height:44px}.gbs-header-actions .gbs-round:first-child{display:grid}
  .gbs-nav{inset-block-start:var(--gbs-drawer-top,108px)}.gbs-mega{inset:106px 0 0}.gbs-checkout-header{min-height:68px;padding:8px 12px}.gbs-checkout-header .gbs-logo img{width:145px}
}

/* V29.1: the mobile drawer must own the viewport below the proof bar/header.
   Using `inset` alone allowed GeneratePress/WP Admin Bar height rules to
   collapse it to the intrinsic 48px height of its first control. */
@media(max-width:900px){
  /* A backdrop filter establishes a containing block for fixed descendants
     in WebKit/Chromium. The drawer lives in the header, so keeping the blur
     here offset it by the sticky header instead of the viewport. */
  .gbs-header{backdrop-filter:none}
  body.gbs-mobile-menu-open .gbs-header{z-index:230}
  .gbs-nav{
    inset-block-start:var(--gbs-drawer-top,108px);
    inset-block-end:0;
    height:calc(100dvh - var(--gbs-drawer-top,108px));
    max-height:calc(100dvh - var(--gbs-drawer-top,108px));
    min-height:0;
    overflow-y:auto;
    overscroll-behavior:contain;
  }
  /* Le scrollport du tiroir est `.gbs-nav` ci-dessus, jamais ce conteneur. C'est ce
     qui laisse `.gbs-mobile-nav-head` saigner de 24 px de chaque cote (`margin:-24px
     -24px 12px`) jusqu'aux bords du tiroir sans etre rogne, et c'est aussi ce qui rend
     son `top:-24px` correct : Chrome retranche le padding du scroll container de la
     zone de collage, donc -24px annule le `padding:24px` de `.gbs-nav` et la barre se
     colle pile en haut du tiroir. Consequence a connaitre avant de crier au bug : ce
     conteneur mesure `scrollWidth` = `clientWidth` + 24 (336 vs 312 a 768 px, 321 vs
     297 a 375 px). C'est le saignement VOULU lu sur une boite `overflow:visible` — il
     ne rogne rien et ne peut pas defiler. La mesure qui fait foi est celle du
     scrollport : `.gbs-nav` reste a `scrollWidth == clientWidth` (345/345 a 375 px,
     360/360 a 768 px), en LTR comme en RTL. Ne pas remettre d'`overflow` ici. */
  .gbs-mobile-nav-content{
    flex:1 0 auto;
    min-height:max-content;
    overflow:visible;
  }
  body.admin-bar .gbs-nav{
    inset-block-start:var(--gbs-drawer-top,calc(108px + var(--wp-admin--admin-bar--height,32px)));
    height:calc(100dvh - var(--gbs-drawer-top,calc(108px + var(--wp-admin--admin-bar--height,32px))));
    max-height:calc(100dvh - var(--gbs-drawer-top,calc(108px + var(--wp-admin--admin-bar--height,32px))));
  }
  body.admin-bar.gbs-mobile-menu-open:after{inset-block-start:var(--gbs-drawer-top,calc(108px + var(--wp-admin--admin-bar--height,32px)))}
}

/* V30 shared geometry. Keep one container/header contract across every route. */
.gbs-shell{width:min(1320px,calc(100% - 48px))}
.gbs-proofbar{padding-inline:max(24px,calc((100% - 1320px)/2))}
.gbs-header{
  grid-template-columns:180px minmax(0,1fr) auto;
  height:73px;
  padding:7px max(24px,calc((100% - 1320px)/2));
}
.gbs-logo img{width:146px;max-width:100%;max-height:58px}
.gbs-nav{gap:24px}
.gbs-mega{padding-inline:max(24px,calc((100% - 1320px)/2))}
.gbs-footer{padding-inline:max(24px,calc((100% - 1320px)/2))}
.gbs-icon-button,.gbs-reco-card__add{
  inline-size:44px;
  min-inline-size:44px;
  block-size:44px;
  flex:0 0 44px;
}
.gbs-reco-card__action>span{min-width:0;font-variant-numeric:tabular-nums}
.gbs-reco-card__link:focus-visible,.gbs-cart-line>a:focus-visible{
  outline:3px solid var(--focus);
  outline-offset:3px;
  border-radius:12px;
}

@media(max-width:900px){
  .gbs-header{
    grid-template-columns:44px minmax(0,1fr) auto;
    height:72px;
    padding:7px 14px;
  }
  /* Le centrage absolu sur le viewport n'est correct que parce que les deux clusters d'icones
     sont SYMETRIQUES : le bloc `.gbs-header>.gbs-header-actions{display:contents}` plus bas
     repartit burger + recherche a gauche et compte + panier a droite (95px de chaque cote).
     Si quelqu'un remet les trois icones a droite, le logo recouvre a nouveau la premiere
     (mesure a l'epoque : 24px a 390px, 39px a 360px) — le centrage exact est alors
     arithmetiquement impossible. Ne pas dissocier les deux blocs. */
  .gbs-header>.gbs-logo{
    position:absolute;
    inset-inline-start:50%;
    transform:translateX(-50%);
    justify-self:auto;
  }
  [dir=rtl] .gbs-header>.gbs-logo{transform:translateX(50%)}
  .gbs-header>.gbs-logo img{width:123px;max-height:56px}
  .gbs-header-actions{justify-self:end}
  .gbs-shell{width:min(calc(100% - 30px),760px)}
  .gbs-mega{top:106px;padding-inline:20px}
}
@media(max-width:480px){
  .gbs-header{padding-inline:7px}
  .gbs-header>.gbs-logo img{width:118px}
  .gbs-shell{width:calc(100% - 24px)}
}

/* V31 — colonne de suggestions verticale (style mood.com). La carte `is-compact` remplace la
   carte horizontale (photo 80x96 a gauche + texte a droite) : photo carree pleine largeur en
   haut, titre 3 lignes reservees, bouton « Ajouter » pleine largeur, et un seul badge
   « Debloque la livraison offerte ». Les regles historiques `.gbs-reco-card` restent dormantes
   (le PHP emet toujours `is-compact`). En-tete du rail reduit a son titre, comme le prototype. */
/* V36 — regle retiree avec le markup qu'elle masquait : le rail n'emet plus d'eyebrow. */
.gbs-reco-rail h2{font-size:15px;line-height:1.25;margin:0 0 12px}
.gbs-reco-list-v29{gap:12px}
.gbs-reco-card.is-compact{display:flex;flex-direction:column;gap:8px;min-height:0;padding:8px 8px 10px}
.gbs-reco-card.is-compact .gbs-reco-card__link{display:flex;flex-direction:column;gap:7px}
.gbs-reco-card.is-compact .gbs-reco-card__media{grid-row:auto;width:100%;height:auto;aspect-ratio:1/1;border-radius:14px;position:relative}
.gbs-reco-card.is-compact .gbs-reco-card__media img{position:absolute;inset:6%;width:88%;height:88%;object-fit:contain}
/* V31.2 — carte produit accueil : image contenue, jamais rognee. Meme cause que reco/catalogue :
   media en aspect-ratio (hauteur non definie) + img height:% qui ne se resout pas -> l'img prend
   sa taille intrinseque et deborde overflow:hidden. Fix : boite absolue ancree (comme la galerie
   fiche). Scopé .home (0,2,1 > home.css 0,1,1) pour NE PAS editer home.css (WIP d'une autre
   session) ; le media accueil est deja position:relative. */
/* Parite template sur l'ACCUEIL sans editer home.css (WIP d'une autre session) : prix en gras
   (le template met .price en 850) et titres cartes plus compacts, via override scope .home
   (specificite superieure a home.css). */
.gbs-reco-card.is-compact strong{font-size:13px;line-height:1.32;height:calc(3 * 1.32em);-webkit-line-clamp:3}
.gbs-reco-card__unlock{display:flex;align-items:center;gap:6px;color:var(--green);font-size:11px;line-height:1.2}
.gbs-reco-card__unlock svg{flex:0 0 auto;width:14px;height:14px}
.gbs-reco-card__foot{display:flex;flex-direction:column;gap:6px}
.gbs-reco-card__price{font-size:16px;font-weight:800;letter-spacing:-.025em;font-variant-numeric:tabular-nums}
.gbs-reco-card__add{width:100%;min-height:40px;border:1px solid var(--green);border-radius:999px;background:transparent;color:var(--green);font-weight:700;cursor:pointer}
.gbs-reco-card__add.is-added{background:var(--green);color:#fff}
/* Complément exact de la borne mobile du tiroir — voir la note sur le masquage de la bande.
   Toute la géométrie desktop du tiroir bascule au MÊME point que le masquage du rail. */
@media not all and (max-width:900px){
  /* Colonne 240 -> 220 px ; la largeur liberee va au panneau du panier, le tiroir garde 720. */
  .gbs-cart{grid-template-columns:220px minmax(0,500px)}
  /* Garantie de 3e photo entiere : la tuile carree s'aplatit juste ce qu'il faut selon la
     hauteur d'ecran. K=478 CALIBRE sur le staging (mesure : 800px -> photo 107, marge 16 ;
     900px -> photo 141, marge 16 ; 1080px -> photo 155 carree pleine, marge 153 ; badge
     livraison present sur la carte 2 = pire cas). L'anatomie de la carte WordPress differe du
     413 du prototype, d'ou la mesure plutot que la copie. */
  .gbs-reco-card.is-compact .gbs-reco-card__media{max-height:calc((100dvh - 478px) / 3)}
}

/* V31 — page de confirmation (order-received). Monochrome, filets 1px, tabular-nums. */
.gbs-confirmation{max-width:640px;margin:60px auto;padding:0 24px;text-align:center}
.gbs-confirmation__title{font-size:clamp(30px,4vw,44px);font-weight:500;margin:0 0 8px}
.gbs-confirmation__lead{color:#686860;margin:0 0 28px}
.gbs-confirmation__order,.gbs-confirmation__next{text-align:start;margin:16px 0;padding:18px 20px;border:1px solid var(--line);border-radius:16px}
.gbs-confirmation__order ul{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:8px}
.gbs-confirmation__order li{display:flex;align-items:baseline;justify-content:space-between;gap:14px}
.gbs-confirmation__order small{color:#686860;white-space:nowrap}
.gbs-confirmation__next ol{margin:8px 0 0;padding:0 0 0 18px;display:grid;gap:7px;font-variant-numeric:tabular-nums}
.gbs-confirmation__actions{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-top:26px}

/* V33 — pied de page aligne sur `.site-footer` du template (mesures getComputedStyle a 1440 et 375).
   Le staging rendait une grille 1.4/.7/.7/1.4 dont la 4e colonne etait une bande de chiffres
   (« 0 DH / 24–48 h / 800 DH » en 32 px) absente du template, un logo laisse en vert sur fond
   #171713 (le template applique brightness(0) invert(1) sur le MEME fichier, il n'existe pas de
   variante blanche dans assets/images/brand/) et des textes en 16 px la ou le template est en 12 px.
   Structure cible : marque + 4 colonnes de liens (la 4e, « Informations », porte les pages
   legales, sans quoi CGV et confidentialite ne sont atteignables depuis aucune page), puis une
   bande basse a filet 1px avec les mentions.
   Points de rupture repris du template (1020 -> 2 colonnes, 640 -> 1 colonne). */
.gbs-footer{background:var(--deep);color:#fff;display:block;padding:65px max(24px,calc((100% - 1320px)/2)) 30px}
.gbs-footer-grid{display:grid;grid-template-columns:1.2fr .65fr .65fr .65fr .65fr;gap:40px}
.gbs-footer-brand .gbs-logo{display:block}
.gbs-footer-brand .gbs-logo img{width:155px;height:64px;max-height:none;object-fit:contain;filter:brightness(0) invert(1)}
.gbs-footer-brand p{max-width:350px;margin:18px 0 0;color:rgba(255,255,255,.58);font-size:12px;line-height:1.7}
.gbs-footer-col{display:flex;flex-direction:column}
.gbs-footer-col h3{margin:0 0 16px;color:var(--gold-soft);font-size:12px;font-weight:700;letter-spacing:.12em;line-height:normal;text-transform:uppercase}
.gbs-footer-col a{display:flex;min-height:44px;align-items:center;color:rgba(255,255,255,.67);font-size:12px;line-height:normal}
.gbs-footer-col a:hover,.gbs-footer-col a:focus-visible{color:#fff}
.gbs-footer-bottom{display:flex;align-items:center;justify-content:space-between;gap:20px;margin-top:52px;padding-top:22px;border-top:1px solid rgba(255,255,255,.18);color:rgba(255,255,255,.45);font-size:12px;line-height:normal}
/* Le passage a 2 colonnes se declenchait a 1020 px alors que le template le place a 900 px
   (`@media(max-width:900px){.footer-grid{grid-template-columns:1fr 1fr}}`). Entre 901 et 1020 px
   le pied rendait donc 2 colonnes au lieu de 4 et mesurait 554 px au lieu de 350 px. */
/* Avec la 4e colonne de liens, la grille porte CINQ enfants : sur deux pistes, le dernier
   restait seul face a une piste vide. La marque prend la largeur pleine, les 4 colonnes de
   liens se rangent alors en 2x2 symetrique. */
@media(max-width:900px){
  .gbs-footer-grid{grid-template-columns:1fr 1fr}
  .gbs-footer-brand{grid-column:1/-1}
}
@media(max-width:640px){
  .gbs-footer{padding:65px 14px 30px}
  .gbs-footer-grid{grid-template-columns:1fr;gap:28px}
  .gbs-footer-bottom{align-items:flex-start;flex-direction:column}
}

/* ── Vignette de ligne de panier : la ligne de grille implicite grandissait a la hauteur de
   l'image, et `height:84%` se resolvait contre ELLE — l'image sortait de sa boite de 126 px
   (jusqu'a +113 px) et `overflow:hidden` la rognait. Fixer la ligne casse la circularite. */
.gbs-cart-line__media{grid-template-rows:100%}
/* Pack : 3 images dans une boite sans regle propre -> empilement de 791 px pour 126 px. */
.gbs-cart-line__media--bundle{grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:repeat(2,minmax(0,1fr));gap:4px;padding:6px}
.gbs-cart-line__media--bundle img{width:100%;height:100%;object-fit:contain}
/* ── Pastille d'objectif sur la vignette des cartes de suggestion (filet, pas d'aplat) */
.gbs-reco-card__media{position:relative}
.gbs-reco-card__tag{position:absolute;z-index:2;bottom:8px;inset-inline-start:8px;max-width:calc(100% - 16px);padding:3px 9px;border:1px solid var(--line-strong);border-radius:999px;background:rgba(255,254,250,.92);color:var(--green-dark);font-size:10.5px;font-weight:700;line-height:1.4;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* ── Confirmation d'ajout ─────────────────────────────────────────────────────────────────────
   DEUX couches par particule, et les axes sont SEPARES : le <span> porte le VERTICAL (courte
   montee puis chute qui accelere), son ::before porte l'HORIZONTAL et la rotation (ejection qui
   decelere sans jamais s'arreter). `transform` etant une propriete unique, tout mettre sur une
   seule couche impose la meme courbe de temps aux deux axes — mesure sur le staging : l'etalement
   restait fige a 163 puis 185 px entre 250 et 450 ms, un temps mort de 200 ms en plein milieu,
   exactement quand l'oeil regarde. Une rotation qui ralentit avec l'ecartement est au passage plus
   juste qu'une rotation lineaire : le papier freine dans l'air.
   Le ::before ne coute aucun markup, donc aucun changement PHP — et donc aucune purge de cache.
   Les vecteurs sont re-tires par `scatterBurst()` (storefront.js) a chaque ajout ; ceux rendus par
   PHP restent le repli si le script ne s'execute pas. */
.gbs-cart-burst{--burst-reach:300px;--burst-drop:clamp(0px,calc(100vh - 110px),560px);--burst-rise:40px;position:absolute;z-index:20;top:64px;inset-inline-start:50%;width:2px;height:2px;pointer-events:none}
.gbs-cart-burst span{position:absolute;top:0;inset-inline-start:0;display:block;transform:translate(-50%,-50%)}
.gbs-cart-burst span::before{content:"";display:block;width:9px;height:14px;border-radius:2px;opacity:0;background:var(--green)}
/* Six teintes de la charte, vert et or. `--gold-soft`, `--green-soft` et le blanc sont ecartes :
   sur `--paper` (#fbf8f2) et sur le rail de reco (#eee8db) ils ne se voient tout simplement pas.
   Les deux valeurs litterales sont derivees de `--gold` et `--green` pour tenir sur ce fond. */
.gbs-cart-burst span:nth-child(6n+2)::before{background:var(--gold)}
.gbs-cart-burst span:nth-child(6n+3)::before{background:var(--green-dark)}
.gbs-cart-burst span:nth-child(6n+4)::before{background:#8c6b2f}
.gbs-cart-burst span:nth-child(6n+5)::before{background:#4c8a6f}
.gbs-cart-burst span:nth-child(6n)::before{background:var(--ink-soft)}
/* Trois formes sur des cycles premiers avec celui des teintes (6), pour que forme et couleur ne
   se resynchronisent pas : languette de papier par defaut, disque, ruban etroit. */
.gbs-cart-burst span:nth-child(4n+1)::before{width:8px;height:8px;border-radius:50%}
.gbs-cart-burst span:nth-child(5n+3)::before{width:4px;height:17px;border-radius:999px}
.gbs-cart.is-celebrating .gbs-cart-burst span{animation:gbsBurstFall 980ms both;animation-delay:var(--burst-delay, 0ms)}
.gbs-cart.is-celebrating .gbs-cart-burst span::before{animation:gbsBurstFly 980ms cubic-bezier(.09,.72,.24,1) both;animation-delay:var(--burst-delay, 0ms)}
/* Vertical. La montee a son PROPRE budget (`--burst-rise`) plutot qu'une fraction de la chute :
   l'origine n'est qu'a 64 px du haut du tiroir, donc une montee proportionnelle a une chute de
   560 px sortait par le haut. 40 px de budget, ratio <= 1, marge preservee.
   `--burst-x` / `--burst-y` sont des RATIOS sans unite tires par `scatterBurst()` ; le budget en
   pixels est ici, parce que seul le CSS connait la largeur du tiroir. Elle vaut `min(720px,100%)`
   au-dela de 900 px et `min(600px,100vw)` en deca — donc sous 600 px elle SUIT le viewport, et
   aucun facteur constant ne peut la couvrir. Le tiroir est en `overflow:hidden`, a NE PAS retirer :
   il protege la croix de fermeture et le bouton « Annuler » (cf. plus bas). */
@keyframes gbsBurstFall{
  0%{transform:translate(-50%,-50%) scale(.42);animation-timing-function:cubic-bezier(.06,.8,.3,1)}
  22%{transform:translate(-50%,calc(-50% - var(--burst-ry, 0) * var(--burst-rise))) scale(1);animation-timing-function:cubic-bezier(.48,.02,.74,.44)}
  100%{transform:translate(-50%,calc(-50% + var(--burst-ry, 0) * var(--burst-drop))) scale(.94)}
}
/* Horizontal + rotation, d'un seul tenant et en decelerant. Le `rotate3d` fait perdre puis
   reprendre de la largeur a l'eclat : c'est ce qui le fait lire comme du PAPIER et non comme un
   trait colore. Pleine opacite des 7 % contre 18 % avant, soit 162 ms d'invisibilite en tete qui
   s'ajoutaient au retard percu. */
@keyframes gbsBurstFly{
  0%{opacity:0;transform:translateX(0) rotate(0) rotate3d(1,1,0,0deg)}
  7%{opacity:1}
  76%{opacity:1}
  100%{opacity:0;transform:translateX(calc(var(--burst-rx, 0) * var(--burst-reach))) rotate(var(--burst-rot, 0deg)) rotate3d(1,1,0,900deg)}
}
/* Sous 900 px le tiroir vaut `min(600px,100vw)` : le plafond de 268 px tient tant qu'il est cape a
   600, le terme en `vw` prend le relais quand l'ecran devient plus etroit que le tiroir.
   Les deux budgets sont bornes A ZERO PAR LE BAS. Ce n'est pas une precaution : mesure dans le
   panneau navigateur, `100vh` s'y resout a 0, donc `calc(100vh - 120px)` valait -120px — un budget
   negatif inverse la trajectoire et envoie la gerbe VERS LE HAUT, hors du tiroir. Zero degenere
   proprement (les eclats restent a l'origine) la ou un negatif ment. */
@media(max-width:900px){.gbs-cart-burst{--burst-reach:clamp(0px,calc(50vw - 24px),268px);--burst-drop:clamp(0px,calc(100vh - 120px),430px);--burst-rise:34px;top:58px}}
@media(prefers-reduced-motion:reduce){.gbs-cart-burst{display:none!important}}

/* ═══ V34 — parité du TIROIR PANIER avec le template ══════════════════════════════════════════
   Blocs ajoutés (ordre du template) : lignes, montée en gamme, bande de suggestions, repères de
   confiance ; puis la bande d'annulation, puis le pied. Tout est scopé sous `.gbs-cart` : les
   noms de classe sont ceux du template (`cart-upgrade`, `cart-undo`, `objective-tag`…) pour que
   la comparaison DOM soit littérale, et le scope empêche toute collision avec les autres
   extensions du site (vérifié : aucune de ces classes n'existe ailleurs dans les CSS installés). */

/* ── Le corps du tiroir devient le conteneur défilant. Auparavant `.gbs-cart-lines` défilait
      seul ; les trois blocs ajoutés doivent défiler AVEC les lignes, pas s'empiler dans une
      rangée de grille fixe qui aurait mangé la hauteur du pied. */
.gbs-cart-panel-v29{grid-template-rows:auto auto minmax(0,1fr) auto auto}
.gbs-cart-body{display:flex;flex-direction:column;min-height:0;overflow:auto;padding:8px 26px}
.gbs-cart-body>*{flex:0 0 auto}
.gbs-cart-lines{overflow:visible;padding:0}

/* ── Ligne de panier : tuile PORTRAIT accordée aux découpes du catalogue.
      La tuile carrée 126×126 laissait le flacon n'occuper que 31 à 45 % de sa boîte (tous les
      cutouts sont en portrait : `object-fit:contain` saturait la hauteur et effondrait la
      largeur). Ce n'était pas un rognage mais un défaut de REMPLISSAGE — d'où la géométrie
      72×82 du template, qui monte le remplissage à ~62 % et raccourcit la ligne. */
.gbs-cart-line{grid-template-columns:72px 1fr;gap:11px;padding:14px 0}
.gbs-cart-line__media{grid-row:1/4;width:72px;height:82px;border-radius:15px;background:linear-gradient(145deg,#ebe7df,#d0c8bc)}
.gbs-cart-line__media img{width:66px;height:76px;object-fit:contain;filter:drop-shadow(0 8px 7px rgba(23,23,19,.16))}
/* Pack : 3 images dans une grille 2×2 = une case vide et 7 % de remplissage. Trois colonnes. */
.gbs-cart-line__media--bundle{grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:100%;gap:3px;padding:5px}
.gbs-cart-line__media--bundle img{width:100%;height:100%;object-fit:contain;filter:none}
/* `right:0` collait la croix du côté du média en arabe : la fermeture se superposait à la photo. */
.gbs-remove{top:12px;right:auto;inset-inline-end:0}

/* ── Pastille d'objectif SUR LA LIGNE (les cartes de suggestion l'avaient déjà). */
/* La croix de suppression est en position absolue dans le coin : sans cette réserve, un titre
   qui passe à la ligne vient se glisser dessous (mesuré à 375 : « …5 %✗ 60 g »). */
.cart-line-identity{display:flex;min-width:0;flex-direction:column;align-items:flex-start;gap:6px;padding-inline-end:30px}
.gbs-cart .cart-line-identity .objective-tag{max-width:100%;overflow:hidden;padding:3px 9px;border:1px solid var(--line-strong);border-radius:999px;color:var(--green-dark);font-size:10.5px;font-weight:700;line-height:1.4;text-overflow:ellipsis;white-space:nowrap}

/* ── Montée en gamme. Le template peint cette carte en BLEU (accent Regaine) ; la charte du
      storefront est monochrome + un seul accent, donc elle est rendue en vert comme le reste. */
.gbs-cart .cart-upgrade{display:grid;grid-template-columns:76px minmax(0,1fr) minmax(150px,auto);align-items:center;gap:13px;margin-top:14px;overflow:hidden;border:1px solid rgba(33,94,75,.28);border-radius:15px;padding:12px;background:linear-gradient(110deg,#eef3ef,#f7f4ec)}
.gbs-cart .drawer-upgrade-media{display:grid;width:76px;height:82px;place-items:center;overflow:hidden;border-radius:12px;background:rgba(255,255,255,.5)}
.gbs-cart .drawer-upgrade-media img{width:70px;height:76px;object-fit:contain;filter:drop-shadow(0 7px 7px rgba(23,23,19,.14))}
.gbs-cart .drawer-upgrade-copy{min-width:0}
.gbs-cart .drawer-upgrade-copy small{color:var(--green);font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}
.gbs-cart .drawer-upgrade-copy h3{margin:3px 0;font-size:15px;font-weight:700;letter-spacing:-.02em;line-height:1.25}
.gbs-cart .drawer-upgrade-copy p{margin:0;color:var(--muted);font-size:12px;line-height:1.4}
.gbs-cart .drawer-upgrade-copy ul{display:flex;flex-wrap:wrap;gap:3px 12px;margin:6px 0 0;padding:0;list-style:none}
.gbs-cart .drawer-upgrade-copy li{position:relative;padding-inline-start:11px;color:var(--muted);font-size:12px;line-height:1.5}
.gbs-cart .drawer-upgrade-copy li::before{content:"";position:absolute;inset-inline-start:0;top:.6em;width:4px;height:4px;border-radius:50%;background:var(--green)}
.gbs-cart .drawer-upgrade-action{display:grid;min-width:150px;justify-items:stretch;gap:7px}
.gbs-cart .drawer-upgrade-action strong{color:var(--green-dark);font-size:18px;font-weight:800;font-variant-numeric:tabular-nums;text-align:end}
.gbs-cart .drawer-upgrade-action button{min-height:46px;border:0;border-radius:11px;padding:9px 12px;background:var(--green);color:#fff;font-size:12px;font-weight:800;cursor:pointer}
.gbs-cart .drawer-upgrade-action button:hover{background:var(--green-dark)}
.gbs-cart .drawer-upgrade-action button:focus-visible{outline:3px solid var(--focus);outline-offset:2px}

/* ── Bande de suggestions dans le corps du panier (le rail latéral reste par ailleurs). */
.gbs-cart .cart-recommendation-band{margin-top:20px;border-top:1px solid var(--line);padding-top:16px}
.gbs-cart .cart-recommendation-band-head{margin-bottom:12px}
.gbs-cart .cart-recommendation-band-head .gbs-eyebrow{display:block;margin:0 0 4px;font-size:11px}
.gbs-cart .cart-recommendation-band-head h2{margin:0;font-size:19px;font-weight:700;letter-spacing:-.03em;line-height:1.15}
.gbs-cart .cart-recommendation-band-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
/* Carte horizontale : même fabrique PHP que le rail, un modificateur de classe pour la forme. */
.gbs-reco-card--band.is-compact{display:grid;grid-template-columns:76px minmax(0,1fr);grid-template-rows:minmax(0,1fr) auto;gap:0;min-height:112px;padding:0;overflow:hidden;border-radius:15px}
.gbs-reco-card--band.is-compact .gbs-reco-card__link{display:contents}
.gbs-reco-card--band.is-compact .gbs-reco-card__media{grid-column:1;grid-row:1/3;align-self:stretch;width:76px;height:auto;min-height:92px;max-height:none;aspect-ratio:auto;border-radius:0;border-inline-end:1px solid var(--line)}
.gbs-reco-card--band.is-compact .gbs-reco-card__media img{inset:8%;width:84%;height:84%}
.gbs-reco-card--band.is-compact strong{grid-column:2;align-self:start;height:auto;margin:0;padding:10px 10px 0;font-size:13px;-webkit-line-clamp:2}
.gbs-reco-card--band.is-compact .gbs-reco-card__unlock{grid-column:2;padding:5px 10px 0}
.gbs-reco-card--band.is-compact .gbs-reco-card__foot{grid-column:2;flex-direction:row;align-items:center;justify-content:space-between;gap:8px;padding:8px 10px 10px}
.gbs-reco-card--band.is-compact .gbs-reco-card__add{width:auto;min-width:0;min-height:36px;flex:0 0 auto;padding:0 13px;font-size:12px}
.gbs-reco-card--band.is-compact .gbs-reco-card__price{font-size:15px}

/* ── Repères de confiance, poussés en bas du corps quand le panier est court. */
.gbs-cart .cart-drawer-trust{margin-top:auto;padding-top:18px}
.gbs-cart .order-trust{display:grid;gap:7px;border-top:1px solid var(--line);padding-top:14px;color:var(--muted);font-size:12.5px}
.gbs-cart .order-trust>span{display:inline-flex;align-items:flex-start;gap:8px}
.gbs-cart .order-trust svg{flex:0 0 15px;width:15px;height:15px;margin-top:1px;color:var(--green)}

/* ── Annulation de suppression : rangée propre entre le corps et le pied. */
.gbs-cart .cart-undo{display:flex;align-items:center;justify-content:space-between;gap:12px;border-top:1px solid var(--line);padding:10px 26px;background:rgba(33,94,75,.06);color:var(--green-dark);font-size:13px}
.gbs-cart .cart-undo[hidden]{display:none}
.gbs-cart .cart-undo>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gbs-cart .cart-undo button{flex:0 0 auto;min-height:36px;border:1px solid currentColor;border-radius:999px;padding:0 14px;background:transparent;color:inherit;font-size:12.5px;font-weight:700;cursor:pointer}
.gbs-cart .cart-undo button:hover{background:rgba(33,94,75,.1)}
.gbs-cart .cart-undo button:focus-visible{outline:3px solid var(--focus);outline-offset:2px}

/* ── Pied : statut de livraison à côté du sous-total, puis la note de réassurance. */
.gbs-cart-footer__total{display:flex;align-items:end;justify-content:space-between;gap:16px}
.gbs-cart-footer__total>div{display:flex;align-items:baseline;gap:10px}
.gbs-cart-footer__total>div>span{color:var(--muted);font-size:12px}
.gbs-cart-footer__total strong{font-size:24px;font-variant-numeric:tabular-nums;letter-spacing:-.035em}
.drawer-shipping-status{display:inline-flex;align-items:center;gap:6px;color:var(--green);font-size:12px;font-weight:800;text-align:end}
.drawer-shipping-status svg{flex:0 0 16px;width:16px;height:16px}
.drawer-footer-note{margin:2px 0 0;color:var(--muted);font-size:11.5px;line-height:1.45;text-align:center}

/* ── Ordre DOM aligné sur le template (panneau AVANT rail) : le placement visuel redevient
      l'affaire de la grille, plus de l'ordre source. Le rail reste à gauche en desktop. */
@media not all and (max-width:900px){
  .gbs-cart>.gbs-reco-rail{grid-column:1;grid-row:1}
  .gbs-cart>.gbs-cart-panel-v29{grid-column:2;grid-row:1}
  /* Le plafond de hauteur des vignettes existe pour garantir 3 photos entières DANS LE RAIL :
     appliqué à `.gbs-reco-card` en général, il écrasait aussi les tuiles de la fiche produit
     (aplaties à ~114 px pour 250–363 px de large) et celles de la bande. */
  .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__media{max-height:calc((100dvh - 478px) / 3)}
}
/* La pastille d'objectif doit rester au-dessus de la photo quel que soit le contexte parent. */
.gbs-reco-card__media{isolation:isolate}
/* La règle « fiche produit : la tuile redevient carrée » vivait ici, scopée à
   `.gbs-merch-grid .gbs-reco-card__media`. La bande de bas de fiche rend désormais des
   `.gbs-routine-card` — mêmes cartes que le bloc du haut, avec bouton d'ajout —, plus aucune
   `.gbs-reco-card` : la règle n'avait plus rien à habiller. `.gbs-reco-card` reste la carte du
   tiroir panier, du tunnel et de la page de remerciement, ses autres règles ne bougent pas. */

@media(max-width:900px){
  /* ═══ V35 — le pied du tiroir redevient FIXE, seul le corps défile ═══════════════════════
     Etat precedent, mesure a 375x812 (1 article) : `.gbs-cart` etait `display:flex` +
     `overflow-y:auto`, donc le tiroir defilait d'un seul bloc sur 2 049 px pour 812 px de
     fenetre — en-tete, jauge, lignes, montee en gamme, suggestions, rail ET pied. Le CTA
     « Commander » se trouvait a 1 436 px du haut du conteneur defilant : invisible sans
     traverser tout le panier.
     Contrat du template (mesure sur `german-beautyshop-storefront.html`, 991 433 o, a 375x812) :
     `.cart-concierge-shell` = grille 1 colonne de hauteur DEFINIE, `overflow:hidden` ;
     `.cart-concierge-panel` = `grid-template-rows:auto auto minmax(0,1fr) auto auto` ;
     `.drawer-body` = `overflow-y:auto;min-height:0`. Rangees relevees : 75 / 72 / 484 / 181 / 0,
     pied a 631-812 px, donc toujours visible.
     PIEGE (deja paye ici) : la rangee `minmax(0,1fr)` s'effondre a 0 px et le corps se peint
     par-dessus le pied des que le PARENT n'impose plus de hauteur — c'est ce qui arrivait quand
     le panneau etait un item flex compressible. La garde n'est donc pas sur l'enfant mais sur la
     geometrie du parent : `.gbs-cart` reste une GRILLE de hauteur definie (`inset-block:0` dans
     `.gbs-layer{position:fixed;inset:0}`) et le panneau prend exactement cette hauteur. */
  .gbs-cart{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);overflow:hidden}
  /* Le rail lateral du desktop restait rendu sous 900 px (`order:2`) : le client voyait la bande
     de suggestions du corps PUIS les 10 memes cartes du rail. Le template le masque des 1 099 px
     (`.cart-recommendations{display:none}`) et ne garde que la bande. */
  .gbs-cart>.gbs-reco-rail{display:none}
  .gbs-cart-panel-v29{grid-template-rows:auto auto minmax(0,1fr) auto auto;height:100%;max-height:100%;min-height:0}
  .gbs-cart-body{overflow:auto;overscroll-behavior:contain;min-height:0;padding:8px 18px}
  /* Le carrousel de suggestions mesure plusieurs centaines de pixels en colonne : il enterrait
     les repères de confiance. On les remonte juste sous la décision, la bande devient la traîne. */
  .gbs-cart-body>.gbs-cart-lines{order:1}
  .gbs-cart-body>.cart-upgrade{order:2}
  .gbs-cart-body>.cart-drawer-trust{order:3;margin-top:0}
  .gbs-cart-body>.cart-recommendation-band{order:4}
  .gbs-cart-line{grid-template-columns:84px 1fr}
  .gbs-cart-line__media{width:84px;height:96px}
  .gbs-cart-line__media img{width:78px;height:90px}
  .gbs-cart .cart-upgrade{grid-template-columns:66px minmax(0,1fr);gap:10px;padding:10px}
  .gbs-cart .drawer-upgrade-media{width:66px;height:72px}
  .gbs-cart .drawer-upgrade-media img{width:60px;height:66px}
  .gbs-cart .drawer-upgrade-action{grid-column:1/-1;grid-template-columns:auto minmax(0,1fr);align-items:center;min-width:0}
  .gbs-cart .drawer-upgrade-action strong{text-align:start}
  .gbs-cart .cart-recommendation-band-grid{grid-template-columns:1fr}
  .gbs-cart .cart-undo{padding-inline:18px}
  .gbs-cart .cart-undo button{min-height:44px}
  .gbs-reco-card--band.is-compact .gbs-reco-card__add{min-height:44px}
}
@media(max-width:480px){
  .gbs-cart-body{padding-inline:16px}
  .gbs-cart .cart-undo{padding-inline:16px}
}

/* ── V34 — en-tête, partie droite. Le badge du panier était `position:absolute` dans un
      `.gbs-round` en `position:static` : il se calait donc sur le HEADER et débordait de son
      padding, sans anneau de séparation. Les ronds passent de 48 à 44 px et l'icône de 21,6
      (héritée de `svg{width:1.35em}`) à 19 px, mesures du template. `.gbs-icon-button` ne reçoit
      que l'ancrage : son aplat vert lui appartient. */
.gbs-round,.gbs-icon-button{position:relative}
/* PAS de `display` ici : `.gbs-mobile-menu-trigger{display:none}` et les boutons contextuels de
   l'en-tête sont masqués par des règles de MÊME spécificité situées plus haut dans ce fichier.
   Redéclarer `display:grid` sur `.gbs-round` les rendait tous visibles en desktop (hamburger,
   retour, WhatsApp), et l'en-tête passait à deux rangées. La forme vient de la règle d'origine. */
.gbs-round{width:44px;height:44px;flex:0 0 44px;border:1px solid var(--line);border-radius:50%;background:transparent;place-items:center;cursor:pointer}
.gbs-round svg{width:19px;height:19px}
.gbs-header-actions{display:flex;align-items:center;justify-content:flex-end;gap:7px}
.gbs-cart-count{position:absolute;top:-4px;inset-inline-end:-2px;transform:none;min-width:22px;height:22px;padding:0 4px;border:2px solid var(--paper);border-radius:999px;background:var(--green);color:#fff;display:grid;place-items:center;font-size:12px;font-weight:800;line-height:1}
/* Colonne de marque à la largeur du template (146 px). La 3e piste reste `auto` et NON 146 px :
   mesuré à 1440, l'en-tête porte QUATRE enfants visibles en desktop — le bouton retour, le logo,
   la navigation, les actions — donc une grille à 3 pistes fixes rejette le 4e dans une colonne
   implicite et pousse la page à 1536 px (96 px de débordement horizontal, barre de défilement
   sur tout le site). Avec `auto`, débordement mesuré à 0. Cette piste souple encaisse aussi les
   boutons d'en-tête ajoutés par ailleurs, sans nouveau comptage.
   Bornée au desktop : les points de rupture mobiles imposent leur propre grille plus haut dans
   ce fichier, une règle inconditionnelle les écraserait. */
@media(min-width:901px){
  .gbs-header{grid-template-columns:146px minmax(0,1fr) auto}
}

/* Actions nommées du header de checkout. Le template écrit « Retour » et « Aide WhatsApp » EN
   TEXTE au-dessus de 900 px, et les réduit à leur seule icône en dessous. La grille du header
   doit suivre : ses pistes de 48 px sont taillées pour un rond, une pilule y déborderait.
   Sous 900 px le libellé est retiré du flux — l'`aria-label` du bouton porte déjà le nom, donc
   rien n'est perdu pour un lecteur d'écran. Placé en fin de fichier : les points de rupture
   mobiles définis plus haut imposent leur propre grille, une règle inconditionnelle les
   écraserait. */
@media(min-width:901px){
  .gbs-checkout-header{grid-template-columns:auto minmax(0,1fr) auto}
  .gbs-round--labelled{display:inline-flex;align-items:center;justify-content:center;gap:8px;width:auto;height:42px;flex:0 0 auto;padding:0 16px;border-radius:999px;white-space:nowrap}
  .gbs-round--labelled span{font-size:13px;font-weight:700;letter-spacing:-.01em}
}
@media(max-width:900px){
  .gbs-round--labelled span{display:none}
}

/* ── En-tête mobile : deux icônes de chaque côté. Le template posait le hamburger seul à gauche
   et trois ronds à droite ; la recherche rejoint le menu. `.gbs-header-actions` passe en
   `display:contents` pour que ses trois ronds deviennent des items de la grille de l'en-tête :
   hamburger piste 1, recherche piste 2, compte et panier pistes 4 et 5. Les QUATRE ronds sont
   placés explicitement — sans quoi l'auto-placement les décale d'une piste dès qu'un frère entre
   ou sort du flux ; c'est exactement ce qui écrasait le logo à 44 px de large (mesuré 65..109 au
   lieu de 129..247) quand il était laissé à l'auto-placement.
   Le logo reçoit `grid-column:1/-1`, PAS `3`, et la nuance est structurelle : il est dans le flux
   aujourd'hui mais une lignée voisine le repasse en `position:absolute` centré, et pour un item
   absolu une ligne de grille redéfinit la CONTAINING BLOCK. Avec `3`, cette boîte démarre à la
   ligne 3 et la translation de centrage le décale de 58 px vers la droite ; avec `3/4` il
   retrouve le centre mais rétrécit de 118 à 72 px. `1/-1` couvre les deux états : dans le flux il
   traverse la grille et `justify-self:center` le pose à 188 px (centre exact, largeur naturelle
   118 px, mesuré) ; en absolu sa containing block redevient la grille entière, donc le centrage
   par translation retombe juste. Les ronds gardent leurs pistes : ils ne bougent d'aucun pixel
   dans les six combinaisons mesurées.
   L'ordre de tabulation reste celui du DOM (menu, logo, recherche, compte, panier) alors que
   l'ordre visuel est menu, recherche, logo, compte, panier : le logo se tabule avant la
   recherche. Compromis assumé — corriger cela demanderait de déplacer le bouton dans
   `header.php`, ce qui déplacerait le même décalage sur le desktop, où la recherche est à droite.
   `column-gap:7px` reprend exactement le `gap` que `.gbs-header-actions` posait plus haut : la
   largeur totale d'encre est inchangée (190 px), donc aucun débordement nouveau — mesuré à 375
   et 320 px, `scrollWidth === innerWidth`. Les pistes étant logiques, le miroir RTL est correct
   sans règle dédiée (vérifié sous `/ar/`).
   INVARIANT : ces règles comptent TROIS enfants dans `.gbs-header-actions` (recherche, compte,
   panier — identique sur accueil, boutique, produit, panier, mon-compte). Tout bouton ajouté ici
   doit recevoir son propre `grid-column`, sinon il atterrit dans la piste souple, au milieu de
   l'en-tête. Bornées à 900 px : au-delà, le hamburger est masqué et l'en-tête retrouve ses trois
   enfants pour ses trois pistes. Placées après la ligne 490 : la grille mobile de la ligne 167 a
   la même spécificité, il faut passer après elle. */
@media(max-width:900px){
  .gbs-header{grid-template-columns:44px 44px minmax(0,1fr) auto auto;column-gap:7px}
  .gbs-header>.gbs-header-actions{display:contents}
  .gbs-header>.gbs-mobile-menu-trigger{grid-column:1}
  .gbs-header>.gbs-header-actions>[data-gbs-open="search"]{grid-column:2}
  .gbs-header>.gbs-logo{grid-column:1/-1}
  .gbs-header>.gbs-header-actions>.gbs-account-button{grid-column:4}
  .gbs-header>.gbs-header-actions>[data-gbs-open="cart"]{grid-column:5}
}

/* ═══ V35 — etats de la navigation principale ═════════════════════════════════════════════════
   Mesure avant, a 1440 : `.gbs-nav a,.gbs-nav button` (la regle gagnante) ne posait ni forme ni
   fond — `border-radius:0`, `padding:1px 6px` sur les boutons (valeur par DEFAUT du navigateur,
   pas une intention) et `0px` sur les liens, `background:transparent`, et `color` INCHANGE une
   fois le mega-menu ouvert (`aria-expanded="true"`), chevron `transform:none`.
   Le template donne une pastille (`border-radius:999px`, `padding:0 13px`, fond `--green-soft`)
   au survol ET a l'ouverture, et fait pivoter le chevron de 180°.
   Borne a >=901 px : sous 900 px `.gbs-nav>.gbs-nav-primary-item{display:none}` — ces items ne
   sont jamais rendus dans le tiroir mobile, qui a son propre composant (`.gbs-mobile-nav-content`).
   Combinateur enfant, comme le template : les liens du mega-menu mobile ne sont pas vises. */
@media(min-width:901px){
  .gbs-nav>a,.gbs-nav>button{
    position:relative;
    display:inline-flex;
    min-width:44px;
    min-height:44px;
    align-items:center;
    justify-content:center;
    gap:6px;
    border:0;
    border-radius:999px;
    padding:0 13px;
    background:transparent;
    color:var(--ink-soft);
    font-size:13px;
    font-weight:700;
    white-space:nowrap;
    cursor:pointer;
    transition:background-color 180ms ease,color 180ms ease;
  }
  .gbs-nav>a:hover,
  .gbs-nav>button:hover,
  .gbs-nav>button[aria-expanded=true]{background:var(--green-soft);color:var(--green-dark)}
  .gbs-nav>a:focus-visible,
  .gbs-nav>button:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
  .gbs-nav>button svg{width:14px;height:14px;transition:transform 180ms ease}
  .gbs-nav>button[aria-expanded=true] svg{transform:rotate(180deg)}
}
@media(prefers-reduced-motion:reduce){
  .gbs-nav>a,.gbs-nav>button,.gbs-nav>button svg{transition:none}
}

/* ═══ V35 — etat « panier vide » ══════════════════════════════════════════════════════════════
   Mesure avant : `.gbs-cart-empty{display:block;padding:40px;text-align:start}`, aucune icone,
   aucun rythme — un `<p>` colle a un bouton.
   Le balisage rend desormais l'anatomie complete du template (jeton d'icone tire du sprite,
   `<h3>` titre, `<p>` secondaire, action), donc les valeurs sont reprises telles quelles de
   `.empty-cart` : jeton 72 px / icone 29 px / `min-height:330px` / titre 27 px en 800 avec
   `letter-spacing:-.035em` (regle groupee du template avec `.drawer-header h2`) / paragraphe
   270 px de large en 12 px (valeur effective du template, son `10px` etant ecrase plus bas).
   Le rythme vertical vient des MARGES du template (17 px sous le jeton, 9 px au-dessus du
   paragraphe), pas d'un `gap` : un `gap` s'ajouterait a ces marges au lieu de les remplacer.
   `align-content:center` plutot que `place-items:center` : le template n'a qu'UN enfant de
   grille (tout est enveloppe dans un `<div>`), ici il y en a quatre — `align-content:stretch`
   (le defaut) etirerait les quatre rangees au lieu de centrer la pile. */
.gbs-cart-empty{
  display:grid;
  min-height:330px;
  align-content:center;
  justify-items:center;
  overflow:auto;
  padding:32px 26px max(32px,env(safe-area-inset-bottom));
  text-align:center;
}
.gbs-cart-empty__icon{
  display:grid;
  width:72px;
  height:72px;
  margin:0 auto 17px;
  place-items:center;
  border-radius:50%;
  background:var(--green-soft);
  color:var(--green);
}
/* Bat la regle globale `svg{width:1.35em;height:1.35em}` par la specificite (0,2,1 > 0,0,1). */
.gbs-cart-empty__icon svg{width:29px;height:29px}
.gbs-cart-empty h3{
  margin:0;
  color:var(--ink);
  font-size:27px;
  font-weight:800;
  letter-spacing:-.035em;
  line-height:1.1;
}
.gbs-cart-empty p{
  max-width:270px;
  margin:9px auto 0;
  color:var(--muted);
  font-size:12px;
  line-height:1.55;
}
.gbs-cart-empty .gbs-button{min-width:min(260px,100%);margin-top:22px}
/* Sans `.gbs-cart-body` VISIBLE, le panneau n'a que l'en-tete, le bloc vide et la bande
   d'annulation : la rangee souple est ramenee en 2e position pour que le bloc occupe la hauteur
   restante. La regle vaut toujours — un enfant en `display:none` n'est PAS un item de grille,
   donc les items places restent les memes trois qu'avant. */
.gbs-cart-panel-v29:has(>.gbs-cart-empty),
.gbs-cart-panel:has(>.gbs-cart-empty){grid-template-rows:auto minmax(0,1fr) auto}
/* `cart_panel()` rend desormais le squelette — jauge, corps, gabarit de ligne, pied — dans les
   DEUX etats, pour qu'un ajout ait ou peindre des la PREMIERE ligne. C'etait la sortie « panier
   vide » de `paintCartAddition()` : sans point d'insertion ni gabarit, le premier ajout laissait
   l'etat vide a l'ecran jusqu'aux fragments (454 a 1 098 ms mesures). Tant que le bloc vide est
   la, ces trois rangees sortent du flux et l'ecran vide est celui d'hier au pixel.
   PAS de drapeau neuf : la presence de `.gbs-cart-empty` EST deja l'etat que la regle ci-dessus
   lit. Une classe supplementaire ferait deux sources de verite pour un seul etat, que le JS
   devrait tenir en coherence ; ici il n'a qu'un geste — RETIRER un noeud rendu par PHP, la seule
   operation que la regle du theme lui autorise.
   `display:none` et rien d'autre : `visibility`/`opacity` laisseraient trois items dans la grille
   (la rangee souple n'irait plus au bloc vide) et surtout garderaient le CTA « Commander » dans
   `visibleFocusables()`, qui filtre sur `getClientRects().length` — il redeviendrait tabulable
   derriere un ecran qui annonce un panier vide. */
.gbs-cart-panel-v29:has(>.gbs-cart-empty)>.gbs-cart-shipping-top,
.gbs-cart-panel-v29:has(>.gbs-cart-empty)>.gbs-cart-body,
.gbs-cart-panel-v29:has(>.gbs-cart-empty)>.gbs-cart-footer,
.gbs-cart-panel:has(>.gbs-cart-empty)>.gbs-cart-shipping-top,
.gbs-cart-panel:has(>.gbs-cart-empty)>.gbs-cart-body,
.gbs-cart-panel:has(>.gbs-cart-empty)>.gbs-cart-footer{display:none}

/* V36 — TIROIR PANIER : echelle typographique, structure de ligne et jauge de livraison.
   La passe V34 « parite du tiroir » avait reecrit la GEOMETRIE (pistes de grille, boites media,
   paddings) sans toucher aux declarations typographiques du bloc minifie de la ligne 17. Le
   tiroir avait donc la bonne mise en page et la mauvaise echelle de texte : nom de produit a
   16 px contre 14, titre a 31 px contre 23, compteur d'articles a 16 px noir contre 12 px gris.
   C'est ce que le proprietaire a lu comme « le texte est trop gros » et « la police n'est pas
   la meme » : la police, elle, est deja identique (canvas measureText, meme chaine a 14 px :
   382,14 px des deux cotes, a toutes les graisses).
   Toutes les valeurs ci-dessous sont MESUREES par getComputedStyle sur le template a 1440x900,
   pas lues dans la feuille : le template empile 30 couches de surcharges et la valeur effective
   n'est presque jamais celle qu'on lit en premier.
   Les `font-weight` ne sont volontairement PAS touches : une seule face est declaree et
   `font-synthesis:none` les rend inertes des deux cotes (cf. note V33 en tete de fichier). */

/* Palette : le tiroir de la reference est peint avec la couche `--v9-*`, plus verte et plus
   chaude que la palette de base. On redefinit les jetons DANS le tiroir seulement — chaque regle
   existante suit sans etre reecrite, et rien ne bouge ailleurs sur le site. */
.gbs-cart{
  --ink:#10251c;--ink-soft:#30463d;--paper:#fbf8f2;
  --green:#174f3c;--green-dark:#0c3427;--green-soft:#dfeae3;
  --gold:#b89c5f;--gold-soft:#eee1c3;
  --line:rgba(16,37,28,.14);--line-strong:rgba(20,61,47,.22);
}

/* En-tete */
.gbs-cart .gbs-cart-head h2{font-size:23px;letter-spacing:-.035em}
.gbs-cart .gbs-cart-head>div>span{display:block;max-width:285px;margin-top:3px;overflow:hidden;color:#626960;font-size:12px;text-overflow:ellipsis;white-space:nowrap}

/* Ligne panier : identite en haut, selecteur a gauche et montant a droite en bas.
   Le media ne couvre plus trois rangees implicites — la colonne 2 n'a qu'un enfant. */
.gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle) .gbs-cart-line__media{grid-row:auto}
.gbs-cart .gbs-cart-line strong{font-size:14px;line-height:1.35}
.gbs-cart .gbs-cart-line__price{font-variant-numeric:tabular-nums;white-space:nowrap}
.gbs-cart .gbs-quantity{display:inline-grid;width:auto;min-height:34px;grid-template-columns:34px 24px 34px;overflow:hidden}
.gbs-cart .gbs-quantity button{width:34px;height:34px;font-size:14px}
.gbs-cart .gbs-quantity span{font-size:13px;font-variant-numeric:tabular-nums;text-align:center}
/* Le « x » etait un glyphe texte sans cible tactile ni etat de survol. */
.gbs-cart .gbs-remove{display:grid;width:44px;height:44px;place-items:center;border-radius:50%}
.gbs-cart .gbs-remove svg{width:15px;height:15px}
.gbs-cart .gbs-remove:hover{color:var(--danger);background:#f5e9e6}

/* Ligne PACK : `cart_panel()` emet `<small>`/`<strong>`/`<em>`, trois elements INLINE, et aucune
   regle ne les visait — les trois textes se collaient en une seule phrase illisible
   (« Pack -5 %Routine cheveux completes3 mois de cure »). La reference les empile parce qu'elle
   utilise `<h3>` et `<p>`. Valeurs alignees sur l'echelle deja etablie du tiroir (titre 14 px
   comme les autres lignes, texte secondaire 12 px sourdine comme le bloc de confiance) et non
   mesurees sur la reference : son panier de demonstration ne contenait pas de pack. */
.gbs-cart .gbs-cart-line--bundle>a>span:last-child{display:flex;min-width:0;flex-direction:column;gap:4px}
.gbs-cart .gbs-cart-line--bundle small{color:var(--green);font-size:11px;letter-spacing:.06em;text-transform:uppercase}
.gbs-cart .gbs-cart-line--bundle strong{font-size:14px;line-height:1.35}
.gbs-cart .gbs-cart-line--bundle em{display:-webkit-box;overflow:hidden;color:var(--muted);font-size:12px;font-style:normal;line-height:1.45;-webkit-box-orient:vertical;-webkit-line-clamp:2}

/* Bande de livraison */
.gbs-cart-shipping-top{padding:11px 26px 13px;border-bottom:1px solid var(--line);background:#f1ece2}
.gbs-cart-shipping-top:empty{display:none}
.gbs-cart .gbs-shipping-progress{display:block;padding:0;border:0;background:transparent;color:var(--ink)}

/* Etat « en cours » : pas d'eyebrow en capitales, une ligne de texte, une barre de 4 px,
   la pastille d'objectif conservee et le pourcentage — absent jusqu'ici. */
.gbs-cart .gbs-shipping-progress__copy{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:8px}
.gbs-cart .gbs-shipping-progress__copy p{display:block;margin:0}
.gbs-cart .gbs-shipping-progress__copy p>strong{display:none}
.gbs-cart .gbs-shipping-progress__copy p>span{display:block;color:var(--ink);font-size:13px;letter-spacing:normal;line-height:1.35;text-transform:none}
.gbs-cart .gbs-shipping-progress__percent{flex:0 0 auto;color:var(--green);font-size:11.5px;font-variant-numeric:tabular-nums}
.gbs-cart .gbs-shipping-progress i{position:relative;display:block;height:4px;margin-top:10px;overflow:visible;border-radius:999px;background:rgba(23,79,60,.13)}
.gbs-cart .gbs-shipping-progress i b{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--green),#2f7a5d);box-shadow:0 3px 9px rgba(23,79,60,.17);transition:width 280ms cubic-bezier(.2,.75,.2,1)}
.gbs-cart .gbs-shipping-progress__truck{position:absolute;top:50%;inset-block-end:auto;inset-inline-end:-1px;width:26px;height:26px;border:2px solid var(--green);background:var(--paper);box-shadow:0 5px 14px rgba(16,37,28,.12);transform:translateY(-50%)}
.gbs-cart .gbs-shipping-progress__truck svg{width:13px;height:13px}
/* `gbsPulse` ne porte qu'un `scale()` : applique ici il ecraserait le `translateY(-50%)` qui
   centre la pastille sur la barre. La variante du tiroir compose les deux. */
.gbs-cart .gbs-shipping-progress.is-pending .gbs-shipping-progress__truck{animation:gbsMarkerNudge 1.8s ease-in-out infinite}
@keyframes gbsMarkerNudge{0%,100%{box-shadow:0 5px 14px rgba(16,37,28,.12);transform:translateY(-50%) scale(1)}50%{box-shadow:0 7px 18px rgba(16,37,28,.16);transform:translateY(-50%) scale(1.06)}}
@media(prefers-reduced-motion:reduce){.gbs-cart .gbs-shipping-progress.is-pending .gbs-shipping-progress__truck{animation:none}}

/* Etat « seuil atteint » : une jauge pleine a 100 % n'a plus rien a dire et consommait la
   hauteur d'un bloc entier. La reference la remplace par une ligne compacte qui porte le delai. */
.gbs-cart .gbs-shipping-progress--unlocked{display:flex;min-height:0;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:4px 12px;padding:13px 15px 14px;border:1px solid rgba(180,145,70,.32);border-radius:16px;background:linear-gradient(135deg,rgba(255,250,238,.96),rgba(238,225,190,.68));box-shadow:0 10px 28px rgba(92,70,24,.06)}
.gbs-cart .gbs-shipping-progress__done{display:inline-flex;align-items:center;gap:7px;color:var(--green-dark);font-size:14px}
/* Le `<strong>` de cette ligne heritait encore de `.gbs-shipping-progress strong` (l. 17), qui
   met l'eyebrow de la jauge en CAPITALES avec 0.12em d'interlettrage : « LIVRAISON OFFERTE »
   au lieu du « Livraison offerte » de la reference. Mesure sur le staging apres deploiement. */
.gbs-cart .gbs-shipping-progress__done strong{font-size:inherit;letter-spacing:normal;text-transform:none}
.gbs-cart .gbs-shipping-progress__done svg{width:16px;height:16px;flex:0 0 16px}
.gbs-cart .gbs-shipping-progress__eta{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12.5px}
.gbs-cart .gbs-shipping-progress__eta svg{width:15px;height:15px;flex:0 0 15px}

/* Rail de suggestions */
.gbs-cart .gbs-reco-rail h2{letter-spacing:-.045em}
.gbs-cart .gbs-reco-card__add{min-height:36px}
.gbs-cart .gbs-reco-card__tag{backdrop-filter:blur(3px)}

/* La bande de recommandations du CORPS faisait doublon avec le rail de gauche : elle etait
   rendue a toutes les largeurs (l. 320) alors que le rail apparait des 901 px (l. 361), si
   bien qu'en desktop les memes suggestions occupaient deux surfaces. On la masque exactement
   la ou le rail est visible — regle symetrique de `.gbs-cart>.gbs-reco-rail{display:none}`
   (l. 395). Elle RESTE sous 900 px, ou le rail est masque et ou elle est la seule surface de
   recommandation ; c'est aussi ce que fait la reference, qui n'affiche jamais les deux. */
/* `not all and (max-width:900px)` et non `min-width:901px` : le COMPLÉMENT EXACT de la borne
   du rail, seul moyen de tenir la promesse « exactement là où le rail est visible » écrite
   juste au-dessus. Les deux bornes chiffrées laissaient un trou : une largeur strictement
   entre 900 et 901 px — que produisent le zoom navigateur et la mise à l'échelle de l'OS —
   n'activait AUCUNE des deux règles, et les deux surfaces s'affichaient ensemble (mesuré au
   `matchMedia` dans une iframe de 900,5 px : rail masqué = false, bande masquée = false).
   Tant que le pool était coupé en deux tranches disjointes, ce défaut ne montrait que des
   produits différents et restait invisible ; depuis que les deux surfaces servent la même
   tête de pool, il ferait apparaître les quatre mêmes cartes deux fois. */
@media not all and (max-width:900px){.gbs-cart .cart-recommendation-band{display:none}}

/* Pied */
.gbs-cart .gbs-cart-footer__total strong{font-size:22px}

/* (Le lissage `-webkit-font-smoothing` + `text-rendering` que cette couche posait ici a ete
   retire au rebase : la regle `body` en tete de fichier les porte desormais, avec la famille
   « Centra No2 » et le repli Helvetica Neue. Deux declarations identiques ne valent pas mieux
   qu'une, et celle d'en haut est au bon endroit.) */


/* ═══ V36 — TIROIR PANIER ══════════════════════════════════════════════════════════════════════
   Le markup du tiroir deploye sur le staging emettait `cart-line-body`, `cart-line-controls` et
   `objective-tag` alors que le CSS servi ne contenait AUCUNE regle pour ces classes : le staging
   recevait le markup d'une branche et la feuille d'une autre, chacune poussee par `scp` depuis
   une worktree differente. Tous les defauts signales viennent de ce seul decalage, pas d'un choix
   de style — le selecteur de quantite retombait sur `.gbs-quantity{width:150px}` (l. 37), la
   pastille d'objectif se collait a lui faute de `gap`, et le `<strong>` de la ligne de livraison
   heritait de `.gbs-shipping-progress strong{text-transform:uppercase;letter-spacing:.12em}`.

   Les valeurs sont MESUREES par getComputedStyle sur `docs/design/templates/
   german-beautyshop-storefront.html` a 1440x900, jamais lues dans la feuille : ce fichier empile
   une trentaine de couches de surcharges et la valeur effective n'est presque jamais la premiere
   qu'on lit. Les `font-weight` ne sont volontairement pas touches : une seule face est declaree
   et `font-synthesis:none` les rend inertes des deux cotes (cf. note V33 en tete de fichier).
   La police, elle, etait deja identique — meme woff2, meme sha1, `measureText` a 382,14 px des
   deux cotes. Ce qui se lisait comme « pas la meme police » etait l'ECHELLE. */

/* Palette : le tiroir de la reference est peint avec la couche `--v9-*`, plus verte et plus
   chaude que la palette de base. On redefinit les jetons DANS le tiroir seulement — chaque regle
   existante suit sans etre reecrite, et rien ne bouge ailleurs sur le site. */
.gbs-cart{
  --ink:#10251c;--ink-soft:#30463d;--paper:#fbf8f2;
  --green:#174f3c;--green-dark:#0c3427;--green-soft:#dfeae3;
  --gold:#b89c5f;--gold-soft:#eee1c3;
  --line:rgba(16,37,28,.14);--line-strong:rgba(20,61,47,.22);
}

/* ── En-tete : 23 px contre 31, compteur en 12 px sourdine contre 16 px encre. */
.gbs-cart .gbs-cart-head h2{font-size:23px;letter-spacing:-.035em}
.gbs-cart .gbs-cart-head>div>span{display:block;max-width:285px;margin-top:3px;overflow:hidden;color:#626960;font-size:12px;text-overflow:ellipsis;white-space:nowrap}

/* ── Ligne de panier : la reference EMPILE titre, prix puis selecteur dans une colonne unique,
      et donne a la croix de suppression sa propre piste de 44 px. L'etat precedent posait le
      selecteur et le montant cote a cote et la croix en position absolue, ce qui obligeait a
      reserver 30 px de padding sous le titre pour qu'il ne passe pas dessous. Trois colonnes
      reelles suppriment la reserve et la superposition. */
.gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle){grid-template-columns:72px minmax(0,1fr) 44px;gap:11px;align-items:start;padding:14px 0}
/* Le media ne couvre plus trois rangees implicites : la colonne 2 n'a qu'un enfant. */
.gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle) .gbs-cart-line__media{grid-row:auto}
.gbs-cart .cart-line-body{display:flex;min-width:0;flex-direction:column;align-items:flex-start}
.gbs-cart .cart-line-body>.gbs-cart-line__title{max-width:100%;margin:2px 0 6px}
.gbs-cart .gbs-cart-line strong{font-size:14px;line-height:1.35}
.gbs-cart .cart-line-body>.gbs-cart-line__price{display:block;font-size:18px;font-variant-numeric:tabular-nums;white-space:nowrap}
.gbs-cart .cart-line-body>.gbs-quantity{margin-top:7px}
/* Selecteur : grille 34/24/34 = 94 x 36 px bordures comprises, contre une boite flex de 150 px
   dont le chiffre heritait des 16 px du corps de page. La pilule pesait 120 x 46 px, autant que
   le prix de la ligne, pour un controle secondaire (l'action primaire du tiroir est Commander).
   Le sizing des boutons est pose ICI, scope au tiroir, et non sur la regle globale
   `.gbs-quantity button` : celle-ci reste la seule source de la forme en pilule, et la laisser
   intacte permet de restaurer 44 px au toucher sous 640 px par simple surcharge.
   Le chiffre passe de 12 a 13 px tabulaires : il etait plus petit que les glyphes « - » et
   « + » alors que c'est la seule information utile du controle.
   PAS de `font-weight` ici, et ce n'est pas un oubli : le theme ne declare qu'UNE face
   @font-face pour "Centra No2" (poids 400, l. 35 ; les .woff2 medium et bold existent sur
   disque mais ne sont references nulle part) et `body{font-synthesis:none}` interdit tout
   emboldissement synthetique. Mesure : la chasse de « 188 » est identique a 400, 600, 700 et
   800 (23,41 px). Toute graisse posee ici serait une propriete morte qui ment au lecteur. */
.gbs-cart .gbs-quantity{display:inline-grid;width:auto;min-height:34px;grid-template-columns:34px 24px 34px;overflow:hidden}
.gbs-cart .gbs-quantity button{width:34px;height:34px;font-size:14px}
.gbs-cart .gbs-quantity span{font-size:13px;font-variant-numeric:tabular-nums;text-align:center}
/* La croix etait un glyphe texte de 25 px sans cible tactile ni etat de survol. La cible et le
   rond valent pour TOUTES les lignes ; la sortie du flux absolu, non.
   La ligne PACK garde ses deux colonnes (`72px 1fr`, l. 314) : lui rendre la croix `static` en
   faisait un item de grille ordinaire, que le placement automatique projetait dans une TROISIEME
   rangee implicite sous le prix. Mesure sur une ligne pack reconstituee dans le DOM du staging :
   croix a x=83 y=124 au lieu du coin, ligne allongee de 44 px. Le `:not()` est donc obligatoire
   partout ou la regle depend des trois pistes, pas seulement sur la regle de grille. */
.gbs-cart .gbs-remove{display:grid;width:44px;height:44px;place-items:center;border-radius:50%}
.gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle) .gbs-remove{position:static}
.gbs-cart .gbs-remove svg{width:15px;height:15px}
.gbs-cart .gbs-remove:hover{color:var(--danger);background:#f5e9e6}

/* ── Ligne PACK : `cart_panel()` emet `<small>`/`<strong>`/`<em>`, trois elements INLINE, et
      aucune regle ne les visait — les trois textes se collaient en une phrase illisible
      (« Pack -5 %Routine cheveux completes3 mois de cure »). La reference les empile parce
      qu'elle utilise `<h3>` et `<p>`. Valeurs alignees sur l'echelle deja etablie du tiroir et
      NON mesurees sur la reference : son panier de demonstration n'avait pas de pack. */
.gbs-cart .gbs-cart-line--bundle>a>span:last-child{display:flex;min-width:0;flex-direction:column;gap:4px}
.gbs-cart .gbs-cart-line--bundle small{color:var(--green);font-size:11px;letter-spacing:.06em;text-transform:uppercase}
.gbs-cart .gbs-cart-line--bundle strong{font-size:14px;line-height:1.35}
.gbs-cart .gbs-cart-line--bundle em{display:-webkit-box;overflow:hidden;color:var(--muted);font-size:12px;font-style:normal;line-height:1.45;-webkit-box-orient:vertical;-webkit-line-clamp:2}

/* ── Bande de livraison. La reference garde sa jauge doree meme a 100 % (eyebrow « AVANTAGE
      DEBLOQUE » + message + piste pleine) ; le storefront a fait le choix contraire d'une ligne
      compacte qui porte le delai, la seule information encore utile une fois le seuil franchi.
      Divergence assumee et conservee. Le commentaire de `gbs_storefront_shipping_progress_html()`
      qui la justifiait affirmait que « Avantage debloque » n'existe nulle part dans la reference :
      c'est faux, il est ligne 11202 du template. Corrige a la source. */
.gbs-cart-shipping-top{padding:11px 26px 13px;border-bottom:1px solid var(--line);background:#f1ece2}
.gbs-cart-shipping-top:empty{display:none}
.gbs-cart .gbs-shipping-progress{display:block;padding:0;border:0;background:transparent;color:var(--ink)}

/* Etat « en cours » : une barre de 4 px, la pastille d'objectif conservee et le pourcentage —
   absent jusqu'ici.
   Le libelle « Objectif livraison » (le `<strong>` de ce `<p>`) est DELIBEREMENT laisse tel
   quel : `fix/gbs-shipping-goal-label` (dd4dad3c) vient de lui donner `display:block` pour le
   decoller du message, et ce correctif est deploye. Une passe anterieure du tiroir le mettait a
   `display:none` ; scopee `.gbs-cart` et posee plus bas, elle aurait annule ce correctif dans le
   tiroir sans que personne ne le voie — la surface ou il a justement ete signale. Cet element
   appartient a ce chantier-la, pas a celui-ci. */
.gbs-cart .gbs-shipping-progress__copy{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:8px}
.gbs-cart .gbs-shipping-progress__copy p{margin:0}
.gbs-cart .gbs-shipping-progress__copy p>span{display:block;color:var(--ink);font-size:13px;letter-spacing:normal;line-height:1.35;text-transform:none}
.gbs-cart .gbs-shipping-progress__percent{flex:0 0 auto;color:var(--green);font-size:11.5px;font-variant-numeric:tabular-nums}
.gbs-cart .gbs-shipping-progress i{position:relative;display:block;height:4px;margin-top:10px;overflow:visible;border-radius:999px;background:rgba(23,79,60,.13)}
.gbs-cart .gbs-shipping-progress i b{display:block;height:100%;border-radius:inherit;background:linear-gradient(90deg,var(--green),#2f7a5d);box-shadow:0 3px 9px rgba(23,79,60,.17);transition:width 280ms cubic-bezier(.2,.75,.2,1)}
.gbs-cart .gbs-shipping-progress__truck{position:absolute;top:50%;inset-block-end:auto;inset-inline-end:-1px;width:26px;height:26px;border:2px solid var(--green);background:var(--paper);box-shadow:0 5px 14px rgba(16,37,28,.12);transform:translateY(-50%)}
.gbs-cart .gbs-shipping-progress__truck svg{width:13px;height:13px}
/* `gbsPulse` ne porte qu'un `scale()` : applique ici il ecraserait le `translateY(-50%)` qui
   centre la pastille sur la barre. La variante du tiroir compose les deux. */
.gbs-cart .gbs-shipping-progress.is-pending .gbs-shipping-progress__truck{animation:gbsMarkerNudge 1.8s ease-in-out infinite}
@keyframes gbsMarkerNudge{0%,100%{box-shadow:0 5px 14px rgba(16,37,28,.12);transform:translateY(-50%) scale(1)}50%{box-shadow:0 7px 18px rgba(16,37,28,.16);transform:translateY(-50%) scale(1.06)}}
@media(prefers-reduced-motion:reduce){.gbs-cart .gbs-shipping-progress.is-pending .gbs-shipping-progress__truck{animation:none}}

/* Etat « seuil atteint ». Les deux items etaient des `<span>` inline dans un parent en grille :
   leurs SVG retombaient sur `svg{width:1.35em}` (l. 37) et se posaient sur la ligne de base du
   texte, d'ou l'icone qui « n'est pas symetrique » avec son libelle. `inline-flex` +
   `align-items:center` + une taille de SVG figee en px alignent les deux centres optiques. */
.gbs-cart .gbs-shipping-progress--unlocked{display:flex;min-height:0;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:4px 12px;padding:13px 15px 14px;border:1px solid rgba(180,145,70,.32);border-radius:16px;background:linear-gradient(135deg,rgba(255,250,238,.96),rgba(238,225,190,.68));box-shadow:0 10px 28px rgba(92,70,24,.06)}
.gbs-cart .gbs-shipping-progress__done{display:inline-flex;align-items:center;gap:7px;color:var(--green-dark);font-size:14px}
/* Le `<strong>` heritait de `.gbs-shipping-progress strong` (l. 37), qui met l'eyebrow de la
   jauge en CAPITALES avec 0.12em d'interlettrage : « LIVRAISON OFFERTE » la ou la reference
   ecrit « Livraison offerte ». */
.gbs-cart .gbs-shipping-progress__done strong{font-size:inherit;letter-spacing:normal;text-transform:none}
.gbs-cart .gbs-shipping-progress__done svg{flex:0 0 16px;width:16px;height:16px}
.gbs-cart .gbs-shipping-progress__eta{display:inline-flex;align-items:center;gap:6px;color:var(--muted);font-size:12.5px}
.gbs-cart .gbs-shipping-progress__eta svg{flex:0 0 15px;width:15px;height:15px}

/* ── Rail de suggestions : carte HORIZONTALE de la reference (media 82x98 a gauche, titre et
      pied a droite) et bouton d'ajout en pastille RONDE de 44x44. L'etat precedent empilait la
      carte a la verticale et donnait au bouton toute la largeur : `.gbs-icon-button,
      .gbs-reco-card__add{block-size:44px}` (l. 152) fixait deja sa hauteur, `width:100%`
      (l. 214) sa largeur, et la regle `min-height:36px` posee plus bas ne pouvait rien contre
      un `block-size` jamais redeclare. La forme horizontale n'est pas une invention : c'est
      celle de `.gbs-reco-card--band` (l. 346), reemployee ici. */
/* 19 px / 1.08 mesures sur la reference (`#cart-recommendations-title`), contre 15 px ici. */
.gbs-cart .gbs-reco-rail h2{font-size:19px;line-height:1.08;letter-spacing:-.045em}
/* Geometrie du rail reprise de la reference : colonne de 240 px et `padding:16px 10px`, soit
   220 px utiles. Une passe anterieure l'avait resserree a 220/`24px 16px` (l. 219) pour donner
   la largeur liberee au panneau — un arbitrage qui se tenait pour une carte VERTICALE, dont le
   prix disposait de toute la largeur. Sur la carte horizontale il ne tient plus : mesure a
   1440x900 avant correction, la colonne de texte tombait a 82 px, le prix a 30 px, et un prix
   barre (« 450 DH 399 DH ») se cassait sur QUATRE lignes en poussant la carte a 148 px. Avec
   les 220 px de la reference, la colonne de texte revient a 64 px — sa valeur mesuree la-bas. */
.gbs-cart .gbs-reco-rail{padding:16px 10px}
@media not all and (max-width:900px){.gbs-cart{grid-template-columns:240px minmax(0,480px)}}
.gbs-cart .gbs-reco-list-v29,.gbs-cart .gbs-reco-list{gap:9px}
/* Le bouton occupe une PISTE PROPRE de 44 px sur toute la hauteur, comme dans la reference, et
   non une place dans le pied a cote du prix : `display:contents` sur `.gbs-reco-card__foot`
   dissout l'enveloppe pour que prix et bouton deviennent des items de la grille de la carte.
   Sans cela, le bouton ampute le prix de ses 44 px et c'est le prix qui se casse. */
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact{
  display:grid;
  grid-template-columns:82px minmax(0,1fr) 44px;
  grid-template-rows:minmax(0,1fr) auto auto;
  align-items:start;
  gap:6px 8px;
  min-height:114px;
  padding:7px;
  border-radius:15px;
}
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__link,
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__foot{display:contents}
/* `max-height` heritee de la regle « 3 photos entieres dans le rail » (l. 365) : elle existait
   pour une carte verticale dont la vignette portait toute la hauteur. La carte horizontale fait
   114 px quelle que soit la fenetre, le plafond n'a plus d'objet et ecraserait le media. */
/* Chaque enfant est place EXPLICITEMENT. Le pied etant dissous par `display:contents`, le
   placement automatique remplissait les cellules dans l'ordre du DOM : le prix tombait dans la
   piste de 44 px reservee au bouton et se cassait sur quatre lignes, le bouton se retrouvait
   dans la colonne de texte. Mesure a 1440x900 : prix large de 44 px, carte a 144 px. */
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__media{grid-column:1;grid-row:1/4;align-self:center;width:82px;height:98px;min-height:0;max-height:none;aspect-ratio:auto;border-radius:11px}
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact strong{grid-column:2;grid-row:1;align-self:start;height:auto;font-size:12px;line-height:1.32;-webkit-line-clamp:3}
/* Le badge prend sa PROPRE ligne, pleine largeur. Dans la colonne de texte il n'avait que 48 px
   pour ses mots (carte de 220 px decoupee en 82/62/44) : « Debloque la livraison offerte » se
   cassait sur QUATRE lignes et portait la carte a 162 px quand ses voisines font 114 — mesure a
   1440x900, le jour ou le badge est revenu dans le rail. La ligne 4 est implicite, donc les
   cartes SANS badge gardent leurs trois lignes et leur hauteur. */
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__unlock{grid-column:1/-1;grid-row:4;font-size:10.5px}
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__price{grid-column:2;grid-row:3;align-self:end;font-size:15px;line-height:1.2}
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__add{grid-column:3;grid-row:1/4;align-self:end;justify-self:end}
/* La pastille d'objectif etait posee sur une vignette pleine largeur. Sur 82 px elle serait
   tronquee des le deuxieme mot (« Cuir ch… ») ; la reference n'en met pas sur ses cartes de
   rail. Elle reste en place partout ailleurs (accueil, catalogue, bande sous 900 px). */
.gbs-cart .gbs-reco-rail .gbs-reco-card.is-compact .gbs-reco-card__tag{display:none}
/* Le bouton : meme geometrie que `.gbs-icon-button` (l. 152 + l. 37), en pastille pleine. */
.gbs-cart .gbs-reco-card__add{
  display:grid;
  width:44px;min-width:44px;height:44px;min-height:44px;flex:0 0 44px;
  place-items:center;
  border:0;border-radius:50%;
  padding:0;
  background:var(--green);color:#fff;
  font-size:24px;line-height:1;
}
/* Sous 900 px le rail disparait et c'est la BANDE qui porte les suggestions. Sa regle propre
   `.gbs-reco-card--band.is-compact .gbs-reco-card__add` (l. 361) pose `width:auto;padding:0 13px`
   — dimensionnee pour le mot « Ajouter ». Avec un « + » et un rayon de 50 %, elle donnait une
   ellipse de 33x44 (mesure a 375x812). Elle est plus specifique que la regle ci-dessus : il faut
   la battre explicitement, pas esperer que la cascade s'en charge. */
.gbs-cart .gbs-reco-card--band.is-compact .gbs-reco-card__add{width:44px;min-width:44px;height:44px;min-height:44px;padding:0;font-size:24px}
.gbs-cart .gbs-reco-card__add:hover{background:var(--green-dark)}
.gbs-cart .gbs-reco-card__add:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
/* L'accuse d'ajout etait « fond vert, texte blanc » — invisible sur un bouton deja vert plein.
   La reference inverse la pastille a la confirmation. */
.gbs-cart .gbs-reco-card__add.is-added{background:var(--green-soft);color:var(--green-dark)}
.gbs-cart .gbs-reco-card__add[disabled]{opacity:.55}

/* La bande de recommandations du CORPS faisait doublon avec le rail de gauche : elle etait
   rendue a toutes les largeurs alors que le rail apparait des 901 px, si bien qu'en desktop les
   memes suggestions occupaient deux surfaces. On la masque exactement la ou le rail est visible
   — regle symetrique de `.gbs-cart>.gbs-reco-rail{display:none}` sous 900 px. Elle RESTE sous
   900 px, ou elle est la seule surface de recommandation ; c'est aussi ce que fait la reference,
   qui n'affiche jamais les deux. */
/* `not all and (max-width:900px)` et non `min-width:901px` : le COMPLÉMENT EXACT de la borne
   du rail, seul moyen de tenir la promesse « exactement là où le rail est visible » écrite
   juste au-dessus. Les deux bornes chiffrées laissaient un trou : une largeur strictement
   entre 900 et 901 px — que produisent le zoom navigateur et la mise à l'échelle de l'OS —
   n'activait AUCUNE des deux règles, et les deux surfaces s'affichaient ensemble (mesuré au
   `matchMedia` dans une iframe de 900,5 px : rail masqué = false, bande masquée = false).
   Tant que le pool était coupé en deux tranches disjointes, ce défaut ne montrait que des
   produits différents et restait invisible ; depuis que les deux surfaces servent la même
   tête de pool, il ferait apparaître les quatre mêmes cartes deux fois. */
@media not all and (max-width:900px){.gbs-cart .cart-recommendation-band{display:none}}

/* ── Pied : 22 px contre 24. */
.gbs-cart .gbs-cart-footer__total strong{font-size:22px}

/* ── Paliers MOBILES du tiroir. La passe precedente n'avait porte que l'echelle desktop : sous
      900 px le tiroir gardait la typographie de bureau, et la reference, elle, a deux paliers
      distincts (mesures a 768x1024 et 375x812 sur le template rendu).

      Defaut corrige au passage : la piste et la vignette avaient DIVERGE. Le bloc mobile
      historique (l. 432-434) pose une vignette de 84x96 pour une piste de 84 px, mais la nouvelle
      grille de ligne impose 72 px et gagne en specificite — l'image debordait donc sa piste de
      12 px a 375 comme a 768. La reference met 82x90 des deux cotes sous 900 px. */
@media(max-width:900px){
  .gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle){grid-template-columns:82px minmax(0,1fr) 44px;gap:13px}
  .gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle) .gbs-cart-line__media{width:82px;height:90px}
  .gbs-cart .gbs-cart-line:not(.gbs-cart-line--bundle) .gbs-cart-line__media img{width:75px;height:83px}
  .gbs-cart .gbs-cart-head h2{font-size:25px}
  .gbs-cart-shipping-top{padding:12px 24px 15px}

  /* La BANDE reprend la carte du rail : la reference emploie la meme carte sur ses deux surfaces
     de recommandation, seul le conteneur change. La forme heritee (vignette de 76 px collee au
     bord, carte sans padding) datait d'une carte verticale et ne s'accorde plus au bouton rond. */
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact{display:grid;grid-template-columns:82px minmax(0,1fr) 44px;grid-template-rows:minmax(0,1fr) auto auto;align-items:start;gap:6px 8px;min-height:114px;padding:7px;overflow:visible;border-radius:15px}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__link,
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__foot{display:contents}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__media{grid-column:1;grid-row:1/4;align-self:center;width:82px;height:98px;min-height:0;max-height:none;aspect-ratio:auto;border-inline-end:0;border-radius:11px}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact strong{grid-column:2;grid-row:1;align-self:start;height:auto;margin:0;padding:0;font-size:12px;line-height:1.32;-webkit-line-clamp:3}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__unlock{grid-column:2;grid-row:2;padding:0;font-size:10.5px}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__price{grid-column:2;grid-row:3;align-self:end;padding:0;font-size:15px;line-height:1.2}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__add{grid-column:3;grid-row:1/4;align-self:end;justify-self:end;width:44px;min-width:44px;height:44px;min-height:44px;padding:0;font-size:24px}
  .gbs-cart .cart-recommendation-band .gbs-reco-card.is-compact .gbs-reco-card__tag{display:none}
}

/* Second palier : la reference descend d'un cran toute son echelle sous 640 px et masque la note
   de pied, qui n'apporte rien sur un ecran de telephone ou le pied est deja fixe. */
@media(max-width:640px){
  .gbs-cart .gbs-cart-head h2{font-size:21px}
  .gbs-cart .gbs-cart-line strong{font-size:13px}
  .gbs-cart .cart-line-body>.gbs-cart-line__price{font-size:17px}
  /* Le retrecissement du selecteur s'arrete au desktop : sous 640 px la cible reste 44 x 44.
     Le chiffre garde en revanche ses 13 px tabulaires, qui ne coutent aucune place. */
  .gbs-cart .gbs-quantity{min-height:44px;grid-template-columns:44px 28px 44px}
  .gbs-cart .gbs-quantity button{width:44px;height:44px;font-size:16px}
  .gbs-cart .gbs-cart-footer__total strong{font-size:19px}
  .gbs-cart .drawer-shipping-status{max-width:140px;justify-content:flex-end}
  .gbs-cart .drawer-footer-note{display:none}
  .gbs-cart-shipping-top{padding:11px 15px 14px}
}

/* Une tablette tactile fait plus de 640 px de large et se manipule pourtant avec le meme doigt :
   la largeur du viewport ne dit RIEN de la capacite de pointage. Sans ce bloc, un iPad (768 ou
   810 px en portrait) tombait dans le bucket « desktop » et recevait des cibles de 34 px, alors
   qu'avant le retrecissement il heritait des 44 px de la regle globale — une regression, pas un
   choix. On restaure donc la cible des que le pointeur est grossier, quelle que soit la largeur.
   Meme motif que reviews.css. A placer APRES le @media(max-width:640px) : specificite egale,
   c'est l'ordre source qui tranche, et sur telephone les deux blocs disent la meme chose. */
@media(pointer:coarse){
  .gbs-cart .gbs-quantity{min-height:44px;grid-template-columns:44px 28px 44px}
  .gbs-cart .gbs-quantity button{width:44px;height:44px;font-size:16px}
}

/* ── En-tête mobile : deux icônes de chaque côté. Le template posait le hamburger seul à gauche
   et trois ronds à droite ; la recherche rejoint le menu. `.gbs-header-actions` passe en
   `display:contents` pour que ses trois ronds deviennent des items de la grille de l'en-tête :
   le hamburger prend la piste 1, la recherche la 2, compte et panier sont replacés explicitement
   sur les pistes 4 et 5. Le logo reste `position:absolute` centré, donc hors flux, et `.gbs-nav`
   `position:fixed` — l'en-tête n'a que ces items dans son flux sous 900 px.
   `column-gap:7px` reprend exactement le `gap` que `.gbs-header-actions` posait plus haut : la
   largeur totale d'encre est inchangée (190 px), donc aucun débordement nouveau — mesuré à 375
   et 320 px, `scrollWidth === innerWidth`. Les pistes étant logiques, le miroir RTL est correct
   sans règle dédiée (vérifié sous `/ar/`).
   INVARIANT : ces règles comptent TROIS enfants dans `.gbs-header-actions` (recherche, compte,
   panier — identique sur accueil, boutique, produit, panier, mon-compte). Tout bouton ajouté ici
   doit recevoir son propre `grid-column`, sinon il atterrit dans la piste souple, au milieu de
   l'en-tête. Bornées à 900 px : au-delà, le hamburger est masqué et l'en-tête retrouve ses trois
   enfants pour ses trois pistes. Placées après la ligne 490 : la grille mobile de la ligne 167 a
   la même spécificité, il faut passer après elle. */
@media(max-width:900px){
  .gbs-header{grid-template-columns:44px 44px minmax(0,1fr) auto auto;column-gap:7px}
  .gbs-header>.gbs-header-actions{display:contents}
  .gbs-header>.gbs-header-actions>.gbs-account-button{grid-column:4}
  .gbs-header>.gbs-header-actions>[data-gbs-open="cart"]{grid-column:5}
}

/* ── Appel WhatsApp transverse ─────────────────────────────────────────────────────────────────
   Ces regles vivaient dans home.css, enqueue seulement si is_front_page() : depuis que footer.php
   rend la bande sur toutes les routes, elles doivent vivre dans la seule feuille servie partout.
   Reprises a l'identique — aucun changement de valeur. */
.gbs-final-cta{padding-block:0 96px}
.gbs-final-cta__shell{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:30px;overflow:hidden;border-radius:34px;padding:53px 58px;background:var(--ink);color:#fff}
.gbs-final-cta__shell h2{max-width:720px;margin:0;font-size:clamp(42px,5vw,66px);font-weight:800;letter-spacing:-.055em;line-height:.92}
.gbs-final-cta__shell p{max-width:620px;margin:14px 0 0;color:rgba(255,255,255,.66);font-size:12px;line-height:1.65}
.gbs-final-cta__shell .gbs-button{white-space:nowrap}
.gbs-final-cta__shell .gbs-button svg{width:18px;height:18px}
[dir=rtl] .gbs-final-cta__shell h2{line-height:1.15}
@media(max-width:900px){
  .gbs-final-cta{padding-block:0 72px}
  .gbs-final-cta__shell{grid-template-columns:1fr}
}
@media(max-width:640px){
  .gbs-final-cta{padding-block:0 52px}
  .gbs-final-cta__shell{border-radius:24px;padding:38px 23px}
  .gbs-final-cta__shell h2{font-size:46px}
  .gbs-final-cta__shell .gbs-button{width:100%}
}

/* ── Bulle WhatsApp permanente.
   z-index 150 : SOUS la barre d'achat produit (160), la barre du tunnel (170), la nav mobile (240),
   le tiroir de filtres (430) et le voile du panier (500). La bulle ne passe donc jamais devant un
   tiroir ni devant un voile. Positionnement en proprietes logiques : sur /ar/ (dir=rtl) elle
   bascule seule du cote gauche, aucune regle .rtl n'est necessaire.
   Le repli de var(--focus) est OBLIGATOIRE : le token n'existe pas dans toutes les lignees de cette
   feuille, et une var() non resolue rend la declaration `outline` entierement invalide — donc
   aucun anneau au clavier. */
.gbs-wa-fab{--gbs-fab-lift:96px;position:fixed;z-index:150;inset-inline-end:max(16px,env(safe-area-inset-right));bottom:max(16px,env(safe-area-inset-bottom));width:56px;height:56px;border-radius:999px;background:var(--green);color:#fff;display:inline-flex;align-items:center;justify-content:center;box-shadow:0 14px 32px rgba(0,0,0,.22);transition:transform .22s ease,opacity .18s ease,visibility .18s ease}
.gbs-wa-fab svg{width:28px;height:28px}
.gbs-wa-fab:hover,.gbs-wa-fab:focus-visible{background:var(--green-dark)}
.gbs-wa-fab:focus-visible{outline:3px solid var(--focus,var(--gold));outline-offset:3px}
.gbs-wa-fab.is-hidden{opacity:0;visibility:hidden;pointer-events:none}

/* La barre d'achat des fiches produit est `position:fixed` pleine largeur : sans ce relevement la
   bulle se poserait dessus des qu'elle glisse a l'ecran (.is-visible). */
body:has(.gbs-buy-dock.is-visible) .gbs-wa-fab{transform:translateY(calc(-1 * var(--gbs-fab-lift)))}
@media(max-width:900px){.gbs-wa-fab{--gbs-fab-lift:82px}}
@media(prefers-reduced-motion:reduce){.gbs-wa-fab{transition:none}}

/* Panier — chiffre en attente du serveur.
   Le tiroir peint la mutation dans la frame du clic (voir `paintCartMutation`, storefront.js),
   mais un pas de quantite laisse un montant que le JS ne sait pas prouver : les paliers remisent
   le prix UNITAIRE et l'arrondissent au dirham. Plutot qu'un chiffre faux corrige une demi-seconde
   plus tard, on marque celui qui attend. Deux surfaces seulement, et jamais le bouton de commande :
   attenuer le CTA principal le ferait lire comme desactive.
   Classe posee sur le panneau, donc emportee par le remplacement de fragments qui l'eteint. */
.gbs-cart-panel-v29.is-syncing .gbs-cart-footer__total strong,
.gbs-cart-panel-v29.is-syncing .gbs-shipping-progress{opacity:.55;transition:opacity 140ms linear}
@media(prefers-reduced-motion:reduce){
  .gbs-cart-panel-v29.is-syncing .gbs-cart-footer__total strong,
  .gbs-cart-panel-v29.is-syncing .gbs-shipping-progress{transition:none}
}

/* Ligne de panier PROVISOIRE — peinte au clic sur une suggestion, avant la reponse serveur.
   Ses trois boutons naissent `disabled` cote PHP : la cle de ligne WooCommerce est un md5 filtre,
   donc imprevisible avant la reponse, et un clic posterait une cle vide (404). L'etat se lit donc
   sur la COULEUR des commandes, pas sur `opacity` : la regle `.is-syncing` posee au chantier
   precedent est chargee, son selecteur matche, et son `opacity` reste sans effet pour une raison
   encore inexpliquee — batir dessus reviendrait a empiler un second etat invisible.
   Les fragments remplacent la ligne par la vraie, cle comprise, ~500 ms plus tard. */
.gbs-cart-line.is-provisional .gbs-quantity,
.gbs-cart-line.is-provisional .gbs-remove{color:var(--muted)}
.gbs-cart-line.is-provisional .gbs-quantity button[disabled],
.gbs-cart-line.is-provisional .gbs-remove[disabled]{cursor:default}
